This is the mail archive of the gcc-patches@gcc.gnu.org mailing 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]

PATCH RFC: -Wstrict-overflow, take 2


Here is a new version of my -Wstrict-overflow patch.  This
incorporates all the comments made on the first version.


-Wstrict-overflow is a new warning about cases where the compiler
optimizes based on the assumption that signed overflow is undefined.
This warning can produce a number of false positives, because the
values which actually appear in the program may be such that overflow
never does, in fact, occur.  Therefore, the warning comes in five
levels.

-Wstrict-overflow is equivalent to -Wstrict-overflow=1.  This level is
automatically enabled by -Wall.  It warns about questionable cases
which are easy to avoid.  For example, it will warn about optimizing
(x + 1 > x) to 1 (this optimization will yield an unexpected result if
X == INT_MAX).

-Wstrict-overflow=2 additionally warns about cases where a conditional
expression is folded to a constant.  A typical example would be
(abs (x) >= 0), which will be folded to 1 (this optimization will yield
an unexpected result if x == INT_MIN).

-Wstrict-overflow=3 additionally warns about cases where a comparison
is changed in some way other than folding it to a constant.  A typical
example would be converting (x + 1 > 1) to (x > 0) (this optimization
will yield an unexpected result if x == INT_MAX).

-Wstrict-overflow=4 additionally warns about warnings not covered by
the above cases (or the case below).  A typical example would be
converting ((x * 10) / 5) to (x * 2) (this optimization will yield an
unexpected result if x == ((INT_MAX / 2) - 1)).

-Wstrict-overflow=5 additionally warns about reducing the magnitude of
a constant involved in a comparison.  This is a particularly fertile
source of false positives, as it is a canonicalization rather than an
optimization per se.  That is why it is segregated from the other
options.  For example: changing (x + 2 > y) to (x + 1 >= y) (this
optimization will yield an unexpected result if x == INT_MAX - 1).


This patch does not implement the warnings appropriate when VRP
optimizes based on undefined signed overflow.  Those warnings will be
provided in a follow on patch.


This patch has been tested with a bootstrap and testsuite run on
i686-pc-linux-gnu.


Compiling the cc1 .i files with -Wstrict-overflow -O2 yields no
warnings at -Wstrict-overflow=1 or -Wstrict-overflow=2.

At -Wstrict-overflow=3 we get 31 warnings:

../../trunk/gcc/expmed.c:3485: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/expmed.c:3511: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/expmed.c:3538: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/expmed.c:4106: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/expmed.c:4272: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/expmed.c:4307: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/expmed.c:4399: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/config/i386/i386.md:20245: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/config/i386/i386.md:20245: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/local-alloc.c:1674: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/local-alloc.c:1675: warning: assuming signed overflow does not occur when combining constants around a comparison
../../trunk/gcc/real.c:949: warning: assuming signed overflow does not occur when combining constants around a comparison
../../trunk/gcc/real.c:951: warning: assuming signed overflow does not occur when combining constants around a comparison
../../trunk/gcc/real.c:979: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/real.c:981: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/real.c:1208: warning: assuming signed overflow does not occur when combining constants around a comparison
../../trunk/gcc/real.c:1293: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/real.c:1299: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/real.c:1551: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/real.c:1589: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/rtlanal.c:4217: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/stmt.c:1144: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/stor-layout.c:263: warning: assuming signed overflow does not occur when eliminating multiplication in comparison with zero
../../trunk/gcc/stor-layout.c:263: warning: assuming signed overflow does not occur when eliminating multiplication in comparison with zero
../../trunk/gcc/stor-layout.c:2036: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/stor-layout.c:2039: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/stor-layout.c:2049: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/stor-layout.c:2053: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/stor-layout.c:2058: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/stor-layout.c:2061: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2
../../trunk/gcc/varasm.c:1450: warning: assuming signed overflow does not occur when changing X +- C1 cmp C2 to X cmp C1 +- C2


At -Wstrict-overflow=4 we get an additional 20 warnings:

../../trunk/gcc/bb-reorder.c:266: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/bb-reorder.c:908: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/bb-reorder.c:910: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/df-problems.c:3466: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/df-problems.c:3466: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/df-problems.c:3634: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/df-problems.c:3634: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/flow.c:2924: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/flow.c:2924: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/flow.c:3811: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/flow.c:3811: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/function.c:3498: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/config/i386/i386.c:12960: warning: assuming signed overflow does not occur when negating a division
../../trunk/gcc/ipa-inline.c:606: warning: assuming signed overflow does not occur when negating a division
../../trunk/gcc/profile.c:549: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/real.c:4829: warning: assuming signed overflow does not occur when distributing negation across division
../../trunk/gcc/regclass.c:1259: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/regclass.c:1259: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/sched-rgn.c:1332: warning: assuming signed overflow does not occur when simplifying division
../../trunk/gcc/sched-rgn.c:2927: warning: assuming signed overflow does not occur when simplifying division


At -Wstrict-overflow=5 we get an additional 11 warnings:

../../trunk/gcc/combine.c:8608: warning: assuming signed overflow does not occur when reducing constant in comparison
../../trunk/gcc/c-ppoutput.c:222: warning: assuming signed overflow does not occur when reducing constant in comparison
../../trunk/gcc/expr.c:5129: warning: assuming signed overflow does not occur when reducing constant in comparison
../../trunk/gcc/local-alloc.c:1675: warning: assuming signed overflow does not occur when reducing constant in comparison
../../trunk/gcc/modulo-sched.c:1422: warning: assuming signed overflow does not occur when reducing constant in comparison
../../trunk/gcc/modulo-sched.c:1422: warning: assuming signed overflow does not occur when reducing constant in comparison
../../trunk/gcc/postreload.c:1348: warning: assuming signed overflow does not occur when reducing constant in comparison
../../trunk/gcc/real.c:2397: warning: assuming signed overflow does not occur when reducing constant in comparison
../../trunk/gcc/regclass.c:2421: warning: assuming signed overflow does not occur when reducing constant in comparison
../../trunk/gcc/rtlanal.c:4095: warning: assuming signed overflow does not occur when reducing constant in comparison
../../trunk/gcc/tree-eh.c:1070: warning: assuming signed overflow does not occur when reducing constant in comparison

