See attached patch. A structure constructor that associates a CLASS
pointer component with a non-class target ICEs in fold_convert_loc for
a scalar component and segfaults in gfc_conv_scalarized_array_ref for
an array component. The POINTER attribute is on CLASS_DATA (cm), not on
cm, so gfc_trans_subcomponent_assign never takes a pointer branch and
treats the value as a derived-type or scalar copy. The patch adds a
branch that points _data at the target, through gfc_conv_expr_descriptor
with direct_byref for an array, sets _vptr from the target's vtab and,
for an unlimited polymorphic component, sets _len to the character
length or zero. A polymorphic value still takes the existing path.
The fix is the new CLASS pointer branch in gfc_trans_subcomponent_assign
in trans-expr.cc. structure_constructor_20.f90 covers scalar components,
including a CHARACTER target for class(*). structure_constructor_21.f90
covers array components and is adapted from test 0555_0400.f90 of the
Fujitsu compiler test suite.
Regression tested on x86_64.
OK for mainline?
Regards,
Jerry
---
fortran: [PR125721] Fix ICE for a class pointer component in a structure
constructor
In a structure constructor, associate a scalar or array CLASS pointer
component with a non-class target: set _data, _vptr and, for an
unlimited polymorphic component, _len.
Assisted-by: Claude Opus 5.5
PR fortran/125721
gcc/fortran/ChangeLog:
* trans-expr.cc (gfc_trans_subcomponent_assign): Handle a CLASS
pointer component with a non-class target.
gcc/testsuite/ChangeLog:
* gfortran.dg/structure_constructor_20.f90: New test.
* gfortran.dg/structure_constructor_21.f90: New test.
>From 089f2437a75af6d5eb848c6a92d74e6a0ea92809 Mon Sep 17 00:00:00 2001
From: Jerry DeLisle <[email protected]>
Date: Wed, 10 Jun 2026 08:36:59 -0700
Subject: [PATCH] fortran: [PR125721] Fix ICE for a class pointer component in
a structure constructor
In a structure constructor, associate a scalar or array CLASS pointer
component with a non-class target: set _data, _vptr and, for an
unlimited polymorphic component, _len.
Assisted-by: Claude Opus 5.5
PR fortran/125721
gcc/fortran/ChangeLog:
* trans-expr.cc (gfc_trans_subcomponent_assign): Handle a CLASS
pointer component with a non-class target.
gcc/testsuite/ChangeLog:
* gfortran.dg/structure_constructor_20.f90: New test.
* gfortran.dg/structure_constructor_21.f90: New test.
---
gcc/fortran/trans-expr.cc | 33 ++++++++++
.../gfortran.dg/structure_constructor_20.f90 | 55 +++++++++++++++++
.../gfortran.dg/structure_constructor_21.f90 | 61 +++++++++++++++++++
3 files changed, 149 insertions(+)
create mode 100644 gcc/testsuite/gfortran.dg/structure_constructor_20.f90
create mode 100644 gcc/testsuite/gfortran.dg/structure_constructor_21.f90
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 2d04fd79061..8ebaba045ad 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -10466,6 +10466,39 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm,
false);
gfc_add_expr_to_block (&block, tmp);
}
+ else if (cm->ts.type == BT_CLASS && CLASS_DATA (cm)->attr.class_pointer
+ && expr->ts.type != BT_CLASS)
+ {
+ /* Associate a CLASS pointer component with a non-class target. */
+ gfc_init_se (&se, NULL);
+ if (CLASS_DATA (cm)->attr.dimension)
+ {
+ se.direct_byref = 1;
+ se.expr = gfc_class_data_get (dest);
+ gfc_conv_expr_descriptor (&se, expr);
+ gfc_add_block_to_block (&block, &se.pre);
+ }
+ else
+ {
+ gfc_conv_expr_reference (&se, expr);
+ gfc_add_block_to_block (&block, &se.pre);
+ tmp = gfc_class_data_get (dest);
+ gfc_add_modify (&block, tmp, fold_convert (TREE_TYPE (tmp), se.expr));
+ }
+ vtab = gfc_get_symbol_decl (gfc_find_vtab (&expr->ts));
+ vtab = gfc_build_addr_expr (NULL_TREE, vtab);
+ tmp = gfc_class_vptr_get (dest);
+ gfc_add_modify (&block, tmp, fold_convert (TREE_TYPE (tmp), vtab));
+ if (UNLIMITED_POLY (cm))
+ {
+ tmp = gfc_class_len_get (dest);
+ gfc_add_modify (&block, tmp,
+ expr->ts.type == BT_CHARACTER
+ ? fold_convert (TREE_TYPE (tmp), se.string_length)
+ : build_zero_cst (TREE_TYPE (tmp)));
+ }
+ gfc_add_block_to_block (&block, &se.post);
+ }
else if ((cm->attr.dimension || cm->attr.codimension)
&& !cm->attr.proc_pointer)
{
diff --git a/gcc/testsuite/gfortran.dg/structure_constructor_20.f90 b/gcc/testsuite/gfortran.dg/structure_constructor_20.f90
new file mode 100644
index 00000000000..fc6b2f7aa5b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/structure_constructor_20.f90
@@ -0,0 +1,55 @@
+! { dg-do run }
+!
+! PR 125721
+!
+! A structure constructor associating a class pointer component (unlimited
+! polymorphic or typed) with a target used to ICE in
+! gfc_trans_subcomponent_assign (fold_convert_loc), because the pointer
+! attribute lives on CLASS_DATA and the code fell through to the derived-type
+! branch. Check that it compiles and performs genuine pointer association.
+
+program p
+ type t
+ integer :: i = 0
+ end type t
+ type, extends(t) :: t2
+ integer :: j = 0
+ end type t2
+ type cu
+ class(*), pointer :: u
+ end type cu
+ type ct
+ class(t), pointer :: p
+ end type ct
+
+ type(t2), target :: tar
+ type(cu) :: a
+ type(ct) :: b
+ character(5), target :: str = "hello"
+
+ ! Unlimited polymorphic pointer component.
+ tar%i = 5
+ a = cu (tar)
+ select type (q => a%u)
+ type is (t2)
+ if (q%i /= 5) stop 1
+ class default
+ stop 2
+ end select
+
+ ! Typed (parent) class pointer component -> genuine association, not a copy.
+ b = ct (tar)
+ if (loc (b%p) /= loc (tar)) stop 3
+ b%p%i = 9
+ if (tar%i /= 9) stop 4
+
+ ! Unlimited polymorphic pointer component with a character target.
+ a = cu (str)
+ select type (q => a%u)
+ type is (character(*))
+ if (len (q) /= 5) stop 5
+ if (q /= "hello") stop 6
+ class default
+ stop 7
+ end select
+end program p
diff --git a/gcc/testsuite/gfortran.dg/structure_constructor_21.f90 b/gcc/testsuite/gfortran.dg/structure_constructor_21.f90
new file mode 100644
index 00000000000..f7e9682b519
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/structure_constructor_21.f90
@@ -0,0 +1,61 @@
+! { dg-do run }
+!
+! PR 125721
+!
+! A structure constructor with a CLASS array POINTER component associated with
+! a target array crashed in gfc_conv_scalarized_array_ref: the pointer
+! attribute lives on CLASS_DATA (cm), so no array branch in
+! gfc_trans_subcomponent_assign fired and the value reached the scalar/derived
+! branch, which converted an array without a scalarizer (se->ss == NULL).
+!
+! This is the array analog of the scalar class-pointer-component fix.
+
+program main
+ implicit none
+
+ type ty
+ integer(kind=8) :: i = 1
+ integer(kind=8) :: ii = 2
+ end type
+ type, extends(ty) :: ty1
+ integer(kind=8) :: j = 3
+ integer(kind=8) :: jj = 4
+ end type
+
+ type conArr
+ integer :: ty_int
+ class(ty), pointer :: ty_class(:,:)
+ end type
+
+ type conStr
+ class(*), pointer :: u(:)
+ end type
+
+ type(conArr) :: obj
+ type(conStr) :: cs
+ character(5), target :: ca(3) = ["aaaaa", "bbbbb", "ccccc"]
+ type(ty1), target :: tar(3,3)
+
+ tar%i = 5
+ obj = conArr(7, tar)
+
+ if (obj%ty_int /= 7) stop 1
+ if (.not. associated (obj%ty_class)) stop 2
+ if (any (shape (obj%ty_class) /= [3,3])) stop 3
+ ! Dynamic type is ty1 (8 int8 = 32 bytes per element); 9 elements = 288.
+ if (sizeof (obj%ty_class) /= 288) stop 4
+ if (obj%ty_class(2,2)%i /= 5) stop 5
+
+ obj%ty_class(2,2)%i = 8
+ if (tar(2,2)%i /= 8) stop 6 ! pointer really aliases the target
+
+ ! Unlimited polymorphic array pointer component with a character target.
+ cs = conStr(ca)
+ select type (q => cs%u)
+ type is (character(*))
+ if (len (q) /= 5) stop 7
+ if (q(2) /= "bbbbb") stop 8
+ class default
+ stop 9
+ end select
+end program main
--
2.56.0