re PR c++/3061 (kde2/artsd miscompilation (part 2))
authorNathan Sidwell <nathan@codesourcery.com>
Fri, 8 Jun 2001 11:10:29 +0000 (11:10 +0000)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 8 Jun 2001 11:10:29 +0000 (07:10 -0400)
        PR c++/3061
        * class.c (build_secondary_vtable): Use assert, rather than an error
        message.
        (dfs_fixup_binfo_vtbls): BINFO_VTABLE might be NULL.
        (dfs_accumulate_vtbl_inits): A lost primary virtual base may
        be between ORIG_BINFO and RTTI_BINFO, but neither of them.
        Don't set BINFO_VTABLE for a primary virtual base.

Co-Authored-By: Jason Merrill <jason@redhat.com>
From-SVN: r43006

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/method.c
gcc/testsuite/g++.old-deja/g++.abi/vtable4.C [new file with mode: 0644]

index fb986e5be3c2827cde6ae737c5f9c21ccf10bb9b..1fa95c8aad522435a62a0e4ced5bcc0f4df5ae7a 100644 (file)
@@ -1,3 +1,14 @@
+2001-06-08  Nathan Sidwell  <nathan@codesourcery.com>
+           Jason Merrill <jason_merrill@redhat.com>
+
+       PR c++/3061
+       * class.c (build_secondary_vtable): Use assert, rather than an error
+       message.
+       (dfs_fixup_binfo_vtbls): BINFO_VTABLE might be NULL.
+       (dfs_accumulate_vtbl_inits): A lost primary virtual base may
+       be between ORIG_BINFO and RTTI_BINFO, but neither of them.
+       Don't set BINFO_VTABLE for a primary virtual base.
+
 2001-06-07  Mark Mitchell  <mark@codesourcery.com>
 
        * decl.c (duplicate_decls): Update source position information
index cdd92b5d4c203906af61521fce88c589614f8ed7..499053c7db12ad2be69d51b9e753f3e48254ad7d 100644 (file)
@@ -768,7 +768,7 @@ copy_virtuals (binfo)
 
   return copies;
 }
-      
+
 /* Build the primary virtual function table for TYPE.  If BINFO is
    non-NULL, build the vtable starting with the initial approximation
    that it is the same as the one which is the head of the association
@@ -866,20 +866,8 @@ build_secondary_vtable (binfo, for_type)
   /* Make fresh virtual list, so we can smash it later.  */
   BINFO_VIRTUALS (binfo) = copy_virtuals (binfo);
 
-  if (TREE_VIA_VIRTUAL (binfo))
-    {
-      tree binfo1 = binfo_for_vbase (BINFO_TYPE (binfo), for_type);
-
-      /* XXX - This should never happen, if it does, the caller should
-        ensure that the binfo is from for_type's binfos, not from any
-        base type's.  We can remove all this code after a while.  */
-      if (binfo1 != binfo)
-       warning ("internal inconsistency: binfo offset error for rtti");
-
-      offset = BINFO_OFFSET (binfo1);
-    }
-  else
-    offset = BINFO_OFFSET (binfo);
+  my_friendly_assert (binfo == CANONICAL_BINFO (binfo, for_type), 20010605);
+  offset = BINFO_OFFSET (binfo);
 
   /* In the new ABI, secondary vtables are laid out as part of the
      same structure as the primary vtable.  */
@@ -6744,12 +6732,12 @@ dfs_get_primary_binfo (binfo, data)
   return NULL_TREE;
 }
 
-/* Returns the binfo for the primary base of BINFO.  Note that in a
-   complex hierarchy the resulting BINFO may not actually *be*
-   primary.  In particular if the resulting BINFO is a virtual base,
-   and it occurs elsewhere in the hierarchy, then this occurrence may
-   not actually be a primary base in the complete object.  Check
-   BINFO_PRIMARY_P to be sure.  */
+/* Returns the unshared binfo for the primary base of BINFO.  Note
+   that in a complex hierarchy the resulting BINFO may not actually
+   *be* primary.  In particular if the resulting BINFO is a virtual
+   base, and it occurs elsewhere in the hierarchy, then this
+   occurrence may not actually be a primary base in the complete
+   object.  Check BINFO_PRIMARY_P to be sure.  */
 
 tree
 get_primary_binfo (binfo)
