]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Catch division by zero errors in array sizes.
authorThomas Koenig <tkoenig@gcc.gnu.org>
Mon, 30 Dec 2019 13:10:37 +0000 (13:10 +0000)
committerThomas Koenig <tkoenig@gcc.gnu.org>
Mon, 30 Dec 2019 13:10:37 +0000 (13:10 +0000)
2019-12-30  Thomas Koenig  <tkoenig@gcc.gnu.org>

Backport from trunk
PR fortran/92961
* gfortran.h (gfc_seen_div0): Add declaration.
* arith.h (gfc_seen_div0): Add definition.
(eval_intrinsic): For integer division by zero, set gfc_seen_div0.
* decl.c (variable_decl):  If resolution resp. simplification
fails for array spec and a division of zero error has been
seen, return MATCH_ERROR.

2019-12-30  Thomas Koenig  <tkoenig@gcc.gnu.org>

Backport from trunk
PR fortran/92961
* gfortran.dg/arith_divide_2.f90: New test.

From-SVN: r279767

gcc/fortran/arith.c
gcc/fortran/decl.c
gcc/fortran/gfortran.h
gcc/testsuite/gfortran.dg/arith_divide_2.f90 [new file with mode: 0644]

index a4f879531d9d6e458af384c4cfc8917d6ca92af5..8c025045b93b6ce41f39f2fcd568d113f9e93f58 100644 (file)
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "target-memory.h"
 #include "constructor.h"
 
+bool gfc_seen_div0;
+
 /* MPFR does not have a direct replacement for mpz_set_f() from GMP.
    It's easily implemented with a few calls though.  */
 
@@ -1620,6 +1622,10 @@ eval_intrinsic (gfc_intrinsic_op op,
       gfc_error (gfc_arith_error (rc), &op1->where);
       if (rc == ARITH_OVERFLOW)
        goto done;
+
+      if (rc == ARITH_DIV0 && op2->ts.type == BT_INTEGER)
+       gfc_seen_div0 = true;
+
       return NULL;
     }
 
index 52a98cd44ed4a451ad753001090c88dc95472f94..053f78321c6d482d846a24614cb53ef48a0519a4 100644 (file)
@@ -2511,6 +2511,8 @@ variable_decl (int elem)
          goto cleanup;
        }
 
+      gfc_seen_div0 = false;
+      
       /* F2018:C830 (R816) An explicit-shape-spec whose bounds are not
         constant expressions shall appear only in a subprogram, derived
         type definition, BLOCK construct, or interface body.  */
@@ -2527,7 +2529,12 @@ variable_decl (int elem)
          for (int i = 0; i < as->rank; i++)
            {
              e = gfc_copy_expr (as->lower[i]);
-             gfc_resolve_expr (e);
+             if (!gfc_resolve_expr (e) && gfc_seen_div0)
+               {
+                 m = MATCH_ERROR;
+                 goto cleanup;
+               }
+
              gfc_simplify_expr (e, 0);
              if (e && (e->expr_type != EXPR_CONSTANT))
                {
@@ -2537,7 +2544,12 @@ variable_decl (int elem)
              gfc_free_expr (e);
 
              e = gfc_copy_expr (as->upper[i]);
-             gfc_resolve_expr (e);
+             if (!gfc_resolve_expr (e)  && gfc_seen_div0)
+               {
+                 m = MATCH_ERROR;
+                 goto cleanup;
+               }
+
              gfc_simplify_expr (e, 0);
              if (e && (e->expr_type != EXPR_CONSTANT))
                {
@@ -2563,7 +2575,12 @@ variable_decl (int elem)
              if (e->expr_type != EXPR_CONSTANT)
                {
                  n = gfc_copy_expr (e);
-                 gfc_simplify_expr (n, 1);
+                 if (!gfc_simplify_expr (n, 1)  && gfc_seen_div0) 
+                   {
+                     m = MATCH_ERROR;
+                     goto cleanup;
+                   }
+
                  if (n->expr_type == EXPR_CONSTANT)
                    gfc_replace_expr (e, n);
                  else
@@ -2573,7 +2590,12 @@ variable_decl (int elem)
              if (e->expr_type != EXPR_CONSTANT)
                {
                  n = gfc_copy_expr (e);
-                 gfc_simplify_expr (n, 1);
+                 if (!gfc_simplify_expr (n, 1)  && gfc_seen_div0) 
+                   {
+                     m = MATCH_ERROR;
+                     goto cleanup;
+                   }
+                 
                  if (n->expr_type == EXPR_CONSTANT)
                    gfc_replace_expr (e, n);
                  else
@@ -2910,6 +2932,7 @@ variable_decl (int elem)
 
 cleanup:
   /* Free stuff up and return.  */
+  gfc_seen_div0 = false;
   gfc_free_expr (initializer);
   gfc_free_array_spec (as);
 
index 29b962d889c390a7ba300d94e2d8f40cf25a4293..d7071ae5fcf51e79344e384ad9865ad61bc55339 100644 (file)
@@ -2967,6 +2967,8 @@ void gfc_arith_done_1 (void);
 arith gfc_check_integer_range (mpz_t p, int kind);
 bool gfc_check_character_range (gfc_char_t, int);
 
+extern bool gfc_seen_div0;
+
 /* trans-types.c */
 bool gfc_check_any_c_kind (gfc_typespec *);
 int gfc_validate_kind (bt, int, bool);
diff --git a/gcc/testsuite/gfortran.dg/arith_divide_2.f90 b/gcc/testsuite/gfortran.dg/arith_divide_2.f90
new file mode 100644 (file)
index 0000000..ffafa26
--- /dev/null
@@ -0,0 +1,9 @@
+! { dg-do compile }
+! PR 92961 - this used to ICE. Original test case by Gerhard Steinmetz.
+program p
+   integer :: a((0)/0)    ! { dg-error "Division by zero" }
+   integer :: b(0/(0))    ! { dg-error "Division by zero" }
+   integer :: c((0)/(0))  ! { dg-error "Division by zero" }
+   integer :: d(0/0)      ! { dg-error "Division by zero" }
+   integer :: x = ubound(a,1) ! { dg-error "must be an array" }
+end