As discussed in the PR, match.pd happily folds 0 * whatever into 0.  That
is undesirable from the C/C++ FE POV, since it can make us accept invalid
initializers.

So fixed in match.pd -- I'd hope there's a better way to do this, but this
seems to work.  There was some fallout, but nothing unexpected or surprising.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2015-05-13  Marek Polacek  <pola...@redhat.com>

        PR middle-end/66127
        * match.pd (0 * X): Preserve divisions by zero.

        * g++.dg/warn/overflow-warn-1.C: Adjust dg-warning and dg-error.
        * g++.dg/warn/overflow-warn-3.C: Likewise.
        * g++.dg/warn/overflow-warn-4.C: Likewise.
        * g++.dg/ubsan/div-by-zero-1.C: Likewise.

diff --git gcc/match.pd gcc/match.pd
index 51a950a..510e2db 100644
--- gcc/match.pd
+++ gcc/match.pd
@@ -78,7 +78,19 @@ along with GCC; see the file COPYING3.  If not see
 
 (simplify
  (mult @0 integer_zerop@1)
- @1)
+ /* Make sure to preserve divisions by zero.  */
+ (with { enum tree_code code = TREE_CODE (@0); }
+  (if ((code != TRUNC_DIV_EXPR
+       && code != EXACT_DIV_EXPR
+       && code != ROUND_DIV_EXPR
+       && code != FLOOR_DIV_EXPR
+       && code != CEIL_DIV_EXPR
+       && code != TRUNC_MOD_EXPR
+       && code != CEIL_MOD_EXPR
+       && code != FLOOR_MOD_EXPR
+       && code != ROUND_MOD_EXPR)
+       || !integer_zerop (TREE_OPERAND (@0, 1)))
+ @1)))
 
 /* Maybe fold x * 0 to 0.  The expressions aren't the same
    when x is NaN, since x * 0 is also NaN.  Nor are they the
--- gcc/testsuite/g++.dg/warn/overflow-warn-1.C
+++ gcc/testsuite/g++.dg/warn/overflow-warn-1.C
@@ -17,7 +17,7 @@ enum e {
   /* But as in DR#031, the 1/0 in an evaluated subexpression means the
      whole expression violates the constraints.  */
   E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
-  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum 
error" { xfail *-*-* } 19 } */
+  /* { dg-error "enumerator value for 'E4' is not an integer constant|not a 
constant.expression" "enum error" { target *-*-* } 19 } */
   E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
   /* { dg-warning "overflow in constant expression" "constant" { target *-*-* 
} 21 } */
   /* Again, overflow in evaluated subexpression.  */
@@ -30,8 +30,9 @@ enum e {
 struct s {
   int a;
   int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
+  /* { dg-error "not an integer constant|not a constant.expression" "bit-field 
error" { target *-*-* } 32 } */
   int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } 
*/
-  /* { dg-warning "overflow in constant expression" "constant" { target *-*-* 
} 33 } */
+  /* { dg-warning "overflow in constant expression" "constant" { target *-*-* 
} 34 } */
 };
 
 void
@@ -45,7 +46,6 @@ f (void)
 /* This expression is neither required to be constant.  */
 static int sc = INT_MAX + 1; /* { dg-warning "integer overflow in expression" 
} */
 
-
 // Test for overflow in null pointer constant.  
 void *n = 0;
 /* The first two of these involve overflow, so are not null pointer
@@ -54,7 +54,7 @@ void *n = 0;
 void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" 
} */
 /* { dg-warning "invalid conversion from 'int' to 'void" "null" { target *-*-* 
} 54 } */
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-error "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* 
} 56 } */
+/* { dg-warning "invalid conversion from 'int' to 'void\\*'" "null" { target 
*-*-* } 56 } */
 void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" 
"" { xfail *-*-* } } */
 
 void
@@ -63,9 +63,10 @@ g (int i)
   switch (i)
     {
     case 0 * (1/0): /* { dg-warning "division by zero" } */
+      /* { dg-error "not a constant.expression" "case error" { target *-*-* } 
65 } */
       ;
     case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in 
expression" } */
-      /* { dg-warning "overflow in constant expression" "constant" { target 
*-*-* } 67 } */
+      /* { dg-warning "overflow in constant expression" "constant" { target 
*-*-* } 68 } */
       ;
     }
 }
