* class.c (add_vcall_offset_vtbl_entries_1): Correct ordering of
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 8 Nov 2002 02:16:48 +0000 (02:16 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 8 Nov 2002 02:16:48 +0000 (02:16 +0000)
vcall offfsets.  Split out ...
(add_vcall_offset): ... new function.

* g++.dg/abi/vthunk3.C: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@58912 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/abi/vthunk3.C [new file with mode: 0644]

index 08f6b25..224c590 100644 (file)
@@ -1,5 +1,9 @@
 2002-11-07  Mark Mitchell  <mark@codesourcery.com>
 
+       * class.c (add_vcall_offset_vtbl_entries_1): Correct ordering of
+       vcall offfsets.  Split out ...
+       (add_vcall_offset): ... new function.
+
        PR c++/8338
        * pt.c (for_each_template_parm): Add htab parameter.
        (process_partial_specialization): Adjust call.
index 82f7c8f..2ca45a6 100644 (file)
@@ -156,6 +156,7 @@ static void build_vbase_offset_vtbl_entries PARAMS ((tree, vtbl_init_data *));
 static void add_vcall_offset_vtbl_entries_r PARAMS ((tree, vtbl_init_data *));
 static void add_vcall_offset_vtbl_entries_1 PARAMS ((tree, vtbl_init_data *));
 static void build_vcall_offset_vtbl_entries PARAMS ((tree, vtbl_init_data *));
+static void add_vcall_offset (tree, tree, vtbl_init_data *);
 static void layout_vtable_decl PARAMS ((tree, int));
 static tree dfs_find_final_overrider PARAMS ((tree, void *));
 static tree find_final_overrider PARAMS ((tree, tree, tree));
@@ -7908,116 +7909,154 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid)
      tree binfo;
      vtbl_init_data* vid;
 {
-  tree derived_virtuals;
-  tree base_virtuals;
-  tree orig_virtuals;
-  tree binfo_inits;
-  /* If BINFO is a primary base, the most derived class which has BINFO as
-     a primary base; otherwise, just BINFO.  */
-  tree non_primary_binfo;
+  tree binfo_in_rtti;
 
-  binfo_inits = NULL_TREE;
+  if (vid->ctor_vtbl_p)
+    binfo_in_rtti = (get_original_base
+                    (binfo, TYPE_BINFO (BINFO_TYPE (vid->rtti_binfo))));
+  else
+    binfo_in_rtti = binfo;
 
-  /* We might be a primary base class.  Go up the inheritance hierarchy
-     until we find the most derived class of which we are a primary base:
-     it is the BINFO_VIRTUALS there that we need to consider.  */
-  non_primary_binfo = binfo;
-  while (BINFO_INHERITANCE_CHAIN (non_primary_binfo))
+  /* Make entries for the rest of the virtuals.  */
+  if (abi_version_at_least (2))
     {
-      tree b;
+      tree orig_fn;
 
-      /* If we have reached a virtual base, then it must be vid->vbase,
-        because we ignore other virtual bases in
-        add_vcall_offset_vtbl_entries_r.  In turn, it must be a primary
-        base (possibly multi-level) of vid->binfo, or we wouldn't
-        have called build_vcall_and_vbase_vtbl_entries for it.  But it
-        might be a lost primary, so just skip down to vid->binfo.  */
-      if (TREE_VIA_VIRTUAL (non_primary_binfo))
+      /* The ABI requires that the methods be processed in declaration
+        order.  G++ 3.2 used the order in the vtable.  */
+      for (orig_fn = TYPE_METHODS (BINFO_TYPE (binfo));
+          orig_fn;
+          orig_fn = TREE_CHAIN (orig_fn))
+       if (DECL_VINDEX (orig_fn))
+         add_vcall_offset (orig_fn, binfo_in_rtti, vid);
+    }
+  else
+    {
+      tree derived_virtuals;
+      tree base_virtuals;
+      tree orig_virtuals;
+      /* If BINFO is a primary base, the most derived class which has
+        BINFO as a primary base; otherwise, just BINFO.  */
+      tree non_primary_binfo;
+
+      /* We might be a primary base class.  Go up the inheritance hierarchy
+        until we find the most derived class of which we are a primary base:
+        it is the BINFO_VIRTUALS there that we need to consider.  */
+      non_primary_binfo = binfo;
+      while (BINFO_INHERITANCE_CHAIN (non_primary_binfo))
        {
-         if (non_primary_binfo != vid->vbase)
-           abort ();
-         non_primary_binfo = vid->binfo;
-         break;
-       }
+         tree b;
+
+         /* If we have reached a virtual base, then it must be vid->vbase,
+            because we ignore other virtual bases in
+            add_vcall_offset_vtbl_entries_r.  In turn, it must be a primary
+            base (possibly multi-level) of vid->binfo, or we wouldn't
+            have called build_vcall_and_vbase_vtbl_entries for it.  But it
+            might be a lost primary, so just skip down to vid->binfo.  */
+         if (TREE_VIA_VIRTUAL (non_primary_binfo))
+           {
+             if (non_primary_binfo != vid->vbase)
+               abort ();
+             non_primary_binfo = vid->binfo;
+             break;
+           }
 
-      b = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
-      if (get_primary_binfo (b) != non_primary_binfo)
-       break;
-      non_primary_binfo = b;
-    }
+         b = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
+         if (get_primary_binfo (b) != non_primary_binfo)
+           break;
+         non_primary_binfo = b;
+       }
 