gcc/ChangeLog:
2007-02-07  Ian Lance Taylor  <iant@google.com>

	* common.opt: Add Wstrict-overflow and Wstrict-overflow=.
	* flags.h (warn_strict_overflow): Declare.
	(enum warn_strict_overflow_code): Define.
	(issue_strict_overflow_warning): New static inline function.
	* opts.c (warn_strict_overflow): New variable.
	(common_handle_option): Handle OPT_Wstrict_overflow and
	OPT_Wstrict_overflow_.
	* c-opts.c (c_common_handle_option): Set warn_strict_overflow for
	OPT_Wall.
	* fold-const.c: Include intl.h.
	(fold_deferring_overflow_warnings): New static variable.
	(fold_deferred_overflow_warning): New static variable.
	(fold_deferred_overflow_code): New static variable.
	(fold_defer_overflow_warnings): New function.
	(fold_undefer_overflow_warnings): New function.
	(fold_undefer_and_ignore_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.
	(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): Ignore fold
	warnings.
	(number_of_iterations_exit, loop_niter_by_eval): Likewise.
	(estimate_numbers_of_iterations): Likewise.
	(scev_probably_wraps_p): Likewise.
	* tree-ssa-ccp.c: Include "toplev.h".
	(evaluate_stmt): Defer fold overflow warnings until we know we are
	going to optimize.
	(struct fold_stmt_r_data): Add stmt field.
	(fold_stmt_r): Defer fold overflow warnings until we know we
	optimized.
	(fold_stmt): Initialize stmt field of fold_stmt_r_data.
	(fold_stmt_inplace): Likewise.
	* tree-cfgcleanup.c: Include "toplev.h" rather than "errors.h".
	(cleanup_control_expr_graph): Defer fold overflow warnings until
	we know we are going to optimize.
	* tree-cfg.c (fold_cond_expr_cond): Likewise.
	* tree-ssa-threadedge.c (simplify_control_stmt_condition):
	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.
	* simplify-rtx.c (simplify_const_relational_operation): Warn when
	assuming that signed overflow does not occur.
	* c-common.c (pointer_int_sum): Ignore fold overflow warnings.
	* tree.h (tree_expr_nonnegative_warnv_p): Declare.
	(fold_defer_overflow_warnings): Declare.
	(fold_undefer_overflow_warnings): Declare.
	(fold_undefer_and_ignore_overflow_warnings): Declare.
	(fold_deferring_overflow_warnings_p): Declare.
	(tree_expr_nonzero_warnv_p): Declare.
	* doc/invoke.texi (Option Summary): Add -Wstrict-overflow to list
	of warning options.
	(Warning Options): Document -Wstrict-overflow.
	* Makefile.in (tree-ssa-threadedge.o): Depend on toplev.h.
	(tree-ssa-ccp.o): Likewise.
	(tree-cfgcleanup.o): Change errors.h dependency to toplev.h.
	(fold-const.o): Depend on intl.h.

gcc/testsuite/ChangeLog:
2007-02-07  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.
	* gcc.dg/Wstrict-overflow-4.c: New test.
	* gcc.dg/Wstrict-overflow-5.c: New test.
	* gcc.dg/Wstrict-overflow-6.c: New test.
	* gcc.dg/Wstrict-overflow-7.c: New test.
	* gcc.dg/Wstrict-overflow-8.c: New test.
	* gcc.dg/Wstrict-overflow-9.c: New test.
	* gcc.dg/Wstrict-overflow-10.c: New test.


Index: gcc/tree-vrp.c
===================================================================
--- gcc/tree-vrp.c	(revision 121691)
+++ 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/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 121691)
+++ gcc/doc/invoke.texi	(working copy)
@@ -247,6 +247,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wreturn-type  -Wsequence-point  -Wshadow @gol
 -Wsign-compare  -Wstack-protector @gol
 -Wstrict-aliasing -Wstrict-aliasing=2 @gol
+-Wstrict-overflow -Wstrict-overflow=@var{n} @gol
 -Wstring-literal-comparison @gol
 -Wswitch  -Wswitch-default  -Wswitch-enum @gol
 -Wsystem-headers  -Wtrigraphs  -Wundef  -Wuninitialized @gol
@@ -2859,6 +2860,55 @@ compiler is using for optimization.  Thi
 @option{-Wstrict-aliasing}, but it will also give a warning for some ambiguous
 cases that are safe.
 
+@item -Wstrict-overflow
+@item -Wstrict-overflow=@var{n}
+@opindex -Wstrict-overflow
+This option is only active when @option{-fstrict-overflow} is active.
+It warns about cases where the compiler optimizes based on the
+assumption that signed overflow does not occur.  Note that it does not
+warn about all cases where the code might overflow: it only warns
+about cases where the compiler implements some optimization.  Thus
+this warning depends on the optimization level.
+
+An optimization which assumes that signed overflow does not occur is
+perfectly safe if the values of the variables involved are such that
+overflow never does, in fact, occur.  Therefore this warning can
+easily give a false positive: a warning about code which is not
+actually a problem.  To help focus on important issues, several
+warning levels are defined.
+
+@table @option
+@item -Wstrict-overflow=1
+Warn about cases which are both questionable and easy to avoid.  For
+example: @code{x + 1 > x}; with @option{-fstrict-overflow}, the
+compiler will simplify this to @code{1}.  @option{-Wstrict-overflow}
+(with no level) is the same as @option{-Wstrict-overflow=1}.  This
+level of @option{-Wstrict-overflow} is enabled by @option{-Wall};
+higher levels are not, and must be explicitly requested.
+
+@item -Wstrict-overflow=2
+Warn about other cases where a comparison is simplified to a constant.
+For example: @code{abs (x) >= 0}.  This can only be simplified when
+@option{-fstrict-overflow} is in effect, because @code{abs (INT_MIN)}
+overflows to @code{INT_MIN}, which is less than zero.
+
+@item -Wstrict-overflow=3
+Warn about other cases where a comparison is simplified.  For example:
+@code{x + 1 > 1} will be simplified to @code{x > 0}.
+
+@item -Wstrict-overflow=4
+Warn about other simplifications not covered by the above cases.  For
+example: @code{(x * 10) / 5} will be simplified to @code{x * 2}.  
+
+@item -Wstrict-overflow=5
+Warn about cases where the compiler reduces the magnitude of a
+constant involved in a comparison.  For example: @code{x + 2 > y} will
+be simplified to @code{x + 1 >= y}.  This is reported only at the
+highest warning level because this simplification applies to many
+comparisons, so this warning level will give a very large number of
+false positives.
+@end table
+
 @item -Warray-bounds
 @opindex Wno-array-bounds
 @opindex Warray-bounds
Index: gcc/flags.h
===================================================================
--- gcc/flags.h	(revision 121691)
+++ gcc/flags.h	(working copy)
@@ -114,6 +114,11 @@ extern HOST_WIDE_INT larger_than_size;
 
 extern int warn_strict_aliasing;
 
+/* Nonzero means warn about optimizations which rely on undefined
+   signed overflow.  */
+
+extern int warn_strict_overflow;
+
 /* Temporarily suppress certain warnings.
    This is set while reading code from a system header file.  */
 
