Catch division by zero errors in array sizes.
authorThomas Koenig <tkoenig@gcc.gnu.org>
Mon, 30 Dec 2019 10:34:11 +0000 (10:34 +0000)
committerThomas Koenig <tkoenig@gcc.gnu.org>
Mon, 30 Dec 2019 10:34:11 +0000 (10:34 +0000)
2019-12-30  Thomas Koenig  <tkoenig@gcc.gnu.org>

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>

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

From-SVN: r279762

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

index 63a6de616b4035d8b1fd36d191dc46c98e22b8f4..5b92597641b86803eea664b5f77a1860d81db619 100644 (file)
@@ -1,3 +1,13 @@
+2019-12-30  Thomas Koenig  <tkoenig@gcc.gnu.org>
+
+       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-21  Harald Anlauf  <anlauf@gmx.de>
 
        PR fortran/92990
index 7f048da95830f3dacacf7f242f7eeb5bfb149bf5..b7699e44f93fbc4d1749927d6b570a433f0597d0 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 affdbf6908d26d17290809a17b294b4b00200503..b43dc2c0831e64f9d223badc8d447c90c528d0e9 100644 (file)
@@ -2535,6 +2535,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.  */
@@ -2551,7 +2553,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))
                {
@@ -2561,7 +2568,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))
                {
@@ -2587,7 +2599,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
@@ -2597,7 +2614,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
@@ -2934,6 +2956,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 b38238a9faaea34888c0246f3bda8557b3ad5ec7..8e414c48eb10affec8eb905040940586d541d89e 100644 (file)
@@ -2995,6 +2995,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);
index dcc0ec9eea9f2004fe9c12a82f9836fa8966d06f..d7044518a0257a78e4eba20e2e575f3c11c7610c 100644 (file)
@@ -1,3 +1,8 @@
+2019-12-30  Thomas Koenig  <tkoenig@gcc.gnu.org>
+
+       PR fortran/92961
+       * gfortran.dg/arith_divide_2.f90: New test.
+
 2019-12-30  Jakub Jelinek  <jakub@redhat.com>
 
        PR c++/92745
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