This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] Fix ICE in pop_binding (regression against 2.95.x)


Hi!

The following testcase ICEs in pop_binding.
The issue is that the foo method is inserted into class_shadowed list, but
as there is a friend with the same name which comes after it, at pop_binding
time when all class_shadowed bindings are poped up the foo method is not
BINDING_VALUE() in the innermost IDENTIFIER_BINDING (but in TREE_CHAIN() of
it). Exchanging the two foo lines in the testcase causes it to work, since
foo method comes last and thus is in the innermost IDENTIFIER_BINDING.
The following patch seems to fix it, bootstrap pending.
Ok to commit if it is succeeds (and no regressions)?

2001-06-08  Jakub Jelinek  <jakub@redhat.com>

	* decl.c (pop_binding): Allow DECL not to be present in the
	innermost binding for ID.

	* g++.old-deja/g++.other/binding1.C: New test.

--- gcc/cp/decl.c.jj	Fri Jun  8 11:37:19 2001
+++ gcc/cp/decl.c	Fri Jun  8 13:53:38 2001
@@ -1174,7 +1174,7 @@ pop_binding (id, decl)
      tree id;
      tree decl;
 {
-  tree binding;
+  tree binding, orig_binding, last_binding = NULL_TREE;
 
   if (id == NULL_TREE)
     /* It's easiest to write the loops that call this function without
@@ -1183,20 +1183,28 @@ pop_binding (id, decl)
     return;
 
   /* Get the innermost binding for ID.  */
-  binding = IDENTIFIER_BINDING (id);
+  orig_binding = IDENTIFIER_BINDING (id);
+
+  for (binding = orig_binding; binding; binding = TREE_CHAIN (binding))
+    {
+      /* The DECL will be either the ordinary binding or the type
+	 binding for this identifier.  Remove that binding.  */
+      if (BINDING_VALUE (binding) == decl)
+	{
+	  BINDING_VALUE (binding) = NULL_TREE;
+	  break;
+	}
+      else if (BINDING_TYPE (binding) == decl)
+	{
+	  BINDING_TYPE (binding) = NULL_TREE;
+	  break;
+	}
+      last_binding = binding;
+    }
 
   /* The name should be bound.  */
   my_friendly_assert (binding != NULL_TREE, 0);
 
-  /* The DECL will be either the ordinary binding or the type
-     binding for this identifier.  Remove that binding.  */
-  if (BINDING_VALUE (binding) == decl)
-    BINDING_VALUE (binding) = NULL_TREE;
-  else if (BINDING_TYPE (binding) == decl)
-    BINDING_TYPE (binding) = NULL_TREE;
-  else
-    my_friendly_abort (0);
-
   if (!BINDING_VALUE (binding) && !BINDING_TYPE (binding))
     {
       /* We're completely done with the innermost binding for this
@@ -1210,6 +1218,14 @@ pop_binding (id, decl)
       /* Clear the BINDING_LEVEL so the garbage collector doesn't walk
 	 it.  */
       BINDING_LEVEL (binding) = NULL;
+    }
+
+  if (last_binding != NULL_TREE)
+    {
+      /* This can happen if a class method is followed by friend with the same
+	 name.  */
+      TREE_CHAIN (last_binding) = IDENTIFIER_BINDING (id);
+      IDENTIFIER_BINDING (id) = orig_binding;
     }
 }
 
--- gcc/testsuite/g++.old-deja/g++.other/binding1.C.jj	Fri Jun  8 13:57:19 2001
+++ gcc/testsuite/g++.old-deja/g++.other/binding1.C	Fri Jun  8 13:57:29 2001
@@ -0,0 +1,9 @@
+// Build don't link:
+
+template <class T> struct A;
+
+template <> struct A<int>
+{
+  A<int> & foo (int);
+  friend A<int> foo (const A<int> &, int);
+};

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]