@@ -289,8 +294,13 @@ extern const char *flag_random_seed;
   (TYPE_UNSIGNED (TYPE) || flag_wrapv)
 
 /* True if overflow is undefined for the given integral type.  We may
-   optimize on the assumption that values in the type never
-   overflow.  */
+   optimize on the assumption that values in the type never overflow.
+
+   IMPORTANT NOTE: Any optimization based on TYPE_OVERFLOW_UNDEFINED
+   must issue a warning based on warn_strict_overflow.  In some cases
+   it will be appropriate to issue the warning immediately, and in
+   other cases it will be appropriate to simply set a flag and let the
+   caller decide whether a warning is appropriate or not.  */
 #define TYPE_OVERFLOW_UNDEFINED(TYPE) \
   (!TYPE_UNSIGNED (TYPE) && !flag_wrapv && !flag_trapv && flag_strict_overflow)
 
@@ -299,4 +309,37 @@ extern const char *flag_random_seed;
 #define TYPE_OVERFLOW_TRAPS(TYPE) \
   (!TYPE_UNSIGNED (TYPE) && flag_trapv)
 
+/* Names for the different levels of -Wstrict-overflow=N.  The numeric
+   values here correspond to N.  */
+
+enum warn_strict_overflow_code
+{
+  /* Overflow warning that should be issued with -Wall: a questionable
+     construct that is easy to avoid even when using macros.  Example:
+     folding (x + CONSTANT > x) to 1.  */
+  WARN_STRICT_OVERFLOW_ALL = 1,
+  /* Overflow warning about folding a comparison to a constant because
+     of undefined signed overflow, other than cases covered by
+     WARN_STRICT_OVERFLOW_ALL.  Example: folding (abs (x) >= 0) to 1
+     (this is false when x == INT_MIN).  */
+  WARN_STRICT_OVERFLOW_CONDITIONAL = 2,
+  /* Overflow warning about changes to comparisons other than folding
+     them to a constant.  Example: folding (x + 1 > 1) to (x > 0).  */
+  WARN_STRICT_OVERFLOW_COMPARISON = 3,
+  /* Overflow warnings not covered by the above cases.  Example:
+     folding ((x * 10) / 5) to (x * 2).  */
+  WARN_STRICT_OVERFLOW_MISC = 4,
+  /* Overflow warnings about reducing magnitude of constants in
+     comparison.  Example: folding (x + 2 > y) to (x + 1 >= y).  */
+  WARN_STRICT_OVERFLOW_MAGNITUDE = 5
+};
+
+/* Whether to emit an overflow warning whose code is C.  */
+
+static inline bool
+issue_strict_overflow_warning (enum warn_strict_overflow_code c)
+{
+  return warn_strict_overflow >= (int) c;
+}
+
 #endif /* ! GCC_FLAGS_H */
Index: gcc/tree-ssa-loop-niter.c
===================================================================
--- gcc/tree-ssa-loop-niter.c	(revision 121691)
+++ gcc/tree-ssa-loop-niter.c	(working copy)
@@ -705,7 +705,13 @@ expand_simple_operations (tree expr)
 	  TREE_OPERAND (ret, i) = ee;
 	}
 
-      return (ret ? fold (ret) : expr);
+      if (!ret)
+	return expr;
+
+      fold_defer_overflow_warnings ();
+      ret = fold (ret);
+      fold_undefer_and_ignore_overflow_warnings ();
+      return ret;
     }
 
   if (TREE_CODE (expr) != SSA_NAME)
@@ -1053,11 +1059,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_and_ignore_overflow_warnings ();
+      return false;
+    }
 
   if (optimize >= 3)
     {
@@ -1078,6 +1091,8 @@ number_of_iterations_exit (struct loop *
 					       niter->may_be_zero,
 					       &niter->additional_info);
 
+  fold_undefer_and_ignore_overflow_warnings ();
+
   if (integer_onep (niter->assumptions))
     return true;
 
@@ -1376,6 +1391,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 +1402,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_and_ignore_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 +1414,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_and_ignore_overflow_warnings ();
+	      return chrec_dont_know;
+	    }
 	}
     }
 
+  fold_undefer_and_ignore_overflow_warnings ();
+
   return chrec_dont_know;
 }
 
@@ -1994,10 +2018,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_and_ignore_overflow_warnings ();
 }
 
 /* Returns true if statement S1 dominates statement S2.  */
@@ -2153,6 +2183,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 +2212,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_and_ignore_overflow_warnings ();
+	  return false;
+	}
+    }
+
+  fold_undefer_and_ignore_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 121691)
+++ gcc/tree-ssa-loop-manip.c	(working copy)
@@ -1,5 +1,5 @@
 /* High-level loop manipulation functions.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
    
 This file is part of GCC.
    
@@ -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 121691)
+++ gcc/tree.h	(working copy)
@@ -3714,6 +3714,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);
 
@@ -4312,6 +4313,10 @@ 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 void fold_undefer_overflow_warnings (bool, tree, int);
+extern void fold_undefer_and_ignore_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);
@@ -4384,6 +4389,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 121691)
+++ gcc/fold-const.c	(working copy)
@@ -59,6 +59,7 @@ Software Foundation, 51 Franklin Street,
 #include "expr.h"
 #include "tm_p.h"
 #include "toplev.h"
+#include "intl.h"
 #include "ggc.h"
 #include "hashtab.h"
 #include "langhooks.h"
@@ -119,7 +120,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 +129,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 +902,122 @@ 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
+   warning per expression.  */
+
+static const char* fold_deferred_overflow_warning;
+
+/* If a warning about undefined overflow is deferred, this is the
+   level at which the warning should be emitted.  */
+
+static enum warn_strict_overflow_code fold_deferred_overflow_code;
+
+/* 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 there is a pending warning,
+   and ISSUE is true, then issue the warning if appropriate.  STMT is
+   the statement with which the warning should be associated (used for
+   location information); STMT may be NULL.  CODE is the level of the
+   warning--a warn_strict_overflow_code value.  This function will use
+   the smaller of CODE and the deferred code when deciding whether to
+   issue the warning.  CODE may be zero to mean to always use the
+   deferred code.  */
+
+void
+fold_undefer_overflow_warnings (bool issue, tree stmt, int code)
+{
+  const char *warnmsg;
+  location_t locus;
+
+  gcc_assert (fold_deferring_overflow_warnings > 0);
+  --fold_deferring_overflow_warnings;
+  if (fold_deferring_overflow_warnings > 0)
+    {
+      if (fold_deferred_overflow_warning != NULL
+	  && code != 0
+	  && code < (int) fold_deferred_overflow_code)
+	fold_deferred_overflow_code = code;
+      return;
+    }
+
+  warnmsg = fold_deferred_overflow_warning;
+  fold_deferred_overflow_warning = NULL;
+
+  if (!issue || warnmsg == NULL)
+    return;
+
+  /* Use the smallest code level when deciding to issue the
+     warning.  */
+  if (code == 0 || code > (int) fold_deferred_overflow_code)
+    code = fold_deferred_overflow_code;
+
+  if (!issue_strict_overflow_warning (code))
+    return;
+
+  if (stmt == NULL_TREE || !expr_has_location (stmt))
+    locus = input_location;
+  else
+    locus = expr_location (stmt);
+  warning (OPT_Wstrict_overflow, "%H%s", &locus, warnmsg);
+}
+
+/* Stop deferring overflow warnings, ignoring any deferred
+   warnings.  */
+
+void
+fold_undefer_and_ignore_overflow_warnings (void)
+{
+  fold_undefer_overflow_warnings (false, NULL_TREE, 0);
+}
+
+/* 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* gmsgid, enum warn_strict_overflow_code wc)
+{
+  gcc_assert (!flag_wrapv && !flag_trapv);
+  if (fold_deferring_overflow_warnings > 0)
+    {
+      if (fold_deferred_overflow_warning == NULL
+	  || wc < fold_deferred_overflow_code)
+	{
+	  fold_deferred_overflow_warning = gmsgid;
+	  fold_deferred_overflow_code = wc;
+	}
+    }
+  else if (issue_strict_overflow_warning (wc))
+    warning (OPT_Wstrict_overflow, gmsgid);
+}
+
 /* Return true if the built-in mathematical function specified by CODE
    is odd, i.e. -f(x) == f(-x).  */
 
