This fixes an endless recursion through fold-const.c associate code. While the testcase is fixed if we "properly" split the TREE_CONSTANT ~(unsigned int) (302806 >> 0) into *conp and *minus_lit this runs into endless recursion during Ada bootstrap as the condition
/* Only do something if we found more than two objects. Otherwise, nothing has changed and we risk infinite recursion. */ if (ok && (2 < ((var0 != 0) + (var1 != 0) + (con0 != 0) + (con1 != 0) + (lit0 != 0) + (lit1 != 0) + (minus_lit0 != 0) + (minus_lit1 != 0)))) is really too simple (when you have var0 and from the above con1 and minus_lit1 you combine back to the original tree but from three components). I suspect this is a latent issue on the path where we split PLUS/MINUS_EXPRs in split_tree as well (didn't try to come up with a testcase, sth like x + (&foo + 1) would probably do). So rather than trying to convince myself about a "better" condition for the above the following simply restricts the "unfolding" trick we apply to ~X to the non-TREE_CONSTANT case. (a condition might be that we need from any of two vars, two cons or two lit/minus-lit from the different sources) Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2016-09-15 Richard Biener <rguent...@suse.de> PR middle-end/77544 * fold-const.c (split_tree): Do not split constant ~X. * c-c++-common/torture/pr77544.c: New testcase. Index: gcc/fold-const.c =================================================================== *** gcc/fold-const.c (revision 240153) --- gcc/fold-const.c (working copy) *************** split_tree (location_t loc, tree in, tre *** 837,851 **** var = negate_expr (var); } } else if (TREE_CODE (in) == BIT_NOT_EXPR && code == PLUS_EXPR) { ! /* -X - 1 is folded to ~X, undo that here. */ *minus_litp = build_one_cst (TREE_TYPE (in)); var = negate_expr (TREE_OPERAND (in, 0)); } - else if (TREE_CONSTANT (in)) - *conp = in; else var = in; --- 837,852 ---- var = negate_expr (var); } } + else if (TREE_CONSTANT (in)) + *conp = in; else if (TREE_CODE (in) == BIT_NOT_EXPR && code == PLUS_EXPR) { ! /* -X - 1 is folded to ~X, undo that here. Do _not_ do this ! when IN is constant. */ *minus_litp = build_one_cst (TREE_TYPE (in)); var = negate_expr (TREE_OPERAND (in, 0)); } else var = in; Index: gcc/testsuite/c-c++-common/torture/pr77544.c =================================================================== *** gcc/testsuite/c-c++-common/torture/pr77544.c (revision 0) --- gcc/testsuite/c-c++-common/torture/pr77544.c (working copy) *************** *** 0 **** --- 1,7 ---- + /* { dg-do compile } */ + + struct { + long a : 17; + } b; + int c, d; + void e() { b.a = d + c + ~(long)(302806U >> 0); }