https://gcc.gnu.org/g:d4df61dc6ed90e6614db213119858adde939fc97

commit r14-11245-gd4df61dc6ed90e6614db213119858adde939fc97
Author: Harald Anlauf <anl...@gmx.de>
Date:   Sun Jan 19 21:06:56 2025 +0100

    Fortran: do not copy back for parameter actual arguments [PR81978]
    
    When an array is packed for passing as an actual argument, and the array
    has the PARAMETER attribute (i.e., it is a named constant that can reside
    in read-only memory), do not copy back (unpack) from the temporary.
    
            PR fortran/81978
    
    gcc/fortran/ChangeLog:
    
            * trans-array.cc (gfc_conv_array_parameter): Do not copy back data
            if actual array parameter has the PARAMETER attribute.
            * trans-expr.cc (gfc_conv_subref_array_arg): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            * gfortran.dg/pr81978.f90: New test.
    
    (cherry picked from commit 0d1e62b83561baa185bf080515750a89dd3ac410)

Diff:
---
 gcc/fortran/trans-array.cc            |  10 +++-
 gcc/fortran/trans-expr.cc             |  11 +++-
 gcc/testsuite/gfortran.dg/pr81978.f90 | 107 ++++++++++++++++++++++++++++++++++
 3 files changed, 124 insertions(+), 4 deletions(-)

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index d9aaa9bceae4..61f641aa4918 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -8653,6 +8653,7 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, 
bool g77,
   bool good_allocatable;
   bool ultimate_ptr_comp;
   bool ultimate_alloc_comp;
+  bool readonly;
   gfc_symbol *sym;
   stmtblock_t block;
   gfc_ref *ref;
@@ -9007,8 +9008,13 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, 
bool g77,
 
       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)
        {
          tmp = build_call_expr_loc (input_location,
                                 gfor_fndecl_in_unpack, 2, desc, ptr);
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 8e74fbfb257d..1efe435f397f 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -5028,6 +5028,7 @@ gfc_conv_subref_array_arg (gfc_se *se, gfc_expr * expr, 
int g77,
   gfc_se work_se;
   gfc_se *parmse;
   bool pass_optional;
+  bool readonly;
 
   pass_optional = fsym && fsym->attr.optional && sym && sym->attr.optional;
 
@@ -5244,8 +5245,14 @@ gfc_conv_subref_array_arg (gfc_se *se, gfc_expr * expr, 
int g77,
 
   /* 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);
diff --git a/gcc/testsuite/gfortran.dg/pr81978.f90 
b/gcc/testsuite/gfortran.dg/pr81978.f90
new file mode 100644
index 000000000000..b377eef7a16c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr81978.f90
@@ -0,0 +1,107 @@
+! { 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

Reply via email to