@@ -1054,6 +1171,11 @@ negate_expr_p (tree t)
     case FLOOR_DIV_EXPR:
     case CEIL_DIV_EXPR:
     case EXACT_DIV_EXPR:
+      /* In general we can't negate A / B, because if A is INT_MIN and
+	 B is 1, we may turn this into INT_MIN / -1 which is undefined
+	 and actually traps on some architectures.  But if overflow is
+	 undefined, we can negate, because - (INT_MIN / 1) is an
+	 overflow.  */
       if (INTEGRAL_TYPE_P (TREE_TYPE (t))
 	  && !TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t)))
         break;
@@ -1215,16 +1337,36 @@ fold_negate_expr (tree t)
     case FLOOR_DIV_EXPR:
     case CEIL_DIV_EXPR:
     case EXACT_DIV_EXPR:
+      /* In general we can't negate A / B, because if A is INT_MIN and
+	 B is 1, we may turn this into INT_MIN / -1 which is undefined
+	 and actually traps on some architectures.  But if overflow is
+	 undefined, we can negate, because - (INT_MIN / 1) is an
+	 overflow.  */
       if (!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type))
         {
+	  const char * const warnmsg = G_("assuming signed overflow does not "
+					  "occur 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));
+	    {
+	      if (INTEGRAL_TYPE_P (type)
+		  && (TREE_CODE (tem) != INTEGER_CST
+		      || tree_int_cst_equal (tem,
+					     build_int_cst (type, 1))))
+		fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MISC);
+	      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));
+	    {
+	      if (INTEGRAL_TYPE_P (type)
+		  && (TREE_CODE (tem) != INTEGER_CST
+		      || tree_int_cst_equal (tem, TYPE_MIN_VALUE (type))))
+		fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MISC);
+	      return fold_build2 (TREE_CODE (t), type,
+				  negate_expr (tem), TREE_OPERAND (t, 1));
+	    }
         }
       break;
 
@@ -3861,12 +4003,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;
@@ -4015,6 +4161,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))
@@ -4796,9 +4945,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 = G_("assuming signed overflow does not occur "
+				  "when simplifying range test");
 
   /* If this is an OR operation, invert both sides; we will invert
      again at the end.  */
@@ -4816,7 +4968,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, WARN_STRICT_OVERFLOW_COMPARISON);
+      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
@@ -4846,9 +5002,14 @@ 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,
+				       WARN_STRICT_OVERFLOW_COMPARISON);
+	      return build2 (code == TRUTH_ANDIF_EXPR
+			     ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
+			     type, lhs, rhs);
+	    }
 	}
     }
 
@@ -5447,10 +5608,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
@@ -5464,14 +5630,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);
@@ -5481,6 +5648,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))
@@ -5537,7 +5705,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;
 
@@ -5547,7 +5716,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);
@@ -5556,7 +5726,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;
 
@@ -5567,12 +5738,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);
-
+	  if (sub_strict_overflow_p)
+	    *strict_overflow_p = true;
 	  return fold_build2 (tcode, ctype, fold_convert (ctype, t1),
 			      fold_convert (ctype, t2));
 	}
@@ -5599,7 +5774,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:
@@ -5607,16 +5782,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.  */
@@ -5697,11 +5877,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)
@@ -5731,15 +5913,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;
 
@@ -7667,7 +7857,9 @@ fold_unary (enum tree_code code, tree ty
 						    targ0));
 	}
       /* ABS_EXPR<ABS_EXPR<x>> = ABS_EXPR<x> 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.  */
