From 43c0185764ec878576ef2255d9df24fbb1961af4 Mon Sep 17 00:00:00 2001 From: Harald Anlauf Date: Wed, 24 Jan 2024 22:28:31 +0100 Subject: [PATCH] Fortran: use name of array component in runtime error message [PR30802] gcc/fortran/ChangeLog: PR fortran/30802 * trans-array.cc (trans_array_bound_check): Derive name of component for use in runtime error message. gcc/testsuite/ChangeLog: PR fortran/30802 * gfortran.dg/bounds_check_fail_8.f90: New test. --- gcc/fortran/trans-array.cc | 34 ++++++++++++++++++ .../gfortran.dg/bounds_check_fail_8.f90 | 35 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/bounds_check_fail_8.f90 diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc index 878a92aff18..f6ddce2d023 100644 --- a/gcc/fortran/trans-array.cc +++ b/gcc/fortran/trans-array.cc @@ -3497,6 +3497,10 @@ trans_array_bound_check (gfc_se * se, gfc_ss *ss, tree index, int n, tree descriptor; char *msg; const char * name = NULL; + char *var_name = NULL; + gfc_expr *expr; + gfc_ref *ref; + size_t len; if (!(gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)) return index; @@ -3509,6 +3513,36 @@ trans_array_bound_check (gfc_se * se, gfc_ss *ss, tree index, int n, name = ss->info->expr->symtree->n.sym->name; gcc_assert (name != NULL); + /* When we have a component ref, compile name for the array section. + Note that there can only be one part ref. */ + expr = ss->info->expr; + if (expr->ref && !compname) + { + len = strlen (name) + 1; + + /* Find a safe length. */ + for (ref = expr->ref; ref; ref = ref->next) + if (ref->type == REF_COMPONENT) + len += 2 + strlen (ref->u.c.component->name); + + var_name = XALLOCAVEC (char, len); + strcpy (var_name, name); + + for (ref = expr->ref; ref; ref = ref->next) + { + /* Append component name. */ + if (ref->type == REF_COMPONENT) + { + strcat (var_name, "%%"); + strcat (var_name, ref->u.c.component->name); + continue; + } + if (ref->type == REF_ARRAY && ref->u.ar.type == AR_SECTION) + break; + } + name = var_name; + } + if (VAR_P (descriptor)) name = IDENTIFIER_POINTER (DECL_NAME (descriptor)); diff --git a/gcc/testsuite/gfortran.dg/bounds_check_fail_8.f90 b/gcc/testsuite/gfortran.dg/bounds_check_fail_8.f90 new file mode 100644 index 00000000000..3397e953ba6 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/bounds_check_fail_8.f90 @@ -0,0 +1,35 @@ +! { dg-do compile } +! { dg-additional-options "-fcheck=bounds -g -fdump-tree-original" } +! { dg-output "At line 22 .*" } +! { dg-shouldfail "dimension 3 of array 'uu%z' outside of expected range" } +! +! PR fortran/30802 - improve bounds-checking for array references +! +! Checking the proper component references is the most important part here. + +program test + implicit none + integer :: k = 0 + type t + real, dimension(10,20,30) :: z = 23 + end type t + type u + type(t) :: vv(4,5) + end type u + type(t) :: uu, ww(1) + type(u) :: x1, x2, y1(1), y2(1) + + print *, uu % z(1,k,:) ! runtime check only for dimension 2 of z + print *, ww(1)% z(1,:,k) ! runtime check only for dimension 3 of z + print *, x1 % vv(2,3)% z(1,:,k) ! runtime check only for dimension 3 of z + print *, x2 % vv(k,:)% z(1,2,3) ! runtime check only for dimension 1 of vv + print *, y1(1)% vv(2,3)% z(1,:,k) ! runtime check only for dimension 3 of z + print *, y2(1)% vv(:,k)% z(1,2,3) ! runtime check only for dimension 2 of vv +end program test + +! { dg-final { scan-tree-dump-times "'uu%%z.' outside of expected range" 2 "original" } } +! { dg-final { scan-tree-dump-times "'ww%%z.' outside of expected range" 2 "original" } } +! { dg-final { scan-tree-dump-times "'x1%%vv%%z.' outside of expected range" 2 "original" } } +! { dg-final { scan-tree-dump-times "'x2%%vv.' outside of expected range" 2 "original" } } +! { dg-final { scan-tree-dump-times "'y1%%vv%%z.' outside of expected range" 2 "original" } } +! { dg-final { scan-tree-dump-times "'y2%%vv.' outside of expected range" 2 "original" } } -- 2.35.3