]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fortran: Pad mismatched charlens in component initializers [PR68155]
authorPaul Thomas <pault@gcc.gnu.org>
Sun, 24 Sep 2023 08:00:52 +0000 (09:00 +0100)
committerPaul Thomas <pault@gcc.gnu.org>
Sun, 24 Sep 2023 08:00:52 +0000 (09:00 +0100)
2023-09-24  Paul Thomas  <pault@gcc.gnu.org>

gcc/fortran
PR fortran/68155
* decl.cc (fix_initializer_charlen): New function broken out of
add_init_expr_to_sym.
(add_init_expr_to_sym, build_struct): Call the new function.

PR fortran/111271
* trans-expr.cc (gfc_conv_intrinsic_to_class): Remove repeated
condition.

gcc/testsuite/
PR fortran/68155
* gfortran.dg/pr68155.f90: New test.

gcc/fortran/decl.cc
gcc/fortran/trans-expr.cc
gcc/testsuite/gfortran.dg/pr68155.f90 [new file with mode: 0644]

index 8182ef29f43ff06eb822512dd7404279ee8bacca..4a3c5b86de007a464c2a9df5209adcb2568ed232 100644 (file)
@@ -1960,6 +1960,45 @@ gfc_free_enum_history (void)
 }
 
 
+/* Function to fix initializer character length if the length of the
+   symbol or component is constant.  */
+
+static bool
+fix_initializer_charlen (gfc_typespec *ts, gfc_expr *init)
+{
+  if (!gfc_specification_expr (ts->u.cl->length))
+    return false;
+
+  int k = gfc_validate_kind (BT_INTEGER, gfc_charlen_int_kind, false);
+
+  /* resolve_charlen will complain later on if the length
+     is too large.  Just skip the initialization in that case.  */
+  if (mpz_cmp (ts->u.cl->length->value.integer,
+              gfc_integer_kinds[k].huge) <= 0)
+    {
+      HOST_WIDE_INT len
+               = gfc_mpz_get_hwi (ts->u.cl->length->value.integer);
+
+      if (init->expr_type == EXPR_CONSTANT)
+       gfc_set_constant_character_len (len, init, -1);
+      else if (init->expr_type == EXPR_ARRAY)
+       {
+         gfc_constructor *cons;
+
+         /* Build a new charlen to prevent simplification from
+            deleting the length before it is resolved.  */
+         init->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
+         init->ts.u.cl->length = gfc_copy_expr (ts->u.cl->length);
+         cons = gfc_constructor_first (init->value.constructor);
+         for (; cons; cons = gfc_constructor_next (cons))
+           gfc_set_constant_character_len (len, cons->expr, -1);
+       }
+    }
+
+  return true;
+}
+
+
 /* Function called by variable_decl() that adds an initialization
    expression to a symbol.  */
 
@@ -2073,40 +2112,10 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus)
                                gfc_copy_expr (init->ts.u.cl->length);
                }
            }
