diff options
author | Thomas Koenig <tkoenig@gcc.gnu.org> | 2010-12-24 08:42:04 +0000 |
---|---|---|
committer | Thomas Koenig <tkoenig@gcc.gnu.org> | 2010-12-24 08:42:04 +0000 |
commit | 07818af47b961b903aee005f6771e14730d3e003 (patch) | |
tree | ba500f5c6a595579533936d48e7faf3bf7b7a1d0 /gcc/fortran | |
parent | ab9d6dcfbeced3e2e0052c1cacb541e79e622bdf (diff) | |
download | gcc-07818af47b961b903aee005f6771e14730d3e003.zip gcc-07818af47b961b903aee005f6771e14730d3e003.tar.gz gcc-07818af47b961b903aee005f6771e14730d3e003.tar.bz2 |
re PR fortran/31821 (character pointer => target(range) should detect if lengths don't match)
2010-12-24 Thomas Koenig <tkoenig@gcc.gnu.org>
PR fortran/31821
* check.c (gfc_var_strlen): New function, also including
substring references.
(gfc_check_same_strlen): Use gfc_var_strlen.
2010-12-24 Thomas Koenig <tkoenig@gcc.gnu.org>
PR fortran/31821
* gfortran.dg/char_pointer_assign_6.f90: New test.
From-SVN: r168224
Diffstat (limited to 'gcc/fortran')
-rw-r--r-- | gcc/fortran/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/fortran/check.c | 77 |
2 files changed, 60 insertions, 24 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 4ffb3e3..980d1b1 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,10 @@ +2010-12-24 Thomas Koenig <tkoenig@gcc.gnu.org> + + PR fortran/31821 + * check.c (gfc_var_strlen): New function, also including + substring references. + (gfc_check_same_strlen): Use gfc_var_strlen. + 2010-12-23 Mikael Morin <mikael.morin@gcc.gnu.org> PR fortran/46978 diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c index ceea6f3..20163f9 100644 --- a/gcc/fortran/check.c +++ b/gcc/fortran/check.c @@ -635,40 +635,69 @@ identical_dimen_shape (gfc_expr *a, int ai, gfc_expr *b, int bi) return ret; } +/* Calculate the length of a character variable, including substrings. + Strip away parentheses if necessary. Return -1 if no length could + be determined. */ + +static long +gfc_var_strlen (const gfc_expr *a) +{ + gfc_ref *ra; + + while (a->expr_type == EXPR_OP && a->value.op.op == INTRINSIC_PARENTHESES) + a = a->value.op.op1; + + for (ra = a->ref; ra != NULL && ra->type != REF_SUBSTRING; ra = ra->next) + ; + + if (ra) + { + long start_a, end_a; + + if (ra->u.ss.start->expr_type == EXPR_CONSTANT + && ra->u.ss.end->expr_type == EXPR_CONSTANT) + { + start_a = mpz_get_si (ra->u.ss.start->value.integer); + end_a = mpz_get_si (ra->u.ss.end->value.integer); + return end_a - start_a + 1; + } + else if (gfc_dep_compare_expr (ra->u.ss.start, ra->u.ss.end) == 0) + return 1; + else + return -1; + } + + if (a->ts.u.cl && a->ts.u.cl->length + && a->ts.u.cl->length->expr_type == EXPR_CONSTANT) + return mpz_get_si (a->ts.u.cl->length->value.integer); + else if (a->expr_type == EXPR_CONSTANT + && (a->ts.u.cl == NULL || a->ts.u.cl->length == NULL)) + return a->value.character.length; + else + return -1; + +} /* Check whether two character expressions have the same length; - returns SUCCESS if they have or if the length cannot be determined. */ + returns SUCCESS if they have or if the length cannot be determined, + otherwise return FAILURE and raise a gfc_error. */ gfc_try gfc_check_same_strlen (const gfc_expr *a, const gfc_expr *b, const char *name) { long len_a, len_b; - len_a = len_b = -1; - - if (a->ts.u.cl && a->ts.u.cl->length - && a->ts.u.cl->length->expr_type == EXPR_CONSTANT) - len_a = mpz_get_si (a->ts.u.cl->length->value.integer); - else if (a->expr_type == EXPR_CONSTANT - && (a->ts.u.cl == NULL || a->ts.u.cl->length == NULL)) - len_a = a->value.character.length; - else - return SUCCESS; - if (b->ts.u.cl && b->ts.u.cl->length - && b->ts.u.cl->length->expr_type == EXPR_CONSTANT) - len_b = mpz_get_si (b->ts.u.cl->length->value.integer); - else if (b->expr_type == EXPR_CONSTANT - && (b->ts.u.cl == NULL || b->ts.u.cl->length == NULL)) - len_b = b->value.character.length; - else - return SUCCESS; + len_a = gfc_var_strlen(a); + len_b = gfc_var_strlen(b); - if (len_a == len_b) + if (len_a == -1 || len_b == -1 || len_a == len_b) return SUCCESS; - - gfc_error ("Unequal character lengths (%ld/%ld) in %s at %L", - len_a, len_b, name, &a->where); - return FAILURE; + else + { + gfc_error ("Unequal character lengths (%ld/%ld) in %s at %L", + len_a, len_b, name, &a->where); + return FAILURE; + } } |