Ian Lance Taylor - PATCH RFC: -Wstrict-overflow (original) (raw)

This is the mail archive of the gcc-patches@gcc.gnu.orgmailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Following -fstrict-overflow, here is the first patch for -Wstrict-overflow. This adds a new warning for cases where gcc optimizes based on the fact that signed overflow is undefined. Note that this is not a warning for code that depends on undefined signed overflow: it is a warning for code which is optimized based on undefined signed overflow.

By way of example, I've attached the list of warnings generated by -Wstrict-overflow on a recent set of cc1 .i files. There is a total of 63 warnings.

This patch deliberately does not warn about cases where VRP relies on undefined signed overflow. I have reserved that for a separate follow-on patch.

I would like to hear comments about this patch. Thanks.

Bootstrapped and tested on i686-pc-linux-gnu.

Ian

../../trunk/gcc/bb-reorder.c: In function âfind_tracesâ: ../../trunk/gcc/bb-reorder.c:266: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/bb-reorder.c: In function âconnect_tracesâ: ../../trunk/gcc/bb-reorder.c:908: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/bb-reorder.c:910: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/calls.c: In function âstore_unaligned_arguments_into_pseudosâ: ../../trunk/gcc/calls.c:885: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/cfgcleanup.c: In function âtry_crossjump_to_edgeâ: ../../trunk/gcc/cfgcleanup.c:1774: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/cfgexpand.c: In function âexpand_gimple_tailcallâ: ../../trunk/gcc/cfgexpand.c:1384: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/cfgexpand.c: In function âconstruct_exit_blockâ: ../../trunk/gcc/cfgexpand.c:1670: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/cfghooks.c: In function âmake_forwarder_blockâ: ../../trunk/gcc/cfghooks.c:674: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/cfghooks.c: In function âduplicate_blockâ: ../../trunk/gcc/cfghooks.c:858: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/df-problems.c: In function âdf_create_unused_noteâ: ../../trunk/gcc/df-problems.c:3466: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/df-problems.c:3466: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/df-problems.c: In function âdf_ri_bb_computeâ: ../../trunk/gcc/df-problems.c:3634: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/df-problems.c:3634: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/emit-rtl.c: In function âset_mem_attributes_minus_bitposâ: ../../trunk/gcc/emit-rtl.c:1659: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/expmed.c: In function âexpand_mult_highpart_optabâ: ../../trunk/gcc/expmed.c:3485: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/expmed.c:3511: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/expmed.c:3538: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/expmed.c: In function âexpand_divmodâ: ../../trunk/gcc/expmed.c:4106: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/expmed.c:4272: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/expmed.c:4307: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/expmed.c:4399: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/flow.c: In function âmark_set_1â: ../../trunk/gcc/flow.c:2924: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/flow.c:2924: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/flow.c: In function âmark_used_regâ: ../../trunk/gcc/flow.c:3811: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/flow.c:3811: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/function.c: In function âassign_stack_temp_for_typeâ: ../../trunk/gcc/function.c:708: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/function.c: In function âpad_belowâ: ../../trunk/gcc/function.c:3498: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/genautomata.c: In function âreserv_sets_are_intersectedâ: ../../trunk/gcc/genautomata.c:3470: warning: assuming signed overflow is undefined when simplifying multiplication ../../trunk/gcc/genautomata.c:3475: warning: assuming signed overflow is undefined when simplifying multiplication ../../trunk/gcc/config/i386/i386.md:20245: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/config/i386/i386.md:20245: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/config/i386/i386.c: In function âexpand_set_or_movmem_via_loopâ: ../../trunk/gcc/config/i386/i386.c:12960: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/config/i386/i386.c:12960: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/ipa-inline.c: In function âlookup_recursive_callsâ: ../../trunk/gcc/ipa-inline.c:606: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/ipa-inline.c:606: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/local-alloc.c: In function âblock_allocâ: ../../trunk/gcc/local-alloc.c:1674: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/local-alloc.c:1675: warning: assuming signed overflow is undefined when combining constants around a comparison ../../trunk/gcc/profile.c: In function âcompute_branch_probabilitiesâ: ../../trunk/gcc/profile.c:549: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/real.c: In function âdo_compareâ: ../../trunk/gcc/real.c:949: warning: assuming signed overflow is undefined when combining constants around a comparison ../../trunk/gcc/real.c:951: warning: assuming signed overflow is undefined when combining constants around a comparison ../../trunk/gcc/real.c: In function âdo_fix_truncâ: ../../trunk/gcc/real.c:979: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/real.c:981: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/real.c: In function âreal_identicalâ: ../../trunk/gcc/real.c:1208: warning: assuming signed overflow is undefined when combining constants around a comparison ../../trunk/gcc/real.c: In function âreal_to_integerâ: ../../trunk/gcc/real.c:1293: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/real.c:1299: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/real.c: In function âreal_to_decimalâ: ../../trunk/gcc/real.c:1551: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/real.c:1589: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/real.c: In function âreal_sqrtâ: ../../trunk/gcc/real.c:4829: warning: assuming signed overflow is undefined when distributing negation across division ../../trunk/gcc/regclass.c: In function âregclassâ: ../../trunk/gcc/regclass.c:1259: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/regclass.c:1259: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/rtlanal.c: In function ânum_sign_bit_copies1â: ../../trunk/gcc/rtlanal.c:4217: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/sched-rgn.c: In function âcompute_dom_prob_psâ: ../../trunk/gcc/sched-rgn.c:1332: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/sched-rgn.c: In function âschedule_insnsâ: ../../trunk/gcc/sched-rgn.c:2927: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/stmt.c: In function âcheck_operand_nalternativesâ: ../../trunk/gcc/stmt.c:1144: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/stor-layout.c: In function âget_mode_alignmentâ: ../../trunk/gcc/stor-layout.c:263: warning: assuming signed overflow is undefined when eliminating multiplication in comparison with zero ../../trunk/gcc/stor-layout.c:263: warning: assuming signed overflow is undefined when eliminating multiplication in comparison with zero ../../trunk/gcc/stor-layout.c: In function âset_min_and_max_values_for_integral_typeâ: ../../trunk/gcc/stor-layout.c:2036: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/stor-layout.c:2039: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/stor-layout.c:2049: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/stor-layout.c:2053: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/stor-layout.c:2058: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/stor-layout.c:2061: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/varasm.c: In function âassemble_start_functionâ: ../../trunk/gcc/varasm.c:1450: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2

gcc/ChangeLog: 2007-01-31 Ian Lance Taylor iant@google.com

* common.opt: Add Wstrict-overflow.
* fold-const.c (fold_deferring_overflow_warnings): New static
variable.
(fold_deferred_overflow_warning): New static variable.
(fold_defer_overflow_warnings): New function.
(fold_undefer_overflow_warnings): New function.
(fold_deferring_overflow_warnings_p): New function.
(fold_overflow_warning): New static function.
(make_range): Add strict_overflow_p parameter.  Change all
callers.
(extract_muldiv, extract_muldiv_1): Likewise.
(fold_unary) [ABS_EXPR]: Check ABS_EXPR before calling
tree_expr_nonnegative_p.
(fold_negate_expr): Call fold_overflow_warning.
(fold_range_test): Likewise.
(fold_comparison): Likewise.
(fold_binary): Likewise.  Call tree_expr_nonnegative_warnv_p
instead of tree_expr_nonnegative_p.
(fold_warnv): New function.
(tree_expr_nonnegative_warnv_p): Rename from
tree_expr_nonnegative_p, add strict_overflow_p parameter.
(tree_expr_nonnegative_p): New function.
(tree_expr_nonzero_warnv_p): Rename from tree_expr_nonzero_p, add
strict_overflow_p parameter.
(tree_expr_nonzero_p): New function.
* passes.c (verify_interpass_invariants): New static function.
(execute_one_pass): Call it.
* tree-ssa-loop-niter.c (expand_simple_operations): Call
fold_warnv instead of fold.
(number_of_iterations_exit): Defer fold warnings.
(loop_niter_by_eval): Likewise.
(estimate_numbers_of_iterations): Likewise.
(scev_probably_wraps_p): Likewise.
* tree-cfgcleanup.c: Include "toplev.h" rather than "errors.h".
(cleanup_control_expr_graph): Call fold_warnv instead of fold, and
handle overflow warning.
* tree-cfg.c (fold_cond_expr_cond): Likewise.
* tree-vrp.c (vrp_expr_computes_nonnegative): Call
tree_expr_nonnegative_warnv_p instead of tree_expr_nonnegative_p.
* tree-ssa-loop-manip.c (create_iv): Likewise.
* c-typeck.c (build_conditional_expr): Likewise.
(build_binary_op): Likewise.
* tree-vrp.c (vrp_expr_computes_nonzero): Call
tree_expr_nonzero_warnv_p instead of tree_expr_nonzero_p.
(extract_range_from_unary_expr): Likewise.
* tree.h (tree_expr_nonnegative_warnv_p): Declare.
(fold_warnv): Declare.
(fold_defer_overflow_warnings): Declare.
(fold_undefer_overflow_warnings): Declare.
(fold_deferring_overflow_warnings_p): Declare.
(tree_expr_nonzero_warnv_p): Declare.

