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); }

Reply via email to