]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fortran: improve checking of substring bounds [PR119118]
authorHarald Anlauf <anlauf@gmx.de>
Thu, 6 Mar 2025 20:45:42 +0000 (21:45 +0100)
committerHarald Anlauf <anlauf@gmx.de>
Thu, 6 Mar 2025 21:41:33 +0000 (22:41 +0100)
After the fix for pr98490 no substring bounds check was generated if the
substring start was not a variable.  While the purpose of that fix was to
suppress a premature check before implied-do indices were substituted, this
prevented a check if the substring start was an expression or a constant.
A better solution is to defer the check until implied-do indices have been
substituted in the start and end expressions.

PR fortran/119118

gcc/fortran/ChangeLog:

* dependency.cc (gfc_contains_implied_index_p): Helper function to
determine if an expression has a dependence on an implied-do index.
* dependency.h (gfc_contains_implied_index_p): Add prototype.
* trans-expr.cc (gfc_conv_substring): Adjust logic to not generate
substring bounds checks before implied-do indices have been
substituted.

gcc/testsuite/ChangeLog:

* gfortran.dg/bounds_check_23.f90: Generalize test.
* gfortran.dg/bounds_check_26.f90: New test.

gcc/fortran/dependency.cc
gcc/fortran/dependency.h
gcc/fortran/trans-expr.cc
gcc/testsuite/gfortran.dg/bounds_check_23.f90
gcc/testsuite/gfortran.dg/bounds_check_26.f90 [new file with mode: 0644]

index 6b3affa60574cd74ea56f5d56b57b0920a63ae45..8354b185f3473d33dba6d69267a87510ab467632 100644 (file)
@@ -1888,6 +1888,87 @@ contains_forall_index_p (gfc_expr *expr)
   return false;
 }
 
