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