-         /* Update initializer character length according symbol.  */
-         else if (sym->ts.u.cl->length->expr_type == EXPR_CONSTANT)
-           {
-             if (!gfc_specification_expr (sym->ts.u.cl->length))
-               return false;
-
-             int k = gfc_validate_kind (BT_INTEGER, gfc_charlen_int_kind,
-                                        false);
-             /* resolve_charlen will complain later on if the length
-                is too large.  Just skeep the initialization in that case.  */
-             if (mpz_cmp (sym->ts.u.cl->length->value.integer,
-                          gfc_integer_kinds[k].huge) <= 0)
-               {
-                 HOST_WIDE_INT len
-                   = gfc_mpz_get_hwi (sym->ts.u.cl->length->value.integer);
-
-                 if (init->expr_type == EXPR_CONSTANT)
-                   gfc_set_constant_character_len (len, init, -1);
-                 else if (init->expr_type == EXPR_ARRAY)
-                   {
-                     gfc_constructor *c;
-
-                     /* Build a new charlen to prevent simplification from
-                        deleting the length before it is resolved.  */
-                     init->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
-                     init->ts.u.cl->length
-                       = gfc_copy_expr (sym->ts.u.cl->length);
-
-                     for (c = gfc_constructor_first (init->value.constructor);
-                          c; c = gfc_constructor_next (c))
-                       gfc_set_constant_character_len (len, c->expr, -1);
-                   }
-               }
-           }
+         /* Update initializer character length according to symbol.  */
+         else if (sym->ts.u.cl->length->expr_type == EXPR_CONSTANT
+                  && !fix_initializer_charlen (&sym->ts, init))
+           return false;
        }
 
       if (sym->attr.flavor == FL_PARAMETER && sym->attr.dimension && sym->as
@@ -2369,6 +2378,13 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
   c->initializer = *init;
   *init = NULL;
 
+  /* Update initializer character length according to component.  */
+  if (c->ts.type == BT_CHARACTER && c->ts.u.cl->length
+      && c->ts.u.cl->length->expr_type == EXPR_CONSTANT
+      && c->initializer && c->initializer->ts.type == BT_CHARACTER
+      && !fix_initializer_charlen (&c->ts, c->initializer))
+    return false;
+
   c->as = *as;
   if (c->as != NULL)
     {
index 244126cdd00191563a1629792a0c304daf4b37cc..cca2f4e186275447c2e9d8fdda5202540288374d 100644 (file)
@@ -1131,13 +1131,7 @@ gfc_conv_intrinsic_to_class (gfc_se *parmse, gfc_expr *e,
 
       gfc_add_modify (&parmse->pre, ctree, fold_convert (TREE_TYPE (ctree), tmp));
     }
-  else if (unlimited_poly)
-    {
-      ctree = gfc_class_len_get (var);
-      gfc_add_modify (&parmse->pre, ctree,
-                     fold_convert (TREE_TYPE (ctree),
-                                   integer_zero_node));
-    }
+
   /* Pass the address of the class object.  */
   parmse->expr = gfc_build_addr_expr (NULL_TREE, var);
 }
diff --git a/gcc/testsuite/gfortran.dg/pr68155.f90 b/gcc/testsuite/gfortran.dg/pr68155.f90
new file mode 100644 (file)
index 0000000..2bd6f78
--- /dev/null
@@ -0,0 +1,29 @@
+! { dg-do run }
+!
+! Fix for PR68155 in which initializers of constant length, character
+! components of derived types were not being padded if they were too short.
+! Originally, mismatched lengths caused ICEs. This seems to have been fixed
+! in 9-branch.
+!
+! Contributed by Gerhard Steinmetz  <gerhard.steinmetz.fortran@t-online.de>
+!
+program p
+  implicit none
+  type t
+    character(3) :: c1(2) = [                 'b', 'c']          ! OK
+    character(3) :: c2(2) = [ character(1) :: 'b', 'c'] // ""    ! OK
+    character(3) :: c3(2) = [                 'b', 'c'] // ""    ! was not padded
+    character(3) :: c4(2) = [                 '' , '' ] // ""    ! was not padded
+    character(3) :: c5(2) = [                 'b', 'c'] // 'a'   ! was not padded
+    character(3) :: c6(2) = [                 'b', 'c'] // 'ax'  ! OK
+    character(3) :: c7(2) = [                 'b', 'c'] // 'axy' ! OK trimmed
+  end type t
+  type(t)      :: z
+  if (z%c1(2) .ne. 'c  ') stop 1
+  if (z%c2(2) .ne. 'c  ') stop 2
+  if (z%c3(2) .ne. 'c  ') stop 3
+  if (z%c4(2) .ne. '   ') stop 4
+  if (z%c5(2) .ne. 'ca ') stop 5
+  if (z%c6(2) .ne. 'cax') stop 6
+  if (z%c7(2) .ne. 'cax') stop 7
+end