Re: [PATCH] fortran: [PR53800] Wrong copy-in/out with CLASS array to assumed-shape TYPE
Mikael Morin <[email protected]> Wed, 5 Aug 2026 12:25:49 +0200
| Newsgroups | gmane.comp.gcc.patches,gmane.comp.gcc.fortran |
|---|---|
| Message-ID | <[email protected]> |
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