Input (valid AFAICT): int f(int x) { return (__builtin_expect(({ x != 0; }) ? 0 : 1, 3) == 0) * -1 << 0; } Output: $ cc1plus -O1 -fsanitize=undefined -g int f(int) Analyzing compilation unit output/ice-fold_covert_loc.cc:2:27: internal compiler error: in fold_convert_loc, at fold-const.c:2402 return (__builtin_expect(({ x != 0; }) ? 0 : 1, 3) == 0) * -1 << 0; ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~ 0x1fb2e1b fold_convert_loc(unsigned int, tree_node*, tree_node*) /home/vegard/git/gcc/gcc/fold-const.c:2401 0x227d824 gimplify_cond_expr /home/vegard/git/gcc/gcc/gimplify.c:4034 0x222a3a6 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /home/vegard/git/gcc/gcc/gimplify.c:11391 0x2236ae1 gimplify_stmt(tree_node**, gimple**) /home/vegard/git/gcc/gcc/gimplify.c:6658 0x227cfbe gimplify_cond_expr /home/vegard/git/gcc/gcc/gimplify.c:4022 0x222a3a6 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /home/vegard/git/gcc/gcc/gimplify.c:11391 0x225b10c gimplify_expr /home/vegard/git/gcc/gcc/gimplify.c:12430 0x22606a8 gimplify_arg(tree_node**, gimple**, unsigned int, bool) /home/vegard/git/gcc/gcc/gimplify.c:3176 0x2262d8b gimplify_call_expr /home/vegard/git/gcc/gcc/gimplify.c:3382 0x222936f gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /home/vegard/git/gcc/gcc/gimplify.c:11406 0x2227a92 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /home/vegard/git/gcc/gcc/gimplify.c:12159 0x22234a7 internal_get_tmp_var /home/vegard/git/gcc/gcc/gimplify.c:575 0x222e2e0 get_initialized_tmp_var(tree_node*, gimple**, gimple**, bool) /home/vegard/git/gcc/gcc/gimplify.c:628 0x222e2e0 gimplify_save_expr /home/vegard/git/gcc/gcc/gimplify.c:5931 0x222e2e0 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /home/vegard/git/gcc/gcc/gimplify.c:11734 0x2227a92 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /home/vegard/git/gcc/gcc/gimplify.c:12159 0x2227ac0 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /home/vegard/git/gcc/gcc/gimplify.c:12161 0x227d943 gimplify_cond_expr /home/vegard/git/gcc/gcc/gimplify.c:4063 0x222a3a6 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) /home/vegard/git/gcc/gcc/gimplify.c:11391 0x227c58d gimplify_stmt(tree_node**, gimple**) /home/vegard/git/gcc/gcc/gimplify.c:6658 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions. Built from r259106. Test case was minimised by C-Reduce. It seems -fsanitize=shift is enough to trigger it. The shift is by 0, though, so it should be valid (even though the shifted value is potentially negative). 7.3.0 seems to accept it just fine.
Started with r255947.
I'll handle this.
The problem is that twoval_comparison_p breaks appart SAVE_EXPR if their argument has no side effects. First, cp_build_binary_op calls save_expr on: (__builtin_expect ((long int) (# DEBUG BEGIN STMT; x != 0; ? 0 : 1), (long int) NON_LVALUE_EXPR <3>) == 0) * -1; and that resulting SAVE_EXPR is used in 2+ places, where one of them is a comparison against INTEGER_CST, which is optimized using twoval_comparison_p as another SAVE_EXPR with __builtin_expect ((long int) (# DEBUG BEGIN STMT; x != 0; ? 0 : 1), (long int) NON_LVALUE_EXPR <3>) == 0; body. As mostly_copy_tree_r does not unshare STATEMENT_LISTs, we hand over to the gimplifier the above two SAVE_EXPRs and both contain the same STATEMENT_LIST, so we try to gimplify it twice, which as we know from other PRs doesn't really work at all. Now, not looking through SAVE_EXPRs in twoval_comparison_p if it contains a STATEMENT_LIST might result in -fcompare-debug failures, because with -g0 there could be no STATEMENT_LIST, while with -g we have one. Not sure what our options are, besides just killing the SAVE_EXPR handling in twoval_comparison_p.
(In reply to Jakub Jelinek from comment #3) > The problem is that twoval_comparison_p breaks appart SAVE_EXPR if their > argument has no side effects. > First, cp_build_binary_op calls save_expr on: > (__builtin_expect ((long int) (# DEBUG BEGIN STMT; > x != 0; ? 0 : 1), (long int) NON_LVALUE_EXPR <3>) == 0) * -1; > and that resulting SAVE_EXPR is used in 2+ places, where one of them is a > comparison against INTEGER_CST, which is optimized using twoval_comparison_p > as > another SAVE_EXPR with > __builtin_expect ((long int) (# DEBUG BEGIN STMT; > x != 0; ? 0 : 1), (long int) NON_LVALUE_EXPR <3>) == 0; > body. As mostly_copy_tree_r does not unshare STATEMENT_LISTs, we hand over > to the gimplifier the above two SAVE_EXPRs and both contain the same > STATEMENT_LIST, so we try to gimplify it twice, which as we know from other > PRs doesn't really work at all. > Now, not looking through SAVE_EXPRs in twoval_comparison_p if it contains a > STATEMENT_LIST might result in -fcompare-debug failures, because with -g0 > there could be no STATEMENT_LIST, while with -g we have one. > Not sure what our options are, besides just killing the SAVE_EXPR handling > in twoval_comparison_p. unshare the expression in twoval_comparison_p?
unshare_expr doesn't unshare the STATEMENT_LISTs embedded inside of it (and wonder what would Alex' code do if we have two separate DEBUG_BEGIN_STMTs for the same statement).
Author: jakub Date: Fri Apr 6 11:24:36 2018 New Revision: 259167 URL: https://gcc.gnu.org/viewcvs?rev=259167&root=gcc&view=rev Log: PR sanitizer/85213 * fold-const.c (twoval_comparison_p): Remove SAVE_P argument and don't look through SAVE_EXPRs with non-side-effects argument. Adjust recursive calls. (fold_comparison): Adjust twoval_comparison_p caller, don't handle save_p here. * c-c++-common/ubsan/pr85213.c: New test. Added: trunk/gcc/testsuite/c-c++-common/ubsan/pr85213.c Modified: trunk/gcc/ChangeLog trunk/gcc/fold-const.c trunk/gcc/testsuite/ChangeLog
Fixed.