--- gcc/testsuite/g++.dg/warn/overflow-warn-3.C
+++ gcc/testsuite/g++.dg/warn/overflow-warn-3.C
@@ -17,7 +17,7 @@ enum e {
   /* But as in DR#031, the 1/0 in an evaluated subexpression means the
      whole expression violates the constraints.  */
   E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
-  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum 
error" { xfail *-*-* } 19 } */
+  /* { dg-error "enumerator value for 'E4' is not an integer constant|not a 
constant.expression" "enum error" { target *-*-* } 19 } */
   E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
   /* { dg-warning "overflow in constant expression" "constant" { target *-*-* 
} 21 } */
   /* Again, overflow in evaluated subexpression.  */
@@ -30,8 +30,9 @@ enum e {
 struct s {
   int a;
   int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
+  /* { dg-error "not an integer constant|not a constant.expression" "bit-field 
error" { target *-*-* } 32 } */
   int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } 
*/
-  /* { dg-warning "overflow in constant expression" "constant" { target *-*-* 
} 33 } */
+  /* { dg-warning "overflow in constant expression" "constant" { target *-*-* 
} 34 } */
 };
 
 void
@@ -40,7 +41,6 @@ f (void)
   /* This expression is not required to be a constant expression, so
      it should just involve undefined behavior at runtime.  */
   int c = INT_MAX + 1; /* { dg-warning "integer overflow in expression" } */
-
 }
 
 /* This expression is neither required to be constant.  */
@@ -56,7 +56,7 @@ void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer 
overflow in expression" }
 /* { dg-warning "invalid conversion from 'int' to 'void" "null" { target *-*-* 
} 55 } */
 
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-warning "invalid conversion from 'int' to 'void*'" "null" { xfail 
*-*-* } 58 } */
+/* { dg-warning "invalid conversion from 'int' to 'void\\*'" "null" { target 
*-*-* } 58 } */
 void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" 
"" { xfail *-*-* } } */
 
 void
@@ -65,9 +65,10 @@ g (int i)
   switch (i)
     {
     case 0 * (1/0): /* { dg-warning "division by zero" } */
+      /* { dg-error "not a constant.expression" "case error" { target *-*-* } 
67 } */
       ;
     case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in 
expression" } */
-      /* { dg-warning "overflow in constant expression" "constant" { target 
*-*-* } 69 } */
+      /* { dg-warning "overflow in constant expression" "constant" { target 
*-*-* } 70 } */
       ;
     }
 }
--- gcc/testsuite/g++.dg/warn/overflow-warn-4.C
+++ gcc/testsuite/g++.dg/warn/overflow-warn-4.C
@@ -17,7 +17,7 @@ enum e {
   /* But as in DR#031, the 1/0 in an evaluated subexpression means the
      whole expression violates the constraints.  */
   E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
-  /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum 
error" { xfail *-*-* } 19 } */
+  /* { dg-error "enumerator value for 'E4' is not an integer constant|not a 
constant.expression" "enum error" { target *-*-* } 19 } */
   E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
   /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 
21 } */
   /* { dg-error "enumerator value for 'E5' is not an integer constant" "enum 
error" { target *-*-* } 21 } */
@@ -32,9 +32,10 @@ enum e {
 struct s {
   int a;
   int : 0 * (1 / 0); /* { dg-warning "division by zero" } */
+  /* { dg-error "not an integer constant|not a constant.expression" "bit-field 
error" { target *-*-* } 34 } */
   int : 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } 
*/
-  /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 
35 } */
-  /* { dg-error "bit-field .* width not an integer constant" "" { target *-*-* 
} 35 } */
+  /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 
36 } */
+  /* { dg-error "bit-field .* width not an integer constant" "" { target *-*-* 
} 36 } */
 };
 
 void
@@ -43,7 +44,6 @@ f (void)
   /* This expression is not required to be a constant expression, so
      it should just involve undefined behavior at runtime.  */
   int c = INT_MAX + 1; /* { dg-warning "integer overflow in expression" } */
-
 }
 
 /* This expression is neither required to be constant.  */
@@ -59,7 +59,7 @@ void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer 
overflow in expression" }
 /* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 
58 } */
 
 void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-error "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* 
} 61 } */
+/* { dg-error "invalid conversion from 'int' to 'void\\*'" "null" { target 
*-*-* } 61 } */
 void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" 
"" { xfail *-*-* } } */
 
 void
@@ -68,9 +68,10 @@ g (int i)
   switch (i)
     {
     case 0 * (1/0): /* { dg-warning "division by zero" } */
+      /* { dg-error "not a constant.expression" "case error" { target *-*-* } 
70 } */
       ;
     case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in 
expression" } */
-      /* { dg-error "overflow in constant expression" "constant" { target 
*-*-* } 72 } */
+      /* { dg-error "overflow in constant expression" "constant" { target 
*-*-* } 73 } */
       ;
     }
 }
--- gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
+++ gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
@@ -1,14 +1,10 @@
 /* { dg-do compile } */
 /* { dg-options "-fsanitize=integer-divide-by-zero" } */
 
-/* TODO: We expect an error on the invalid case here, because that
-   must be a constant-expression.  This will be fixed when we have
-   proper delayed folding.  */
-
 void
 foo (int i)
 {
   switch (i)
   case 0 * (1 / 0): /* { dg-warning "division by zero" } */
-    ;  /* { dg-error "division by zero" "" { xfail *-*-* } 10 } */
+    ;  /* { dg-error "not a constant.expression" "" { target *-*-* } 8 } */
 }

        Marek

Reply via email to