@@ -7397,7 +7385,8 @@ dfs_fixup_binfo_vtbls (binfo, data)
 
   /* If we scribbled the construction vtable vptr into BINFO, clear it
      out now.  */
-  if (TREE_CODE (BINFO_VTABLE (binfo)) == TREE_LIST
+  if (BINFO_VTABLE (binfo)
+      && TREE_CODE (BINFO_VTABLE (binfo)) == TREE_LIST
       && (TREE_PURPOSE (BINFO_VTABLE (binfo)) 
          == TREE_VALUE ((tree) data)))
     BINFO_VTABLE (binfo) = TREE_CHAIN (BINFO_VTABLE (binfo));
@@ -7543,41 +7532,80 @@ dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l)
          virtual base.  If it is not the same primary in the hierarchy of T,
          we'll need to generate a ctor vtable for it, to place at its
          location in T.  If it is the same primary, we still need a VTT
-         entry for the vtable, but that must be the base it is a
-         primary for within the sub-hierarchy of RTTI_BINFO.  */
-      tree parent;
-      tree best_primary = NULL;
-      tree primary_for;
-      
-      my_friendly_assert (BINFO_PRIMARY_P (binfo), 20010131);
+         entry for the vtable, but it should point to the ctor vtable for the
+        base it is a primary for within the sub-hierarchy of RTTI_BINFO.
 
-      for (primary_for = BINFO_PRIMARY_BASE_OF (binfo);
-           primary_for;
-           primary_for = BINFO_PRIMARY_BASE_OF (primary_for))
-        {
-          for (parent = primary_for;
-               parent;
-               parent = BINFO_INHERITANCE_CHAIN (parent))
-             {
-               if (parent == rtti_binfo)
-                 {
-                   best_primary = primary_for;
-                   break;
-                 }
-             }
-           if (!parent)
-             break;
-        }
-      if (best_primary)
-        {
-          vtbl = BINFO_VTABLE (best_primary);
-          if (TREE_CODE (vtbl) == TREE_LIST)
-            {
-              my_friendly_assert (TREE_PURPOSE (vtbl) == rtti_binfo,
-                                  20010126);
-              vtbl = TREE_VALUE (vtbl);
-            }
+        There are three possible cases:
+
+         1) We are in the same place.
+        2) We are a primary base within a lost primary virtual base of
+           RTTI_BINFO.
+        3) We are not primary to anything else in RTTI_BINFO.  */
+
+      tree primary = NULL_TREE;
+      if (tree_int_cst_equal (BINFO_OFFSET (orig_binfo),
+                             size_diffop (BINFO_OFFSET (binfo),
+                                          BINFO_OFFSET (rtti_binfo))))
+       {
+         /* Case 1: We're in the same place relative to RTTI_BINFO as we
+            were in the complete type, so we are primary either to
+            RTTI_BINFO or one of its secondary bases.  */
+
+         tree b = BINFO_PRIMARY_BASE_OF (binfo);
+
+         /* Walk down our until we either find the last primary base or
+            rtti_binfo.  */
+         for (; b; b = BINFO_PRIMARY_BASE_OF (b))
+           {
+             primary = b;
+             if (b == rtti_binfo)
+               break;
+           }
         }