@@ -7884,11 +8076,14 @@ fold_minmax (enum tree_code code, tree t
    by changing CODE to reduce the magnitude of constants involved in
    ARG0 of the comparison.
    Returns a canonicalized comparison tree if a simplification was
-   possible, otherwise returns NULL_TREE.  */
+   possible, otherwise returns NULL_TREE.
+   Set *STRICT_OVERFLOW_P to true if the canonicalization is only
+   valid if signed overflow is undefined.  */
 
 static tree
 maybe_canonicalize_comparison_1 (enum tree_code code, tree type,
-				 tree arg0, tree arg1)
+				 tree arg0, tree arg1,
+				 bool *strict_overflow_p)
 {
   enum tree_code code0 = TREE_CODE (arg0);
   tree t, cst0 = NULL_TREE;
@@ -7955,6 +8150,7 @@ maybe_canonicalize_comparison_1 (enum tr
 	code = GT_EXPR;
       else
 	return NULL_TREE;
+      *strict_overflow_p = true;
     }
 
   /* Now build the constant reduced in magnitude.  */
@@ -7981,6 +8177,9 @@ maybe_canonicalize_comparison (enum tree
 			       tree arg0, tree arg1)
 {
   tree t;
+  bool strict_overflow_p;
+  const char * const warnmsg = G_("assuming signed overflow does not occur "
+				  "when reducing constant in comparison");
 
   /* In principle pointers also have undefined overflow behavior,
      but that causes problems elsewhere.  */
@@ -7989,14 +8188,25 @@ maybe_canonicalize_comparison (enum tree
     return NULL_TREE;
 
   /* Try canonicalization by simplifying arg0.  */
-  t = maybe_canonicalize_comparison_1 (code, type, arg0, arg1);
+  strict_overflow_p = false;
+  t = maybe_canonicalize_comparison_1 (code, type, arg0, arg1,
+				       &strict_overflow_p);
   if (t)
-    return t;
+    {
+      if (strict_overflow_p)
+	fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MAGNITUDE);
+      return t;
+    }
 
   /* Try canonicalization by simplifying arg1 using the swapped
      comparison.  */
   code = swap_tree_comparison (code);
-  return maybe_canonicalize_comparison_1 (code, type, arg1, arg0);
+  strict_overflow_p = false;
+  t = maybe_canonicalize_comparison_1 (code, type, arg1, arg0,
+				       &strict_overflow_p);
+  if (t && strict_overflow_p)
+    fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MAGNITUDE);
+  return t;
 }
 
 /* Subroutine of fold_binary.  This routine performs all of the
@@ -8046,7 +8256,13 @@ 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 does not occur "
+				  "when changing X +- C1 cmp C2 to "
+				  "X cmp C1 +- C2"),
+				 WARN_STRICT_OVERFLOW_COMPARISON);
+	  return fold_build2 (code, type, variable, lhs);
+	}
     }
 
   /* For comparisons of pointers we can decompose it to a compile time
@@ -8211,6 +8427,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 = G_("assuming signed overflow does not "
+				      "occur 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.  */
@@ -8219,20 +8438,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, WARN_STRICT_OVERFLOW_COMPARISON);
+	  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, WARN_STRICT_OVERFLOW_COMPARISON);
+	  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
@@ -8252,6 +8477,11 @@ fold_comparison (enum tree_code code, tr
 
       gcc_assert (!integer_zerop (const1));
 
+      fold_overflow_warning (("assuming signed overflow does not occur when "
+			      "eliminating multiplication in comparison "
+			      "with zero"),
+			     WARN_STRICT_OVERFLOW_COMPARISON);
+
       /* 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);
@@ -8687,6 +8917,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))
@@ -9434,11 +9665,20 @@ 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 does not "
+					"occur when simplifying "
+					"multiplication"),
+				       WARN_STRICT_OVERFLOW_MISC);
+	      return fold_convert (type, tem);
+	    }
 
 	  /* Optimize z * conj(z) for integer complex numbers.  */
 	  if (TREE_CODE (arg0) == CONJ_EXPR
@@ -10338,8 +10578,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)
@@ -10347,6 +10589,11 @@ 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 does not "
+					"occur when simplifying A / (B << N)"),
+				       WARN_STRICT_OVERFLOW_MISC);
+
 	      sh_cnt = fold_build2 (PLUS_EXPR, TREE_TYPE (sh_cnt),
 				    sh_cnt, build_int_cst (NULL_TREE, pow2));
 	      return fold_build2 (RSHIFT_EXPR, type,
@@ -10374,13 +10621,27 @@ 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 does not occur "
+				    "when distributing negation across "
+				    "division"),
+				   WARN_STRICT_OVERFLOW_MISC);
+	  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 does not occur "
+				    "when distributing negation across "
+				    "division"),
+				   WARN_STRICT_OVERFLOW_MISC);
+	  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.
@@ -10392,9 +10653,17 @@ 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 does not occur "
+				    "when simplifying division"),
+				   WARN_STRICT_OVERFLOW_MISC);
+	  return fold_convert (type, tem);
+	}
 
       return NULL_TREE;
 
@@ -10426,8 +10695,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,
@@ -10439,6 +10710,11 @@ 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 does not "
+					"occur when simplifying "
+					"X % (power of two)"),
+				       WARN_STRICT_OVERFLOW_MISC);
 	      return fold_build2 (BIT_AND_EXPR, type,
 				  fold_convert (type, arg0),
 				  fold_convert (type, mask));
@@ -10466,8 +10742,15 @@ 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 does not occur "
+				    "when simplifying modulos"),
+				   WARN_STRICT_OVERFLOW_MISC);
+	  return fold_convert (type, tem);
+	}
 
       return NULL_TREE;
 
@@ -11296,27 +11579,59 @@ 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 does not "
+					"occur when assuming that (X - c) > X "
+					"is always false"),
+				       WARN_STRICT_OVERFLOW_ALL);
+	      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 does not "
+					"occur when assuming that "
+					"(X + c) < X is always false"),
+				       WARN_STRICT_OVERFLOW_ALL);
+	      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 does not "
+					"occur when assuming that "
+					"(X - c) <= X is always true"),
+				       WARN_STRICT_OVERFLOW_ALL);
+	      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 does not "
+					"occur when assuming that "
+					"(X + c) >= X is always true"),
+				       WARN_STRICT_OVERFLOW_ALL);
+	      return constant_boolean_node (1, type);
+	    }
 
 	  if (TREE_CODE (arg01) == INTEGER_CST)
 	    {
@@ -11324,23 +11639,51 @@ 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 does "
+					    "not occur when assuming that "
+					    "(X + c) > X is always true"),
+					   WARN_STRICT_OVERFLOW_ALL);
+		  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 does "
+					    "not occur when assuming that "
+					    "(X - c) < X is always true"),
+					   WARN_STRICT_OVERFLOW_ALL);
+		  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 does "
+					    "not occur when assuming that "
+					    "(X + c) <= X is always false"),
+					   WARN_STRICT_OVERFLOW_ALL);
+		  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 does "
+					    "not occur when assuming that "
+					    "(X - c) >= X is always true"),
+					   WARN_STRICT_OVERFLOW_ALL);
+		  return constant_boolean_node (0, type);
+		}
 	    }
 	}
 
@@ -11541,18 +11884,34 @@ fold_binary (enum tree_code code, tree t
 				    TREE_OPERAND (arg0, 0), arg1));
 
       /* Convert ABS_EXPR<x> >= 0 to true.  */
+      strict_overflow_p = false;
       if (code == GE_EXPR
-	  && tree_expr_nonnegative_p (arg0)
 	  && (integer_zerop (arg1)
 	      || (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
-		  && real_zerop (arg1))))
-	return omit_one_operand (type, integer_one_node, arg0);
+		  && real_zerop (arg1)))
+	  && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))
+	{
+	  if (strict_overflow_p)
+	    fold_overflow_warning (("assuming signed overflow does not occur "
+				    "when simplifying comparison of "
+				    "absolute value and zero"),
+				   WARN_STRICT_OVERFLOW_CONDITIONAL);
+	  return omit_one_operand (type, integer_one_node, arg0);
+	}
 
       /* Convert ABS_EXPR<x> < 0 to false.  */
+      strict_overflow_p = false;
       if (code == LT_EXPR
-	  && tree_expr_nonnegative_p (arg0)
-	  && (integer_zerop (arg1) || real_zerop (arg1)))
-	return omit_one_operand (type, integer_zero_node, arg0);
+	  && (integer_zerop (arg1) || real_zerop (arg1))
+	  && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))
+	{
+	  if (strict_overflow_p)
+	    fold_overflow_warning (("assuming signed overflow does not occur "
+				    "when simplifying comparison of "
+				    "absolute value and zero"),
+				   WARN_STRICT_OVERFLOW_CONDITIONAL);
+	  return omit_one_operand (type, integer_zero_node, arg0);
+	}
 
       /* If X is unsigned, convert X < (1 << Y) into X >> Y == 0
 	 and similarly for >= into !=.  */
