The following regression tested on x86_64. I will commit as very simple.
See attached. Regards, Jerry commit 2a78f5b5259ae3a503ca06b997a6dd1c3190021a Author: Christopher Albert <[email protected]> Date: Wed Feb 25 09:41:27 2026 +0100 fortran: Fix ICE in ALLOCATE of sub-objects with recursive types The deep-copy wrapper generation for recursive allocatable array components (PR121628) calls cgraph_node::add_new_function to register the wrapper. During PARSING state, add_new_function calls finalize_function which triggers ggc_collect(). This garbage collection frees locally-computed tree nodes (COMPONENT_REFs etc.) in caller stack frames of structure_alloc_comps that are not yet attached to any GC-rooted structure, causing a segfault when those nodes are subsequently accessed. Use finalize_function with no_collect=true to skip the collection. The GC will run at a safe point later. PR fortran/124235 gcc/fortran/ChangeLog: * trans-array.cc (generate_element_copy_wrapper): Use cgraph_node::finalize_function with no_collect=true instead of cgraph_node::add_new_function to avoid garbage collection while caller frames hold unrooted tree nodes. gcc/testsuite/ChangeLog: * gfortran.dg/pr124235.f90: New test. Signed-off-by: Christopher Albert <[email protected]>
commit 2a78f5b5259ae3a503ca06b997a6dd1c3190021a Author: Christopher Albert <[email protected]> Date: Wed Feb 25 09:41:27 2026 +0100 fortran: Fix ICE in ALLOCATE of sub-objects with recursive types The deep-copy wrapper generation for recursive allocatable array components (PR121628) calls cgraph_node::add_new_function to register the wrapper. During PARSING state, add_new_function calls finalize_function which triggers ggc_collect(). This garbage collection frees locally-computed tree nodes (COMPONENT_REFs etc.) in caller stack frames of structure_alloc_comps that are not yet attached to any GC-rooted structure, causing a segfault when those nodes are subsequently accessed. Use finalize_function with no_collect=true to skip the collection. The GC will run at a safe point later. PR fortran/124235 gcc/fortran/ChangeLog: * trans-array.cc (generate_element_copy_wrapper): Use cgraph_node::finalize_function with no_collect=true instead of cgraph_node::add_new_function to avoid garbage collection while caller frames hold unrooted tree nodes. gcc/testsuite/ChangeLog: * gfortran.dg/pr124235.f90: New test. Signed-off-by: Christopher Albert <[email protected]> diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc index e7666416213..73bb90a4b60 100644 --- a/gcc/fortran/trans-array.cc +++ b/gcc/fortran/trans-array.cc @@ -10165,7 +10165,13 @@ generate_element_copy_wrapper (gfc_symbol *der_type, tree comp_type, pop_cfun (); - cgraph_node::add_new_function (fndecl, false); + /* Use finalize_function with no_collect=true to skip the ggc_collect + call that add_new_function would trigger. This function is called + during tree lowering of structure_alloc_comps where caller stack + frames hold locally-computed tree nodes (COMPONENT_REFs etc.) that + are not yet attached to any GC root. A collection at this point + would free those nodes and cause segfaults. PR124235. */ + cgraph_node::finalize_function (fndecl, true); return build1 (ADDR_EXPR, get_copy_helper_pointer_type (), fndecl); } diff --git a/gcc/testsuite/gfortran.dg/pr124235.f90 b/gcc/testsuite/gfortran.dg/pr124235.f90 new file mode 100644 index 00000000000..30735ff2295 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/pr124235.f90 @@ -0,0 +1,46 @@ +! { dg-do compile } +! PR fortran/124235 - ICE in ALLOCATE of sub-objects with recursive types +! +! Mutually-referencing derived types with a mix of allocatable and +! fixed-size array components. Allocating a sub-object of an +! already-allocated component triggered a segfault during tree lowering +! because garbage collection during deep-copy wrapper generation +! invalidated locally-computed COMPONENT_REF tree nodes. + +program pr124235 + implicit none + + type :: alpha_t + integer, allocatable :: vals(:) + type(alpha_t), allocatable :: a_kids(:) + type(gamma_t), allocatable :: g_ref(:) + integer :: tag + type(beta_t), allocatable :: b_ref(:) + end type + + type :: beta_t + integer, allocatable :: vals(:) + type(alpha_t) :: a_fixed(4) + type(beta_t), allocatable :: b_kids(:) + integer :: tag + type(gamma_t), allocatable :: g_ref(:) + end type + + type :: gamma_t + integer, allocatable :: vals(:) + type(beta_t) :: b_fixed(4) + integer :: tag + type(gamma_t), allocatable :: g_kids(:) + end type + + type :: container_t + type(gamma_t), allocatable :: items(:) + type(gamma_t), allocatable :: spares(:) + end type + + type(container_t) :: box + + allocate(box%items(6)) + allocate(box%items(2)%g_kids(3)) + +end program