+      else
+       {
+         /* Case 2 or 3: We're not in the same place.  We might still be
+            primary to something within a lost primary virtual base of
+            RTTI_BINFO.  */
+
+         tree b = BINFO_PRIMARY_BASE_OF (binfo);
+         tree last;
+
+         /* First, look through the bases we are primary to for a virtual
+            base.  */
+         for (; b; b = BINFO_PRIMARY_BASE_OF (b))
+           {
+             last = b;
+             if (TREE_VIA_VIRTUAL (b))
+               break;
+           }
+         /* If we run out of primary links, keep looking down our
+            inheritance chain; we might be an indirect primary of a
+            virtual base.  */
+         if (b == NULL_TREE)
+           for (b = last; b; b = BINFO_INHERITANCE_CHAIN (b))
+             if (TREE_VIA_VIRTUAL (b))
+               break;
+
+         /* If we found a virtual base B and it is a base of RTTI_BINFO, we
+            share our vtable with LAST, i.e. the derived-most base within
+            B of which we are a primary.  Otherwise, we get our own.  */
+         if (b && binfo_for_vbase (BINFO_TYPE (b),
+                                   BINFO_TYPE (rtti_binfo)))
+           primary = last;
+       }
+
+      if (primary)
+       {
+          vtbl = BINFO_VTABLE (primary);
+         /* If we haven't already been here for our primary derivation,
+            all bets are off.  Especially for case 2 above, we need
+            the derived vtable to have been generated.  */
+         my_friendly_assert (TREE_CODE (vtbl) == TREE_LIST
+                             && TREE_PURPOSE (vtbl) == rtti_binfo,
+                             20010126);
+         vtbl = TREE_VALUE (vtbl);
+       }
     }
   else if (!BINFO_NEW_VTABLE_MARKED (orig_binfo, BINFO_TYPE (rtti_binfo)))
     return inits;
@@ -7610,9 +7638,10 @@ dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l)
   if (!ctor_vtbl_p)
     {
       /* For an ordinary vtable, set BINFO_VTABLE.  */
-      BINFO_VTABLE (binfo) = vtbl;
       if (BINFO_PRIMARY_P (binfo) && TREE_VIA_VIRTUAL (binfo))
-        inits = NULL_TREE;
+       inits = NULL_TREE;
+      else
+       BINFO_VTABLE (binfo) = vtbl;
     }
   else
     /* For a construction vtable, we can't overwrite BINFO_VTABLE.
index 4acf6b670b0331ba1926869611bb695bcfb0ce69..ceb569c70d7f3615d2c82e4a4049e4caec5639d2 100644 (file)
@@ -292,7 +292,7 @@ request for member `%D' is ambiguous in multiple inheritance lattice",
 /* Return a thunk to FUNCTION.  For a virtual thunk, DELTA is the
    offset to this used to locate the vptr, and VCALL_INDEX is used to
    look up the eventual subobject location.  For a non-virtual thunk,
-   DELTA is the offset to this and VCALL_INDEX is zero.  */
+   DELTA is the offset to this and VCALL_INDEX is NULL.  */
 
 tree
 make_thunk (function, delta, vcall_index)
diff --git a/gcc/testsuite/g++.old-deja/g++.abi/vtable4.C b/gcc/testsuite/g++.old-deja/g++.abi/vtable4.C
new file mode 100644 (file)
index 0000000..8190c0e
--- /dev/null
@@ -0,0 +1,27 @@
+// Test for proper handling of extreme virtual inheritance.
+// Previously we failed to recognise that in the constructor vtable
+// for B_skel in C_skel, A_base was still primary to B_base, even though
+// not to B_skel.
+
+// From PR c++/3061.
+
+struct A_base {
+  virtual void foo() { }
+};
+class A_skel : virtual public A_base { };
+class B_base : virtual public A_base { };
+class B_skel : virtual public B_base, virtual public A_skel { };
+class C_base : virtual public B_base { };
+class C_skel : virtual public C_base, virtual public B_skel { };
+class D_base : virtual public C_base { };
+class D_skel : virtual public D_base, virtual public C_skel { };
+class D_impl : virtual public D_skel { };
+int main()
+{
+  D_impl i;
+}