Hello,

Le 30/07/2026 à 19:21, Jerry D a écrit :
See the attached patch.

As stated in the PR we were missing the stride multiplier (ie span)

I will note as a useful tool: I had an initial patch for this but wanted to exercise it. I prompted Claude Pro Opus 5 to create numerous variations on the original test case provided by Tobias Burnus in the original report. The result was 25 to 30 variations which were helpful in identifying code paths I would not have otherwise found.  I am not using those test cases here.

I flagged out this one to work on as it has been around a long time and we were giving wrong results without any idea it was happening.

I also wanted to mention that the fortran standardese is difficult to interpret but I think I got this right.

Regression tested on x86_64.

OK for mainline?

Comments appreciated.

Regards,

Jerry
---
    fortran: [PR53800] Wrong copy-in/out with CLASS array to assumed- shape TYPE

    A CLASS array actual passed to a plain assumed-shape derived-type dummy     was always copied in and out, so pointers associated with the dummy went
     stale on return.  F2023 15.5.2.5 paragraph 9 requires the dummy to be
    associated with the actual's storage when it has the TARGET attribute and     lacks CONTIGUOUS and VALUE; paragraph 8 leaves every other case free to     use a copy.  Pass such a dummy by reference and address its elements with
     the descriptor's runtime span.


diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 7b28ecfce47..4063bbe70c4 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -1070,6 +1070,7 @@ struct GTY(()) lang_decl {
   unsigned int scalar_pointer : 1;
   unsigned int scalar_target : 1;
   unsigned int optional_arg : 1;
+  unsigned int span_array : 1;
 };


@@ -1087,12 +1088,16 @@ struct GTY(()) lang_decl {
   (DECL_LANG_SPECIFIC (node)->scalar_target)
 #define GFC_DECL_OPTIONAL_ARGUMENT(node) \
   (DECL_LANG_SPECIFIC (node)->optional_arg)
+#define GFC_DECL_SPAN_ARRAY_P(node) \
+  (DECL_LANG_SPECIFIC (node)->span_array)
 #define GFC_DECL_GET_SCALAR_ALLOCATABLE(node) \
   (DECL_LANG_SPECIFIC (node) ? GFC_DECL_SCALAR_ALLOCATABLE (node) : 0)
 #define GFC_DECL_GET_SCALAR_POINTER(node) \
   (DECL_LANG_SPECIFIC (node) ? GFC_DECL_SCALAR_POINTER (node) : 0)
 #define GFC_DECL_GET_SCALAR_TARGET(node) \
   (DECL_LANG_SPECIFIC (node) ? GFC_DECL_SCALAR_TARGET (node) : 0)
+#define GFC_DECL_GET_SPAN_ARRAY_P(node) \
+  (DECL_LANG_SPECIFIC (node) ? GFC_DECL_SPAN_ARRAY_P (node) : 0)
 #define GFC_DECL_PACKED_ARRAY(node) DECL_LANG_FLAG_0(node)
 #define GFC_DECL_PARTIAL_PACKED_ARRAY(node) DECL_LANG_FLAG_1(node)
 #define GFC_DECL_ASSIGN(node) DECL_LANG_FLAG_2(node)

I have the impression that the information provided by the new flag is somehow redundant with the existing flag GFC_DECL_PTR_ARRAY_P, and indeed, need_span is used everywhere side by side with is_pointer_array. Could the flags be merged together, or maybe just reuse GFC_DECL_PTR_ARRAY_P?

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index cf7eddf6e1d..0daa3f2ddad 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 585d27fa5a2..c9e1f66edb1 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -7222,6 +7224,26 @@ conv_null_actual (gfc_se * parmse, gfc_expr * e, 
gfc_symbol * fsym)
 }
