diff options
author | Daniel Kraft <d@domob.eu> | 2008-09-21 17:33:37 +0200 |
---|---|---|
committer | Daniel Kraft <domob@gcc.gnu.org> | 2008-09-21 17:33:37 +0200 |
commit | 4b7f8314ba66ab03974e94bf80718b157cc1350f (patch) | |
tree | 7e12ab2f71e4936cfd889e91f274ac7585d3640b /gcc/fortran/trans-expr.c | |
parent | 74a9b8976475b250d6d9d68b2ea557cc0e778f4e (diff) | |
download | gcc-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.c | 93 |
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) |