aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Thomas <pault@gcc.gnu.org>2023-09-24 09:00:52 +0100
committerPaul Thomas <pault@gcc.gnu.org>2023-09-24 09:00:52 +0100
commitc23ce23e9ce162c49bca8900c8a20079b49501c9 (patch)
treec2a0286d153ec5abc81ed4d58b5412856f9c72dc
parent1bf0cd05cb30889cae4b6cf06e80b7f3a13c40c1 (diff)
downloadgcc-c23ce23e9ce162c49bca8900c8a20079b49501c9.zip
gcc-c23ce23e9ce162c49bca8900c8a20079b49501c9.tar.gz
gcc-c23ce23e9ce162c49bca8900c8a20079b49501c9.tar.bz2
Fortran: Pad mismatched charlens in component initializers [PR68155]
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.
-rw-r--r--gcc/fortran/decl.cc84
-rw-r--r--gcc/fortran/trans-expr.cc8
-rw-r--r--gcc/testsuite/gfortran.dg/pr68155.f9029
3 files changed, 80 insertions, 41 deletions
diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc
index 8182ef2..4a3c5b8 100644
--- a/gcc/fortran/decl.cc
+++ b/gcc/fortran/decl.cc
@@ -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)
{
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 244126c..cca2f4e 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -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
index 0000000..2bd6f78
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr68155.f90
@@ -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