aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/array.c
diff options
context:
space:
mode:
authorThomas Koenig <tkoenig@gcc.gnu.org>2013-08-25 22:55:12 +0000
committerThomas Koenig <tkoenig@gcc.gnu.org>2013-08-25 22:55:12 +0000
commit8cd61b3c8b6bc6ff336995312e06748c602ec6dd (patch)
treea2e63d552ee312ff52abe80fd7a8922174507b77 /gcc/fortran/array.c
parent7ecc260031bb303b3fb04895f1951d8914ac7f73 (diff)
downloadgcc-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.c66
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);