gcc/testsuite/ChangeLog: 2007-01-31 Ian Lance Taylor iant@google.com

* gcc.dg/Wstrict-overflow-1.c: New test.
* gcc.dg/Wstrict-overflow-2.c: New test.
* gcc.dg/Wstrict-overflow-3.c: New test.

Index: gcc/tree-vrp.c

--- gcc/tree-vrp.c (revision 121377) +++ gcc/tree-vrp.c (working copy) @@ -414,7 +414,10 @@ symbolic_range_p (value_range_t vr) static bool vrp_expr_computes_nonnegative (tree expr) { - return tree_expr_nonnegative_p (expr); + bool ovf; + + / FIXME: May need to record overflow information here. / + return tree_expr_nonnegative_warnv_p (expr, &ovf); } / Like tree_expr_nonzero_p, but this function uses value ranges @@ -423,7 +426,10 @@ vrp_expr_computes_nonnegative (tree expr static bool vrp_expr_computes_nonzero (tree expr) { - if (tree_expr_nonzero_p (expr)) + bool ovf; + + /* FIXME: May need to record overflow information here. / + if (tree_expr_nonzero_warnv_p (expr, &ovf)) return true; / If we have an expression of the form &X->a, then the expression @@ -1697,7 +1703,10 @@ extract_range_from_unary_expr (value_ran determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]). / if (POINTER_TYPE_P (TREE_TYPE (expr)) || POINTER_TYPE_P (TREE_TYPE (op0))) { - if (range_is_nonnull (&vr0) || tree_expr_nonzero_p (expr)) + bool ovf; + + / FIXME: May need to record overflow information here. */ + if (range_is_nonnull (&vr0) || tree_expr_nonzero_warnv_p (expr, &ovf)) set_value_range_to_nonnull (vr, TREE_TYPE (expr)); else if (range_is_null (&vr0)) set_value_range_to_null (vr, TREE_TYPE (expr)); Index: gcc/tree-ssa-loop-niter.c

--- gcc/tree-ssa-loop-niter.c (revision 121377) +++ gcc/tree-ssa-loop-niter.c (working copy) @@ -681,6 +681,7 @@ expand_simple_operations (tree expr) unsigned i, n; tree ret = NULL_TREE, e, ee, stmt; enum tree_code code; + const char ignore; if (expr == NULL_TREE) return expr; @@ -705,7 +706,7 @@ expand_simple_operations (tree expr) TREE_OPERAND (ret, i) = ee; } - return (ret ? fold (ret) : expr); + return (ret ? fold_warnv (ret, &ignore) : expr); } if (TREE_CODE (expr) != SSA_NAME) @@ -1053,11 +1054,18 @@ number_of_iterations_exit (struct loop * if (!simple_iv (loop, stmt, op1, &iv1, false)) return false; + / We don't want to see undefined signed overflow warnings while + computing the nmber of iterations. */ + fold_defer_overflow_warnings (); + iv0.base = expand_simple_operations (iv0.base); iv1.base = expand_simple_operations (iv1.base); if (!number_of_iterations_cond (type, &iv0, code, &iv1, niter, loop_only_exit_p (loop, exit))) - return false; + { + fold_undefer_overflow_warnings (); + return false; + } if (optimize >= 3) { @@ -1078,6 +1086,8 @@ number_of_iterations_exit (struct loop * niter->may_be_zero, &niter->additional_info); + fold_undefer_overflow_warnings (); + if (integer_onep (niter->assumptions)) return true; @@ -1376,6 +1386,9 @@ loop_niter_by_eval (struct loop loop, e } } + / Don't issue signed overflow warnings. / + fold_defer_overflow_warnings (); + for (i = 0; i < MAX_ITERATIONS_TO_TRACK; i++) { for (j = 0; j < 2; j++) @@ -1384,6 +1397,7 @@ loop_niter_by_eval (struct loop *loop, e acnd = fold_binary (cmp, boolean_type_node, aval[0], aval[1]); if (acnd && integer_zerop (acnd)) { + fold_undefer_overflow_warnings (); if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Proved that loop %d iterates %d times using brute force.\n", @@ -1395,10 +1409,15 @@ loop_niter_by_eval (struct loop *loop, e { val[j] = get_val_for (next[j], val[j]); if (!is_gimple_min_invariant (val[j])) - return chrec_dont_know; + { + fold_undefer_overflow_warnings (); + return chrec_dont_know; + } } } + fold_undefer_overflow_warnings (); + return chrec_dont_know; } @@ -1994,10 +2013,16 @@ estimate_numbers_of_iterations (void) loop_iterator li; struct loop *loop; + /* We don't want to issue signed overflow warnings while getting + loop iteration estimates. */ + fold_defer_overflow_warnings (); + FOR_EACH_LOOP (li, loop, 0) { estimate_numbers_of_iterations_loop (loop); } + + fold_undefer_overflow_warnings (); } /* Returns true if statement S1 dominates statement S2. */ @@ -2153,6 +2178,9 @@ scev_probably_wraps_p (tree base, tree s if (use_overflow_semantics && nowrap_type_p (type)) return false; + /* Don't issue signed overflow warnings. */ + fold_defer_overflow_warnings (); + /* Otherwise, compute the number of iterations before we reach the bound of the type, and verify that the loop is exited before this occurs. */ @@ -2179,8 +2207,15 @@ scev_probably_wraps_p (tree base, tree s estimate_numbers_of_iterations_loop (loop); for (bound = loop->bounds; bound; bound = bound->next) - if (n_of_executions_at_most (at_stmt, bound, valid_niter)) - return false; + { + if (n_of_executions_at_most (at_stmt, bound, valid_niter)) + { + fold_undefer_overflow_warnings (); + return false; + } + } + + fold_undefer_overflow_warnings (); / At this point we still don't have a proof that the iv does not overflow: give up. */ Index: gcc/tree-ssa-loop-manip.c

--- gcc/tree-ssa-loop-manip.c (revision 121377) +++ gcc/tree-ssa-loop-manip.c (working copy) @@ -86,7 +86,9 @@ create_iv (tree base, tree step, tree va } else { - if (!tree_expr_nonnegative_p (step) + bool ovf; + + if (!tree_expr_nonnegative_warnv_p (step, &ovf) && may_negate_without_overflow_p (step)) { incr_op = MINUS_EXPR; Index: gcc/tree.h

--- gcc/tree.h (revision 121377) +++ gcc/tree.h (working copy) @@ -3716,6 +3716,7 @@ extern int tree_int_cst_msb (tree); extern int tree_int_cst_sgn (tree); extern int tree_int_cst_sign_bit (tree); extern bool tree_expr_nonnegative_p (tree); +extern bool tree_expr_nonnegative_warnv_p (tree, bool *); extern bool may_negate_without_overflow_p (tree); extern tree get_inner_array_type (tree); @@ -4297,6 +4298,7 @@ extern int folding_initializer; subexpressions are not changed. */ extern tree fold (tree); +extern tree fold_warnv (tree, const char **); extern tree fold_unary (enum tree_code, tree, tree); extern tree fold_binary (enum tree_code, tree, tree, tree); extern tree fold_ternary (enum tree_code, tree, tree, tree, tree); @@ -4314,6 +4316,9 @@ extern tree fold_single_bit_test (enum t extern tree fold_ignored_result (tree); extern tree fold_abs_const (tree, tree); extern tree fold_indirect_ref_1 (tree, tree); +extern void fold_defer_overflow_warnings (void); +extern const char* fold_undefer_overflow_warnings (void); +extern bool fold_deferring_overflow_warnings_p (void); extern tree force_fit_type_double (tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT, int, bool); @@ -4386,6 +4391,7 @@ extern bool ptr_difference_const (tree, extern enum tree_code invert_tree_comparison (enum tree_code, bool); extern bool tree_expr_nonzero_p (tree); +extern bool tree_expr_nonzero_warnv_p (tree, bool ); / In builtins.c */ extern tree fold_builtin (tree, tree, bool); Index: gcc/fold-const.c

--- gcc/fold-const.c (revision 121377) +++ gcc/fold-const.c (working copy) @@ -119,7 +119,7 @@ static int simple_operand_p (tree); static tree range_binop (enum tree_code, tree, tree, int, tree, int); static tree range_predecessor (tree); static tree range_successor (tree); -static tree make_range (tree, int *, tree *, tree *); +static tree make_range (tree, int *, tree *, tree *, bool *); static tree build_range_check (tree, tree, int, tree, tree); static int merge_ranges (int , tree , tree , int, tree, tree, int, tree, tree); @@ -128,8 +128,8 @@ static tree fold_cond_expr_with_comparis static tree unextend (tree, int, int, tree); static tree fold_truthop (enum tree_code, tree, tree, tree); static tree optimize_minmax_comparison (enum tree_code, tree, tree, tree); -static tree extract_muldiv (tree, tree, enum tree_code, tree); -static tree extract_muldiv_1 (tree, tree, enum tree_code, tree); +static tree extract_muldiv (tree, tree, enum tree_code, tree, bool ); +static tree extract_muldiv_1 (tree, tree, enum tree_code, tree, bool ); static int multiple_of_p (tree, tree, tree); static tree fold_binary_op_with_conditional_arg (enum tree_code, tree, tree, tree, @@ -901,6 +901,73 @@ div_if_zero_remainder (enum tree_code co return build_int_cst_wide (type, quol, quoh); } +/ This is non-zero if we should defer warnings about undefined + overflow. This facility exists because these warnings are a + special case. The code to estimate loop iterations does not want + to issue any warnings, since it works with expressions which do not + occur in user code. Various bits of cleanup code call fold(), but + only use the result if it has certain characteristics (e.g., is a + constant); that code only wants to issue a warning if the result is + used. / + +static int fold_deferring_overflow_warnings; + +/ If a warning about undefined overflow is deferred, this is the + warning. Note that this may cause us to turn two warnings into + one, but that is fine since it is sufficient to only give one such + warning per expression. / + +static const char fold_deferred_overflow_warning; + +/ Start deferring overflow warnings. We could use a stack here to + permit nested calls, but at present it is not necessary. / + +void +fold_defer_overflow_warnings (void) +{ + ++fold_deferring_overflow_warnings; +} + +/ Stop deferring overflow warnings. If a warning was seen, and we + are no longer deferring warnings, it is returned. Otherwise this + function returns NULL. / + +const char +fold_undefer_overflow_warnings (void) +{ + const char ret = NULL; + + gcc_assert (fold_deferring_overflow_warnings > 0); + --fold_deferring_overflow_warnings; + if (fold_deferring_overflow_warnings == 0) + { + ret = fold_deferred_overflow_warning; + fold_deferred_overflow_warning = NULL; + } + return ret; +} + +/ Whether we are deferring overflow warnings. / + +bool +fold_deferring_overflow_warnings_p (void) +{ + return fold_deferring_overflow_warnings > 0; +} + +/ This is called when we fold something based on the fact that signed + overflow is undefined. / + +static void +fold_overflow_warning (const char warnmsg) +{ + gcc_assert (!flag_wrapv && !flag_trapv); + if (fold_deferring_overflow_warnings > 0) + fold_deferred_overflow_warning = warnmsg; + else + warning (OPT_Wstrict_overflow, warnmsg); +} + / Return true if the built-in mathematical function specified by CODE is odd, i.e. -f(x) == f(-x). / @@ -1197,14 +1264,22 @@ fold_negate_expr (tree t) case EXACT_DIV_EXPR: if (!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) { + const char * const warnmsg = ("assuming signed overflow is " + "undefined when negating a division"); tem = TREE_OPERAND (t, 1); if (negate_expr_p (tem)) - return fold_build2 (TREE_CODE (t), type, - TREE_OPERAND (t, 0), negate_expr (tem)); + { + fold_overflow_warning (warnmsg); + return fold_build2 (TREE_CODE (t), type, + TREE_OPERAND (t, 0), negate_expr (tem)); + } tem = TREE_OPERAND (t, 0); if (negate_expr_p (tem)) - return fold_build2 (TREE_CODE (t), type, - negate_expr (tem), TREE_OPERAND (t, 1)); + { + fold_overflow_warning (warnmsg); + return fold_build2 (TREE_CODE (t), type, + negate_expr (tem), TREE_OPERAND (t, 1)); + } } break; @@ -3841,12 +3916,16 @@ range_binop (enum tree_code code, tree t / Given EXP, a logical expression, set the range it is testing into variables denoted by PIN_P, PLOW, and PHIGH. Return the expression - actually being tested. *PLOW and *PHIGH will be made of the same type - as the returned expression. If EXP is not a comparison, we will most - likely not be returning a useful value and range. */ + actually being tested. *PLOW and *PHIGH will be made of the same + type as the returned expression. If EXP is not a comparison, we + will most likely not be returning a useful value and range. Set + *STRICT_OVERFLOW_P to true if the return value is only valid + because signed overflow is undefined; otherwise, do not change + *STRICT_OVERFLOW_P. */ static tree -make_range (tree exp, int *pin_p, tree *plow, tree *phigh) +make_range (tree exp, int *pin_p, tree *plow, tree *phigh, + bool *strict_overflow_p) { enum tree_code code; tree arg0 = NULL_TREE, arg1 = NULL_TREE; @@ -3995,6 +4074,9 @@ make_range (tree exp, int *pin_p, tree * || (n_high != 0 && TREE_OVERFLOW (n_high))) break; + if (TYPE_OVERFLOW_UNDEFINED (arg0_type)) + strict_overflow_p = true; + / Check for an unsigned range which has wrapped around the maximum value thus making n_high < n_low, and normalize it. */ if (n_low && n_high && tree_int_cst_lt (n_high, n_low)) @@ -4776,9 +4858,12 @@ fold_range_test (enum tree_code code, tr || code == TRUTH_OR_EXPR); int in0_p, in1_p, in_p; tree low0, low1, low, high0, high1, high; - tree lhs = make_range (op0, &in0_p, &low0, &high0); - tree rhs = make_range (op1, &in1_p, &low1, &high1); + bool strict_overflow_p = false; + tree lhs = make_range (op0, &in0_p, &low0, &high0, &strict_overflow_p); + tree rhs = make_range (op1, &in1_p, &low1, &high1, &strict_overflow_p); tree tem; + const char * const warnmsg = ("assuming signed overflow is undefined when " + "folding range test"); /* If this is an OR operation, invert both sides; we will invert again at the end. */ @@ -4796,7 +4881,11 @@ fold_range_test (enum tree_code code, tr lhs != 0 ? lhs : rhs != 0 ? rhs : integer_zero_node, in_p, low, high)))) - return or_op ? invert_truthvalue (tem) : tem; + { + if (strict_overflow_p) + fold_overflow_warning (warnmsg); + return or_op ? invert_truthvalue (tem) : tem; + } /* On machines where the branch cost is expensive, if this is a short-circuited branch and the underlying object on both sides @@ -4826,9 +4915,13 @@ fold_range_test (enum tree_code code, tr && (0 != (rhs = build_range_check (type, common, or_op ? ! in1_p : in1_p, low1, high1)))) - return build2 (code == TRUTH_ANDIF_EXPR - ? TRUTH_AND_EXPR : TRUTH_OR_EXPR, - type, lhs, rhs); + { + if (strict_overflow_p) + fold_overflow_warning (warnmsg); + return build2 (code == TRUTH_ANDIF_EXPR + ? TRUTH_AND_EXPR : TRUTH_OR_EXPR, + type, lhs, rhs); + } } } @@ -5427,10 +5520,15 @@ optimize_minmax_comparison (enum tree_co addressing calculation. If we return a non-null expression, it is an equivalent form of the - original computation, but need not be in the original type. */ + original computation, but need not be in the original type. + + We set *STRICT_OVERFLOW_P to true if the return values depends on + signed overflow being undefined. Otherwise we do not change + *STRICT_OVERFLOW_P. */ static tree -extract_muldiv (tree t, tree c, enum tree_code code, tree wide_type) +extract_muldiv (tree t, tree c, enum tree_code code, tree wide_type, + bool *strict_overflow_p) { /* To avoid exponential search depth, refuse to allow recursion past three levels. Beyond that (1) it's highly unlikely that we'll find @@ -5444,14 +5542,15 @@ extract_muldiv (tree t, tree c, enum tre return NULL; depth++; - ret = extract_muldiv_1 (t, c, code, wide_type); + ret = extract_muldiv_1 (t, c, code, wide_type, strict_overflow_p); depth--; return ret; } static tree -extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type) +extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type, + bool *strict_overflow_p) { tree type = TREE_TYPE (t); enum tree_code tcode = TREE_CODE (t); @@ -5461,6 +5560,7 @@ extract_muldiv_1 (tree t, tree c, enum t tree t1, t2; int same_p = tcode == code; tree op0 = NULL_TREE, op1 = NULL_TREE; + bool sub_strict_overflow_p; /* Don't deal with constants of zero here; they confuse the code below. */ if (integer_zerop (c)) @@ -5517,7 +5617,8 @@ extract_muldiv_1 (tree t, tree c, enum t && !TREE_OVERFLOW (t2) && (0 != (t1 = extract_muldiv (op0, t2, code, code == MULT_EXPR - ? ctype : NULL_TREE)))) + ? ctype : NULL_TREE, + strict_overflow_p)))) return t1; break; @@ -5527,7 +5628,8 @@ extract_muldiv_1 (tree t, tree c, enum t if (TYPE_UNSIGNED (ctype) && !TYPE_UNSIGNED (type)) { tree cstype = (*lang_hooks.types.signed_type) (ctype); - if ((t1 = extract_muldiv (op0, c, code, cstype)) != 0) + if ((t1 = extract_muldiv (op0, c, code, cstype, strict_overflow_p)) + != 0) { t1 = fold_build1 (tcode, cstype, fold_convert (cstype, t1)); return fold_convert (ctype, t1); @@ -5536,7 +5638,8 @@ extract_muldiv_1 (tree t, tree c, enum t } /* FALLTHROUGH */ case NEGATE_EXPR: - if ((t1 = extract_muldiv (op0, c, code, wide_type)) != 0) + if ((t1 = extract_muldiv (op0, c, code, wide_type, strict_overflow_p)) + != 0) return fold_build1 (tcode, ctype, fold_convert (ctype, t1)); break; @@ -5547,12 +5650,16 @@ extract_muldiv_1 (tree t, tree c, enum t break; /* MIN (a, b) / 5 -> MIN (a / 5, b / 5) */ - if ((t1 = extract_muldiv (op0, c, code, wide_type)) != 0 - && (t2 = extract_muldiv (op1, c, code, wide_type)) != 0) + sub_strict_overflow_p = false; + if ((t1 = extract_muldiv (op0, c, code, wide_type, + &sub_strict_overflow_p)) != 0 + && (t2 = extract_muldiv (op1, c, code, wide_type, + &sub_strict_overflow_p)) != 0) { if (tree_int_cst_sgn (c) < 0) tcode = (tcode == MIN_EXPR ? MAX_EXPR : MIN_EXPR);

@@ -5579,7 +5686,7 @@ extract_muldiv_1 (tree t, tree c, enum t return extract_muldiv (build2 (tcode == LSHIFT_EXPR ? MULT_EXPR : FLOOR_DIV_EXPR, ctype, fold_convert (ctype, op0), t1), - c, code, wide_type); + c, code, wide_type, strict_overflow_p); break; case PLUS_EXPR: case MINUS_EXPR: @@ -5587,16 +5694,21 @@ extract_muldiv_1 (tree t, tree c, enum t can return a new PLUS or MINUS. If we can't, the only remaining cases where we can do anything are if the second operand is a constant. / - t1 = extract_muldiv (op0, c, code, wide_type); - t2 = extract_muldiv (op1, c, code, wide_type); + sub_strict_overflow_p = false; + t1 = extract_muldiv (op0, c, code, wide_type, &sub_strict_overflow_p); + t2 = extract_muldiv (op1, c, code, wide_type, &sub_strict_overflow_p); if (t1 != 0 && t2 != 0 && (code == MULT_EXPR / If not multiplication, we can only do this if both operands are divisible by c. */ || (multiple_of_p (ctype, op0, c) && multiple_of_p (ctype, op1, c)))) - return fold_build2 (tcode, ctype, fold_convert (ctype, t1), - fold_convert (ctype, t2)); + { + if (sub_strict_overflow_p) + strict_overflow_p = true; + return fold_build2 (tcode, ctype, fold_convert (ctype, t1), + fold_convert (ctype, t2)); + } / If this was a subtraction, negate OP1 and set it to be an addition. This simplifies the logic below. */ @@ -5677,11 +5789,13 @@ extract_muldiv_1 (tree t, tree c, enum t new operation. Likewise for the RHS from a MULT_EXPR. Otherwise, do something only if the second operand is a constant. / if (same_p - && (t1 = extract_muldiv (op0, c, code, wide_type)) != 0) + && (t1 = extract_muldiv (op0, c, code, wide_type, + strict_overflow_p)) != 0) return fold_build2 (tcode, ctype, fold_convert (ctype, t1), fold_convert (ctype, op1)); else if (tcode == MULT_EXPR && code == MULT_EXPR - && (t1 = extract_muldiv (op1, c, code, wide_type)) != 0) + && (t1 = extract_muldiv (op1, c, code, wide_type, + strict_overflow_p)) != 0) return fold_build2 (tcode, ctype, fold_convert (ctype, op0), fold_convert (ctype, t1)); else if (TREE_CODE (op1) != INTEGER_CST) @@ -5711,15 +5825,23 @@ extract_muldiv_1 (tree t, tree c, enum t && code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR))) { if (integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0))) - return fold_build2 (tcode, ctype, fold_convert (ctype, op0), - fold_convert (ctype, - const_binop (TRUNC_DIV_EXPR, - op1, c, 0))); + { + if (TYPE_OVERFLOW_UNDEFINED (ctype)) + strict_overflow_p = true; + return fold_build2 (tcode, ctype, fold_convert (ctype, op0), + fold_convert (ctype, + const_binop (TRUNC_DIV_EXPR, + op1, c, 0))); + } else if (integer_zerop (const_binop (TRUNC_MOD_EXPR, c, op1, 0))) - return fold_build2 (code, ctype, fold_convert (ctype, op0), - fold_convert (ctype, - const_binop (TRUNC_DIV_EXPR, - c, op1, 0))); + { + if (TYPE_OVERFLOW_UNDEFINED (ctype)) + strict_overflow_p = true; + return fold_build2 (code, ctype, fold_convert (ctype, op0), + fold_convert (ctype, + const_binop (TRUNC_DIV_EXPR, + c, op1, 0))); + } } break; @@ -7618,7 +7740,9 @@ fold_unary (enum tree_code code, tree ty targ0)); } / ABS_EXPR<ABS_EXPR> = ABS_EXPR even if flag_wrapv is on. / - else if (tree_expr_nonnegative_p (arg0) || TREE_CODE (arg0) == ABS_EXPR) + else if (TREE_CODE (arg0) == ABS_EXPR) + return arg0; + else if (tree_expr_nonnegative_p (arg0)) return arg0; / Strip sign ops from argument. / @@ -7931,6 +8055,15 @@ maybe_canonicalize_comparison (enum tree || POINTER_TYPE_P (TREE_TYPE (arg0))) return NULL_TREE; + / We don't call fold_overflow_warning here. This is a judgement + call. This optimization will change INT_MAX + 1 > 0 into INT_MAX + >= 0. If signed overflow wraps, this will change the condition + from false to true. That is why we can't implement this if + flag_wrapv is true. By not warning, we are assuming that people + will not rely on wrapping semantics for this sort of code. If we + did issue a warning here, we would get a large number of false + positives. / + / Try canonicalization by simplifying arg0. / t = maybe_canonicalize_comparison_1 (code, type, arg0, arg1); if (t) @@ -7989,7 +8122,12 @@ fold_comparison (enum tree_code code, tr if (TREE_CODE (lhs) == TREE_CODE (arg1) && (TREE_CODE (lhs) != INTEGER_CST || !TREE_OVERFLOW (lhs))) - return fold_build2 (code, type, variable, lhs); + { + fold_overflow_warning ("assuming signed overflow is undefined " + "when changing X +- C1 cmp C2 to " + "X cmp C1 +- C2"); + return fold_build2 (code, type, variable, lhs); + } } / For comparisons of pointers we can decompose it to a compile time @@ -8154,6 +8292,9 @@ fold_comparison (enum tree_code code, tr tree variable1 = TREE_OPERAND (arg0, 0); tree variable2 = TREE_OPERAND (arg1, 0); tree cst; + const char * const warnmsg = ("assuming signed overflow is undefined " + "when combining constants around a " + "comparison"); / Put the constant on the side where it doesn't overflow and is of lower absolute value than before. / @@ -8162,20 +8303,26 @@ fold_comparison (enum tree_code code, tr const2, const1, 0); if (!TREE_OVERFLOW (cst) && tree_int_cst_compare (const2, cst) == tree_int_cst_sgn (const2)) - return fold_build2 (code, type, - variable1, - fold_build2 (TREE_CODE (arg1), TREE_TYPE (arg1), - variable2, cst)); + { + fold_overflow_warning (warnmsg); + return fold_build2 (code, type, + variable1, + fold_build2 (TREE_CODE (arg1), TREE_TYPE (arg1), + variable2, cst)); + } cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1) ? MINUS_EXPR : PLUS_EXPR, const1, const2, 0); if (!TREE_OVERFLOW (cst) && tree_int_cst_compare (const1, cst) == tree_int_cst_sgn (const1)) - return fold_build2 (code, type, - fold_build2 (TREE_CODE (arg0), TREE_TYPE (arg0), - variable1, cst), - variable2); + { + fold_overflow_warning (warnmsg); + return fold_build2 (code, type, + fold_build2 (TREE_CODE (arg0), TREE_TYPE (arg0), + variable1, cst), + variable2); + } } / Transform comparisons of the form X * C1 CMP 0 to X CMP 0 in the @@ -8195,6 +8342,10 @@ fold_comparison (enum tree_code code, tr gcc_assert (!integer_zerop (const1)); + fold_overflow_warning ("assuming signed overflow is undefined when " + "eliminating multiplication in comparison " + "with zero"); + / If const1 is negative we swap the sense of the comparison. */ if (tree_int_cst_sgn (const1) < 0) cmp_code = swap_tree_comparison (cmp_code); @@ -8630,6 +8781,7 @@ fold_binary (enum tree_code code, tree t enum tree_code_class kind = TREE_CODE_CLASS (code); tree arg0, arg1, tem; tree t1 = NULL_TREE; + bool strict_overflow_p; gcc_assert ((IS_EXPR_CODE_CLASS (kind) || IS_GIMPLE_STMT_CODE_CLASS (kind)) @@ -9340,11 +9492,18 @@ fold_binary (enum tree_code code, tree t return fold_build2 (LSHIFT_EXPR, type, arg1, TREE_OPERAND (arg0, 1)); + strict_overflow_p = false; if (TREE_CODE (arg1) == INTEGER_CST && 0 != (tem = extract_muldiv (op0, fold_convert (type, arg1), - code, NULL_TREE))) - return fold_convert (type, tem); + code, NULL_TREE, + &strict_overflow_p))) + { + if (strict_overflow_p) + fold_overflow_warning ("assuming signed overflow is undefined " + "when simplifying multiplication"); + return fold_convert (type, tem); + } /* Optimize z * conj(z) for integer complex numbers. */ if (TREE_CODE (arg0) == CONJ_EXPR @@ -10244,8 +10403,10 @@ fold_binary (enum tree_code code, tree t case FLOOR_DIV_EXPR: /* Simplify A / (B << N) where A and B are positive and B is a power of 2, to A >> (N + log2(B)). / + strict_overflow_p = false; if (TREE_CODE (arg1) == LSHIFT_EXPR - && (TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (arg0))) + && (TYPE_UNSIGNED (type) + || tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))) { tree sval = TREE_OPERAND (arg1, 0); if (integer_pow2p (sval) && tree_int_cst_sgn (sval) > 0) @@ -10253,6 +10414,10 @@ fold_binary (enum tree_code code, tree t tree sh_cnt = TREE_OPERAND (arg1, 1); unsigned long pow2 = exact_log2 (TREE_INT_CST_LOW (sval)); + if (strict_overflow_p) + fold_overflow_warning ("assuming signed overflow is defined " + "when simplifying A / (B << N)"); + sh_cnt = fold_build2 (PLUS_EXPR, TREE_TYPE (sh_cnt), sh_cnt, build_int_cst (NULL_TREE, pow2)); return fold_build2 (RSHIFT_EXPR, type, @@ -10280,13 +10445,25 @@ fold_binary (enum tree_code code, tree t if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) && TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1)) - return fold_build2 (code, type, TREE_OPERAND (arg0, 0), - negate_expr (arg1)); + { + if (INTEGRAL_TYPE_P (type)) + fold_overflow_warning ("assuming signed overflow is undefined " + "when distributing negation across " + "division"); + return fold_build2 (code, type, TREE_OPERAND (arg0, 0), + negate_expr (arg1)); + } if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) && TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0)) - return fold_build2 (code, type, negate_expr (arg0), - TREE_OPERAND (arg1, 0)); + { + if (INTEGRAL_TYPE_P (type)) + fold_overflow_warning ("assuming signed overflow is undefined " + "when distributing negation across " + "division"); + return fold_build2 (code, type, negate_expr (arg0), + TREE_OPERAND (arg1, 0)); + } /* If arg0 is a multiple of arg1, then rewrite to the fastest div operation, EXACT_DIV_EXPR. @@ -10298,9 +10475,16 @@ fold_binary (enum tree_code code, tree t && multiple_of_p (type, arg0, arg1)) return fold_build2 (EXACT_DIV_EXPR, type, arg0, arg1); + strict_overflow_p = false; if (TREE_CODE (arg1) == INTEGER_CST - && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE))) - return fold_convert (type, tem); + && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE, + &strict_overflow_p))) + { + if (strict_overflow_p) + fold_overflow_warning ("assuming signed overflow is undefined " + "when simplifying division"); + return fold_convert (type, tem); + } return NULL_TREE; @@ -10332,8 +10516,10 @@ fold_binary (enum tree_code code, tree t /* Optimize TRUNC_MOD_EXPR by a power of two into a BIT_AND_EXPR, i.e. "X % C" into "X & (C - 1)", if X and C are positive. */ + strict_overflow_p = false; if ((code == TRUNC_MOD_EXPR || code == FLOOR_MOD_EXPR) - && (TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (arg0))) + && (TYPE_UNSIGNED (type) + || tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))) { tree c = arg1; /* Also optimize A % (C << N) where C is a power of 2, @@ -10345,6 +10531,9 @@ fold_binary (enum tree_code code, tree t { tree mask = fold_build2 (MINUS_EXPR, TREE_TYPE (arg1), arg1, build_int_cst (TREE_TYPE (arg1), 1)); + if (strict_overflow_p) + fold_overflow_warning ("assuming signed overflow is undefined " + "when simplifying X % (power of two)"); return fold_build2 (BIT_AND_EXPR, type, fold_convert (type, arg0), fold_convert (type, mask)); @@ -10372,8 +10561,14 @@ fold_binary (enum tree_code code, tree t fold_convert (type, TREE_OPERAND (arg1, 0))); if (TREE_CODE (arg1) == INTEGER_CST - && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE))) - return fold_convert (type, tem); + && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE, + &strict_overflow_p))) + { + if (strict_overflow_p) + fold_overflow_warning ("assuming signed overflow is undefined " + "when simplifying modulos"); + return fold_convert (type, tem); + } return NULL_TREE; @@ -11202,27 +11397,55 @@ fold_binary (enum tree_code code, tree t if (code == GT_EXPR && ((code0 == MINUS_EXPR && is_positive >= 0) || (code0 == PLUS_EXPR && is_positive <= 0))) - return constant_boolean_node (0, type); + { + if (TREE_CODE (arg01) == INTEGER_CST + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning ("assuming signed overflow is undefined " + "when assuming that (X - c) > X " + "is always false"); + return constant_boolean_node (0, type); + } / Likewise (X + c) < X becomes false. */ if (code == LT_EXPR && ((code0 == PLUS_EXPR && is_positive >= 0) || (code0 == MINUS_EXPR && is_positive <= 0))) - return constant_boolean_node (0, type); + { + if (TREE_CODE (arg01) == INTEGER_CST + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning ("assuming signed overflow is undefined " + "when assuming that (X + c) < X " + "is always false"); + return constant_boolean_node (0, type); + } /* Convert (X - c) <= X to true. */ if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))) && code == LE_EXPR && ((code0 == MINUS_EXPR && is_positive >= 0) || (code0 == PLUS_EXPR && is_positive <= 0))) - return constant_boolean_node (1, type); + { + if (TREE_CODE (arg01) == INTEGER_CST + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning ("assuming signed overflow is undefined " + "when assuming that (X - c) <= X " + "is always true"); + return constant_boolean_node (1, type); + } /* Convert (X + c) >= X to true. / if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))) && code == GE_EXPR && ((code0 == PLUS_EXPR && is_positive >= 0) || (code0 == MINUS_EXPR && is_positive <= 0))) - return constant_boolean_node (1, type); + { + if (TREE_CODE (arg01) == INTEGER_CST + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning ("assuming signed overflow is undefined " + "when assuming that (X + c) >= X " + "is always true"); + return constant_boolean_node (1, type); + } if (TREE_CODE (arg01) == INTEGER_CST) { @@ -11230,23 +11453,47 @@ fold_binary (enum tree_code code, tree t if (code == GT_EXPR && ((code0 == PLUS_EXPR && is_positive > 0) || (code0 == MINUS_EXPR && is_positive < 0))) - return constant_boolean_node (1, type); + { + if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning ("assuming signed overflow is " + "undefined when assuming that " + "(X + c) > X is always true"); + return constant_boolean_node (1, type); + } if (code == LT_EXPR && ((code0 == MINUS_EXPR && is_positive > 0) || (code0 == PLUS_EXPR && is_positive < 0))) - return constant_boolean_node (1, type); + { + if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning ("assuming signed overflow is " + "undefined when assuming that " + "(X - c) < X is always true"); + return constant_boolean_node (1, type); + } /* Convert X + c <= X and X - c >= X to false for integers. / if (code == LE_EXPR && ((code0 == PLUS_EXPR && is_positive > 0) || (code0 == MINUS_EXPR && is_positive < 0))) - return constant_boolean_node (0, type); + { + if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning ("assuming signed overflow is " + "undefined when assuming that " + "(X + c) <= X is always false"); + return constant_boolean_node (0, type); + } if (code == GE_EXPR && ((code0 == MINUS_EXPR && is_positive > 0) || (code0 == PLUS_EXPR && is_positive < 0))) - return constant_boolean_node (0, type); + { + if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning ("assuming signed overflow is " + "undefined when assuming that " + "(X - c) >= X is always true"); + return constant_boolean_node (0, type); + } } } @@ -11448,16 +11695,16 @@ fold_binary (enum tree_code code, tree t / Convert ABS_EXPR >= 0 to true. / if (code == GE_EXPR - && tree_expr_nonnegative_p (arg0) && (integer_zerop (arg1) || (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))) - && real_zerop (arg1)))) + && real_zerop (arg1))) + && tree_expr_nonnegative_p (arg0)) return omit_one_operand (type, integer_one_node, arg0); / Convert ABS_EXPR < 0 to false. */ if (code == LT_EXPR - && tree_expr_nonnegative_p (arg0) - && (integer_zerop (arg1) || real_zerop (arg1))) + && (integer_zerop (arg1) || real_zerop (arg1)) + && tree_expr_nonnegative_p (arg0)) return omit_one_operand (type, integer_zero_node, arg0); /* If X is unsigned, convert X < (1 << Y) into X >> Y == 0 @@ -12198,6 +12445,22 @@ recursive_label: #endif +/ Fold EXPR. Don't issue any warnings about the use of undefined + signed overflow. Instead, set *OVERFLOW_WARNING to NULL if there + were no warnings, or to the warning string if there was a + warning. */ + +tree +fold_warnv (tree expr, const char *overflow_warning) +{ + tree ret; + + fold_defer_overflow_warnings (); + ret = fold (expr); + overflow_warning = fold_undefer_overflow_warnings (); + return ret; +} + / Fold a unary tree expression with code CODE of type TYPE with an operand OP0. Return a folded expression if successful. Otherwise, return a tree expression with code CODE of type TYPE with an @@ -12534,10 +12797,13 @@ multiple_of_p (tree type, tree top, tree } } -/ Return true if t' is known to be non-negative. */ +/* Return true if t' is known to be non-negative. If the return + value is based on the assumption that signed overflow is undefined, + set *STRICT_OVERFLOW_P to true; otherwise, don't change + *STRICT_OVERFLOW_P. */ bool -tree_expr_nonnegative_p (tree t) +tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p) { if (t == error_mark_node) return false; @@ -12558,7 +12824,10 @@ tree_expr_nonnegative_p (tree t) if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) return true; if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t))) - return true; + { + strict_overflow_p = true; + return true; + } break; case INTEGER_CST: @@ -12569,8 +12838,10 @@ tree_expr_nonnegative_p (tree t) case PLUS_EXPR: if (FLOAT_TYPE_P (TREE_TYPE (t))) - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)) - && tree_expr_nonnegative_p (TREE_OPERAND (t, 1)); + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); / zero_extend(x) + zero_extend(y) is non-negative if x and y are both unsigned and at least 2 bits shorter than the result. / @@ -12596,8 +12867,10 @@ tree_expr_nonnegative_p (tree t) / x * x for floating point x is always non-negative. / if (operand_equal_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1), 0)) return true; - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)) - && tree_expr_nonnegative_p (TREE_OPERAND (t, 1)); + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); } / zero_extend(x) * zero_extend(y) is non-negative if x and y are @@ -12617,8 +12890,10 @@ tree_expr_nonnegative_p (tree t) case BIT_AND_EXPR: case MAX_EXPR: - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)) - || tree_expr_nonnegative_p (TREE_OPERAND (t, 1)); + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + || tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); case BIT_IOR_EXPR: case BIT_XOR_EXPR: @@ -12628,8 +12903,10 @@ tree_expr_nonnegative_p (tree t) case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: case ROUND_DIV_EXPR: - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)) - && tree_expr_nonnegative_p (TREE_OPERAND (t, 1)); + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); case TRUNC_MOD_EXPR: case CEIL_MOD_EXPR: @@ -12638,19 +12915,24 @@ tree_expr_nonnegative_p (tree t) case SAVE_EXPR: case NON_LVALUE_EXPR: case FLOAT_EXPR: - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)); + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); case COMPOUND_EXPR: case MODIFY_EXPR: case GIMPLE_MODIFY_STMT: - return tree_expr_nonnegative_p (GENERIC_TREE_OPERAND (t, 1)); + return tree_expr_nonnegative_warnv_p (GENERIC_TREE_OPERAND (t, 1), + strict_overflow_p); case BIND_EXPR: - return tree_expr_nonnegative_p (expr_last (TREE_OPERAND (t, 1))); + return tree_expr_nonnegative_warnv_p (expr_last (TREE_OPERAND (t, 1)), + strict_overflow_p); case COND_EXPR: - return tree_expr_nonnegative_p (TREE_OPERAND (t, 1)) - && tree_expr_nonnegative_p (TREE_OPERAND (t, 2)); + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 2), + strict_overflow_p)); case NOP_EXPR: { @@ -12660,18 +12942,21 @@ tree_expr_nonnegative_p (tree t) if (TREE_CODE (outer_type) == REAL_TYPE) { if (TREE_CODE (inner_type) == REAL_TYPE) - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)); + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); if (TREE_CODE (inner_type) == INTEGER_TYPE) { if (TYPE_UNSIGNED (inner_type)) return true; - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)); + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); } } else if (TREE_CODE (outer_type) == INTEGER_TYPE) { if (TREE_CODE (inner_type) == REAL_TYPE) - return tree_expr_nonnegative_p (TREE_OPERAND (t,0)); + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t,0), + strict_overflow_p); if (TREE_CODE (inner_type) == INTEGER_TYPE) return TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type) && TYPE_UNSIGNED (inner_type); @@ -12687,7 +12972,7 @@ tree_expr_nonnegative_p (tree t) /* If the initializer is non-void, then it's a normal expression that will be assigned to the slot. */ if (!VOID_TYPE_P (t)) - return tree_expr_nonnegative_p (t); + return tree_expr_nonnegative_warnv_p (t, strict_overflow_p); /* Otherwise, the initializer sets the slot in some way. One common way is an assignment statement at the end of the initializer. */ @@ -12706,7 +12991,8 @@ tree_expr_nonnegative_p (tree t) if ((TREE_CODE (t) == MODIFY_EXPR || TREE_CODE (t) == GIMPLE_MODIFY_STMT) && GENERIC_TREE_OPERAND (t, 0) == temp) - return tree_expr_nonnegative_p (GENERIC_TREE_OPERAND (t, 1)); + return tree_expr_nonnegative_warnv_p (GENERIC_TREE_OPERAND (t, 1), + strict_overflow_p); return false; } @@ -12742,7 +13028,8 @@ tree_expr_nonnegative_p (tree t) /* sqrt(-0.0) is -0.0. */ if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (t)))) return true; - return tree_expr_nonnegative_p (TREE_VALUE (arglist)); + return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p); CASE_FLT_FN (BUILT_IN_ASINH): CASE_FLT_FN (BUILT_IN_ATAN): @@ -12772,21 +13059,30 @@ tree_expr_nonnegative_p (tree t) CASE_FLT_FN (BUILT_IN_TANH): CASE_FLT_FN (BUILT_IN_TRUNC): /* True if the 1st argument is nonnegative. */ - return tree_expr_nonnegative_p (TREE_VALUE (arglist)); + return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p); CASE_FLT_FN (BUILT_IN_FMAX): /* True if the 1st OR 2nd arguments are nonnegative. */ - return tree_expr_nonnegative_p (TREE_VALUE (arglist)) - || tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist))); + return (tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p) + || (tree_expr_nonnegative_warnv_p + (TREE_VALUE (TREE_CHAIN (arglist)), + strict_overflow_p))); CASE_FLT_FN (BUILT_IN_FMIN): /* True if the 1st AND 2nd arguments are nonnegative. */ - return tree_expr_nonnegative_p (TREE_VALUE (arglist)) - && tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist))); + return (tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p) + && (tree_expr_nonnegative_warnv_p + (TREE_VALUE (TREE_CHAIN (arglist)), + strict_overflow_p))); CASE_FLT_FN (BUILT_IN_COPYSIGN): /* True if the 2nd argument is nonnegative. */ - return tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist))); + return (tree_expr_nonnegative_warnv_p + (TREE_VALUE (TREE_CHAIN (arglist)), + strict_overflow_p)); CASE_FLT_FN (BUILT_IN_POWI): /* True if the 1st argument is nonnegative or the second @@ -12797,7 +13093,8 @@ tree_expr_nonnegative_p (tree t) if ((TREE_INT_CST_LOW (arg1) & 1) == 0) return true; } - return tree_expr_nonnegative_p (TREE_VALUE (arglist)); + return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p); CASE_FLT_FN (BUILT_IN_POW): /* True if the 1st argument is nonnegative or the second @@ -12818,7 +13115,8 @@ tree_expr_nonnegative_p (tree t) return true; } } - return tree_expr_nonnegative_p (TREE_VALUE (arglist)); + return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p); default: break; @@ -12837,14 +13135,36 @@ tree_expr_nonnegative_p (tree t) return false; } +/* Return true if `t' is known to be non-negative. Handle warnings + about undefined signed overflow. */ + +bool +tree_expr_nonnegative_p (tree t) +{ + bool ret, strict_overflow_p; + + strict_overflow_p = false; + ret = tree_expr_nonnegative_warnv_p (t, &strict_overflow_p); + if (strict_overflow_p) + fold_overflow_warning ("assuming signed overflow is undefined when " + "determining that expression is always " + "non-negative"); + return ret; +} + /* Return true when T is an address and is known to be nonzero. For floating point we further ensure that T is not denormal. - Similar logic is present in nonzero_address in rtlanal.h. */ + Similar logic is present in nonzero_address in rtlanal.h. + + If the return value is based on the assumption that signed overflow + is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't + change *STRICT_OVERFLOW_P. */ bool -tree_expr_nonzero_p (tree t) +tree_expr_nonzero_warnv_p (tree t, bool *strict_overflow_p) { tree type = TREE_TYPE (t); + bool sub_strict_overflow_p; /* Doing something useful for floating point would need more work. */ if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) @@ -12858,7 +13178,8 @@ tree_expr_nonzero_p (tree t) return ssa_name_nonzero_p (t); case ABS_EXPR: - return tree_expr_nonzero_p (TREE_OPERAND (t, 0)); + return tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); case INTEGER_CST: return !integer_zerop (t); @@ -12868,20 +13189,34 @@ tree_expr_nonzero_p (tree t) { /* With the presence of negative values it is hard to say something. */ - if (!tree_expr_nonnegative_p (TREE_OPERAND (t, 0)) - || !tree_expr_nonnegative_p (TREE_OPERAND (t, 1))) + sub_strict_overflow_p = false; + if (!tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + &sub_strict_overflow_p) + || !tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p)) return false; /* One of operands must be positive and the other non-negative. */ - return (tree_expr_nonzero_p (TREE_OPERAND (t, 0)) - || tree_expr_nonzero_p (TREE_OPERAND (t, 1))); + /* We don't set *STRICT_OVERFLOW_P here: even if this value + overflows, on a twos-complement machine the sum of two + nonnegative numbers can never be zero. */ + return (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + || tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); } break; case MULT_EXPR: if (TYPE_OVERFLOW_UNDEFINED (type)) { - return (tree_expr_nonzero_p (TREE_OPERAND (t, 0)) - && tree_expr_nonzero_p (TREE_OPERAND (t, 1))); + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)) + { + *strict_overflow_p = true; + return true; + } } break; @@ -12891,7 +13226,8 @@ tree_expr_nonzero_p (tree t) tree outer_type = TREE_TYPE (t); return (TYPE_PRECISION (outer_type) >= TYPE_PRECISION (inner_type) - && tree_expr_nonzero_p (TREE_OPERAND (t, 0))); + && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p)); } break; @@ -12914,42 +13250,76 @@ tree_expr_nonzero_p (tree t) } case COND_EXPR: - return (tree_expr_nonzero_p (TREE_OPERAND (t, 1)) - && tree_expr_nonzero_p (TREE_OPERAND (t, 2))); + sub_strict_overflow_p = false; + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p) + && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 2), + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + return true; + } + break; case MIN_EXPR: - return (tree_expr_nonzero_p (TREE_OPERAND (t, 0)) - && tree_expr_nonzero_p (TREE_OPERAND (t, 1))); + sub_strict_overflow_p = false; + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + &sub_strict_overflow_p) + && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + } + break; case MAX_EXPR: - if (tree_expr_nonzero_p (TREE_OPERAND (t, 0))) + sub_strict_overflow_p = false; + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + &sub_strict_overflow_p)) { + if (sub_strict_overflow_p) + strict_overflow_p = true; + / When both operands are nonzero, then MAX must be too. / - if (tree_expr_nonzero_p (TREE_OPERAND (t, 1))) + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)) return true; / MAX where operand 0 is positive is positive. / - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)); + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); } / MAX where operand 1 is positive is positive. */ - else if (tree_expr_nonzero_p (TREE_OPERAND (t, 1)) - && tree_expr_nonnegative_p (TREE_OPERAND (t, 1))) - return true; + else if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + strict_overflow_p = true; + return true; + } break; case COMPOUND_EXPR: case MODIFY_EXPR: case GIMPLE_MODIFY_STMT: case BIND_EXPR: - return tree_expr_nonzero_p (GENERIC_TREE_OPERAND (t, 1)); + return tree_expr_nonzero_warnv_p (GENERIC_TREE_OPERAND (t, 1), + strict_overflow_p); case SAVE_EXPR: case NON_LVALUE_EXPR: - return tree_expr_nonzero_p (TREE_OPERAND (t, 0)); + return tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); case BIT_IOR_EXPR: - return tree_expr_nonzero_p (TREE_OPERAND (t, 1)) - || tree_expr_nonzero_p (TREE_OPERAND (t, 0)); + return (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p) + || tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p)); case CALL_EXPR: return alloca_call_p (t); @@ -12960,6 +13330,23 @@ tree_expr_nonzero_p (tree t) return false; } +/ Return true when T is an address and is known to be nonzero. + Handle warnings about undefined signed overflow. / + +bool +tree_expr_nonzero_p (tree t) +{ + bool ret, strict_overflow_p; + + strict_overflow_p = false; + ret = tree_expr_nonzero_warnv_p (t, &strict_overflow_p); + if (strict_overflow_p) + fold_overflow_warning ("assuming signed overflow is undefined when " + "determining that expression is always " + "non-zero"); + return ret; +} + / Given the components of a binary expression CODE, TYPE, OP0 and OP1, attempt to fold the expression to a constant without modifying TYPE, OP0 or OP1. Index: gcc/ChangeLog