-  if (vid->ctor_vtbl_p)
-    /* For a ctor vtable we need the equivalent binfo within the hierarchy
-       where rtti_binfo is the most derived type.  */
-    non_primary_binfo = get_original_base
+      if (vid->ctor_vtbl_p)
+       /* For a ctor vtable we need the equivalent binfo within the hierarchy
+          where rtti_binfo is the most derived type.  */
+       non_primary_binfo = get_original_base
           (non_primary_binfo, TYPE_BINFO (BINFO_TYPE (vid->rtti_binfo)));
+      
+      for (base_virtuals = BINFO_VIRTUALS (binfo),
+            derived_virtuals = BINFO_VIRTUALS (non_primary_binfo),
+            orig_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo)));
+          base_virtuals;
+          base_virtuals = TREE_CHAIN (base_virtuals),
+            derived_virtuals = TREE_CHAIN (derived_virtuals),
+            orig_virtuals = TREE_CHAIN (orig_virtuals))
+       {
+         tree orig_fn;
 
-  /* Make entries for the rest of the virtuals.  */
-  for (base_virtuals = BINFO_VIRTUALS (binfo),
-        derived_virtuals = BINFO_VIRTUALS (non_primary_binfo),
-        orig_virtuals = BINFO_VIRTUALS (TYPE_BINFO (BINFO_TYPE (binfo)));
-       base_virtuals;
-       base_virtuals = TREE_CHAIN (base_virtuals),
-        derived_virtuals = TREE_CHAIN (derived_virtuals),
-        orig_virtuals = TREE_CHAIN (orig_virtuals))
-    {
-      tree orig_fn;
-      tree fn;
-      size_t i;
-      tree vcall_offset;
+         /* Find the declaration that originally caused this function to
+            be present in BINFO_TYPE (binfo).  */
+         orig_fn = BV_FN (orig_virtuals);
 
-      /* Find the declaration that originally caused this function to
-        be present in BINFO_TYPE (binfo).  */
-      orig_fn = BV_FN (orig_virtuals);
+         /* When processing BINFO, we only want to generate vcall slots for
+            function slots introduced in BINFO.  So don't try to generate
+            one if the function isn't even defined in BINFO.  */
+         if (!same_type_p (DECL_CONTEXT (orig_fn), BINFO_TYPE (binfo)))
+           continue;
 
-      /* When processing BINFO, we only want to generate vcall slots for
-        function slots introduced in BINFO.  So don't try to generate
-        one if the function isn't even defined in BINFO.  */
-      if (!same_type_p (DECL_CONTEXT (orig_fn), BINFO_TYPE (binfo)))
-       continue;
+         add_vcall_offset (orig_fn, binfo_in_rtti, vid);
+       }
+    }
+}
 
-      /* Find the overriding function.  */
-      fn = BV_FN (derived_virtuals);
+/* Add a vcall offset entry for ORIG_FN to the vtable.  In a
+   construction vtable, BINFO_IN_RTTI is the base corresponding to the
+   vtable base in VID->RTTI_BINFO.  */
 
