The associate case in folding ignores overflow when one of the literals involved has TREE_OVERFLOW set. That is obviously wrong as TREE_OVERFLOW doesn't necessarily mean sth undefined happened (and thus GIGO) as we are setting TREE_OVERFLOW also on implementation-defined unsigned->int conversions.
Simply drop that wart and the overflow flag from literals in split_tree to avoid doing less than before. Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk sofar. Richard. 2017-06-14 Richard Biener <rguent...@suse.de> PR middle-end/81088 * fold-const.c (split_tree): Drop TREE_OVERFLOW flag from literal constants. (fold_binary_loc): When associating do not treat pre-existing TREE_OVERFLOW on literal constants as a reason to allow TREE_OVERFLOW on associated literal constants. * c-c++-common/ubsan/pr81088.c: New testcase. Index: gcc/fold-const.c =================================================================== *** gcc/fold-const.c (revision 249185) --- gcc/fold-const.c (working copy) *************** split_tree (location_t loc, tree in, tre *** 880,885 **** --- 880,892 ---- } } + if (*litp + && TREE_OVERFLOW_P (*litp)) + *litp = drop_tree_overflow (*litp); + if (*minus_litp + && TREE_OVERFLOW_P (*minus_litp)) + *minus_litp = drop_tree_overflow (*minus_litp); + return var; } *************** fold_binary_loc (location_t loc, *** 9703,9713 **** + (lit0 != 0) + (lit1 != 0) + (minus_lit0 != 0) + (minus_lit1 != 0)))) { - bool any_overflows = false; - if (lit0) any_overflows |= TREE_OVERFLOW (lit0); - if (lit1) any_overflows |= TREE_OVERFLOW (lit1); - if (minus_lit0) any_overflows |= TREE_OVERFLOW (minus_lit0); - if (minus_lit1) any_overflows |= TREE_OVERFLOW (minus_lit1); var0 = associate_trees (loc, var0, var1, code, atype); con0 = associate_trees (loc, con0, con1, code, atype); lit0 = associate_trees (loc, lit0, lit1, code, atype); --- 9710,9715 ---- *************** fold_binary_loc (location_t loc, *** 9738,9746 **** } /* Don't introduce overflows through reassociation. */ ! if (!any_overflows ! && ((lit0 && TREE_OVERFLOW_P (lit0)) ! || (minus_lit0 && TREE_OVERFLOW_P (minus_lit0)))) return NULL_TREE; if (minus_lit0) --- 9740,9747 ---- } /* Don't introduce overflows through reassociation. */ ! if ((lit0 && TREE_OVERFLOW_P (lit0)) ! || (minus_lit0 && TREE_OVERFLOW_P (minus_lit0))) return NULL_TREE; if (minus_lit0) Index: gcc/testsuite/c-c++-common/ubsan/pr81088.c =================================================================== *** gcc/testsuite/c-c++-common/ubsan/pr81088.c (nonexistent) --- gcc/testsuite/c-c++-common/ubsan/pr81088.c (working copy) *************** *** 0 **** --- 1,11 ---- + /* { dg-do run } */ + /* { dg-options "-fsanitize=undefined -fsanitize-undefined-trap-on-error" } */ + + short s = 2; + short y = 1; + int i; + int main() + { + i = -(s + (int)(~(unsigned)(0 / y))) + 0x7fffffff; + return 0; + }