+
+/* Traverse expr, checking all EXPR_VARIABLE symbols for their
+   implied_index attribute.  Return true if any variable may be
+   used as an implied-do index.  It is safe to pessimistically
+   return true, and assume a dependency.  */
+
+bool
+gfc_contains_implied_index_p (gfc_expr *expr)
+{
+  gfc_actual_arglist *arg;
+  gfc_constructor *c;
+  gfc_ref *ref;
+  int i;
+
+  if (!expr)
+    return false;
+
+  switch (expr->expr_type)
+    {
+    case EXPR_VARIABLE:
+      if (expr->symtree->n.sym->attr.implied_index)
+       return true;
+      break;
+
+    case EXPR_OP:
+      if (gfc_contains_implied_index_p (expr->value.op.op1)
+         || gfc_contains_implied_index_p (expr->value.op.op2))
+       return true;
+      break;
+
+    case EXPR_FUNCTION:
+      for (arg = expr->value.function.actual; arg; arg = arg->next)
+       if (gfc_contains_implied_index_p (arg->expr))
+         return true;
+      break;
+
+    case EXPR_CONSTANT:
+    case EXPR_NULL:
+    case EXPR_SUBSTRING:
+      break;
+
+    case EXPR_STRUCTURE:
+    case EXPR_ARRAY:
+      for (c = gfc_constructor_first (expr->value.constructor);
+          c; gfc_constructor_next (c))
+       if (gfc_contains_implied_index_p (c->expr))
+         return true;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  for (ref = expr->ref; ref; ref = ref->next)
+    switch (ref->type)
+      {
+      case REF_ARRAY:
+       for (i = 0; i < ref->u.ar.dimen; i++)
+         if (gfc_contains_implied_index_p (ref->u.ar.start[i])
+             || gfc_contains_implied_index_p (ref->u.ar.end[i])
+             || gfc_contains_implied_index_p (ref->u.ar.stride[i]))
+           return true;
+       break;
+
+      case REF_COMPONENT:
+       break;
+
+      case REF_SUBSTRING:
+       if (gfc_contains_implied_index_p (ref->u.ss.start)
+           || gfc_contains_implied_index_p (ref->u.ss.end))
+         return true;
+       break;
+
+      default:
+       gcc_unreachable ();
+      }
+
+  return false;
+}
+
+
 /* Determines overlapping for two single element array references.  */
 
 static gfc_dependency
index 3f81d406082fc7fa010bf7a6cfaf154d18bc5dc9..2fc2e567a4cfe60da6fe448b93be7a7657ad6616 100644 (file)
@@ -41,6 +41,7 @@ bool gfc_dep_resolver (gfc_ref *, gfc_ref *, gfc_reverse *,
                      bool identical = false);
 bool gfc_are_equivalenced_arrays (gfc_expr *, gfc_expr *);
 bool gfc_omp_expr_prefix_same (gfc_expr *, gfc_expr *);
+bool gfc_contains_implied_index_p (gfc_expr *);
 
 gfc_expr * gfc_discard_nops (gfc_expr *);
 
index fbe7333fd711f071413b04b37da40f8b87098862..d965539f11e7071c2e51965af913448fd992b26b 100644 (file)
@@ -2814,8 +2814,8 @@ gfc_conv_substring (gfc_se * se, gfc_ref * ref, int kind,
     end.expr = gfc_evaluate_now (end.expr, &se->pre);
 
   if ((gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)
-      && (ref->u.ss.start->symtree
-         && !ref->u.ss.start->symtree->n.sym->attr.implied_index))
+      && !gfc_contains_implied_index_p (ref->u.ss.start)
+      && !gfc_contains_implied_index_p (ref->u.ss.end))
     {
       tree nonempty = fold_build2_loc (input_location, LE_EXPR,
                                       logical_type_node, start.expr,
index 8de90c77c0104d394a4f448d5baab69e2ce12764..4ef03a55efcb49488fa75d6db5199fcd604cd7f2 100644 (file)
@@ -5,6 +5,8 @@
 program test
   implicit none
   call sub('Lorem ipsum')
+  call sub2('Lorem ipsum')
+  call sub3('Lorem ipsum')
 contains
   subroutine sub( text )
     character(len=*), intent(in)  :: text
@@ -13,6 +15,20 @@ contains
     c = [ ( text(i:i), i = 1, len(text) ) ]
     if (c(1) /= 'L') stop 1
   end subroutine sub
+  subroutine sub2 (txt2)
+    character(len=*), intent(in)  :: txt2
+    character(len=1), allocatable :: c(:)
+    integer :: i
+    c = [ ( txt2(i+0:i), i = 1, len(txt2) ) ]
+    if (c(1) /= 'L') stop 2
+  end subroutine sub2
+  subroutine sub3 (txt3)
+    character(len=*), intent(in)  :: txt3
+    character(len=1), allocatable :: c(:)
+    integer :: i
+    c = [ ( txt3(i:i+0), i = 1, len(txt3) ) ]
+    if (c(1) /= 'L') stop 3
+  end subroutine sub3
 end program test
 
-! { dg-final { scan-tree-dump-times "Substring out of bounds:" 2 "original" } }
+! { dg-final { scan-tree-dump-times "Substring out of bounds:" 6 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/bounds_check_26.f90 b/gcc/testsuite/gfortran.dg/bounds_check_26.f90
new file mode 100644 (file)
index 0000000..69ac9fb
--- /dev/null
@@ -0,0 +1,24 @@
+! { dg-do compile }
+! { dg-options "-fcheck=bounds -fdump-tree-original" }
+!
+! PR fortran/119118
+
+program main
+  implicit none
+  character(10) :: str = "1234567890"
+  integer       :: n   = 3
+
+  print *,      str(-1:-2)  ! zero-length substring: OK
+
+  print *,      str(-1:n)   ! 2 checked bounds
+  print *, len (str(-1:n))  ! 2 checked bounds
+
+  print *,      str(-n:1)   ! 1 checked bound / 1 eliminated
+  print *, len (str(-n:1))  ! 1 checked bound / 1 eliminated
+
+  print *,      str(-n:11)  ! 2 checked bounds
+  print *, len (str(-n:11)) ! 2 checked bounds
+
+end program main
+
+! { dg-final { scan-tree-dump-times "Substring out of bounds:" 10 "original" } }