-      /* If there is already an entry for a function with the same
-        signature as FN, then we do not need a second vcall offset.
-        Check the list of functions already present in the derived
-        class vtable.  */
-      for (i = 0; i < VARRAY_ACTIVE_SIZE (vid->fns); ++i) 
-       {
-         tree derived_entry;
-
-         derived_entry = VARRAY_TREE (vid->fns, i);
-         if (same_signature_p (BV_FN (derived_entry), fn)
-             /* We only use one vcall offset for virtual destructors,
-                even though there are two virtual table entries.  */
-             || (DECL_DESTRUCTOR_P (BV_FN (derived_entry))
-                 && DECL_DESTRUCTOR_P (fn)))
-           break;
-       }
-      if (i != VARRAY_ACTIVE_SIZE (vid->fns))
-       continue;
+static void
+add_vcall_offset (tree orig_fn, tree binfo_in_rtti,
+                 vtbl_init_data *vid)
+{
+  size_t i;
+  tree vcall_offset;
 
-      /* If we are building these vcall offsets as part of building
-        the vtable for the most derived class, remember the vcall
-        offset.  */
-      if (vid->binfo == TYPE_BINFO (vid->derived))
-       CLASSTYPE_VCALL_INDICES (vid->derived) 
-         = tree_cons (fn, vid->index, CLASSTYPE_VCALL_INDICES (vid->derived));
+  /* If there is already an entry for a function with the same
+     signature as FN, then we do not need a second vcall offset.
+     Check the list of functions already present in the derived
+     class vtable.  */
+  for (i = 0; i < VARRAY_ACTIVE_SIZE (vid->fns); ++i) 
+    {
+      tree derived_entry;
 
-      /* The next vcall offset will be found at a more negative
-        offset.  */
-      vid->index = size_binop (MINUS_EXPR, vid->index,
-                              ssize_int (TARGET_VTABLE_DATA_ENTRY_DISTANCE));
+      derived_entry = VARRAY_TREE (vid->fns, i);
+      if (same_signature_p (derived_entry, orig_fn)
+         /* We only use one vcall offset for virtual destructors,
+            even though there are two virtual table entries.  */
+         || (DECL_DESTRUCTOR_P (derived_entry)
+             && DECL_DESTRUCTOR_P (orig_fn)))
+       return;
+    }
 
-      /* Keep track of this function.  */
-      VARRAY_PUSH_TREE (vid->fns, derived_virtuals);
+  /* If we are building these vcall offsets as part of building
+     the vtable for the most derived class, remember the vcall
+     offset.  */
+  if (vid->binfo == TYPE_BINFO (vid->derived))
+    CLASSTYPE_VCALL_INDICES (vid->derived) 
+      = tree_cons (orig_fn, vid->index, 
+                  CLASSTYPE_VCALL_INDICES (vid->derived));
 
-      if (vid->generate_vcall_entries)
-       {
-         tree base;
-         tree base_binfo;
+  /* The next vcall offset will be found at a more negative
+     offset.  */
+  vid->index = size_binop (MINUS_EXPR, vid->index,
+                          ssize_int (TARGET_VTABLE_DATA_ENTRY_DISTANCE));
+
+  /* Keep track of this function.  */
+  VARRAY_PUSH_TREE (vid->fns, orig_fn);
+
+  if (vid->generate_vcall_entries)
+    {
+      tree base;
+      tree base_binfo;
+      tree fn;
 
+      /* Find the overriding function.  */
+      fn = find_final_overrider (BINFO_TYPE (vid->rtti_binfo), 
+                                binfo_in_rtti, orig_fn);
+      if (fn == error_mark_node)
+       vcall_offset = build1 (NOP_EXPR, vtable_entry_type,
+                              integer_zero_node);
+      else
+       {
+         fn = TREE_PURPOSE (fn);
          /* The FN comes from BASE.  So, we must calculate the
             adjustment from vid->vbase to BASE.  We can just look for
             BASE in the complete object because we are converting
@@ -8037,10 +8076,10 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid)
                                      vcall_offset);
          vcall_offset = fold (build1 (NOP_EXPR, vtable_entry_type,
                                       vcall_offset));
-
-         *vid->last_init = build_tree_list (NULL_TREE, vcall_offset);
-         vid->last_init = &TREE_CHAIN (*vid->last_init);
        }
+      /* Add the intiailizer to the vtable.  */
+      *vid->last_init = build_tree_list (NULL_TREE, vcall_offset);
+      vid->last_init = &TREE_CHAIN (*vid->last_init);
     }
 }
 
index c817452..679029e 100644 (file)
@@ -1,5 +1,7 @@
 2002-11-07  Mark Mitchell  <mark@codesourcery.com>
 
+       * g++.dg/abi/vthunk3.C: New test.
+
        PR c++/8338
        * g++.dg/template/crash2.C: New test.
 
diff --git a/gcc/testsuite/g++.dg/abi/vthunk3.C b/gcc/testsuite/g++.dg/abi/vthunk3.C
new file mode 100644 (file)
index 0000000..59e6067
--- /dev/null
@@ -0,0 +1,26 @@
+// { dg-do compile }
+// { dg-options "-fabi-version=0" }
+
+struct A {
+  virtual void a ();
+};
+
+struct B : virtual public A {
+  virtual void b ();
+  virtual void a ();
+};
+
+struct C {
+  virtual void c ();
+};
+
+struct D : public C, public B {
+};
+
+struct E : virtual public D {
+  void b ();
+};
+
+void E::b () {}
+
+// { dg-final { scan-assembler _ZTvn4_n20_N1E1bEv } }