--- gcc/ChangeLog (revision 121377) +++ gcc/ChangeLog (working copy) @@ -1,3 +1,11 @@ +2007-01-31 Ian Lance Taylor iant@google.com + + * tree-vrp.c (vrp_expr_computes_nonnegative): Call + tree_expr_nonnegative_warnv_p instead of tree_expr_nonnegative_p. + (vrp_expr_computes_nonzero): Call tree_expr_nonzero_warnv_p + instead of tree_expr_nonzero_p. + (extract_range_from_unary_expr): Likewise. + 2007-01-31 Kazu Hirata kazu@codesourcery.com * gcc/config/arm/unwind-arm.h (_sleb128_t, _uleb128_t): New. Index: gcc/testsuite/gcc.dg/Wstrict-overflow-2.c

--- gcc/testsuite/gcc.dg/Wstrict-overflow-2.c (revision 0) +++ gcc/testsuite/gcc.dg/Wstrict-overflow-2.c (revision 0) @@ -0,0 +1,13 @@ +/* { dg-do compile } / +/ { dg-options "-fstrict-overflow -O2 -Wstrict-overflow" } / + +/ Source: Ian Lance Taylor. Based on strict-overflow-2.c. / + +/ We can only simplify the division when using strict overflow + semantics. / + +int +foo (int i) +{ + return (i * 100) / 10; / { dg-warning "assuming signed overflow is undefined" "correct warning" } */ +} Index: gcc/testsuite/gcc.dg/Wstrict-overflow-1.c