@@ -12628,10 +12987,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;
@@ -12652,7 +13014,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:
@@ -12663,8 +13028,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.  */
@@ -12690,8 +13057,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
@@ -12711,8 +13080,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:
@@ -12722,8 +13093,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:
@@ -12732,19 +13105,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:
       {
@@ -12754,18 +13132,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);
@@ -12781,7 +13162,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.  */
@@ -12800,7 +13181,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;
       }
@@ -12836,7 +13218,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):
@@ -12866,21 +13249,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
@@ -12891,7 +13283,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
@@ -12912,7 +13305,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;
@@ -12931,14 +13325,37 @@ 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 does not occur when "
+			    "determining that expression is always "
+			    "non-negative"),
+			   WARN_STRICT_OVERFLOW_MISC);
+  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))
@@ -12952,7 +13369,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);
@@ -12962,20 +13380,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;
 
@@ -12985,7 +13417,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;
 
@@ -13008,42 +13441,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);
@@ -13054,6 +13521,24 @@ 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 does not occur when "
+			    "determining that expression is always "
+			    "non-zero"),
+			   WARN_STRICT_OVERFLOW_MISC);
+  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/testsuite/gcc.dg/Wstrict-overflow-5.c
===================================================================
--- gcc/testsuite/gcc.dg/Wstrict-overflow-5.c	(revision 0)
+++ gcc/testsuite/gcc.dg/Wstrict-overflow-5.c	(revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=3" } */
+
+/* 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 does not occur" "correct warning" } */
+}
Index: gcc/testsuite/gcc.dg/Wstrict-overflow-7.c
===================================================================
--- gcc/testsuite/gcc.dg/Wstrict-overflow-7.c	(revision 0)
+++ gcc/testsuite/gcc.dg/Wstrict-overflow-7.c	(revision 0)
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow" } */
+
+/* Source: Ian Lance Taylor.  */
+
+int
+foo (int i)
+{
+  return i + 10 > i; /* { dg-warning "assuming signed overflow does not occur" "correct warning" } */
+}
Index: gcc/testsuite/gcc.dg/Wstrict-overflow-9.c
===================================================================
--- gcc/testsuite/gcc.dg/Wstrict-overflow-9.c	(revision 0)
+++ gcc/testsuite/gcc.dg/Wstrict-overflow-9.c	(revision 0)
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=2" } */
+
+/* Source: Ian Lance Taylor.  */
+
+int
+foo (int i)
+{
+  return __builtin_abs (i) >= 0; /* { dg-warning "assuming signed overflow does not occur" "correct warning" } */
+}
Index: gcc/testsuite/gcc.dg/Wstrict-overflow-10.c
===================================================================
--- gcc/testsuite/gcc.dg/Wstrict-overflow-10.c	(revision 0)
+++ gcc/testsuite/gcc.dg/Wstrict-overflow-10.c	(revision 0)
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=1" } */
+
+/* Source: Ian Lance Taylor.  */
+
+int
+foo (int i)
+{
+  return __builtin_abs (i) >= 0;
+}
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=2" } */
+
+/* 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;
+}
Index: gcc/testsuite/gcc.dg/Wstrict-overflow-4.c
===================================================================
--- gcc/testsuite/gcc.dg/Wstrict-overflow-4.c	(revision 0)
+++ gcc/testsuite/gcc.dg/Wstrict-overflow-4.c	(revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=3" } */
+
+/* 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;
+}
Index: gcc/testsuite/gcc.dg/Wstrict-overflow-6.c
===================================================================
--- gcc/testsuite/gcc.dg/Wstrict-overflow-6.c	(revision 0)
+++ gcc/testsuite/gcc.dg/Wstrict-overflow-6.c	(revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=2" } */
+
+/* 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;
+}
Index: gcc/testsuite/gcc.dg/Wstrict-overflow-8.c
===================================================================
--- gcc/testsuite/gcc.dg/Wstrict-overflow-8.c	(revision 0)
+++ gcc/testsuite/gcc.dg/Wstrict-overflow-8.c	(revision 0)
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wall -Wno-strict-overflow" } */
+
+/* Source: Ian Lance Taylor.  */
+
+int
+foo (int i)
+{
+  return i + 10 > i;
+}
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=3" } */
+
+/* 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 does not occur" "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=4" } */
+
+/* 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 does not occur" "correct warning" } */
+}
Index: gcc/tree-ssa-ccp.c
===================================================================
--- gcc/tree-ssa-ccp.c	(revision 121691)
+++ gcc/tree-ssa-ccp.c	(working copy)
@@ -1,5 +1,5 @@
 /* Conditional constant propagation pass for the GNU compiler.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
    Free Software Foundation, Inc.
    Adapted from original RTL SSA-CCP by Daniel Berlin <dberlin@dberlin.org>
    Adapted to GIMPLE trees by Diego Novillo <dnovillo@redhat.com>
@@ -207,6 +207,7 @@ Software Foundation, 51 Franklin Street,
 #include "tree-ssa-propagate.h"
 #include "langhooks.h"
 #include "target.h"
+#include "toplev.h"
 
 
 /* Possible lattice values.  */
@@ -1132,9 +1133,12 @@ evaluate_stmt (tree stmt)
   prop_value_t val;
   tree simplified = NULL_TREE;
   ccp_lattice_t likelyvalue = likely_value (stmt);
+  bool is_constant;
 
   val.mem_ref = NULL_TREE;
 
+  fold_defer_overflow_warnings ();
+
   /* If the statement is likely to have a CONSTANT result, then try
      to fold the statement to determine the constant value.  */
   if (likelyvalue == CONSTANT)
@@ -1151,7 +1155,11 @@ evaluate_stmt (tree stmt)
   else if (!simplified)
     simplified = fold_const_aggregate_ref (get_rhs (stmt));
 
