Hi!

As reported in the PR and can be seen on this simplified testcase
everywhere, the FEs sometimes call operand_equal_p e.g. on a SAVE_EXPR
that contains a BIND_EXPR in it, and if arg0 == arg1, operand_equal_p
can return non-zero on it.
The ICE is because inchash::add_expr is unprepared to hash some trees,
it handles just tcc_declaration, selected specific trees and expressions of
all kinds, the last one usually by just recursing on all their operands.
For BIND_EXPR, the last operand is usually a BLOCK which we ICE on though,
and the middle argument usually a STATEMENT_LIST that we ICE on as well.

The first hunk is just an optimization (but fixes the ICE anyway),
I think we really don't need to verify that a hash function for the same
argument always returns the same value.  But I can imagine e.g.
a SAVE_EXPR of BIND_EXPR + var and var + the same SAVE_EXPR being compared
using operand_equal_p and there we wouldn't be equal at the top level and
still ICE.
The second hunk alone fixes the ICE too, by making sure we handle those
(just ignoring BLOCK and OMP_CLAUSE (the latter for now, if we find we want
to hash pre-OMP expansion trees too often we could adjust).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2016-04-28  Jakub Jelinek  <ja...@redhat.com>

        PR middle-end/70843
        * fold-const.c (operand_equal_p): Don't verify hash value equality
        if arg0 == arg1.
        * tree.c (inchash::add_expr): Handle STATEMENT_LIST.  Ignore BLOCK
        and OMP_CLAUSE.

        * gcc.dg/pr70843.c: New test.

--- gcc/fold-const.c.jj 2016-04-27 15:29:05.000000000 +0200
+++ gcc/fold-const.c    2016-04-28 13:28:56.272276557 +0200
@@ -2756,12 +2756,15 @@ operand_equal_p (const_tree arg0, const_
     {
       if (operand_equal_p (arg0, arg1, flags | OEP_NO_HASH_CHECK))
        {
-         inchash::hash hstate0 (0), hstate1 (0);
-         inchash::add_expr (arg0, hstate0, flags);
-         inchash::add_expr (arg1, hstate1, flags);
-         hashval_t h0 = hstate0.end ();
-         hashval_t h1 = hstate1.end ();
-         gcc_assert (h0 == h1);
+         if (arg0 != arg1)
+           {
+             inchash::hash hstate0 (0), hstate1 (0);
+             inchash::add_expr (arg0, hstate0, flags);
+             inchash::add_expr (arg1, hstate1, flags);
+             hashval_t h0 = hstate0.end ();
+             hashval_t h1 = hstate1.end ();
+             gcc_assert (h0 == h1);
+           }
          return 1;
        }
       else
--- gcc/tree.c.jj       2016-04-27 09:45:27.000000000 +0200
+++ gcc/tree.c  2016-04-28 13:24:01.770245254 +0200
@@ -7836,6 +7836,10 @@ add_expr (const_tree t, inchash::hash &h
     case PLACEHOLDER_EXPR:
       /* The node itself doesn't matter.  */
       return;
+    case BLOCK:
+    case OMP_CLAUSE:
+      /* Ignore.  */
+      return;
     case TREE_LIST:
       /* A list of expressions, for a CALL_EXPR or as the elements of a
         VECTOR_CST.  */
@@ -7854,6 +7858,14 @@ add_expr (const_tree t, inchash::hash &h
          }
        return;
       }
+    case STATEMENT_LIST:
+      {
+       tree_stmt_iterator i;
+       for (i = tsi_start (CONST_CAST_TREE (t));
+            !tsi_end_p (i); tsi_next (&i))
+         inchash::add_expr (tsi_stmt (i), hstate, flags);
+       return;
+      }
     case FUNCTION_DECL:
       /* When referring to a built-in FUNCTION_DECL, use the __builtin__ form.
         Otherwise nodes that compare equal according to operand_equal_p might
--- gcc/testsuite/gcc.dg/pr70843.c.jj   2016-04-28 13:37:54.596022706 +0200
+++ gcc/testsuite/gcc.dg/pr70843.c      2016-04-28 13:37:38.000000000 +0200
@@ -0,0 +1,9 @@
+/* PR middle-end/70843 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+int
+foo (int x, int y)
+{
+  return ({ int a = 5; a += x; a *= y; a; }) ? : 2;
+}

        Jakub

Reply via email to