+/* Return true if a CLASS array actual may alias the derived-type dummy
+   FSYM rather than be passed through a copy-in/copy-out temporary.  F2023
+   15.5.2.5 paragraph 9 requires the association only for a TARGET
+   assumed-shape dummy without CONTIGUOUS or VALUE.  */
+
+static bool
+class_actual_aliases_type_dummy (gfc_symbol *fsym, bool nodesc_arg)
+{
+  return fsym != NULL
+        && fsym->ts.type == BT_DERIVED

The check on type is probably unneeded.
Here is a (failing) variation of the testcase with integer type:

diff --git a/gcc/testsuite/gfortran.dg/class_to_type_5.f90 b/gcc/testsuite/gfortran.dg/class_to_type_5.f90
index ad299db514d..50753bdf922 100644
--- a/gcc/testsuite/gfortran.dg/class_to_type_5.f90
+++ b/gcc/testsuite/gfortran.dg/class_to_type_5.f90
@@ -16,20 +16,20 @@ program class_to_type
     integer :: j
   end type t2
   class(t), target, allocatable :: a(:,:)
-  type(t), pointer :: ptr
+  integer, pointer :: ptr

   allocate (t2 :: a(5,5))
   a(:,:)%i = 53
   a(3,3)%i = 42
   a(4,4)%i = 74

-  call f (a)
-  if (ptr%i /= 42) stop 1
+  call f (a%i)
+  if (ptr /= 42) stop 1
   a(3,3)%i = 999
-  if (ptr%i /= 999) stop 2
+  if (ptr /= 999) stop 2
 contains
   subroutine f(x)
-    type(t), target :: x(:,:)
+    integer, target :: x(:,:)
     ptr => x(3,3)
   end subroutine f
 end program class_to_type


+        && fsym->attr.target
+        && !fsym->attr.pointer
Same for the check for pointer with the following variant:

diff --git a/gcc/testsuite/gfortran.dg/class_to_type_5.f90 b/gcc/testsuite/gfortran.dg/class_to_type_5.f90
index ad299db514d..3fcec17ec11 100644
--- a/gcc/testsuite/gfortran.dg/class_to_type_5.f90
+++ b/gcc/testsuite/gfortran.dg/class_to_type_5.f90
@@ -15,7 +15,7 @@ program class_to_type
   type, extends(t) :: t2
     integer :: j
   end type t2
-  class(t), target, allocatable :: a(:,:)
+  class(t), pointer :: a(:,:)
   type(t), pointer :: ptr

   allocate (t2 :: a(5,5))
@@ -27,9 +27,10 @@ program class_to_type
   if (ptr%i /= 42) stop 1
   a(3,3)%i = 999
   if (ptr%i /= 999) stop 2
+  deallocate(a)
 contains
   subroutine f(x)
-    type(t), target :: x(:,:)
+    type(t), pointer :: x(:,:)
     ptr => x(3,3)
   end subroutine f
 end program class_to_type


+        && !fsym->attr.value
+        && !fsym->attr.contiguous
+        && !nodesc_arg
+        && fsym->as != NULL
+        && fsym->as->type == AS_ASSUMED_SHAPE;
There is also AS_DEFERRED for the pointer case above, and also AS_ASSUMED_RANK with this variant:

diff --git a/gcc/testsuite/gfortran.dg/class_to_type_5.f90 b/gcc/testsuite/gfortran.dg/class_to_type_5.f90
index ad299db514d..84a8ef4aa7e 100644
--- a/gcc/testsuite/gfortran.dg/class_to_type_5.f90
+++ b/gcc/testsuite/gfortran.dg/class_to_type_5.f90
@@ -29,7 +29,12 @@ program class_to_type
   if (ptr%i /= 999) stop 2
 contains
   subroutine f(x)
-    type(t), target :: x(:,:)
-    ptr => x(3,3)
+    type(t), target :: x(..)
+    select rank(x)
+      rank(2)
+        ptr => x(3,3)
+      rank default
+        error stop 3
+    end select
   end subroutine f
 end program class_to_type


For the rest, the two get_array_span would need to be reworked to have the flags merged, but I think that's doable, and the rest looks good.

Mikael

Reply via email to