aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/trans-expr.c
diff options
context:
space:
mode:
authorDaniel Kraft <d@domob.eu>2008-09-21 17:33:37 +0200
committerDaniel Kraft <domob@gcc.gnu.org>2008-09-21 17:33:37 +0200
commit4b7f8314ba66ab03974e94bf80718b157cc1350f (patch)
tree7e12ab2f71e4936cfd889e91f274ac7585d3640b /gcc/fortran/trans-expr.c
parent74a9b8976475b250d6d9d68b2ea557cc0e778f4e (diff)
downloadgcc-4b7f8314ba66ab03974e94bf80718b157cc1350f.zip
gcc-4b7f8314ba66ab03974e94bf80718b157cc1350f.tar.gz
gcc-4b7f8314ba66ab03974e94bf80718b157cc1350f.tar.bz2
re PR fortran/35846 (ICE on nested character constructors)
2008-09-21 Daniel Kraft <d@domob.eu> PR fortran/35846 * trans.h (gfc_conv_string_length): New argument `expr'. * trans-expr.c (flatten_array_ctors_without_strlen): New method. (gfc_conv_string_length): New argument `expr' that is used in a new special case handling if cl->length is NULL. (gfc_conv_subref_array_arg): Pass expr to gfc_conv_string_length. * trans-array.c (gfc_conv_expr_descriptor): Ditto. (gfc_trans_auto_array_allocation): Pass NULL as new expr. (gfc_trans_g77_array), (gfc_trans_dummy_array_bias): Ditto. (gfc_trans_deferred_array): Ditto. (gfc_trans_array_constructor): Save and restore old values of globals used for bounds checking. * trans-decl.c (gfc_trans_dummy_character): Ditto. (gfc_trans_auto_character_variable): Ditto. 2008-09-21 Daniel Kraft <d@domob.eu> PR fortran/35846 * gfortran.dg/nested_array_constructor_1.f90: New test. * gfortran.dg/nested_array_constructor_2.f90: New test. * gfortran.dg/nested_array_constructor_3.f90: New test. * gfortran.dg/nested_array_constructor_4.f90: New test. * gfortran.dg/nested_array_constructor_5.f90: New test. * gfortran.dg/nested_array_constructor_6.f90: New test. From-SVN: r140529
Diffstat (limited to 'gcc/fortran/trans-expr.c')
-rw-r--r--gcc/fortran/trans-expr.c93
1 files changed, 89 insertions, 4 deletions
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 216b3df..e0f2f77 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -241,17 +241,102 @@ gfc_get_expr_charlen (gfc_expr *e)
return length;
}
-
+
+/* For each character array constructor subexpression without a ts.cl->length,
+ replace it by its first element (if there aren't any elements, the length
+ should already be set to zero). */
+
+static void
+flatten_array_ctors_without_strlen (gfc_expr* e)
+{
+ gfc_actual_arglist* arg;
+ gfc_constructor* c;
+
+ if (!e)
+ return;
+
+ switch (e->expr_type)
+ {
+
+ case EXPR_OP:
+ flatten_array_ctors_without_strlen (e->value.op.op1);
+ flatten_array_ctors_without_strlen (e->value.op.op2);
+ break;
+
+ case EXPR_COMPCALL:
+ /* TODO: Implement as with EXPR_FUNCTION when needed. */
+ gcc_unreachable ();
+
+ case EXPR_FUNCTION:
+ for (arg = e->value.function.actual; arg; arg = arg->next)
+ flatten_array_ctors_without_strlen (arg->expr);
+ break;
+
+ case EXPR_ARRAY:
+
+ /* We've found what we're looking for. */
+ if (e->ts.type == BT_CHARACTER && !e->ts.cl->length)
+ {
+ gfc_expr* new_expr;
+ gcc_assert (e->value.constructor);
+
+ new_expr = e->value.constructor->expr;
+ e->value.constructor->expr = NULL;
+
+ flatten_array_ctors_without_strlen (new_expr);
+ gfc_replace_expr (e, new_expr);
+ break;
+ }
+
+ /* Otherwise, fall through to handle constructor elements. */
+ case EXPR_STRUCTURE:
+ for (c = e->value.constructor; c; c = c->next)
+ flatten_array_ctors_without_strlen (c->expr);
+ break;
+
+ default:
+ break;
+
+ }
+}
+
/* Generate code to initialize a string length variable. Returns the
- value. */
+ value. For array constructors, cl->length might be NULL and in this case,
+ the first element of the constructor is needed. expr is the original
+ expression so we can access it but can be NULL if this is not needed. */
void
-gfc_conv_string_length (gfc_charlen * cl, stmtblock_t * pblock)
+gfc_conv_string_length (gfc_charlen * cl, gfc_expr * expr, stmtblock_t * pblock)
{
gfc_se se;
gfc_init_se (&se, NULL);
+
+ /* If cl->length is NULL, use gfc_conv_expr to obtain the string length but
+ "flatten" array constructors by taking their first element; all elements
+ should be the same length or a cl->length should be present. */
+ if (!cl->length)
+ {
+ gfc_expr* expr_flat;
+ gcc_assert (expr);
+
+ expr_flat = gfc_copy_expr (expr);
+ flatten_array_ctors_without_strlen (expr_flat);
+ gfc_resolve_expr (expr_flat);
+
+ gfc_conv_expr (&se, expr_flat);
+ gfc_add_block_to_block (pblock, &se.pre);
+ cl->backend_decl = convert (gfc_charlen_type_node, se.string_length);
+
+ gfc_free_expr (expr_flat);
+ return;
+ }
+
+ /* Convert cl->length. */
+
+ gcc_assert (cl->length);
+
gfc_conv_expr_type (&se, cl->length, gfc_charlen_type_node);
se.expr = fold_build2 (MAX_EXPR, gfc_charlen_type_node, se.expr,
build_int_cst (gfc_charlen_type_node, 0));
@@ -2092,7 +2177,7 @@ gfc_conv_subref_array_arg (gfc_se * parmse, gfc_expr * expr,
/* Build an ss for the temporary. */
if (expr->ts.type == BT_CHARACTER && !expr->ts.cl->backend_decl)
- gfc_conv_string_length (expr->ts.cl, &parmse->pre);
+ gfc_conv_string_length (expr->ts.cl, expr, &parmse->pre);
base_type = gfc_typenode_for_spec (&expr->ts);
if (GFC_ARRAY_TYPE_P (base_type)