https://gcc.gnu.org/g:9b35083d58c92a70a47c16be0d1d84d09f7a6e23

commit 9b35083d58c92a70a47c16be0d1d84d09f7a6e23
Author: Mikael Morin <mik...@gcc.gnu.org>
Date:   Fri May 30 15:33:58 2025 +0200

    Correction régression char_length_23

Diff:
---
 gcc/fortran/Make-lang.in        |   2 +-
 gcc/fortran/trans-descriptor.cc | 123 +++++++++++++++-
 gcc/fortran/trans-types.cc      | 307 +++++++++++++++++++++++-----------------
 3 files changed, 299 insertions(+), 133 deletions(-)

diff --git a/gcc/fortran/Make-lang.in b/gcc/fortran/Make-lang.in
index 2ddb0366e9dc..2914855eb225 100644
--- a/gcc/fortran/Make-lang.in
+++ b/gcc/fortran/Make-lang.in
@@ -45,7 +45,7 @@ GFORTRAN_TARGET_INSTALL_NAME := 
$(target_noncanonical)-$(shell echo gfortran|sed
 #^L
 
 # Use strict warnings for this front end.
-fortran-warn = $(STRICT_WARN)
+fortran-warn = $(STRICT_WARN) -Wno-error=infinite-recursion
 
 # These are the groups of object files we have.  The F95_PARSER_OBJS are
 # all the front end files, the F95_OBJS are the files for the translation
diff --git a/gcc/fortran/trans-descriptor.cc b/gcc/fortran/trans-descriptor.cc
index 3fdc2f4c5d72..d2f882d7076c 100644
--- a/gcc/fortran/trans-descriptor.cc
+++ b/gcc/fortran/trans-descriptor.cc
@@ -174,6 +174,85 @@ gfc_get_cfi_dim_sm (tree desc, tree idx)
 #define UBOUND_SUBFIELD 2
 
 
+static tree
+substitute_placeholder_in_type (tree type, tree root_struct)
+{
+  tree type_size = TYPE_SIZE (type);
+  tree modified_type_size = SUBSTITUTE_PLACEHOLDER_IN_EXPR (type_size,
+                                                           root_struct);
+  tree type_size_unit = TYPE_SIZE_UNIT (type);
+  tree modified_type_size_unit = SUBSTITUTE_PLACEHOLDER_IN_EXPR 
(type_size_unit,
+                                                                root_struct);
+
+  switch (TREE_CODE (type))
+    {
+    case POINTER_TYPE:
+      {
+       tree subtype = TREE_TYPE (type);
+       tree modified_subtype = substitute_placeholder_in_type (subtype,
+                                                               root_struct);
+       if (modified_subtype == subtype
+           && modified_type_size == type_size
+           && modified_type_size_unit == type_size_unit)
+         return type;
+       else
+         return build_pointer_type (modified_subtype);
+      }
+      break;
+
+    case ARRAY_TYPE:
+      {
+       tree elt_type = TREE_TYPE (type);
+       tree modified_elt_type = substitute_placeholder_in_type (elt_type,
+                                                                root_struct);
+       tree idx_type = TYPE_DOMAIN (type);
+       tree modified_idx_type = substitute_placeholder_in_type (idx_type,
+                                                                root_struct);
+       if (modified_elt_type == elt_type
+           && modified_idx_type == idx_type
+           && modified_type_size == type_size
+           && modified_type_size_unit == type_size_unit)
+         return type;
+       else
+         {
+           tree new_type = build_array_type (modified_elt_type,
+                                             modified_idx_type);
+           TYPE_STRING_FLAG (new_type) = TYPE_STRING_FLAG (type);
+           return new_type;
+         }
+      }
+      break;
+
+    case INTEGER_TYPE:
+      {
+       tree min_val = TYPE_MIN_VALUE (type);
+       tree modified_min_val = SUBSTITUTE_PLACEHOLDER_IN_EXPR (min_val,
+                                                               root_struct);
+       tree max_val = TYPE_MAX_VALUE (type);
+       tree modified_max_val = SUBSTITUTE_PLACEHOLDER_IN_EXPR (max_val,
+                                                               root_struct);
+       if (modified_min_val == min_val
+           && modified_max_val == max_val
+           && modified_type_size == type_size
+           && modified_type_size_unit == type_size_unit)
+         return type;
+       else
+         {
+           tree new_type = build_range_type (type, modified_min_val,
+                                             modified_max_val);
+           TYPE_SIZE (new_type) = modified_type_size;
+           TYPE_SIZE_UNIT (new_type) = modified_type_size_unit;
+           return new_type;
+         }
+      }
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+
 namespace gfc_descriptor
 {
 
@@ -223,7 +302,11 @@ conv_data_get (tree desc)
   gcc_assert (TREE_CODE (type) != REFERENCE_TYPE);
 
   tree field = get_data (desc);
-  tree t = fold_convert (GFC_TYPE_ARRAY_DATAPTR_TYPE (type), field);
+  tree target_type = GFC_TYPE_ARRAY_DATAPTR_TYPE (type);
+  gcc_assert (TREE_CODE (target_type) == POINTER_TYPE);
+  if (type_contains_placeholder_p (TREE_TYPE (target_type)))
+    target_type = substitute_placeholder_in_type (target_type, desc);
+  tree t = fold_convert (target_type, field);
   return non_lvalue_loc (input_location, t);
 }
 
@@ -3025,6 +3108,42 @@ gfc_conv_descriptor_cosize (tree desc, int rank, int 
corank)
 }
 
 
+static bool
+placeholder_free_element_type (tree type)
+{
+  if (!GFC_DESCRIPTOR_TYPE_P (type))
+    return true;
+
+  tree data_ptr_type = GFC_TYPE_ARRAY_DATAPTR_TYPE (type);
+  gcc_assert (TREE_CODE (data_ptr_type) == POINTER_TYPE);
+
+  return !type_contains_placeholder_p (TREE_TYPE (data_ptr_type));
+}
+
+
+static tree
+get_descriptor_dtype (tree desc, int * prank)
+{
+  tree type = TREE_TYPE (desc);
+
+  if (placeholder_free_element_type (type))
+    return gfc_get_dtype (type, prank);
+  else
+    {
+      tree data_ptr_type = GFC_TYPE_ARRAY_DATAPTR_TYPE (type);
+      data_ptr_type = substitute_placeholder_in_type (data_ptr_type, desc);
+
+      gcc_assert (TREE_CODE (data_ptr_type) == POINTER_TYPE);
+      tree etype = TREE_TYPE (data_ptr_type);
+      if (TREE_CODE (etype) == ARRAY_TYPE && ! TYPE_STRING_FLAG (etype))
+       etype = TREE_TYPE (etype);
+
+      int rank = prank ? *prank : GFC_TYPE_ARRAY_RANK (type);
+      return gfc_get_dtype_rank_type (rank, etype);
+    }
+}
+
+
 void
 gfc_set_descriptor (stmtblock_t *block, tree dest, tree src, gfc_expr 
*src_expr,
                    int rank, int corank, gfc_ss *ss, gfc_array_info *info,
@@ -3064,7 +3183,7 @@ gfc_set_descriptor (stmtblock_t *block, tree dest, tree 
src, gfc_expr *src_expr,
       dtype = gfc_conv_descriptor_dtype_get (tmp2);
     }
   else
-    dtype = gfc_get_dtype (TREE_TYPE (src), &rank);
+    dtype = get_descriptor_dtype (src, &rank);
   gfc_conv_descriptor_dtype_set (block, dest, dtype);
 
   /* The 1st element in the section.  */
diff --git a/gcc/fortran/trans-types.cc b/gcc/fortran/trans-types.cc
index ff19922638c8..cec5869603f5 100644
--- a/gcc/fortran/trans-types.cc
+++ b/gcc/fortran/trans-types.cc
@@ -2992,7 +2992,6 @@ gfc_get_derived_type (gfc_symbol * derived, int codimen)
 {
   tree typenode = NULL, field = NULL, field_type = NULL;
   tree canonical = NULL_TREE, class_canonical = NULL_TREE;
-  tree *chain = NULL;
   bool got_canonical = false;
   bool self_is_canonical = false;
   bool unlimited_entity = false;
@@ -3216,142 +3215,190 @@ gfc_get_derived_type (gfc_symbol * derived, int 
codimen)
      through only the top-level linked list of components so we correctly
      build UNION_TYPE nodes for BT_UNION components. MAPs and other nested
      types are built as part of gfc_get_union_type.  */
-  for (c = derived->components; c; c = c->next)
-    {
-      bool same_alloc_type = c->attr.allocatable
-                            && derived == c->ts.u.derived;
-      /* Prevent infinite recursion, when the procedure pointer type is
-        the same as derived, by forcing the procedure pointer component to
-        be built as if the explicit interface does not exist.  */
-      if (c->attr.proc_pointer
-         && (c->ts.type != BT_DERIVED || (c->ts.u.derived
-                   && !gfc_compare_derived_types (derived, c->ts.u.derived)))
-         && (c->ts.type != BT_CLASS || (CLASS_DATA (c)->ts.u.derived
-                   && !gfc_compare_derived_types (derived, CLASS_DATA 
(c)->ts.u.derived))))
-       field_type = gfc_get_ppc_type (c);
-      else if (c->attr.proc_pointer && derived->backend_decl)
-       {
-         tmp = build_function_type (derived->backend_decl, NULL_TREE);
-         field_type = build_pointer_type (tmp);
-       }
-      else if (c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS)
-       field_type = c->ts.u.derived->backend_decl;
-      else if (c->attr.caf_token)
-       field_type = pvoid_type_node;
-      else
-       {
-         if (c->ts.type == BT_CHARACTER
-             && !c->ts.deferred && !c->attr.pdt_string)
-           {
-             /* Evaluate the string length.  */
-             gfc_conv_const_charlen (c->ts.u.cl);
-             gcc_assert (c->ts.u.cl->backend_decl);
-           }
+  {
+    auto_vec <tree> fields;
 
-         field_type = gfc_typenode_for_spec (&c->ts, codimen);
-       }
+    unsigned i;
+    bool do_loop = true;
+    while (do_loop)
+      {
+       do_loop = false;
+       for (c = derived->components, i = 0; c; c = c->next, i++)
+         {
+           if (c->backend_decl)
+             continue;
 
-      /* This returns an array descriptor type.  Initialization may be
-         required.  */
-      if ((c->attr.dimension || c->attr.codimension) && !c->attr.proc_pointer )
-       {
-         if (c->attr.pointer || c->attr.allocatable || c->attr.pdt_array)
-           {
-             enum gfc_array_kind akind;
-             bool is_ptr = ((c == derived->components
-                             && derived->components->ts.type == BT_DERIVED
-                             && startswith (derived->name, "__class")
-                             && (strcmp (derived->components->name, "_data")
-                                 == 0))
-                            ? c->attr.class_pointer : c->attr.pointer);
-             if (is_ptr)
-               akind = c->attr.contiguous ? GFC_ARRAY_POINTER_CONT
-                                          : GFC_ARRAY_POINTER;
-             else if (c->attr.allocatable)
-               akind = GFC_ARRAY_ALLOCATABLE;
-             else if (c->as->type == AS_ASSUMED_RANK)
-               akind = GFC_ARRAY_ASSUMED_RANK;
-             else
-               /* FIXME – see PR fortran/104651.  Additionally, the following
-                  gfc_build_array_type should use !is_ptr instead of
-                  c->attr.pointer and codim unconditionally without '? :'. */
-               akind = GFC_ARRAY_ASSUMED_SHAPE;
-
-             /* Use char as array element type for unlimited_polymorphic
-                entities.  */
-             if (c->ts.type == BT_DERIVED
-                 && c->ts.u.derived->attr.unlimited_polymorphic
-                 && field_type == ptr_type_node)
-               field_type = char_type_node;
-
-             bt type_type = derived->attr.is_class
-                            && strcmp (c->name, "_data") == 0
-                            ? BT_CLASS : c->ts.type;
-
-             /* Pointers to arrays aren't actually pointer types.  The
-                descriptors are separate, but the data is common.  Every
-                array pointer in a coarray derived type needs to provide space
-                for the coarray management, too.  Therefore treat coarrays
-                and pointers to coarrays in derived types the same.  */
-             field_type = gfc_build_array_type
-               (
-                 field_type, c->as, akind, !c->attr.target && !c->attr.pointer,
-                 c->attr.contiguous,
-                 c->attr.codimension || c->attr.pointer ? codimen : 0,
-                 type_type
-               );
-           }
-         else
-           field_type = gfc_get_nodesc_array_type (field_type, c->as,
-                                                   PACKED_STATIC,
-                                                   !c->attr.target,
-                                                   c->ts.type);
-       }
-      else if ((c->attr.pointer || c->attr.allocatable || c->attr.pdt_string)
-              && !c->attr.proc_pointer
-              && !(unlimited_entity && c == derived->components))
-       field_type = build_pointer_type (field_type);
-
-      if (c->attr.pointer || same_alloc_type)
-       field_type = gfc_nonrestricted_type (field_type);
-
-      /* vtype fields can point to different types to the base type.  */
-      if (c->ts.type == BT_DERIVED
-           && c->ts.u.derived && c->ts.u.derived->attr.vtype)
-         field_type = build_pointer_type_for_mode (TREE_TYPE (field_type),
-                                                   ptr_mode, true);
-
-      /* Ensure that the CLASS language specific flag is set.  */
-      if (c->ts.type == BT_CLASS)
-       {
-         if (POINTER_TYPE_P (field_type))
-           GFC_CLASS_TYPE_P (TREE_TYPE (field_type)) = 1;
-         else
-           GFC_CLASS_TYPE_P (field_type) = 1;
-       }
+           bool same_alloc_type = c->attr.allocatable
+                                  && derived == c->ts.u.derived;
+           /* Prevent infinite recursion, when the procedure pointer type is
+              the same as derived, by forcing the procedure pointer component 
to
+              be built as if the explicit interface does not exist.  */
+           if (c->attr.proc_pointer
+               && (c->ts.type != BT_DERIVED || (c->ts.u.derived
+                         && !gfc_compare_derived_types (derived, 
c->ts.u.derived)))
+               && (c->ts.type != BT_CLASS || (CLASS_DATA (c)->ts.u.derived
+                         && !gfc_compare_derived_types (derived, CLASS_DATA 
(c)->ts.u.derived))))
+             field_type = gfc_get_ppc_type (c);
+           else if (c->attr.proc_pointer && derived->backend_decl)
+             {
+               tmp = build_function_type (derived->backend_decl, NULL_TREE);
+               field_type = build_pointer_type (tmp);
+             }
+           else if (c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS)
+             field_type = c->ts.u.derived->backend_decl;
+           else if (c->attr.caf_token)
+             field_type = pvoid_type_node;
+           else
+             {
+               if (c->ts.type == BT_CHARACTER
+                   && !c->ts.deferred && !c->attr.pdt_string)
+                 {
+                   /* Evaluate the string length.  */
+                   gfc_conv_const_charlen (c->ts.u.cl);
+                   gcc_assert (c->ts.u.cl->backend_decl);
+                 }
 
-      field = gfc_add_field_to_struct (typenode,
-                                      get_identifier (c->name),
-                                      field_type, &chain);
-      if (GFC_LOCUS_IS_SET (c->loc))
-       gfc_set_decl_location (field, &c->loc);
-      else if (GFC_LOCUS_IS_SET (derived->declared_at))
-       gfc_set_decl_location (field, &derived->declared_at);
+               field_type = gfc_typenode_for_spec (&c->ts, codimen);
+               tree strlen_field;
+               if (gfc_deferred_strlen (c, &strlen_field))
+                 {
+                   if (strlen_field == nullptr)
+                     {
+                       do_loop = true;
+                       continue;
+                     }
+
+                   gcc_assert (TREE_CODE (field_type) == ARRAY_TYPE);
+                   if (TYPE_MAX_VALUE (TYPE_DOMAIN (field_type)) == NULL_TREE)
+                     {
+                       tree domain_type = TYPE_DOMAIN (field_type);
+                       domain_type = build_distinct_type_copy (domain_type);
+                       field_type = build_distinct_type_copy (field_type);
+                       TYPE_DOMAIN (field_type) = domain_type;
+                       tree max = build3 (COMPONENT_REF, TREE_TYPE 
(strlen_field),
+                                          build0 (PLACEHOLDER_EXPR, typenode),
+                                          strlen_field, NULL_TREE);
+                       TYPE_MAX_VALUE (domain_type) = max;
+                     }
+                 }
+             }
 
-      gfc_finish_decl_attrs (field, &c->attr);
+           /* This returns an array descriptor type.  Initialization may be
+              required.  */
+           if ((c->attr.dimension || c->attr.codimension) && 
!c->attr.proc_pointer )
+             {
+               if (c->attr.pointer || c->attr.allocatable || c->attr.pdt_array)
+                 {
+                   enum gfc_array_kind akind;
+                   bool is_ptr = ((c == derived->components
+                                   && derived->components->ts.type == 
BT_DERIVED
+                                   && startswith (derived->name, "__class")
+                                   && (strcmp (derived->components->name, 
"_data")
+                                       == 0))
+                                  ? c->attr.class_pointer : c->attr.pointer);
+                   if (is_ptr)
+                     akind = c->attr.contiguous ? GFC_ARRAY_POINTER_CONT
+                                                : GFC_ARRAY_POINTER;
+                   else if (c->attr.allocatable)
+                     akind = GFC_ARRAY_ALLOCATABLE;
+                   else if (c->as->type == AS_ASSUMED_RANK)
+                     akind = GFC_ARRAY_ASSUMED_RANK;
+                   else
+                     /* FIXME – see PR fortran/104651.  Additionally, the 
following
+                        gfc_build_array_type should use !is_ptr instead of
+                        c->attr.pointer and codim unconditionally without '? 
:'. */
+                     akind = GFC_ARRAY_ASSUMED_SHAPE;
+
+                   /* Use char as array element type for unlimited_polymorphic
+                      entities.  */
+                   if (c->ts.type == BT_DERIVED
+                       && c->ts.u.derived->attr.unlimited_polymorphic
+                       && field_type == ptr_type_node)
+                     field_type = char_type_node;
+
+                   bt type_type = derived->attr.is_class
+                                  && strcmp (c->name, "_data") == 0
+                                  ? BT_CLASS : c->ts.type;
+
+                   /* Pointers to arrays aren't actually pointer types.  The
+                      descriptors are separate, but the data is common.  Every
+                      array pointer in a coarray derived type needs to provide 
space
+                      for the coarray management, too.  Therefore treat 
coarrays
+                      and pointers to coarrays in derived types the same.  */
+                   field_type = gfc_build_array_type
+                     (
+                       field_type, c->as, akind, !c->attr.target && 
!c->attr.pointer,
+                       c->attr.contiguous,
+                       c->attr.codimension || c->attr.pointer ? codimen : 0,
+                       type_type
+                     );
+                 }
+               else
+                 field_type = gfc_get_nodesc_array_type (field_type, c->as,
+                                                         PACKED_STATIC,
+                                                         !c->attr.target,
+                                                         c->ts.type);
+             }
+           else if ((c->attr.pointer || c->attr.allocatable || 
c->attr.pdt_string)
+                    && !c->attr.proc_pointer
+                    && !(unlimited_entity && c == derived->components))
+             field_type = build_pointer_type (field_type);
+
+           if (c->attr.pointer || same_alloc_type)
+             field_type = gfc_nonrestricted_type (field_type);
+
+           /* vtype fields can point to different types to the base type.  */
+           if (c->ts.type == BT_DERIVED
+                 && c->ts.u.derived && c->ts.u.derived->attr.vtype)
+               field_type = build_pointer_type_for_mode (TREE_TYPE 
(field_type),
+                                                         ptr_mode, true);
+
+           /* Ensure that the CLASS language specific flag is set.  */
+           if (c->ts.type == BT_CLASS)
+             {
+               if (POINTER_TYPE_P (field_type))
+                 GFC_CLASS_TYPE_P (TREE_TYPE (field_type)) = 1;
+               else
+                 GFC_CLASS_TYPE_P (field_type) = 1;
+             }
 
-      DECL_PACKED (field) |= TYPE_PACKED (typenode);
+           field = gfc_add_field_to_struct (typenode,
+                                            get_identifier (c->name),
+                                            field_type, nullptr);
+           if (i >= fields.length ())
+             fields.safe_grow_cleared (i + 1);
 
-      gcc_assert (field);
-      /* Overwrite for class array to supply different bounds for different
-        types.  */
-      if (class_coarray_flag || !c->backend_decl || c->attr.caf_token)
-       c->backend_decl = field;
+           fields[i] = field;
 
-      if (c->attr.pointer && (c->attr.dimension || c->attr.codimension)
-         && !(c->ts.type == BT_DERIVED && strcmp (c->name, "_data") == 0))
-       GFC_DECL_PTR_ARRAY_P (c->backend_decl) = 1;
-    }
+           if (GFC_LOCUS_IS_SET (c->loc))
+             gfc_set_decl_location (field, &c->loc);
+           else if (GFC_LOCUS_IS_SET (derived->declared_at))
+             gfc_set_decl_location (field, &derived->declared_at);
+
+           gfc_finish_decl_attrs (field, &c->attr);
+
+           DECL_PACKED (field) |= TYPE_PACKED (typenode);
+
+           gcc_assert (field);
+           /* Overwrite for class array to supply different bounds for 
different
+              types.  */
+           if (class_coarray_flag || !c->backend_decl || c->attr.caf_token)
+             c->backend_decl = field;
+
+           if (c->attr.pointer && (c->attr.dimension || c->attr.codimension)
+               && !(c->ts.type == BT_DERIVED && strcmp (c->name, "_data") == 
0))
+             GFC_DECL_PTR_ARRAY_P (c->backend_decl) = 1;
+         }
+      }
+
+    tree* ptr = &TYPE_FIELDS (typenode);
+    for (c = derived->components, i = 0; c; c = c->next, i++)
+      {
+       tree field = fields[i];
+       *ptr = field;
+       ptr = &DECL_CHAIN (field);
+      }
+  }
 
   if (derived->attr.is_class)
     GFC_CLASS_TYPE_P (typenode) = 1;

Reply via email to