--- gcc/testsuite/gcc.dg/Wstrict-overflow-1.c (revision 0) +++ gcc/testsuite/gcc.dg/Wstrict-overflow-1.c (revision 0) @@ -0,0 +1,13 @@ +/* { dg-do compile } / +/ { dg-options "-fstrict-overflow -O2 -Wstrict-overflow" } / + +/ Source: Ian Lance Taylor. Based on strict-overflow-1.c. / + +/ We can only simplify the conditional when using strict overflow + semantics. / + +int +foo (int i) +{ + return i - 5 < 10; / { dg-warning "assuming signed overflow is undefined" "correct warning" } */ +} Index: gcc/testsuite/gcc.dg/Wstrict-overflow-3.c

--- gcc/testsuite/gcc.dg/Wstrict-overflow-3.c (revision 0) +++ gcc/testsuite/gcc.dg/Wstrict-overflow-3.c (revision 0) @@ -0,0 +1,13 @@ +/* { dg-do compile } / +/ { dg-options "-fstrict-overflow -O2 -Wstrict-overflow" } / + +/ Source: Ian Lance Taylor. Based on strict-overflow-3.c. / + +/ We can only simplify the conditional when using strict overflow + semantics. / + +int +foo (int i, int j) +{ + return i + 100 < j + 1000; / { dg-warning "assuming signed overflow is undefined" "correct warning" } */ +} Index: gcc/c-typeck.c

