re PR c++/80913 (Infinite loop in cc1plus with stat hack patch)
authorNathan Sidwell <nathan@acm.org>
Tue, 30 May 2017 14:43:45 +0000 (14:43 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Tue, 30 May 2017 14:43:45 +0000 (14:43 +0000)
PR c++/80913
* name-lookup.c (add_decl_to_level): Assert not making a circular
chain.
(update_binding): Don't prematurely slide artificial decl.

* g++.dg/lookup/pr80913.C: New.

From-SVN: r248687

gcc/cp/ChangeLog
gcc/cp/name-lookup.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/lookup/pr80913.C [new file with mode: 0644]

index f4da40732bd02d0de25b48c301ee8961c7af3ce9..1aa5df8f65db4be017417446bd4908d6648f888b 100644 (file)
@@ -1,3 +1,10 @@
+2017-05-30  Nathan Sidwell  <nathan@acm.org>
+
+       PR c++/80913
+       * name-lookup.c (add_decl_to_level): Assert not making a circular
+       chain.
+       (update_binding): Don't prematurely slide artificial decl.
+
 2017-05-29  Alexandre Oliva <aoliva@redhat.com>
 
        * cp-tree.h (lang_identifier): Drop oracle_looked_up, unused.
index 861580fc21d000482ef50ca0affa0b790f076733..3a11d507698dd0b4939bc8ccfbf13188e031f848 100644 (file)
@@ -132,6 +132,11 @@ add_decl_to_level (cp_binding_level *b, tree decl)
     }
   else
     {
+      /* Make sure we don't create a circular list.  xref_tag can end
+        up pushing the same artificial decl more than once.  We
+        should have already detected that in update_binding.  */
+      gcc_assert (b->names != decl);
+
       /* We build up the list in reverse order, and reverse it later if
         necessary.  */
       TREE_CHAIN (decl) = b->names;
@@ -1720,17 +1725,43 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
                tree old, tree decl, bool is_friend)
 {
   tree to_val = decl;
-  tree to_type = NULL_TREE;
+  tree old_type = slot ? MAYBE_STAT_TYPE (*slot) : binding->type;
+  tree to_type = old_type;
 
   gcc_assert (level->kind == sk_namespace ? !binding
              : level->kind != sk_class && !slot);
   if (old == error_mark_node)
     old = NULL_TREE;
 
+  if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl))
+    {
+      tree other = to_type;
+
+      if (old && TREE_CODE (old) == TYPE_DECL && DECL_ARTIFICIAL (old))
+       other = old;
+
+      /* Pushing an artificial typedef.  See if this matches either
+        the type slot or the old value slot.  */
+      if (!other)
+       ;
+      else if (same_type_p (TREE_TYPE (other), TREE_TYPE (decl)))
+       /* Two artificial decls to same type.  Do nothing.  */
+       return other;
+      else
+       goto conflict;
+
+      if (old)
+       {
+         /* Slide decl into the type slot, keep old unaltered  */
+         to_type = decl;
+         to_val = old;
+         goto done;
+       }
+    }
+
   if (old && TREE_CODE (old) == TYPE_DECL && DECL_ARTIFICIAL (old))
     {
-      /* Slide the tdef out of the way.  We'll undo this below, if
-        we're pushing a matching tdef.  */
+      /* Slide old into the type slot.  */
       to_type = old;
       old = NULL_TREE;
     }
@@ -1767,39 +1798,14 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
 
       to_val = ovl_insert (decl, old);
     }
-  else if (to_type && TREE_CODE (decl) == TYPE_DECL)
-    {
-      /* We thought we wanted to slide an artificial typedef out of
-        the way, to make way for another typedef.  That's not always
-        what we want to do.  */
-      if (!DECL_ARTIFICIAL (decl))
-       ; /* Slide.  */
-      else if (same_type_p (TREE_TYPE (to_type), TREE_TYPE (decl)))
-       /* Two artificial decls to same type.  Do nothing.  */
-       return to_type;
-      else
-       goto conflict;
-    }
   else if (!old)
     ;
-  else if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl))
-    {
-      /* Slide DECL into the type slot.  */
-      to_type = decl;
-      to_val = old;
-    }
   else if (TREE_CODE (old) != TREE_CODE (decl))
     /* Different kinds of decls conflict.  */
     goto conflict;
   else if (TREE_CODE (old) == TYPE_DECL)
     {
-      if (DECL_ARTIFICIAL (decl))
-       {
-         /* Slide DECL into the type slot instead.  */
-         to_type = decl;
-         to_val = old;
-       }
-      else if (same_type_p (TREE_TYPE (old), TREE_TYPE (decl)))
+      if (same_type_p (TREE_TYPE (old), TREE_TYPE (decl)))
        /* Two type decls to the same type.  Do nothing.  */
        return old;
       else
@@ -1835,6 +1841,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
       to_val = NULL_TREE;
     }
 
+ done:
   if (to_val)
     {
       if (level->kind != sk_namespace
@@ -1854,12 +1861,10 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
          add_decl_to_level (level, to_add);
        }
 
-      if (to_type == (slot ? MAYBE_STAT_TYPE (*slot) : binding->type))
-       to_type = NULL_TREE;
-
-      if (to_type)
+      if (to_type != old_type)
        {
-         gcc_checking_assert (TREE_CODE (to_type) == TYPE_DECL
+         gcc_checking_assert (!old_type
+                              && TREE_CODE (to_type) == TYPE_DECL
                               && DECL_ARTIFICIAL (to_type));
 
          tree type = TREE_TYPE (to_type);
@@ -1875,8 +1880,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
        {
          if (STAT_HACK_P (*slot))
            {
-             if (to_type)
-               STAT_TYPE (*slot) = to_type;
+             STAT_TYPE (*slot) = to_type;
              STAT_DECL (*slot) = to_val;
            }
          else if (to_type)
@@ -1886,8 +1890,7 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
        }
       else
        {
-         if (to_type)
-           binding->type = to_type;
+         binding->type = to_type;
          binding->value = to_val;
        }
     }
index e40a3ed63134ce05cf0b56b58f39412e0fc32869..97b5493e068a5e38480013f8858af1278be31b32 100644 (file)
@@ -1,3 +1,8 @@
+2017-05-30  Nathan Sidwell  <nathan@acm.org>
+
+       PR c++/80913
+       * g++.dg/lookup/pr80913.C: New.
+
 2017-05-30  Richard Biener  <rguenther@suse.de>
 
        PR middle-end/80901
diff --git a/gcc/testsuite/g++.dg/lookup/pr80913.C b/gcc/testsuite/g++.dg/lookup/pr80913.C
new file mode 100644 (file)
index 0000000..a7866bc
--- /dev/null
@@ -0,0 +1,11 @@
+// PR 80913 infinite look on spelling corrector caused by incorrectly
+// chained decl
+
+extern int meminfo ();
+struct meminfo {};
+
+void frob ()
+{
+  meminf (); // { dg-error "not declared" }
+  // { dg-message "suggested alternative" "" { target *-*-* } .-1 }
+}