Hi! Seems since delayed C++ folding fold_* can sometimes be called with operand(s) that are NOP_EXPR of INTEGER_CST. Unfortunately the folder is heavily unprepared to deal with that, I think it is not dozens but hundreds of places where it assumes that if argN (result of STRIP_NOPS) is INTEGER_CST then argN == opN and there is no need to fold_convert it to type. So it seems easier to make sure we don't do that again. The problem is in cp_fold, where it folded both arguments, but if any of them for COMPOUND_EXPR or MODIFY_EXPR has side effects, it throws the folded arguments on the floor and keeps using the old thing. While it is (probably) inappropriate to fold the whole COMPOUND_EXPR or MODIFY_EXPR in that case, we should at least build a new COMPOUND_EXPR or MODIFY_EXPR and stick the folded argument(s) into it.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2016-01-11 Jakub Jelinek <ja...@redhat.com> PR c++/69211 * cp-gimplify.c (cp_fold): If COMPOUND_EXPR or MODIFY_EXPR folded operands have side-effects, but folding changed any of them, build a new tree with the folded operands instead of returning the unfolded tree. * g++.dg/opt/pr69211.C: New test. --- gcc/cp/cp-gimplify.c.jj 2016-01-11 13:22:36.000000000 +0100 +++ gcc/cp/cp-gimplify.c 2016-01-11 15:26:46.898802115 +0100 @@ -2089,7 +2089,11 @@ cp_fold (tree x) if ((code == COMPOUND_EXPR || code == MODIFY_EXPR) && ((op1 && TREE_SIDE_EFFECTS (op1)) || (op0 && TREE_SIDE_EFFECTS (op0)))) - break; + { + if (op0 != TREE_OPERAND (x, 0) || op1 != TREE_OPERAND (x, 1)) + x = build2_loc (loc, code, TREE_TYPE (x), op0, op1); + break; + } if (TREE_CODE (x) == COMPOUND_EXPR && !op0) op0 = build_empty_stmt (loc); --- gcc/testsuite/g++.dg/opt/pr69211.C.jj 2016-01-11 15:27:58.283816511 +0100 +++ gcc/testsuite/g++.dg/opt/pr69211.C 2016-01-11 15:27:41.000000000 +0100 @@ -0,0 +1,10 @@ +// PR c++/69211 +// { dg-do compile } + +int a, b; + +int +foo () +{ + return (a & 5UL | (b = 4, 4L)) > 4; +} Jakub