Commit f5178456 by Richard Sandiford Committed by Richard Sandiford

c-common.c (c_fully_fold_internal): Issue a warning if a binary operation overflows.

gcc/
	* c-common.c (c_fully_fold_internal): Issue a warning if a binary
	operation overflows.  Likewise non-cast unary arithmetic.
	If one arm of a conditional expression is always taken,
	inhibit evaluation warnings for the other arm.  Likewise inhibit
	evaluation warnings for the second && or || operand if the first
	operand is enough to determine the result.
	* c-typeck.c (build_conditional_expr): Apply the same inhibition
	rules here.
	(build_binary_op): Prevent duplicate evaluation warnings.

gcc/testsuite/
	* gcc.dg/overflow-warn-8.c: New test.

From-SVN: r150594
parent 8f048d2f
2009-08-09 Richard Sandiford <rdsandiford@googlemail.com> 2009-08-09 Richard Sandiford <rdsandiford@googlemail.com>
* c-common.c (c_fully_fold_internal): Issue a warning if a binary
operation overflows. Likewise non-cast unary arithmetic.
If one arm of a conditional expression is always taken,
inhibit evaluation warnings for the other arm. Likewise inhibit
evaluation warnings for the second && or || operand if the first
operand is enough to determine the result.
* c-typeck.c (build_conditional_expr): Apply the same inhibition
rules here.
(build_binary_op): Prevent duplicate evaluation warnings.
2009-08-09 Richard Sandiford <rdsandiford@googlemail.com>
* tree-out-of-ssa.c (insert_value_copy_on_edge): If the source * tree-out-of-ssa.c (insert_value_copy_on_edge): If the source
and destination have different modes, Use promote_mode to and destination have different modes, Use promote_mode to
determine the signedness of the conversion. Assert that the determine the signedness of the conversion. Assert that the
......
...@@ -1133,6 +1133,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, ...@@ -1133,6 +1133,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
bool op0_const = true, op1_const = true, op2_const = true; bool op0_const = true, op1_const = true, op2_const = true;
bool op0_const_self = true, op1_const_self = true, op2_const_self = true; bool op0_const_self = true, op1_const_self = true, op2_const_self = true;
bool nowarning = TREE_NO_WARNING (expr); bool nowarning = TREE_NO_WARNING (expr);
int unused_p;
/* This function is not relevant to C++ because C++ folds while /* This function is not relevant to C++ because C++ folds while
parsing, and may need changes to be correct for C++ when C++ parsing, and may need changes to be correct for C++ when C++
...@@ -1308,6 +1309,10 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, ...@@ -1308,6 +1309,10 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
: fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1); : fold_build2_loc (loc, code, TREE_TYPE (expr), op0, op1);
else else
ret = fold (expr); ret = fold (expr);
if (TREE_OVERFLOW_P (ret)
&& !TREE_OVERFLOW_P (op0)
&& !TREE_OVERFLOW_P (op1))
overflow_warning (EXPR_LOCATION (expr), ret);
goto out; goto out;
case INDIRECT_REF: case INDIRECT_REF:
...@@ -1342,6 +1347,20 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, ...@@ -1342,6 +1347,20 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr); TREE_SIDE_EFFECTS (ret) = TREE_SIDE_EFFECTS (expr);
TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr); TREE_THIS_VOLATILE (ret) = TREE_THIS_VOLATILE (expr);
} }
switch (code)
{
case FIX_TRUNC_EXPR:
case FLOAT_EXPR:
CASE_CONVERT:
/* Don't warn about explicit conversions. We will already
have warned about suspect implicit conversions. */
break;
default:
if (TREE_OVERFLOW_P (ret) && !TREE_OVERFLOW_P (op0))
overflow_warning (EXPR_LOCATION (expr), ret);
break;
}
goto out; goto out;
case TRUTH_ANDIF_EXPR: case TRUTH_ANDIF_EXPR:
...@@ -1351,7 +1370,14 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, ...@@ -1351,7 +1370,14 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
orig_op0 = op0 = TREE_OPERAND (expr, 0); orig_op0 = op0 = TREE_OPERAND (expr, 0);
orig_op1 = op1 = TREE_OPERAND (expr, 1); orig_op1 = op1 = TREE_OPERAND (expr, 1);
op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self); op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self);
unused_p = (op0 == (code == TRUTH_ANDIF_EXPR
? truthvalue_false_node
: truthvalue_true_node));
c_inhibit_evaluation_warnings += unused_p;
op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self); op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self);
c_inhibit_evaluation_warnings -= unused_p;
if (op0 != orig_op0 || op1 != orig_op1 || in_init) if (op0 != orig_op0 || op1 != orig_op1 || in_init)
ret = in_init ret = in_init
? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1) ? fold_build2_initializer_loc (loc, code, TREE_TYPE (expr), op0, op1)
...@@ -1380,8 +1406,15 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, ...@@ -1380,8 +1406,15 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
orig_op1 = op1 = TREE_OPERAND (expr, 1); orig_op1 = op1 = TREE_OPERAND (expr, 1);
orig_op2 = op2 = TREE_OPERAND (expr, 2); orig_op2 = op2 = TREE_OPERAND (expr, 2);
op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self); op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self);
c_inhibit_evaluation_warnings += (op0 == truthvalue_false_node);
op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self); op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self);
c_inhibit_evaluation_warnings -= (op0 == truthvalue_false_node);
c_inhibit_evaluation_warnings += (op0 == truthvalue_true_node);
op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self); op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self);
c_inhibit_evaluation_warnings -= (op0 == truthvalue_true_node);
if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2) if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2)
ret = fold_build3_loc (loc, code, TREE_TYPE (expr), op0, op1, op2); ret = fold_build3_loc (loc, code, TREE_TYPE (expr), op0, op1, op2);
else else
......
...@@ -3912,10 +3912,19 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, ...@@ -3912,10 +3912,19 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
that folding in this case even without that folding in this case even without
warn_sign_compare to avoid warning options warn_sign_compare to avoid warning options
possibly affecting code generation. */ possibly affecting code generation. */
c_inhibit_evaluation_warnings
+= (ifexp == truthvalue_false_node);
op1 = c_fully_fold (op1, require_constant_value, op1 = c_fully_fold (op1, require_constant_value,
&op1_maybe_const); &op1_maybe_const);
c_inhibit_evaluation_warnings
-= (ifexp == truthvalue_false_node);
c_inhibit_evaluation_warnings
+= (ifexp == truthvalue_true_node);
op2 = c_fully_fold (op2, require_constant_value, op2 = c_fully_fold (op2, require_constant_value,
&op2_maybe_const); &op2_maybe_const);
c_inhibit_evaluation_warnings
-= (ifexp == truthvalue_true_node);
if (warn_sign_compare) if (warn_sign_compare)
{ {
...@@ -9509,10 +9518,12 @@ build_binary_op (location_t location, enum tree_code code, ...@@ -9509,10 +9518,12 @@ build_binary_op (location_t location, enum tree_code code,
build_conditional_expr. This requires the build_conditional_expr. This requires the
"original" values to be folded, not just op0 and "original" values to be folded, not just op0 and
op1. */ op1. */
c_inhibit_evaluation_warnings++;
op0 = c_fully_fold (op0, require_constant_value, op0 = c_fully_fold (op0, require_constant_value,
&op0_maybe_const); &op0_maybe_const);
op1 = c_fully_fold (op1, require_constant_value, op1 = c_fully_fold (op1, require_constant_value,
&op1_maybe_const); &op1_maybe_const);
c_inhibit_evaluation_warnings--;
orig_op0_folded = c_fully_fold (orig_op0, orig_op0_folded = c_fully_fold (orig_op0,
require_constant_value, require_constant_value,
NULL); NULL);
......
2009-08-09 Richard Sandiford <rdsandiford@googlemail.com>
* gcc.dg/overflow-warn-8.c: New test.
2009-08-09 Ira Rosen <irar@il.ibm.com> 2009-08-09 Ira Rosen <irar@il.ibm.com>
PR tree-optimization/41008 PR tree-optimization/41008
......
#include <limits.h>
void foo (int j)
{
int i1 = (int)(double)1.0 + INT_MAX; /* { dg-warning "integer overflow" } */
int i2 = (int)(double)1 + INT_MAX; /* { dg-warning "integer overflow" } */
int i3 = 1 + INT_MAX; /* { dg-warning "integer overflow" } */
int i4 = +1 + INT_MAX; /* { dg-warning "integer overflow" } */
int i5 = (int)((double)1.0 + INT_MAX);
int i6 = (double)1.0 + INT_MAX; /* { dg-warning "overflow in implicit constant" } */
int i7 = 0 ? (int)(double)1.0 + INT_MAX : 1;
int i8 = 1 ? 1 : (int)(double)1.0 + INT_MAX;
int i9 = j ? (int)(double)1.0 + INT_MAX : 1; /* { dg-warning "integer overflow" } */
unsigned int i10 = 0 ? (int)(double)1.0 + INT_MAX : 9U;
unsigned int i11 = 1 ? 9U : (int)(double)1.0 + INT_MAX;
unsigned int i12 = j ? (int)(double)1.0 + INT_MAX : 9U; /* { dg-warning "integer overflow" } */
int i13 = 1 || (int)(double)1.0 + INT_MAX < 0;
int i14 = 0 && (int)(double)1.0 + INT_MAX < 0;
int i15 = 0 || (int)(double)1.0 + INT_MAX < 0; /* { dg-warning "integer overflow" } */
int i16 = 1 && (int)(double)1.0 + INT_MAX < 0; /* { dg-warning "integer overflow" } */
int i17 = j || (int)(double)1.0 + INT_MAX < 0; /* { dg-warning "integer overflow" } */
int i18 = j && (int)(double)1.0 + INT_MAX < 0; /* { dg-warning "integer overflow" } */
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment