OSDN Git Service

./:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 13 Feb 2007 22:34:45 +0000 (22:34 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 13 Feb 2007 22:34:45 +0000 (22:34 +0000)
* 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.
testsuite/:
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@121895 138bc75d-0d04-0410-961f-82ee72b054a4

31 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-common.c
gcc/c-opts.c
gcc/c-typeck.c
gcc/common.opt
gcc/doc/invoke.texi
gcc/flags.h
gcc/fold-const.c
gcc/opts.c
gcc/passes.c
gcc/simplify-rtx.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/Wstrict-overflow-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wstrict-overflow-10.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wstrict-overflow-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wstrict-overflow-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wstrict-overflow-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wstrict-overflow-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wstrict-overflow-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wstrict-overflow-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wstrict-overflow-8.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/Wstrict-overflow-9.c [new file with mode: 0644]
gcc/tree-cfg.c
gcc/tree-cfgcleanup.c
gcc/tree-ssa-ccp.c
gcc/tree-ssa-loop-manip.c
gcc/tree-ssa-loop-niter.c
gcc/tree-ssa-threadedge.c
gcc/tree-vrp.c
gcc/tree.h

index d504109..4c6f084 100644 (file)
@@ -1,5 +1,87 @@
 2007-02-13  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.
+
+2007-02-13  Ian Lance Taylor  <iant@google.com>
+
        PR middle-end/30751
        * lower-subreg.c (resolve_simple_move): Decompose subregs in
        addresses.
index 7bb1434..6ea4280 100644 (file)
@@ -2059,7 +2059,7 @@ tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_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.c $(CONFIG_H) $(SYSTEM_H) \
    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_FLOW_H) $(CONFIG_H) \
    $(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 cfd3829..0bbb439 100644 (file)
@@ -2543,7 +2543,7 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
 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 resultcode, tree ptrop, tree intop)
   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 resultcode, tree ptrop, tree intop)
                                    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;
 }
 \f
 /* Return whether EXPR is a declaration whose address can never be
index 2b0bc5f..9ac433a 100644 (file)
@@ -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, const char *arg, int value)
        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 c807a7e..28ce2ba 100644 (file)
@@ -3270,6 +3270,8 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
 
          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 op1, tree op2)
              /* 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");
@@ -8303,6 +8307,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
              else
                {
                  tree sop, uop;
+                 bool ovf;
 
                  if (op0_signed)
                    sop = xop0, uop = xop1;
@@ -8314,7 +8319,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
                     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 dd3deb3..c6a9557 100644 (file)
@@ -158,6 +158,14 @@ Wstrict-aliasing=
 Common Joined UInteger Warning
 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) Warning
 Warn about comparisons to constant string literals
index 8274d74..8e81193 100644 (file)
@@ -248,6 +248,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
@@ -2972,6 +2973,56 @@ compiler is using for optimization.  This warning catches more cases than
 @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
+Also 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
+Also 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
+Also 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
+Also 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 2671ec3..1996bd1 100644 (file)
@@ -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 d20d78f..7d66736 100644 (file)
@@ -59,6 +59,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #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_comparison (tree, tree, tree, tree);
 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 code, tree arg1, tree arg2)
   return build_int_cst_wide (type, quol, quoh);
 }
 \f
+/* 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);
+}
+\f
 /* 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,35 @@ 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
+                     || integer_onep (tem)))
+               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 +4002,16 @@ range_binop (enum tree_code code, tree type, tree arg0, int upper0_p,
 \f
 /* 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 +4160,9 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
              || (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 +4944,12 @@ fold_range_test (enum tree_code code, tree type, tree op0, tree op1)
               || 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 +4967,11 @@ fold_range_test (enum tree_code code, tree type, tree op0, tree op1)
                                         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 +5001,14 @@ fold_range_test (enum tree_code code, tree type, tree op0, tree op1)
              && (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 +5607,15 @@ optimize_minmax_comparison (enum tree_code code, tree type, tree op0, tree op1)
    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 +5629,15 @@ extract_muldiv (tree t, tree c, enum tree_code code, tree wide_type)
     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 +5647,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
   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 +5704,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
          && !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 +5715,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
       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 +5725,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
         }
       /* 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 +5737,16 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
        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 +5773,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
        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 +5781,21 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
         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 +5876,13 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
         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 +5912,23 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
                  && 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 +7856,9 @@ fold_unary (enum tree_code code, tree type, tree op0)
                                                    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 +8075,14 @@ fold_minmax (enum tree_code code, tree type, tree op0, tree op1)
    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 +8149,7 @@ maybe_canonicalize_comparison_1 (enum tree_code code, tree type,
        code = GT_EXPR;
       else
        return NULL_TREE;
+      *strict_overflow_p = true;
     }
 
   /* Now build the constant reduced in magnitude.  */
@@ -7981,6 +8176,9 @@ maybe_canonicalize_comparison (enum tree_code code, tree type,
                               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 +8187,25 @@ maybe_canonicalize_comparison (enum tree_code code, tree type,
     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
@@ -8080,7 +8289,13 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
       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
@@ -8245,6 +8460,9 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
       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.  */
@@ -8253,20 +8471,26 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
                             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
@@ -8286,6 +8510,11 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
 
       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);
@@ -8721,6 +8950,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
   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))
