bool good_allocatable;
bool ultimate_ptr_comp;
bool ultimate_alloc_comp;
+ bool readonly;
gfc_symbol *sym;
stmtblock_t block;
gfc_ref *ref;
gfc_start_block (&block);
- /* Copy the data back. */
- if (fsym == NULL || fsym->attr.intent != INTENT_IN)
+ /* Copy the data back. If input expr is read-only, e.g. a PARAMETER
+ array, copying back modified values is undefined behavior. */
+ readonly = (expr->expr_type == EXPR_VARIABLE
+ && expr->symtree
+ && expr->symtree->n.sym->attr.flavor == FL_PARAMETER);
+
+ if ((fsym == NULL || fsym->attr.intent != INTENT_IN) && !readonly)
{
if (ctree)
{
gfc_se work_se;
gfc_se *parmse;
bool pass_optional;
+ bool readonly;
pass_optional = fsym && fsym->attr.optional && sym && sym->attr.optional;
/* Wrap the whole thing up by adding the second loop to the post-block
and following it by the post-block of the first loop. In this way,
- if the temporary needs freeing, it is done after use! */
- if (intent != INTENT_IN)
+ if the temporary needs freeing, it is done after use!
+ If input expr is read-only, e.g. a PARAMETER array, copying back
+ modified values is undefined behavior. */
+ readonly = (expr->expr_type == EXPR_VARIABLE
+ && expr->symtree
+ && expr->symtree->n.sym->attr.flavor == FL_PARAMETER);
+
+ if ((intent != INTENT_IN) && !readonly)
{
gfc_add_block_to_block (&parmse->post, &loop2.pre);
gfc_add_block_to_block (&parmse->post, &loop2.post);
--- /dev/null
+! { dg-do run }
+! PR fortran/81978 - do not copy back for parameter actual arguments
+
+module test_mod
+ implicit none
+
+ type pp_struct
+ character(10) :: name
+ real :: value
+ end type pp_struct
+
+ type(pp_struct), parameter :: pp(4) = [ &
+ pp_struct('one', 1.), &
+ pp_struct('two', 2.), &
+ pp_struct('three', 3.), &
+ pp_struct('four', 4.) ]
+
+contains
+
+ subroutine match_word (names)
+ character(*) :: names(:)
+ end subroutine match_word
+
+ subroutine sub0 (a)
+ real :: a(:)
+ end
+
+ subroutine sub1 (a, n)
+ integer, intent(in) :: n
+ real :: a(n)
+ end
+
+ subroutine subx (a)
+ real :: a(..)
+ end
+end module
+
+program test
+ use test_mod
+ implicit none
+ integer :: i, n
+ integer, parameter :: m = 8
+ real, parameter :: x(m) = [(i,i=1,m)]
+
+ n = size (x)
+ call sub0 (x)
+ call sub1 (x, n)
+ call sub2 (x, n)
+ call subx (x)
+
+ i = 1
+ call sub0 (x(1::i))
+ call sub1 (x(1::i), n)
+ call sub2 (x(1::i), n)
+ call subx (x(1::i))
+
+ n = size (x(1::2))
+ call sub0 (x(1::2))
+ call sub1 (x(1::2), n)
+ call sub2 (x(1::2), n)
+ call subx (x(1::2))
+
+ i = 2
+ call sub0 (x(1::i))
+ call sub1 (x(1::i), n)
+ call sub2 (x(1::i), n)
+ call subx (x(1::i))
+
+ call match_word (pp%name)
+ call sub0 (pp%value)
+ call subx (pp%value)
+ call match_word (pp(1::2)%name)
+ call sub0 (pp(1::2)%value)
+ call subx (pp(1::2)%value)
+ i = 1
+ call match_word (pp(1::i)%name)
+ call sub0 (pp(1::i)%value)
+ call subx (pp(1::i)%value)
+ i = 2
+ call match_word (pp(1::i)%name)
+ call sub0 (pp(1::i)%value)
+ call subx (pp(1::i)%value)
+
+ call foo (pp%name, size(pp%name))
+ call foo (pp(1::2)%name, size(pp(1::2)%name))
+ call sub1 (pp(1::2)%value, size(pp(1::2)%value))
+ call sub2 (pp(1::2)%value, size(pp(1::2)%value))
+ i = 1
+ call foo (pp(1::i)%name, size(pp(1::i)%name))
+ call sub1 (pp(1::i)%value, size(pp(1::i)%value))
+ call sub2 (pp(1::i)%value, size(pp(1::i)%value))
+ i = 2
+ call foo (pp(1::i)%name, size(pp(1::i)%name))
+ call sub1 (pp(1::i)%value, size(pp(1::i)%value))
+ call sub2 (pp(1::i)%value, size(pp(1::i)%value))
+end program
+
+subroutine sub2 (a, n)
+ integer, intent(in) :: n
+ real :: a(n)
+end
+
+subroutine foo (s, n)
+ integer, intent(in) :: n
+ character(*) :: s(*)
+! print *, len(s), n, s(n)
+end