This avoids introducing undefined overflow by not folding unsigned conditional negation to ABS_EXPR. IMHO we want a well-defined ABS_EXPR with unsigned result at some point, but that also needs target support (or auditing at least if we want to keep the existing abs expanders).
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2015-10-29 Richard Biener <rguent...@suse.de> PR middle-end/56956 * fold-const.c (fold_cond_expr_with_comparison): Do not fold unsigned conditonal negation to ABS_EXPR. * c-c++-common/ubsan/pr56956.c: New testcase. Index: gcc/fold-const.c =================================================================== *** gcc/fold-const.c (revision 229481) --- gcc/fold-const.c (working copy) *************** fold_cond_expr_with_comparison (location *** 4993,5000 **** case GE_EXPR: case GT_EXPR: if (TYPE_UNSIGNED (TREE_TYPE (arg1))) ! arg1 = fold_convert_loc (loc, signed_type_for ! (TREE_TYPE (arg1)), arg1); tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1); return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, tem)); case UNLE_EXPR: --- 4973,4979 ---- case GE_EXPR: case GT_EXPR: if (TYPE_UNSIGNED (TREE_TYPE (arg1))) ! break; tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1); return pedantic_non_lvalue_loc (loc, fold_convert_loc (loc, type, tem)); case UNLE_EXPR: *************** fold_cond_expr_with_comparison (location *** 5004,5011 **** case LE_EXPR: case LT_EXPR: if (TYPE_UNSIGNED (TREE_TYPE (arg1))) ! arg1 = fold_convert_loc (loc, signed_type_for ! (TREE_TYPE (arg1)), arg1); tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1); return negate_expr (fold_convert_loc (loc, type, tem)); default: --- 4983,4989 ---- case LE_EXPR: case LT_EXPR: if (TYPE_UNSIGNED (TREE_TYPE (arg1))) ! break; tem = fold_build1_loc (loc, ABS_EXPR, TREE_TYPE (arg1), arg1); return negate_expr (fold_convert_loc (loc, type, tem)); default: Index: gcc/testsuite/c-c++-common/ubsan/pr56956.c =================================================================== *** gcc/testsuite/c-c++-common/ubsan/pr56956.c (revision 0) --- gcc/testsuite/c-c++-common/ubsan/pr56956.c (working copy) *************** *** 0 **** --- 1,15 ---- + /* { dg-do run } */ + /* { dg-options "-fsanitize=undefined -fsanitize-undefined-trap-on-error" } */ + + unsigned int __attribute__((noinline,noclone)) + foo (unsigned int x) + { + return x <= __INT_MAX__ ? x : -x; + } + + int + main () + { + volatile unsigned int tem = foo (-__INT_MAX__ - 1); + return 0; + }