@@ -9468,11 +9698,20 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            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
@@ -10372,8 +10611,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
     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)
@@ -10381,6 +10622,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              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,
@@ -10408,13 +10654,27 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
       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.
@@ -10426,9 +10686,17 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          && 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;
 
@@ -10460,8 +10728,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
 
       /* 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,
@@ -10473,6 +10743,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            {
              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));
@@ -10500,8 +10775,15 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                            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;
 
@@ -11330,27 +11612,59 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          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)
            {
@@ -11358,23 +11672,51 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
              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);
+               }
            }
        }
 
@@ -11575,18 +11917,34 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                                    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 !=.  */
@@ -12662,10 +13020,13 @@ multiple_of_p (tree type, tree top, tree bottom)
     }
 }
 
-/* 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;
@@ -12686,7 +13047,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:
@@ -12697,8 +13061,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.  */
@@ -12724,8 +13090,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
@@ -12745,8 +13113,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:
@@ -12756,8 +13126,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:
@@ -12766,19 +13138,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:
       {
@@ -12788,18 +13165,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);
@@ -12815,7 +13195,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.  */
@@ -12834,7 +13214,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;
       }
@@ -12870,7 +13251,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):
@@ -12900,21 +13282,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
@@ -12925,7 +13316,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
@@ -12946,7 +13338,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;
@@ -12965,14 +13358,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))
@@ -12986,7 +13402,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);
@@ -12996,20 +13413,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;
 
@@ -13019,7 +13450,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;
 
@@ -13042,42 +13474,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);
@@ -13088,6 +13554,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 daa9c9e..1361eb7 100644 (file)
@@ -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;
 
@@ -1104,6 +1108,11 @@ common_handle_option (size_t scode, const char *arg, int value,
       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 35e4164..6f1a99d 100644 (file)
@@ -952,6 +952,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
@@ -1063,6 +1074,7 @@ execute_one_pass (struct tree_opt_pass *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 f8e613d..cb1c4f6 100644 (file)
@@ -4086,7 +4086,15 @@ simplify_const_relational_operation (enum rtx_code code,
              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;
+               }
            }
 
          /* Optimize popcount (x) < 0.  */
@@ -4104,7 +4112,15 @@ simplify_const_relational_operation (enum rtx_code code,
              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;
+               }
            }
 
          /* Optimize popcount (x) >= 0.  */
index 0137d21..f5e9922 100644 (file)
@@ -1,3 +1,16 @@
+2007-02-13  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.
+
 2007-02-13  Roger Sayle  <roger@eyesopen.com>
 
        * gcc.target/ia64/builtin-bswap-2.c: New test case.
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-1.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-1.c
new file mode 100644 (file)
index 0000000..068bfe4
--- /dev/null
@@ -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" } */
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-10.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-10.c
new file mode 100644 (file)
index 0000000..d2c2597
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-2.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-2.c
new file mode 100644 (file)
index 0000000..2112571
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-3.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-3.c
new file mode 100644 (file)
index 0000000..22f6a56
--- /dev/null
@@ -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" } */
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-4.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-4.c
new file mode 100644 (file)
index 0000000..e880bef
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-5.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-5.c
new file mode 100644 (file)
index 0000000..9af0adb
--- /dev/null
@@ -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" } */
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-6.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-6.c
new file mode 100644 (file)
index 0000000..c3a160c
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-7.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-7.c
new file mode 100644 (file)
index 0000000..5bf7b60
--- /dev/null
@@ -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" } */
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-8.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-8.c
new file mode 100644 (file)
index 0000000..566729f
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-9.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-9.c
new file mode 100644 (file)
index 0000000..425a121
--- /dev/null
@@ -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 e3e2134..7d28aa9 100644 (file)
@@ -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 f78be8e..8cf66cb 100644 (file)
@@ -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 bb, block_stmt_iterator bsi)
     {
       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 bb, block_stmt_iterator bsi)
        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 bb, block_stmt_iterator bsi)
 
       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 bb, block_stmt_iterator bsi)
          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 b6c3599..459894b 100644 (file)
@@ -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, Fifth Floor, Boston, MA
 #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_subtrees, void *data)
       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 6b220e9..715c412 100644 (file)
@@ -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 var, struct loop *loop,
        }
       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 c2a9f9c..95a9e46 100644 (file)
@@ -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 *loop, edge exit,
   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 *loop, edge exit,
                                               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, edge exit)
        }
     }
 
+  /* 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, edge exit)
       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, edge exit)
        {
          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 step,
   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 step,
 
   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 e48cd65..72018c0 100644 (file)
@@ -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 2babe1a..fffeefc 100644 (file)
@@ -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_range_t *vr, tree expr)
      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 50b0149..ed0379c 100644 (file)
@@ -3735,6 +3735,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);
 
@@ -4333,6 +4334,10 @@ extern tree fold_single_bit_test (enum tree_code, tree, tree, tree);
 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);
@@ -4405,6 +4410,7 @@ extern bool ptr_difference_const (tree, tree, HOST_WIDE_INT *);
 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);