Bootstrapped and tested on x86_64-unknown-linux-gnu, applied. Richard.
2015-09-23 Richard Biener <rguent...@suse.de> PR middle-end/67662 * fold-const.c (fold_binary_loc): Do not reassociate two vars with undefined overflow unless they will cancel out. * gcc.dg/ubsan/pr67662.c: New testcase. Index: gcc/fold-const.c =================================================================== --- gcc/fold-const.c (revision 228037) +++ gcc/fold-const.c (working copy) @@ -9493,25 +9511,32 @@ fold_binary_loc (location_t loc, { tree tmp0 = var0; tree tmp1 = var1; + bool one_neg = false; if (TREE_CODE (tmp0) == NEGATE_EXPR) - tmp0 = TREE_OPERAND (tmp0, 0); + { + tmp0 = TREE_OPERAND (tmp0, 0); + one_neg = !one_neg; + } if (CONVERT_EXPR_P (tmp0) && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (tmp0, 0))) && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (tmp0, 0))) <= TYPE_PRECISION (atype))) tmp0 = TREE_OPERAND (tmp0, 0); if (TREE_CODE (tmp1) == NEGATE_EXPR) - tmp1 = TREE_OPERAND (tmp1, 0); + { + tmp1 = TREE_OPERAND (tmp1, 0); + one_neg = !one_neg; + } if (CONVERT_EXPR_P (tmp1) && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (tmp1, 0))) && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (tmp1, 0))) <= TYPE_PRECISION (atype))) tmp1 = TREE_OPERAND (tmp1, 0); /* The only case we can still associate with two variables - is if they are the same, modulo negation and bit-pattern - preserving conversions. */ - if (!operand_equal_p (tmp0, tmp1, 0)) + is if they cancel out. */ + if (!one_neg + || !operand_equal_p (tmp0, tmp1, 0)) ok = false; } } Index: gcc/testsuite/gcc.dg/ubsan/pr67662.c =================================================================== --- gcc/testsuite/gcc.dg/ubsan/pr67662.c (revision 0) +++ gcc/testsuite/gcc.dg/ubsan/pr67662.c (working copy) @@ -0,0 +1,14 @@ +/* { dg-do run } */ +/* { dg-options "-fsanitize=undefined" } */ + +extern void abort (void); + +int +main (void) +{ + int halfmaxval = __INT_MAX__ / 2 + 1; + int maxval = halfmaxval - 1 + halfmaxval; + if (maxval != __INT_MAX__) + abort (); + return 0; +}