https://gcc.gnu.org/g:a1fe2cfa8965ac298f6541d46b90156b1cb34726
commit r16-5094-ga1fe2cfa8965ac298f6541d46b90156b1cb34726 Author: Jerry DeLisle <[email protected]> Date: Fri Nov 7 18:46:54 2025 -0800 fortran: [PR121628] The PR121628 deep-copy helper reused a static seen_derived_types set across wrapper generation, so recursive allocatable arrays that appeared multiple times in a derived type caused infinite compile-time recursion. Save and restore the set around each wrapper build, polish follow-ups, and add a regression test to keep the scenario covered. gcc/fortran/ChangeLog: PR fortran/121628 * trans-array.cc (seen_derived_types): Move to file scope and preserve/restore around generate_element_copy_wrapper. * trans-intrinsic.cc (conv_intrinsic_atomic_op): Reuse gfc_trans_force_lval when forcing addressable CAF temps. gcc/testsuite/ChangeLog: PR fortran/121628 * gfortran.dg/alloc_comp_deep_copy_7.f90: New test. libgfortran/ChangeLog: PR fortran/121628 * Makefile.in: Keep continuation indentation within 80 columns. * aclocal.m4: Regenerate. * libgfortran.h: Drop unused forward declaration. Signed-off-by: Christopher Albert <[email protected]> Diff: --- gcc/fortran/trans-array.cc | 57 ++++++++++++++++------ gcc/fortran/trans-intrinsic.cc | 35 +++++++------ .../gfortran.dg/alloc_comp_deep_copy_7.f90 | 23 +++++++++ libgfortran/Makefile.in | 15 +++--- libgfortran/aclocal.m4 | 44 ++++++++--------- libgfortran/libgfortran.h | 3 -- 6 files changed, 111 insertions(+), 66 deletions(-) diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc index 1bfc0ce46b8c..cd137212260f 100644 --- a/gcc/fortran/trans-array.cc +++ b/gcc/fortran/trans-array.cc @@ -10025,6 +10025,7 @@ enum {DEALLOCATE_ALLOC_COMP = 1, NULLIFY_ALLOC_COMP, static gfc_actual_arglist *pdt_param_list; static bool generating_copy_helper; +static hash_set<gfc_symbol *> seen_derived_types; /* Forward declaration of structure_alloc_comps for wrapper generator. */ static tree structure_alloc_comps (gfc_symbol *, tree, tree, int, int, int, @@ -10115,6 +10116,17 @@ generate_element_copy_wrapper (gfc_symbol *der_type, tree comp_type, bool saved_generating = generating_copy_helper; generating_copy_helper = true; + /* When generating a wrapper, we need a fresh type tracking state to + avoid inheriting the parent context's seen_derived_types, which would + cause infinite recursion when the wrapper tries to handle the same + recursive type. Save elements, clear the set, generate wrapper, then + restore elements. */ + vec<gfc_symbol *> saved_symbols = vNULL; + for (hash_set<gfc_symbol *>::iterator it = seen_derived_types.begin (); + it != seen_derived_types.end (); ++it) + saved_symbols.safe_push (*it); + seen_derived_types.empty (); + der_type_ptr = build_pointer_type (comp_type); dest_typed = fold_convert (der_type_ptr, dest_parm); src_typed = fold_convert (der_type_ptr, src_parm); @@ -10126,6 +10138,11 @@ generate_element_copy_wrapper (gfc_symbol *der_type, tree comp_type, 0, purpose, caf_mode, NULL, false); gfc_add_expr_to_block (&block, body); + /* Restore saved symbols. */ + seen_derived_types.empty (); + for (unsigned i = 0; i < saved_symbols.length (); i++) + seen_derived_types.add (saved_symbols[i]); + saved_symbols.release (); generating_copy_helper = saved_generating; body = gfc_finish_block (&block); @@ -10173,7 +10190,6 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, tree dest, int caf_dereg_mode; symbol_attribute *attr; bool deallocate_called; - static hash_set<gfc_symbol *> seen_derived_types; gfc_init_block (&fnblock); @@ -10984,9 +11000,10 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, tree dest, false, false, NULL_TREE, NULL_TREE); gfc_add_expr_to_block (&fnblock, tmp); } - /* Special case: recursive allocatable array components require runtime - helper to avoid compile-time infinite recursion. Generate a call to - _gfortran_cfi_deep_copy_array with an element copy wrapper. */ + /* Special case: recursive allocatable array components require + runtime helpers to avoid compile-time infinite recursion. Generate + a call to _gfortran_cfi_deep_copy_array with an element copy + wrapper. When inside a wrapper, reuse current_function_decl. */ else if (c->attr.allocatable && c->as && cmp_has_alloc_comps && same_type && purpose == COPY_ALLOC_COMP && !c->attr.proc_pointer && !c->attr.codimension && !caf_in_coarray (caf_mode) @@ -10997,8 +11014,9 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, tree dest, tree alloc_expr; int comp_rank; - /* Get the element type from ctype (which is already the component type). - For arrays, we need the element type, not the array type. */ + /* Get the element type from ctype (already the component + type). For arrays we need the element type, not the array + type. */ elem_type = ctype; if (GFC_DESCRIPTOR_TYPE_P (ctype)) elem_type = gfc_get_element_type (ctype); @@ -11012,29 +11030,36 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, tree dest, comp_rank); gfc_add_expr_to_block (&fnblock, alloc_expr); - /* Generate or reuse the element copy helper. Inside an existing helper - we can reuse the current function to prevent recursive generation. */ + /* Generate or reuse the element copy helper. Inside an + existing helper we can reuse the current function to + prevent recursive generation. */ if (inside_wrapper) - copy_wrapper = gfc_build_addr_expr (NULL_TREE, current_function_decl); + copy_wrapper + = gfc_build_addr_expr (NULL_TREE, current_function_decl); else - copy_wrapper = generate_element_copy_wrapper (c->ts.u.derived, - elem_type, - purpose, caf_mode); + copy_wrapper + = generate_element_copy_wrapper (c->ts.u.derived, elem_type, + purpose, caf_mode); copy_wrapper = fold_convert (helper_ptr_type, copy_wrapper); /* Build addresses of descriptors. */ dest_addr = gfc_build_addr_expr (pvoid_type_node, dcmp); src_addr = gfc_build_addr_expr (pvoid_type_node, comp); - /* Build call: _gfortran_cfi_deep_copy_array (&dcmp, &comp, wrapper). */ + /* Build call: _gfortran_cfi_deep_copy_array (&dcmp, &comp, + wrapper). */ call = build_call_expr_loc (input_location, gfor_fndecl_cfi_deep_copy_array, 3, - dest_addr, src_addr, copy_wrapper); + dest_addr, src_addr, + copy_wrapper); gfc_add_expr_to_block (&fnblock, call); } else if (c->attr.allocatable && !c->attr.proc_pointer - && (add_when_allocated != NULL_TREE || !cmp_has_alloc_comps || !c->as - || c->attr.codimension || caf_in_coarray (caf_mode))) + && (add_when_allocated != NULL_TREE + || !cmp_has_alloc_comps + || !c->as + || c->attr.codimension + || caf_in_coarray (caf_mode))) { rank = c->as ? c->as->rank : 0; if (c->attr.codimension) diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc index 289a366a12f7..91c0301c522c 100644 --- a/gcc/fortran/trans-intrinsic.cc +++ b/gcc/fortran/trans-intrinsic.cc @@ -12559,24 +12559,23 @@ conv_intrinsic_atomic_op (gfc_code *code) else image_index = integer_zero_node; - /* Create a temporary if value is not already a pointer, or if it's an - address of a constant (which is invalid in C). */ - bool need_tmp = !POINTER_TYPE_P (TREE_TYPE (value)); - if (POINTER_TYPE_P (TREE_TYPE (value)) - && TREE_CODE (value) == ADDR_EXPR - && TREE_CONSTANT (TREE_OPERAND (value, 0))) - need_tmp = true; - - if (need_tmp) - { - tmp = gfc_create_var (TREE_TYPE (TREE_TYPE (atom)), "value"); - if (POINTER_TYPE_P (TREE_TYPE (value))) - gfc_add_modify (&block, tmp, - fold_convert (TREE_TYPE (tmp), - build_fold_indirect_ref (value))); - else - gfc_add_modify (&block, tmp, fold_convert (TREE_TYPE (tmp), value)); - value = gfc_build_addr_expr (NULL_TREE, tmp); + /* Ensure VALUE names addressable storage: taking the address of a + constant is invalid in C, and scalars need a temporary as well. */ + if (!POINTER_TYPE_P (TREE_TYPE (value))) + { + tree elem + = fold_convert (TREE_TYPE (TREE_TYPE (atom)), value); + elem = gfc_trans_force_lval (&block, elem); + value = gfc_build_addr_expr (NULL_TREE, elem); + } + else if (TREE_CODE (value) == ADDR_EXPR + && TREE_CONSTANT (TREE_OPERAND (value, 0))) + { + tree elem + = fold_convert (TREE_TYPE (TREE_TYPE (atom)), + build_fold_indirect_ref (value)); + elem = gfc_trans_force_lval (&block, elem); + value = gfc_build_addr_expr (NULL_TREE, elem); } gfc_init_se (&argse, NULL); diff --git a/gcc/testsuite/gfortran.dg/alloc_comp_deep_copy_7.f90 b/gcc/testsuite/gfortran.dg/alloc_comp_deep_copy_7.f90 new file mode 100644 index 000000000000..749a71262751 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/alloc_comp_deep_copy_7.f90 @@ -0,0 +1,23 @@ +! { dg-do compile } +! +! PR fortran/121628 +! Test that derived types with multiple recursive allocatable array +! components compile without ICE. This was broken by the initial deep-copy +! patch which caused infinite compile-time recursion due to seen_derived_types +! persisting across wrapper generation. +! +! The fix saves and restores seen_derived_types when generating element +! copy wrappers to prevent inheriting parent context state. +! + +program alloc_comp_deep_copy_7 + implicit none + + type :: nested_t + type(nested_t), allocatable :: children(:) + type(nested_t), allocatable :: relatives(:) + end type nested_t + + type(nested_t) :: a + +end program alloc_comp_deep_copy_7 diff --git a/libgfortran/Makefile.in b/libgfortran/Makefile.in index 116e80ffe3ce..88b6197e4e98 100644 --- a/libgfortran/Makefile.in +++ b/libgfortran/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.15.1 from Makefile.am. +# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2017 Free Software Foundation, Inc. +# Copyright (C) 1994-2014 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -231,8 +231,8 @@ libgfortran_la_LIBADD = @LIBGFOR_MINIMAL_FALSE@ runtime/fpu.lo runtime/main.lo \ @LIBGFOR_MINIMAL_FALSE@ runtime/pause.lo runtime/stop.lo am__objects_3 = runtime/bounds.lo runtime/compile_options.lo \ - runtime/deep_copy.lo runtime/memory.lo runtime/string.lo runtime/select.lo \ - $(am__objects_1) $(am__objects_2) + runtime/deep_copy.lo runtime/memory.lo runtime/string.lo \ + runtime/select.lo $(am__objects_1) $(am__objects_2) am__objects_4 = generated/matmul_i1.lo generated/matmul_i2.lo \ generated/matmul_i4.lo generated/matmul_i8.lo \ generated/matmul_i16.lo generated/matmul_r4.lo \ @@ -1013,9 +1013,9 @@ gfor_helper_src = intrinsics/associated.c intrinsics/abort.c \ @IEEE_SUPPORT_TRUE@ieee/ieee_exceptions.F90 \ @IEEE_SUPPORT_TRUE@ieee/ieee_features.F90 -gfor_src = runtime/bounds.c runtime/compile_options.c runtime/deep_copy.c \ - runtime/memory.c runtime/string.c runtime/select.c $(am__append_6) \ - $(am__append_7) +gfor_src = runtime/bounds.c runtime/compile_options.c \ + runtime/deep_copy.c runtime/memory.c runtime/string.c \ + runtime/select.c $(am__append_6) $(am__append_7) i_matmul_c = \ generated/matmul_i1.c \ generated/matmul_i2.c \ @@ -4492,6 +4492,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/bounds.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/compile_options.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/convert_char.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/deep_copy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/environ.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/error.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/fpu.Plo@am__quote@ diff --git a/libgfortran/aclocal.m4 b/libgfortran/aclocal.m4 index 9cbf1a8922d9..36c9396d1035 100644 --- a/libgfortran/aclocal.m4 +++ b/libgfortran/aclocal.m4 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.15.1 -*- Autoconf -*- +# generated automatically by aclocal 1.15 -*- Autoconf -*- -# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -20,7 +20,7 @@ You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) -# Copyright (C) 2002-2017 Free Software Foundation, Inc. +# Copyright (C) 2002-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -35,7 +35,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.15' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.15.1], [], +m4_if([$1], [1.15], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -51,14 +51,14 @@ m4_define([_AM_AUTOCONF_VERSION], []) # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.15.1])dnl +[AM_AUTOMAKE_VERSION([1.15])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -110,7 +110,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd` # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2017 Free Software Foundation, Inc. +# Copyright (C) 1997-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -141,7 +141,7 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -332,7 +332,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -408,7 +408,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], # Do all the work for Automake. -*- Autoconf -*- -# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -605,7 +605,7 @@ for _am_header in $config_headers :; do done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -629,7 +629,7 @@ AC_SUBST([install_sh])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering -# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -664,7 +664,7 @@ AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) # Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -714,7 +714,7 @@ rm -f confinc confmf # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997-2017 Free Software Foundation, Inc. +# Copyright (C) 1997-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -753,7 +753,7 @@ fi # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -782,7 +782,7 @@ AC_DEFUN([_AM_SET_OPTIONS], AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -# Copyright (C) 1999-2017 Free Software Foundation, Inc. +# Copyright (C) 1999-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -829,7 +829,7 @@ AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -848,7 +848,7 @@ AC_DEFUN([AM_RUN_LOG], # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996-2017 Free Software Foundation, Inc. +# Copyright (C) 1996-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -929,7 +929,7 @@ AC_CONFIG_COMMANDS_PRE( rm -f conftest.file ]) -# Copyright (C) 2009-2017 Free Software Foundation, Inc. +# Copyright (C) 2009-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -989,7 +989,7 @@ AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) -# Copyright (C) 2001-2017 Free Software Foundation, Inc. +# Copyright (C) 2001-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1017,7 +1017,7 @@ fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006-2017 Free Software Foundation, Inc. +# Copyright (C) 2006-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1036,7 +1036,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004-2017 Free Software Foundation, Inc. +# Copyright (C) 2004-2014 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h index 71ec640b3351..f4c66d4640b8 100644 --- a/libgfortran/libgfortran.h +++ b/libgfortran/libgfortran.h @@ -914,9 +914,6 @@ internal_proto(xcalloc); extern void *xrealloc (void *, size_t); internal_proto(xrealloc); -/* deep_copy.c - Runtime helper for recursive allocatable array components */ - -struct CFI_cdesc_t; extern void cfi_deep_copy_array (gfc_array_void *, gfc_array_void *, void (*copy_element) (void *, void *));
