diff options
author | Paul Thomas <pault@gcc.gnu.org> | 2007-08-30 22:10:55 +0000 |
---|---|---|
committer | Paul Thomas <pault@gcc.gnu.org> | 2007-08-30 22:10:55 +0000 |
commit | 07368af0833c1bfc29e35a1eabb4f269eafd8825 (patch) | |
tree | 4d0ce764a2da2a85fc1156dfef15707121d08af7 /gcc/fortran/resolve.c | |
parent | 54b0bc0008d05bb93fd3b1608c616299724fc942 (diff) | |
download | gcc-07368af0833c1bfc29e35a1eabb4f269eafd8825.zip gcc-07368af0833c1bfc29e35a1eabb4f269eafd8825.tar.gz gcc-07368af0833c1bfc29e35a1eabb4f269eafd8825.tar.bz2 |
re PR fortran/31879 (ICE with function having array of character variables argument)
2007-08-31 Paul Thomas <pault@gcc.gnu.org>
PR fortran/31879
PR fortran/31197
PR fortran/31258
PR fortran/32703
* gfortran.h : Add prototype for gfc_resolve_substring_charlen.
* resolve.c (gfc_resolve_substring_charlen): New function.
(resolve_ref): Call gfc_resolve_substring_charlen.
(gfc_resolve_character_operator): New function.
(gfc_resolve_expr): Call the new functions in cases where the
character length is missing.
* iresolve.c (cshift, eoshift, merge, pack, reshape, spread,
transpose, unpack): Call gfc_resolve_substring_charlen for
source expressions that are character and have a reference.
* trans.h (gfc_trans_init_string_length) Change name to
gfc_conv_string_length; modify references in trans-expr.c,
trans-array.c and trans-decl.c.
* trans-expr.c (gfc_trans_string_length): Handle case of no
backend_decl.
(gfc_conv_aliased_arg): Remove code for treating substrings
and replace with call to gfc_trans_string_length.
* trans-array.c (gfc_conv_expr_descriptor): Remove code for
treating strings and call gfc_trans_string_length instead.
2007-08-31 Paul Thomas <pault@gcc.gnu.org>
PR fortran/31879
* gfortran.dg/char_length_7.f90: New test.
* gfortran.dg/char_length_9.f90: New test.
* gfortran.dg/char_assign_1.f90: Add extra warning.
PR fortran/31197
PR fortran/31258
* gfortran.dg/char_length_8.f90: New test.
From-SVN: r127939
Diffstat (limited to 'gcc/fortran/resolve.c')
-rw-r--r-- | gcc/fortran/resolve.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 4610c08..424acfc 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -3535,6 +3535,70 @@ resolve_substring (gfc_ref *ref) } +/* This function supplies missing substring charlens. */ + +void +gfc_resolve_substring_charlen (gfc_expr *e) +{ + gfc_ref *char_ref; + gfc_expr *start, *end; + + for (char_ref = e->ref; char_ref; char_ref = char_ref->next) + if (char_ref->type == REF_SUBSTRING) + break; + + if (!char_ref) + return; + + gcc_assert (char_ref->next == NULL); + + if (e->ts.cl) + { + if (e->ts.cl->length) + gfc_free_expr (e->ts.cl->length); + else if (e->expr_type == EXPR_VARIABLE + && e->symtree->n.sym->attr.dummy) + return; + } + + e->ts.type = BT_CHARACTER; + e->ts.kind = gfc_default_character_kind; + + if (!e->ts.cl) + { + e->ts.cl = gfc_get_charlen (); + e->ts.cl->next = gfc_current_ns->cl_list; + gfc_current_ns->cl_list = e->ts.cl; + } + + if (char_ref->u.ss.start) + start = gfc_copy_expr (char_ref->u.ss.start); + else + start = gfc_int_expr (1); + + if (char_ref->u.ss.end) + end = gfc_copy_expr (char_ref->u.ss.end); + else if (e->expr_type == EXPR_VARIABLE) + end = gfc_copy_expr (e->symtree->n.sym->ts.cl->length); + else + end = NULL; + + if (!start || !end) + return; + + /* Length = (end - start +1). */ + e->ts.cl->length = gfc_subtract (end, start); + e->ts.cl->length = gfc_add (e->ts.cl->length, gfc_int_expr (1)); + + e->ts.cl->length->ts.type = BT_INTEGER; + e->ts.cl->length->ts.kind = gfc_charlen_int_kind;; + + /* Make sure that the length is simplified. */ + gfc_simplify_expr (e->ts.cl->length, 1); + gfc_resolve_expr (e->ts.cl->length); +} + + /* Resolve subtype references. */ static try @@ -3908,6 +3972,78 @@ check_host_association (gfc_expr *e) } +static void +gfc_resolve_character_operator (gfc_expr *e) +{ + gfc_expr *op1 = e->value.op.op1; + gfc_expr *op2 = e->value.op.op2; + gfc_expr *e1 = NULL; + gfc_expr *e2 = NULL; + + gcc_assert (e->value.op.operator == INTRINSIC_CONCAT); + + if (op1->ts.cl && op1->ts.cl->length) + e1 = gfc_copy_expr (op1->ts.cl->length); + else if (op1->expr_type == EXPR_CONSTANT) + e1 = gfc_int_expr (op1->value.character.length); + + if (op2->ts.cl && op2->ts.cl->length) + e2 = gfc_copy_expr (op2->ts.cl->length); + else if (op2->expr_type == EXPR_CONSTANT) + e2 = gfc_int_expr (op2->value.character.length); + + e->ts.cl = gfc_get_charlen (); + e->ts.cl->next = gfc_current_ns->cl_list; + gfc_current_ns->cl_list = e->ts.cl; + + if (!e1 || !e2) + return; + + e->ts.cl->length = gfc_add (e1, e2); + e->ts.cl->length->ts.type = BT_INTEGER; + e->ts.cl->length->ts.kind = gfc_charlen_int_kind;; + gfc_simplify_expr (e->ts.cl->length, 0); + gfc_resolve_expr (e->ts.cl->length); + + return; +} + + +/* Ensure that an character expression has a charlen and, if possible, a + length expression. */ + +static void +fixup_charlen (gfc_expr *e) +{ + /* The cases fall through so that changes in expression type and the need + for multiple fixes are picked up. In all circumstances, a charlen should + be available for the middle end to hang a backend_decl on. */ + switch (e->expr_type) + { + case EXPR_OP: + gfc_resolve_character_operator (e); + + case EXPR_ARRAY: + if (e->expr_type == EXPR_ARRAY) + gfc_resolve_character_array_constructor (e); + + case EXPR_SUBSTRING: + if (!e->ts.cl && e->ref) + gfc_resolve_substring_charlen (e); + + default: + if (!e->ts.cl) + { + e->ts.cl = gfc_get_charlen (); + e->ts.cl->next = gfc_current_ns->cl_list; + gfc_current_ns->cl_list = e->ts.cl; + } + + break; + } +} + + /* Resolve an expression. That is, make sure that types of operands agree with their operators, intrinsic operators are converted to function calls for overloaded types and unresolved function references are resolved. */ @@ -3937,6 +4073,11 @@ gfc_resolve_expr (gfc_expr *e) if (t == SUCCESS) expression_rank (e); } + + if (e->ts.type == BT_CHARACTER && e->ts.cl == NULL && e->ref + && e->ref->type != REF_SUBSTRING) + gfc_resolve_substring_charlen (e); + break; case EXPR_SUBSTRING: @@ -3985,6 +4126,9 @@ gfc_resolve_expr (gfc_expr *e) gfc_internal_error ("gfc_resolve_expr(): Bad expression type"); } + if (e->ts.type == BT_CHARACTER && t == SUCCESS && !e->ts.cl) + fixup_charlen (e); + return t; } |