diff options
author | Thomas Koenig <tkoenig@gcc.gnu.org> | 2013-08-25 22:55:12 +0000 |
---|---|---|
committer | Thomas Koenig <tkoenig@gcc.gnu.org> | 2013-08-25 22:55:12 +0000 |
commit | 8cd61b3c8b6bc6ff336995312e06748c602ec6dd (patch) | |
tree | a2e63d552ee312ff52abe80fd7a8922174507b77 /gcc/fortran/array.c | |
parent | 7ecc260031bb303b3fb04895f1951d8914ac7f73 (diff) | |
download | gcc-8cd61b3c8b6bc6ff336995312e06748c602ec6dd.zip gcc-8cd61b3c8b6bc6ff336995312e06748c602ec6dd.tar.gz gcc-8cd61b3c8b6bc6ff336995312e06748c602ec6dd.tar.bz2 |
re PR fortran/58146 (Array slice bounds checking)
2013-08-26 Thomas Koenig <tkoenig@gcc.gnu.org>
PR fortran/58146
* array.c (gfc_ref_dimen_size): If possible, use
gfc_dep_difference to calculate array refrence
sizes. Fall back to integer code otherwise.
* dependency.c (discard_nops). Move up.
Also discarde widening integer conversions.
(gfc_dep_compare_expr): Use discard_nops.
2013-08-26 Thomas Koenig <tkoenig@gcc.gnu.org>
PR fortran/58146
* gfortran.dg/bounds_check_18.f90: New test.
From-SVN: r201981
Diffstat (limited to 'gcc/fortran/array.c')
-rw-r--r-- | gcc/fortran/array.c | 66 |
1 files changed, 56 insertions, 10 deletions
diff --git a/gcc/fortran/array.c b/gcc/fortran/array.c index f07bc64..687ae3d 100644 --- a/gcc/fortran/array.c +++ b/gcc/fortran/array.c @@ -2112,6 +2112,7 @@ bool gfc_ref_dimen_size (gfc_array_ref *ar, int dimen, mpz_t *result, mpz_t *end) { mpz_t upper, lower, stride; + mpz_t diff; bool t; if (dimen < 0 || ar == NULL || dimen > ar->dimen - 1) @@ -2130,9 +2131,63 @@ gfc_ref_dimen_size (gfc_array_ref *ar, int dimen, mpz_t *result, mpz_t *end) break; case DIMEN_RANGE: + + mpz_init (stride); + + if (ar->stride[dimen] == NULL) + mpz_set_ui (stride, 1); + else + { + if (ar->stride[dimen]->expr_type != EXPR_CONSTANT) + { + mpz_clear (stride); + return false; + } + mpz_set (stride, ar->stride[dimen]->value.integer); + } + + /* Calculate the number of elements via gfc_dep_differce, but only if + start and end are both supplied in the reference or the array spec. + This is to guard against strange but valid code like + + subroutine foo(a,n) + real a(1:n) + n = 3 + print *,size(a(n-1:)) + + where the user changes the value of a variable. If we have to + determine end as well, we cannot do this using gfc_dep_difference. + Fall back to the constants-only code then. */ + + if (end == NULL) + { + bool use_dep; + + use_dep = gfc_dep_difference (ar->end[dimen], ar->start[dimen], + &diff); + if (!use_dep && ar->end[dimen] == NULL && ar->start[dimen] == NULL) + use_dep = gfc_dep_difference (ar->as->upper[dimen], + ar->as->lower[dimen], &diff); + + if (use_dep) + { + mpz_init (*result); + mpz_add (*result, diff, stride); + mpz_div (*result, *result, stride); + if (mpz_cmp_ui (*result, 0) < 0) + mpz_set_ui (*result, 0); + + mpz_clear (stride); + mpz_clear (diff); + return true; + } + + } + + /* Constant-only code here, which covers more cases + like a(:4) etc. */ mpz_init (upper); mpz_init (lower); - mpz_init (stride); t = false; if (ar->start[dimen] == NULL) @@ -2163,15 +2218,6 @@ gfc_ref_dimen_size (gfc_array_ref *ar, int dimen, mpz_t *result, mpz_t *end) mpz_set (upper, ar->end[dimen]->value.integer); } - if (ar->stride[dimen] == NULL) - mpz_set_ui (stride, 1); - else - { - if (ar->stride[dimen]->expr_type != EXPR_CONSTANT) - goto cleanup; - mpz_set (stride, ar->stride[dimen]->value.integer); - } - mpz_init (*result); mpz_sub (*result, upper, lower); mpz_add (*result, *result, stride); |