-  if (simplified && is_gimple_min_invariant (simplified))
+  is_constant = simplified && is_gimple_min_invariant (simplified);
+
+  fold_undefer_overflow_warnings (is_constant, stmt, 0);
+
+  if (is_constant)
     {
       /* The statement produced a constant value.  */
       val.lattice_val = CONSTANT;
@@ -1966,8 +1974,9 @@ maybe_fold_stmt_addition (tree expr)
 
 struct fold_stmt_r_data
 {
-    bool *changed_p;
-    bool *inside_addr_expr_p;
+  tree stmt;
+  bool *changed_p;
+  bool *inside_addr_expr_p;
 };
 
 /* Subroutine of fold_stmt called via walk_tree.  We perform several
@@ -2063,10 +2072,16 @@ fold_stmt_r (tree *expr_p, int *walk_sub
       if (COMPARISON_CLASS_P (TREE_OPERAND (expr, 0)))
         {
 	  tree op0 = TREE_OPERAND (expr, 0);
-          tree tem = fold_binary (TREE_CODE (op0), TREE_TYPE (op0),
-				  TREE_OPERAND (op0, 0),
-				  TREE_OPERAND (op0, 1));
-	  if (tem && set_rhs (expr_p, tem))
+          tree tem;
+	  bool set;
+
+	  fold_defer_overflow_warnings ();
+	  tem = fold_binary (TREE_CODE (op0), TREE_TYPE (op0),
+			     TREE_OPERAND (op0, 0),
+			     TREE_OPERAND (op0, 1));
+	  set = tem && set_rhs (expr_p, tem);
+	  fold_undefer_overflow_warnings (set, fold_stmt_r_data->stmt, 0);
+	  if (set)
 	    {
 	      t = *expr_p;
 	      break;
@@ -2373,11 +2388,12 @@ fold_stmt (tree *stmt_p)
   bool changed = false;
   bool inside_addr_expr = false;
 
+  stmt = *stmt_p;
+
+  fold_stmt_r_data.stmt = stmt;
   fold_stmt_r_data.changed_p = &changed;
   fold_stmt_r_data.inside_addr_expr_p = &inside_addr_expr;
 
-  stmt = *stmt_p;
-
   /* If we replaced constants and the statement makes pointer dereferences,
      then we may need to fold instances of *&VAR into VAR, etc.  */
   if (walk_tree (stmt_p, fold_stmt_r, &fold_stmt_r_data, NULL))
@@ -2472,6 +2488,7 @@ fold_stmt_inplace (tree stmt)
   bool changed = false;
   bool inside_addr_expr = false;
 
+  fold_stmt_r_data.stmt = stmt;
   fold_stmt_r_data.changed_p = &changed;
   fold_stmt_r_data.inside_addr_expr_p = &inside_addr_expr;
 
Index: gcc/opts.c
===================================================================
--- gcc/opts.c	(revision 121691)
+++ gcc/opts.c	(working copy)
@@ -61,6 +61,10 @@ HOST_WIDE_INT larger_than_size;
    strict-aliasing safe.  */
 int warn_strict_aliasing;
 
+/* Nonzero means warn about optimizations which rely on undefined
+   signed overflow.  */
+int warn_strict_overflow;
+
 /* Hack for cooperation between set_Wunused and set_Wextra.  */
 static bool maybe_warn_unused_parameter;
 
@@ -721,6 +725,11 @@ common_handle_option (size_t scode, cons
       warn_strict_aliasing = value;
       break;
 
+    case OPT_Wstrict_overflow:
+    case OPT_Wstrict_overflow_:
+      warn_strict_overflow = value;
+      break;
+
     case OPT_Wunused:
       set_Wunused (value);
       break;
Index: gcc/c-typeck.c
===================================================================
--- gcc/c-typeck.c	(revision 121691)
+++ 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 121691)
+++ gcc/tree-cfgcleanup.c	(working copy)
@@ -1,5 +1,6 @@
 /* CFG cleanup for trees.
-   Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -28,7 +29,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,6 +79,9 @@ cleanup_control_expr_graph (basic_block 
     {
       edge e;
       edge_iterator ei;
+      bool warned;
+
+      fold_defer_overflow_warnings ();
 
       switch (TREE_CODE (expr))
 	{
@@ -88,7 +92,10 @@ cleanup_control_expr_graph (basic_block 
 	case SWITCH_EXPR:
 	  val = fold (SWITCH_COND (expr));
 	  if (TREE_CODE (val) != INTEGER_CST)
-	    return false;
+	    {
+	      fold_undefer_and_ignore_overflow_warnings ();
+	      return false;
+	    }
 	  break;
 
 	default:
@@ -97,13 +104,24 @@ cleanup_control_expr_graph (basic_block 
 
       taken_edge = find_taken_edge (bb, val);
       if (!taken_edge)
-	return false;
+	{
+	  fold_undefer_and_ignore_overflow_warnings ();
+	  return false;
+	}
 
       /* Remove all the edges except the one that is always executed.  */
+      warned = false;
       for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
 	{
 	  if (e != taken_edge)
 	    {
+	      if (!warned)
+		{
+		  fold_undefer_overflow_warnings
+		    (true, expr, WARN_STRICT_OVERFLOW_CONDITIONAL);
+		  warned = true;
+		}
+
 	      taken_edge->probability += e->probability;
 	      taken_edge->count += e->count;
 	      remove_edge (e);
@@ -112,6 +130,8 @@ cleanup_control_expr_graph (basic_block 
 	  else
 	    ei_next (&ei);
 	}
+      if (!warned)
+	fold_undefer_and_ignore_overflow_warnings ();
       if (taken_edge->probability > REG_BR_PROB_BASE)
 	taken_edge->probability = REG_BR_PROB_BASE;
     }
Index: gcc/c-opts.c
===================================================================
--- gcc/c-opts.c	(revision 121691)
+++ gcc/c-opts.c	(working copy)
@@ -1,5 +1,6 @@
 /* C/ObjC/C++ command line option handling.
-   Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Neil Booth.
 
 This file is part of GCC.
@@ -394,6 +395,7 @@ c_common_handle_option (size_t scode, co
 	warn_sign_compare = value;
       warn_switch = value;
       warn_strict_aliasing = value;
+      warn_strict_overflow = value;
       warn_string_literal_comparison = value;
       warn_always_true = value;
       warn_array_bounds = value;
Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c	(revision 121691)
+++ gcc/simplify-rtx.c	(working copy)
@@ -3986,7 +3986,15 @@ simplify_const_relational_operation (enu
 	      tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
 						       : trueop0;
 	      if (GET_CODE (tem) == ABS)
-		return const0_rtx;
+		{
+		  if (INTEGRAL_MODE_P (mode)
+		      && (issue_strict_overflow_warning
+			  (WARN_STRICT_OVERFLOW_CONDITIONAL)))
+		    warning (OPT_Wstrict_overflow,
+			     ("assuming signed overflow does not occur when "
+			      "assuming abs (x) < 0 is false"));
+		  return const0_rtx;
+		}
 	    }
 	  break;
 
@@ -4000,7 +4008,15 @@ simplify_const_relational_operation (enu
 	      tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
 						       : trueop0;
 	      if (GET_CODE (tem) == ABS)
-		return const_true_rtx;
+		{
+		  if (INTEGRAL_MODE_P (mode)
+		      && (issue_strict_overflow_warning
+			  (WARN_STRICT_OVERFLOW_CONDITIONAL)))
+		    warning (OPT_Wstrict_overflow,
+			     ("assuming signed overflow does not occur when "
+			      "assuming abs (x) >= 0 is true"));
+		  return const_true_rtx;
+		}
 	    }
 	  break;
 
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 121691)
+++ gcc/common.opt	(working copy)
@@ -141,6 +141,14 @@ Wstrict-aliasing=
 Common Joined UInteger
 Warn about code which might break strict aliasing rules
 
+Wstrict-overflow
+Common
+Warn about optimizations that assume that signed overflow is undefined
+
+Wstrict-overflow=
+Common Joined UInteger
+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/c-common.c
===================================================================
--- gcc/c-common.c	(revision 121691)
+++ gcc/c-common.c	(working copy)
@@ -2543,7 +2543,7 @@ shorten_compare (tree *op0_ptr, tree *op
 tree
 pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
 {
-  tree size_exp;
+  tree size_exp, ret;
 
   /* The result is a pointer of the same type that is being added.  */
 
@@ -2570,6 +2570,12 @@ pointer_int_sum (enum tree_code resultco
   else
     size_exp = size_in_bytes (TREE_TYPE (result_type));
 
+  /* We are manipulating pointer values, so we don't need to warn
+     about relying on undefined signed overflow.  We disable the
+     warning here because we use integer types so fold won't know that
+     they are really pointers.  */
+  fold_defer_overflow_warnings ();
+
   /* If what we are about to multiply by the size of the elements
      contains a constant term, apply distributive law
      and multiply that constant term separately.
@@ -2618,7 +2624,11 @@ pointer_int_sum (enum tree_code resultco
 				    convert (TREE_TYPE (intop), size_exp), 1));
 
   /* Create the sum or difference.  */
-  return fold_build2 (resultcode, result_type, ptrop, intop);
+  ret = fold_build2 (resultcode, result_type, ptrop, intop);
+
+  fold_undefer_and_ignore_overflow_warnings ();
+
+  return ret;
 }
 
 /* Return whether EXPR is a declaration whose address can never be
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 121691)
+++ gcc/Makefile.in	(working copy)
@@ -2059,7 +2059,7 @@ tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $
    tree-ssa-propagate.h
 tree-cfgcleanup.o : tree-cfgcleanup.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
    $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \
-   $(DIAGNOSTIC_H) errors.h $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
+   $(DIAGNOSTIC_H) toplev.h $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
    $(TREE_DUMP_H) except.h langhooks.h $(CFGLOOP_H) tree-pass.h \
    $(CFGLAYOUT_H) $(BASIC_BLOCK_H) hard-reg-set.h $(HASHTAB_H) toplev.h \
    tree-ssa-propagate.h
@@ -2256,7 +2256,7 @@ tree-pretty-print.o : tree-pretty-print.
    value-prof.h
 fold-const.o : fold-const.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) $(FLAGS_H) $(REAL_H) toplev.h $(HASHTAB_H) $(EXPR_H) $(RTL_H) \
-   $(GGC_H) $(TM_P_H) langhooks.h $(MD5_H)
+   $(GGC_H) $(TM_P_H) langhooks.h $(MD5_H) intl.h
 diagnostic.o : diagnostic.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(TREE_H) version.h $(TM_P_H) $(FLAGS_H) input.h toplev.h intl.h \
    $(DIAGNOSTIC_H) langhooks.h $(LANGHOOKS_DEF_H) diagnostic.def opts.h
@@ -2507,7 +2507,7 @@ tree-ssa-ccp.o : tree-ssa-ccp.c $(TREE_F
    $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \
    $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
    $(TREE_DUMP_H) $(BASIC_BLOCK_H) tree-pass.h langhooks.h \
-   tree-ssa-propagate.h $(FLAGS_H) $(TARGET_H)
+   tree-ssa-propagate.h $(FLAGS_H) $(TARGET_H) toplev.h
 tree-sra.o : tree-sra.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(RTL_H) \
     $(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_H) $(TREE_INLINE_H) \
     $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_GIMPLE_H) \
Index: gcc/tree-cfg.c
===================================================================
--- gcc/tree-cfg.c	(revision 121691)
+++ gcc/tree-cfg.c	(working copy)
@@ -408,10 +408,18 @@ fold_cond_expr_cond (void)
       if (stmt
 	  && TREE_CODE (stmt) == COND_EXPR)
 	{
-	  tree cond = fold (COND_EXPR_COND (stmt));
-	  if (integer_zerop (cond))
+	  tree cond;
+	  bool zerop, onep;
+
+	  fold_defer_overflow_warnings ();
+	  cond = fold (COND_EXPR_COND (stmt));
+	  zerop = integer_zerop (cond);
+	  onep = integer_onep (cond);
+	  fold_undefer_overflow_warnings (zerop || onep, stmt,
+					  WARN_STRICT_OVERFLOW_CONDITIONAL);
+	  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 121691)
+++ gcc/passes.c	(working copy)
@@ -933,6 +933,17 @@ execute_todo (unsigned int flags)
     }
 }
 
+/* Verify invariants that should hold between passes.  This is a place
+   to put simple sanity checks.  */
+
+static void
+verify_interpass_invariants (void)
+{
+#ifdef ENABLE_CHECKING
+  gcc_assert (!fold_deferring_overflow_warnings_p ());
+#endif
+}
+
 /* Clear the last verified flag.  */
 
 static void
@@ -1044,6 +1055,7 @@ execute_one_pass (struct tree_opt_pass *
 
   /* Run post-pass cleanup and verification.  */
   execute_todo (todo_after | pass->todo_flags_finish);
+  verify_interpass_invariants ();
 
   if (!current_function_decl)
     cgraph_process_new_functions ();
Index: gcc/tree-ssa-threadedge.c
===================================================================
--- gcc/tree-ssa-threadedge.c	(revision 121691)
+++ gcc/tree-ssa-threadedge.c	(working copy)
@@ -1,5 +1,5 @@
 /* SSA Jump Threading
-   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
    Contributed by Jeff Law  <law@redhat.com>
 
 This file is part of GCC.
@@ -425,12 +425,17 @@ simplify_control_stmt_condition (edge e,
 
       /* We absolutely do not care about any type conversions
          we only care about a zero/nonzero value.  */
+      fold_defer_overflow_warnings ();
+
       cached_lhs = fold (COND_EXPR_COND (dummy_cond));
       while (TREE_CODE (cached_lhs) == NOP_EXPR
 	     || TREE_CODE (cached_lhs) == CONVERT_EXPR
 	     || TREE_CODE (cached_lhs) == NON_LVALUE_EXPR)
 	cached_lhs = TREE_OPERAND (cached_lhs, 0);
-	    
+
+      fold_undefer_overflow_warnings (is_gimple_min_invariant (cached_lhs),
+				      stmt, WARN_STRICT_OVERFLOW_CONDITIONAL);
+
       /* If we have not simplified the condition down to an invariant,
 	 then use the pass specific callback to simplify the condition.  */
       if (! is_gimple_min_invariant (cached_lhs))


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