--- gcc/c-typeck.c (revision 121377) +++ gcc/c-typeck.c (working copy) @@ -3270,6 +3270,8 @@ build_conditional_expr (tree ifexp, tree if (unsigned_op1 ^ unsigned_op2) { + bool ovf; + /* Do not warn if the result type is signed, since the signed type will only be chosen if it can represent all the values of the unsigned type. / @@ -3278,8 +3280,10 @@ build_conditional_expr (tree ifexp, tree / Do not warn if the signed quantity is an unsuffixed integer literal (or some static constant expression involving such literals) and it is non-negative. / - else if ((unsigned_op2 && tree_expr_nonnegative_p (op1)) - || (unsigned_op1 && tree_expr_nonnegative_p (op2))) + else if ((unsigned_op2 + && tree_expr_nonnegative_warnv_p (op1, &ovf)) + || (unsigned_op1 + && tree_expr_nonnegative_warnv_p (op2, &ovf))) / OK */; else warning (0, "signed and unsigned type in conditional expression"); @@ -8301,6 +8305,7 @@ build_binary_op (enum tree_code code, tr else { tree sop, uop; + bool ovf; if (op0_signed) sop = xop0, uop = xop1; @@ -8312,7 +8317,7 @@ build_binary_op (enum tree_code code, tr constant expression involving such literals or a conditional expression involving such literals) and it is non-negative. / - if (tree_expr_nonnegative_p (sop)) + if (tree_expr_nonnegative_warnv_p (sop, &ovf)) / OK /; / Do not warn if the comparison is an equality operation, the unsigned quantity is an integral constant, and it Index: gcc/tree-cfgcleanup.c

--- gcc/tree-cfgcleanup.c (revision 121377) +++ gcc/tree-cfgcleanup.c (working copy) @@ -28,7 +28,7 @@ Boston, MA 02110-1301, USA. / #include "hard-reg-set.h" #include "basic-block.h" #include "output.h" -#include "errors.h" +#include "toplev.h" #include "flags.h" #include "function.h" #include "expr.h" @@ -78,15 +78,16 @@ cleanup_control_expr_graph (basic_block { edge e; edge_iterator ei; + const char warnmsg; switch (TREE_CODE (expr)) { case COND_EXPR: - val = fold (COND_EXPR_COND (expr)); + val = fold_warnv (COND_EXPR_COND (expr), &warnmsg); break; case SWITCH_EXPR: - val = fold (SWITCH_COND (expr)); + val = fold_warnv (SWITCH_COND (expr), &warnmsg); if (TREE_CODE (val) != INTEGER_CST) return false; break; @@ -104,6 +105,20 @@ cleanup_control_expr_graph (basic_block { if (e != taken_edge) { + if (warnmsg != NULL) + { + location_t locus; + + if (!expr_has_location (expr)) + locus = input_location; + else + locus = expr_location (expr); + warning (OPT_Wstrict_overflow, "%H%s", &locus, warnmsg); + + /* Only warn once. */ + warnmsg = NULL; + } + taken_edge->probability += e->probability; taken_edge->count += e->count; remove_edge (e); Index: gcc/common.opt

--- gcc/common.opt (revision 121377) +++ gcc/common.opt (working copy) @@ -141,6 +141,10 @@ Wstrict-aliasing= Common Joined UInteger Warn about code which might break strict aliasing rules +Wstrict-overflow +Common Var(warn_strict_overflow) +Warn about optimizations that assume that signed overflow is undefined + Wstring-literal-comparison Common Var(warn_string_literal_comparison) Warn about comparisons to constant string literals Index: gcc/tree-cfg.c

--- gcc/tree-cfg.c (revision 121377) +++ gcc/tree-cfg.c (working copy) @@ -421,10 +421,27 @@ fold_cond_expr_cond (void) if (stmt && TREE_CODE (stmt) == COND_EXPR) { - tree cond = fold (COND_EXPR_COND (stmt)); - if (integer_zerop (cond)) + const char* warnmsg; + bool zerop, onep; + + tree cond = fold_warnv (COND_EXPR_COND (stmt), &warnmsg); + zerop = integer_zerop (cond); + onep = integer_onep (cond); + + if (warnmsg != NULL && (zerop || onep)) + { + location_t locus; + + if (!expr_has_location (stmt)) + locus = input_location; + else + locus = expr_location (stmt); + warning (OPT_Wstrict_overflow, "%H%s", &locus, warnmsg); + } + + if (zerop) COND_EXPR_COND (stmt) = boolean_false_node; - else if (integer_onep (cond)) + else if (onep) COND_EXPR_COND (stmt) = boolean_true_node; } } Index: gcc/passes.c

--- gcc/passes.c (revision 121377) +++ gcc/passes.c (working copy) @@ -926,6 +926,17 @@ execute_todo (unsigned int flags) } }

+/* Verify invariants that should hold between passes. This is a place

@@ -1037,6 +1048,7 @@ execute_one_pass (struct tree_opt_pass *

/* Run post-pass cleanup and verification. */ execute_todo (todo_after | pass->todo_flags_finish);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]