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