Hi,

the attached should be mostly self-explaining.  Division by zero handling
appeared to be incomplete.  It was not dealt with properly when occurring
in declaration statements.  We now try to handle this.

OK for mainline?

Thanks,
Harald



PR fortran/93499 - ICE on division by zero in declaration statements

        Division by zero in declaration statements could sometimes
        generate NULL pointers being passed around that lead to ICEs.

gcc/fortran/ChangeLog:

2020-05-09  Harald Anlauf  <anl...@gmx.de>

        PR fortran/93499
        * arith.c (gfc_divide): Catch division by zero.
        (eval_intrinsic_f3): Safeguard for NULL operands.

gcc/testsuite/ChangeLog:

2020-05-09  Harald Anlauf  <anl...@gmx.de>

        PR fortran/93499
        * gfortran.dg/pr93499.f90: New test.

diff --git a/gcc/fortran/arith.c b/gcc/fortran/arith.c
index 422ef40c431..1cd0867a941 100644
--- a/gcc/fortran/arith.c
+++ b/gcc/fortran/arith.c
@@ -1746,6 +1746,9 @@ eval_intrinsic_f3 (gfc_intrinsic_op op,
   gfc_expr *result;
   eval_f f;

+  if (!op1 && !op2)
+    return NULL;
+
   result = reduce_binary0 (op1, op2);
   if (result != NULL)
     return eval_type_intrinsic0(op, result);
@@ -1803,6 +1806,37 @@ gfc_multiply (gfc_expr *op1, gfc_expr *op2)
 gfc_expr *
 gfc_divide (gfc_expr *op1, gfc_expr *op2)
 {
+  if (op2 && op2->expr_type == EXPR_CONSTANT)
+    {
+      arith rc = ARITH_OK;
+      switch (op2->ts.type)
+	{
+	case BT_INTEGER:
+	  /* non-integer divided by integer 0 is handled elsewhere.  */
+	  if (mpz_sgn (op2->value.integer) == 0
+	      && op1->ts.type == BT_INTEGER)
+	    rc = ARITH_DIV0;
+	  break;
+	case BT_REAL:
+	  if (mpfr_sgn (op2->value.real) == 0
+	      && flag_range_check == 1)
+	    rc = ARITH_DIV0;
+	  break;
+	case BT_COMPLEX:
+	  if (mpc_cmp_si_si (op2->value.complex, 0, 0) == 0
+	      && flag_range_check == 1)
+	    rc = ARITH_DIV0;
+	  break;
+	default:
+	  gfc_internal_error ("gfc_divide(): Bad basic type");
+	}
+      if (rc == ARITH_DIV0)
+	{
+	  gfc_seen_div0 = true;
+	  gfc_error ("Division by zero at %L", &op2->where);
+	  return NULL;
+	}
+    }
   return eval_intrinsic_f3 (INTRINSIC_DIVIDE, gfc_arith_divide, op1, op2);
 }

diff --git a/gcc/testsuite/gfortran.dg/pr93499.f90 b/gcc/testsuite/gfortran.dg/pr93499.f90
new file mode 100644
index 00000000000..7a414bb6016
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr93499.f90
@@ -0,0 +1,10 @@
+! { dg-do compile }
+! PR 93499 - this used to ICE. Original test case by Gerhard Steinmetz.
+
+program p
+  integer :: a((0.)/0)  ! { dg-error "Division by zero" }
+  type t(n)
+     integer, len :: n
+  end type t
+  type(t((0)/0))  :: x  ! { dg-error "Division by zero" }
+end

Reply via email to