This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: ABI tweaks
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 3 Nov 2002 17:46:19 -0800
- Subject: C++ PATCH: ABI tweaks
- Reply-to: mark at codesourcery dot com
Our ABI testsuite found a few more problems; fortunately, all can be
fixed in a backwards-compatible way. These problems were:
(1) Thunks not being emitted, even when they are supposed to be.
(2) Failure to emit VTTs when emitting an ordinary vtable; they should
always be emitted at the same time. (Technically, in a single
COMDAT group, but we don't have support for COMDAT yet...)
Tested on i686-pc-linux-gnu, applied on the mainline.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
2002-11-03 Mark Mitchell <mark@codesourcery.com>
* call.c (build_special_member_call): Do not try to lookup VTTs by
name.
* class.c (vtbl_init_data): Add generate_vcall_entries.
(get_vtable_decl): Do not look up virtual tables by name.
(copy_virtuals): Do not use BV_USE_VCALL_INDEX_P.
(set_primary_base): Do not set CLASSTYPE_RTTI.
(determine_primary_base): Likewise.
(get_matching_virtual): Remove.
(get_vcall_index): New function.
(update_vtable_entry_for_fn): Do not try to use virtual thunks
when they are not required. Assign vcall indices at this point.
(finish_struct_1): Do not set CLASSTYPE_NEEDS_VIRTUAL_REINIT.
Do update dynamic_classes.
(build_vtt): Do not add VTTs to the symbol table.
(build_ctor_vtbl_group): Likewise.
(build_vtbl_initializer): Simplify handling of vcall indices.
(build_vcall_offset_vtbl_entries): Pretend to build vcall offsets
for the most derived class.
(add_vcall_offset_vtbl_entries_1): But do not actually add them to
the vtable.
* cp-tree.h (dynamic_classes): New macro.
(lang_type_class): Remove rtti. Add vtables. Add vcall_indices.
(CLASSTYPE_RTTI): Remove.
(CLASSTYPE_NEEDS_VIRTUAL_REINIT): Remove.
(CLASSTYPE_VCALL_INDICES): New macro.
(CLASSTYPE_VTABLES): Likewise.
(BV_USE_VCALL_INDEX_P): Remove.
(build_vtable_path): Remove.
* decl2.c (finish_vtable_vardecl): Remove.
(key_method): Remove #if 0'd code.
(finish_vtable_vardecl): Rename to ...
(maybe_emit_vtables): ... this.
(finish_file): Use it.
* search.c (look_for_overrides_here): Update comment.
2002-11-03 Mark Mitchell <mark@codesourcery.com>
* g++.dg/abi/thunk1.C: New test.
* g++.dg/abi/thunk2.C: Likewise.
* g++.dg/abi/vtt1.C: Likewise.
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.338
diff -c -5 -p -r1.338 call.c
*** cp/call.c 31 Oct 2002 21:38:38 -0000 1.338
--- cp/call.c 4 Nov 2002 01:34:23 -0000
*************** build_special_member_call (tree instance
*** 4710,4720 ****
tree sub_vtt;
/* If the current function is a complete object constructor
or destructor, then we fetch the VTT directly.
Otherwise, we look it up using the VTT we were given. */
! vtt = IDENTIFIER_GLOBAL_VALUE (get_vtt_name (current_class_type));
vtt = decay_conversion (vtt);
vtt = build (COND_EXPR, TREE_TYPE (vtt),
build (EQ_EXPR, boolean_type_node,
current_in_charge_parm, integer_zero_node),
current_vtt_parm,
--- 4710,4720 ----
tree sub_vtt;
/* If the current function is a complete object constructor
or destructor, then we fetch the VTT directly.
Otherwise, we look it up using the VTT we were given. */
! vtt = TREE_CHAIN (CLASSTYPE_VTABLES (current_class_type));
vtt = decay_conversion (vtt);
vtt = build (COND_EXPR, TREE_TYPE (vtt),
build (EQ_EXPR, boolean_type_node,
current_in_charge_parm, integer_zero_node),
current_vtt_parm,
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.489
diff -c -5 -p -r1.489 class.c
*** cp/class.c 30 Oct 2002 15:54:05 -0000 1.489
--- cp/class.c 4 Nov 2002 01:34:25 -0000
*************** typedef struct vtbl_init_data_s
*** 85,94 ****
--- 85,97 ----
vtable. */
int primary_vtbl_p;
/* Nonzero if we are building the initializer for a construction
vtable. */
int ctor_vtbl_p;
+ /* True when adding vcall offset entries to the vtable. False when
+ merely computing the indices. */
+ bool generate_vcall_entries;
} vtbl_init_data;
/* The type of a function passed to walk_subobject_offsets. */
typedef int (*subobject_offset_fn) PARAMS ((tree, tree, splay_tree));
*************** static bool type_requires_array_cookie P
*** 207,216 ****
--- 210,220 ----
static bool contains_empty_class_p (tree);
static tree dfs_base_derived_from (tree, void *);
static bool base_derived_from (tree, tree);
static int empty_base_at_nonzero_offset_p (tree, tree, splay_tree);
static tree end_of_base (tree);
+ static tree get_vcall_index (tree, tree);
/* Macros for dfs walking during vtt construction. See
dfs_ctor_vtable_bases_queue_p, dfs_build_secondary_vptr_vtt_inits
and dfs_fixup_binfo_vtbls. */
#define VTT_TOP_LEVEL_P(NODE) TREE_UNSIGNED (NODE)
*************** build_vtable (class_type, name, vtable_t
*** 538,562 ****
tree
get_vtable_decl (type, complete)
tree type;
int complete;
{
! tree name = get_vtable_name (type);
! tree decl = IDENTIFIER_GLOBAL_VALUE (name);
!
! if (decl)
! {
! my_friendly_assert (TREE_CODE (decl) == VAR_DECL
! && DECL_VIRTUAL_P (decl), 20000118);
! return decl;
! }
!
! decl = build_vtable (type, name, void_type_node);
! decl = pushdecl_top_level (decl);
! my_friendly_assert (IDENTIFIER_GLOBAL_VALUE (name) == decl,
! 20000517);
/* At one time the vtable info was grabbed 2 words at a time. This
fails on sparc unless you have 8-byte alignment. (tiemann) */
DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),
DECL_ALIGN (decl));
--- 542,559 ----
tree
get_vtable_decl (type, complete)
tree type;
int complete;
{
! tree decl;
!
! if (CLASSTYPE_VTABLES (type))
! return CLASSTYPE_VTABLES (type);
+ decl = build_vtable (type, get_vtable_name (type), void_type_node);
+ CLASSTYPE_VTABLES (type) = decl;
+
/* At one time the vtable info was grabbed 2 words at a time. This
fails on sparc unless you have 8-byte alignment. (tiemann) */
DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),
DECL_ALIGN (decl));
*************** copy_virtuals (binfo)
*** 579,592 ****
tree copies;
tree t;
copies = copy_list (BINFO_VIRTUALS (binfo));
for (t = copies; t; t = TREE_CHAIN (t))
! {
! BV_VCALL_INDEX (t) = NULL_TREE;
! BV_USE_VCALL_INDEX_P (t) = 0;
! }
return copies;
}
/* Build the primary virtual function table for TYPE. If BINFO is
--- 576,586 ----
tree copies;
tree t;
copies = copy_list (BINFO_VIRTUALS (binfo));
for (t = copies; t; t = TREE_CHAIN (t))
! BV_VCALL_INDEX (t) = NULL_TREE;
return copies;
}
/* Build the primary virtual function table for TYPE. If BINFO is
*************** set_primary_base (t, binfo)
*** 1557,1567 ****
CLASSTYPE_PRIMARY_BINFO (t) = binfo;
basetype = BINFO_TYPE (binfo);
TYPE_BINFO_VTABLE (t) = TYPE_BINFO_VTABLE (basetype);
TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS (basetype);
TYPE_VFIELD (t) = TYPE_VFIELD (basetype);
- CLASSTYPE_RTTI (t) = CLASSTYPE_RTTI (basetype);
}
/* Determine the primary class for T. */
static void
--- 1551,1560 ----
*************** determine_primary_base (t)
*** 1583,1598 ****
tree base_binfo = BINFO_BASETYPE (type_binfo, i);
tree basetype = BINFO_TYPE (base_binfo);
if (TYPE_CONTAINS_VPTR_P (basetype))
{
- /* Even a virtual baseclass can contain our RTTI
- information. But, we prefer a non-virtual polymorphic
- baseclass. */
- if (!CLASSTYPE_HAS_PRIMARY_BASE_P (t))
- CLASSTYPE_RTTI (t) = CLASSTYPE_RTTI (basetype);
-
/* We prefer a non-virtual base, although a virtual one will
do. */
if (TREE_VIA_VIRTUAL (base_binfo))
continue;
--- 1576,1585 ----
*************** find_final_overrider (t, binfo, fn)
*** 2323,2347 ****
}
return ffod.candidates;
}
! /* Returns the function from the BINFO_VIRTUALS entry in T which matches
! the signature of FUNCTION_DECL FN, or NULL_TREE if none. In other words,
! the function that the slot in T's primary vtable points to. */
- static tree get_matching_virtual PARAMS ((tree, tree));
static tree
! get_matching_virtual (t, fn)
! tree t, fn;
{
! tree f;
! for (f = BINFO_VIRTUALS (TYPE_BINFO (t)); f; f = TREE_CHAIN (f))
! if (same_signature_p (BV_FN (f), fn))
! return BV_FN (f);
! return NULL_TREE;
}
/* Update an entry in the vtable for BINFO, which is in the hierarchy
dominated by T. FN has been overriden in BINFO; VIRTUALS points to the
corresponding position in the BINFO_VIRTUALS list. */
--- 2310,2336 ----
}
return ffod.candidates;
}
! /* Return the index of the vcall offset for FN when TYPE is used as a
! virtual base. */
static tree
! get_vcall_index (tree fn, tree type)
{
! tree v;
! for (v = CLASSTYPE_VCALL_INDICES (type); v; v = TREE_CHAIN (v))
! if ((DECL_DESTRUCTOR_P (fn) && DECL_DESTRUCTOR_P (TREE_PURPOSE (v)))
! || same_signature_p (fn, TREE_PURPOSE (v)))
! break;
!
! /* There should always be an appropriate index. */
! my_friendly_assert (v, 20021103);
!
! return TREE_VALUE (v);
}
/* Update an entry in the vtable for BINFO, which is in the hierarchy
dominated by T. FN has been overriden in BINFO; VIRTUALS points to the
corresponding position in the BINFO_VIRTUALS list. */
*************** update_vtable_entry_for_fn (t, binfo, fn
*** 2405,2415 ****
}
/* Compute the constant adjustment to the `this' pointer. The
`this' pointer, when this function is called, will point at BINFO
(or one of its primary bases, which are at the same offset). */
-
if (virtual_base)
/* The `this' pointer needs to be adjusted from the declaration to
the nearest virtual base. */
delta = size_diffop (BINFO_OFFSET (virtual_base),
BINFO_OFFSET (first_defn));
--- 2394,2403 ----
*************** update_vtable_entry_for_fn (t, binfo, fn
*** 2418,2466 ****
entry in our vtable. Except possibly in a constructor vtable,
if we happen to get our primary back. In that case, the offset
will be zero, as it will be a primary base. */
delta = size_zero_node;
else
! {
! /* The `this' pointer needs to be adjusted from pointing to
! BINFO to pointing at the base where the final overrider
! appears. */
! delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)),
! BINFO_OFFSET (binfo));
!
! if (! integer_zerop (delta))
! {
! /* We'll need a thunk. But if we have a (perhaps formerly)
! primary virtual base, we have a vcall slot for this function,
! so we can use it rather than create a non-virtual thunk. */
!
! b = get_primary_binfo (first_defn);
! for (; b; b = get_primary_binfo (b))
! {
! tree f = get_matching_virtual (BINFO_TYPE (b), fn);
! if (!f)
! /* b doesn't have this function; no suitable vbase. */
! break;
! if (TREE_VIA_VIRTUAL (b))
! {
! /* Found one; we can treat ourselves as a virtual base. */
! virtual_base = binfo;
! delta = size_zero_node;
! break;
! }
! }
! }
! }
modify_vtable_entry (t,
binfo,
TREE_PURPOSE (overrider),
delta,
virtuals);
if (virtual_base)
! BV_USE_VCALL_INDEX_P (*virtuals) = 1;
}
/* Called from modify_all_vtables via dfs_walk. */
static tree
--- 2406,2431 ----
entry in our vtable. Except possibly in a constructor vtable,
if we happen to get our primary back. In that case, the offset
will be zero, as it will be a primary base. */
delta = size_zero_node;
else
! /* The `this' pointer needs to be adjusted from pointing to
! BINFO to pointing at the base where the final overrider
! appears. */
! delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)),
! BINFO_OFFSET (binfo));
modify_vtable_entry (t,
binfo,
TREE_PURPOSE (overrider),
delta,
virtuals);
if (virtual_base)
! BV_VCALL_INDEX (*virtuals)
! = get_vcall_index (TREE_PURPOSE (overrider),
! BINFO_TYPE (virtual_base));
}
/* Called from modify_all_vtables via dfs_walk. */
static tree
*************** layout_class_type (tree t, tree *virtual
*** 5099,5134 ****
/* Clean up. */
splay_tree_delete (empty_base_offsets);
}
! /* Create a RECORD_TYPE or UNION_TYPE node for a C struct or union declaration
! (or C++ class declaration).
!
! For C++, we must handle the building of derived classes.
! Also, C++ allows static class members. The way that this is
! handled is to keep the field name where it is (as the DECL_NAME
! of the field), and place the overloaded decl in the bit position
! of the field. layout_record and layout_union will know about this.
!
! More C++ hair: inline functions have text in their
! DECL_PENDING_INLINE_INFO nodes which must somehow be parsed into
! meaningful tree structure. After the struct has been laid out, set
! things up so that this can happen.
!
! And still more: virtual functions. In the case of single inheritance,
! when a new virtual function is seen which redefines a virtual function
! from the base class, the new virtual function is placed into
! the virtual function table at exactly the same address that
! it had in the base class. When this is extended to multiple
! inheritance, the same thing happens, except that multiple virtual
! function tables must be maintained. The first virtual function
! table is treated in exactly the same way as in the case of single
! inheritance. Additional virtual function tables have different
! DELTAs, which tell how to adjust `this' to point to the right thing.
!
! ATTRIBUTES is the set of decl attributes to be applied, if any. */
void
finish_struct_1 (t)
tree t;
{
--- 5064,5075 ----
/* Clean up. */
splay_tree_delete (empty_base_offsets);
}
! /* Perform processing required when the definition of T (a class type)
! is complete. */
void
finish_struct_1 (t)
tree t;
{
*************** finish_struct_1 (t)
*** 5151,5161 ****
/* If this type was previously laid out as a forward reference,
make sure we lay it out again. */
TYPE_SIZE (t) = NULL_TREE;
CLASSTYPE_GOT_SEMICOLON (t) = 0;
CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE;
- CLASSTYPE_RTTI (t) = NULL_TREE;
fixup_inline_methods (t);
/* Make assumptions about the class; we'll reset the flags if
necessary. */
--- 5092,5101 ----
*************** finish_struct_1 (t)
*** 5208,5235 ****
build_primary_vtable (NULL_TREE, t);
else if (! BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (t), t))
/* Here we know enough to change the type of our virtual
function table, but we will wait until later this function. */
build_primary_vtable (CLASSTYPE_PRIMARY_BINFO (t), t);
-
- /* If this type has basetypes with constructors, then those
- constructors might clobber the virtual function table. But
- they don't if the derived class shares the exact vtable of the base
- class. */
- CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
- }
- /* If we didn't need a new vtable, see if we should copy one from
- the base. */
- else if (CLASSTYPE_HAS_PRIMARY_BASE_P (t))
- {
- tree binfo = CLASSTYPE_PRIMARY_BINFO (t);
-
- /* If this class uses a different vtable than its primary base
- then when we will need to initialize our vptr after the base
- class constructor runs. */
- if (TYPE_BINFO_VTABLE (t) != BINFO_VTABLE (binfo))
- CLASSTYPE_NEEDS_VIRTUAL_REINIT (t) = 1;
}
if (TYPE_CONTAINS_VPTR_P (t))
{
int vindex;
--- 5148,5157 ----
*************** finish_struct_1 (t)
*** 5251,5260 ****
--- 5173,5185 ----
fn = TREE_CHAIN (fn),
vindex += (TARGET_VTABLE_USES_DESCRIPTORS
? TARGET_VTABLE_USES_DESCRIPTORS : 1))
if (TREE_CODE (DECL_VINDEX (BV_FN (fn))) != INTEGER_CST)
DECL_VINDEX (BV_FN (fn)) = build_shared_int_cst (vindex);
+
+ /* Add this class to the list of dynamic classes. */
+ dynamic_classes = tree_cons (NULL_TREE, t, dynamic_classes);
}
finish_struct_bits (t);
/* Complete the rtl for any static member objects of the type we're
*************** build_vtt (t)
*** 7066,7077 ****
type = build_index_type (size_int (list_length (inits) - 1));
type = build_cplus_array_type (const_ptr_type_node, type);
/* Now, build the VTT object itself. */
vtt = build_vtable (t, get_vtt_name (t), type);
- pushdecl_top_level (vtt);
initialize_array (vtt, inits);
dump_vtt (t, vtt);
}
/* The type corresponding to BASE_BINFO is a base of the type of BINFO, but
--- 6991,7004 ----
type = build_index_type (size_int (list_length (inits) - 1));
type = build_cplus_array_type (const_ptr_type_node, type);
/* Now, build the VTT object itself. */
vtt = build_vtable (t, get_vtt_name (t), type);
initialize_array (vtt, inits);
+ /* Add the VTT to the vtables list. */
+ TREE_CHAIN (vtt) = TREE_CHAIN (CLASSTYPE_VTABLES (t));
+ TREE_CHAIN (CLASSTYPE_VTABLES (t)) = vtt;
dump_vtt (t, vtt);
}
/* The type corresponding to BASE_BINFO is a base of the type of BINFO, but
*************** build_ctor_vtbl_group (binfo, t)
*** 7402,7412 ****
type = build_index_type (size_int (list_length (inits) - 1));
type = build_cplus_array_type (vtable_entry_type, type);
TREE_TYPE (vtbl) = type;
/* Initialize the construction vtable. */
! pushdecl_top_level (vtbl);
initialize_array (vtbl, inits);
dump_vtable (t, binfo, vtbl);
}
/* Add the vtbl initializers for BINFO (and its bases other than
--- 7329,7339 ----
type = build_index_type (size_int (list_length (inits) - 1));
type = build_cplus_array_type (vtable_entry_type, type);
TREE_TYPE (vtbl) = type;
/* Initialize the construction vtable. */
! CLASSTYPE_VTABLES (t) = chainon (CLASSTYPE_VTABLES (t), vtbl);
initialize_array (vtbl, inits);
dump_vtable (t, binfo, vtbl);
}
/* Add the vtbl initializers for BINFO (and its bases other than
*************** build_vtbl_initializer (binfo, orig_binf
*** 7619,7628 ****
--- 7546,7556 ----
vid.derived = t;
vid.rtti_binfo = rtti_binfo;
vid.last_init = &vid.inits;
vid.primary_vtbl_p = (binfo == TYPE_BINFO (t));
vid.ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_binfo), t);
+ vid.generate_vcall_entries = true;
/* The first vbase or vcall offset is at index -3 in the vtable. */
vid.index = ssize_int (-3 * TARGET_VTABLE_DATA_ENTRY_DISTANCE);
/* Add entries to the vtable for RTTI. */
build_rtti_vtbl_entries (binfo, &vid);
*************** build_vtbl_initializer (binfo, orig_binf
*** 7702,7719 ****
if (! init)
{
/* Pull the offset for `this', and the function to call, out of
the list. */
delta = BV_DELTA (v);
!
! if (BV_USE_VCALL_INDEX_P (v))
! {
! vcall_index = BV_VCALL_INDEX (v);
! my_friendly_assert (vcall_index != NULL_TREE, 20000621);
! }
! else
! vcall_index = NULL_TREE;
my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
/* You can't call an abstract virtual function; it's abstract.
--- 7630,7640 ----
if (! init)
{
/* Pull the offset for `this', and the function to call, out of
the list. */
delta = BV_DELTA (v);
! vcall_index = BV_VCALL_INDEX (v);
my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
/* You can't call an abstract virtual function; it's abstract.
*************** build_vbase_offset_vtbl_entries (binfo,
*** 7898,7932 ****
static void
build_vcall_offset_vtbl_entries (binfo, vid)
tree binfo;
vtbl_init_data *vid;
{
! /* We only need these entries if this base is a virtual base. */
! if (!TREE_VIA_VIRTUAL (binfo))
! return;
!
! /* We need a vcall offset for each of the virtual functions in this
! vtable. For example:
!
! class A { virtual void f (); };
! class B1 : virtual public A { virtual void f (); };
! class B2 : virtual public A { virtual void f (); };
! class C: public B1, public B2 { virtual void f (); };
!
! A C object has a primary base of B1, which has a primary base of A. A
! C also has a secondary base of B2, which no longer has a primary base
! of A. So the B2-in-C construction vtable needs a secondary vtable for
! A, which will adjust the A* to a B2* to call f. We have no way of
! knowing what (or even whether) this offset will be when we define B2,
! so we store this "vcall offset" in the A sub-vtable and look it up in
! a "virtual thunk" for B2::f.
!
! We need entries for all the functions in our primary vtable and
! in our non-virtual bases' secondary vtables. */
! vid->vbase = binfo;
! /* Now, walk through the non-virtual bases, adding vcall offsets. */
! add_vcall_offset_vtbl_entries_r (binfo, vid);
}
/* Build vcall offsets, starting with those for BINFO. */
static void
--- 7819,7859 ----
static void
build_vcall_offset_vtbl_entries (binfo, vid)
tree binfo;
vtbl_init_data *vid;
{
! /* We only need these entries if this base is a virtual base. We
! compute the indices -- but do not add to the vtable -- when
! building the main vtable for a class. */
! if (TREE_VIA_VIRTUAL (binfo) || binfo == TYPE_BINFO (vid->derived))
! {
! /* We need a vcall offset for each of the virtual functions in this
! vtable. For example:
!
! class A { virtual void f (); };
! class B1 : virtual public A { virtual void f (); };
! class B2 : virtual public A { virtual void f (); };
! class C: public B1, public B2 { virtual void f (); };
!
! A C object has a primary base of B1, which has a primary base of A. A
! C also has a secondary base of B2, which no longer has a primary base
! of A. So the B2-in-C construction vtable needs a secondary vtable for
! A, which will adjust the A* to a B2* to call f. We have no way of
! knowing what (or even whether) this offset will be when we define B2,
! so we store this "vcall offset" in the A sub-vtable and look it up in
! a "virtual thunk" for B2::f.
!
! We need entries for all the functions in our primary vtable and
! in our non-virtual bases' secondary vtables. */
! vid->vbase = binfo;
! /* If we are just computing the vcall indices -- but do not need
! the actual entries -- not that. */
! if (!TREE_VIA_VIRTUAL (binfo))
! vid->generate_vcall_entries = false;
! /* Now, walk through the non-virtual bases, adding vcall offsets. */
! add_vcall_offset_vtbl_entries_r (binfo, vid);
! }
}
/* Build vcall offsets, starting with those for BINFO. */
static void
*************** add_vcall_offset_vtbl_entries_1 (binfo,
*** 8023,8034 ****
derived_virtuals = TREE_CHAIN (derived_virtuals),
orig_virtuals = TREE_CHAIN (orig_virtuals))
{
tree orig_fn;
tree fn;
- tree base;
- tree base_binfo;
size_t i;
tree vcall_offset;
/* Find the declaration that originally caused this function to
be present in BINFO_TYPE (binfo). */
--- 7950,7959 ----
*************** add_vcall_offset_vtbl_entries_1 (binfo,
*** 8055,8108 ****
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)))
! {
! if (!vid->ctor_vtbl_p)
! BV_VCALL_INDEX (derived_virtuals)
! = BV_VCALL_INDEX (derived_entry);
! break;
! }
}
if (i != VARRAY_ACTIVE_SIZE (vid->fns))
continue;
! /* 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 from a virtual base, so if there
! were multiple copies, there would not be a unique final overrider
! and vid->derived would be ill-formed. */
! base = DECL_CONTEXT (fn);
! base_binfo = lookup_base (vid->derived, base, ba_any, NULL);
!
! /* Compute the vcall offset. */
! /* As mentioned above, the vbase we're working on is a primary base of
! vid->binfo. But it might be a lost primary, so its BINFO_OFFSET
! might be wrong, so we just use the BINFO_OFFSET from vid->binfo. */
! vcall_offset = BINFO_OFFSET (vid->binfo);
! vcall_offset = size_diffop (BINFO_OFFSET (base_binfo),
! 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);
!
! /* Keep track of the vtable index where this vcall offset can be
! found. For a construction vtable, we already made this
! annotation when we built the original vtable. */
! if (!vid->ctor_vtbl_p)
! BV_VCALL_INDEX (derived_virtuals) = vid->index;
/* 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, derived_virtuals);
}
}
/* Return vtbl initializers for the RTTI entries coresponding to the
BINFO's vtable. The RTTI entries should indicate the object given
--- 7980,8037 ----
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;
! /* 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));
/* 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, derived_virtuals);
+
+ if (vid->generate_vcall_entries)
+ {
+ tree base;
+ tree base_binfo;
+
+ /* 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
+ from a virtual base, so if there were multiple copies,
+ there would not be a unique final overrider and
+ vid->derived would be ill-formed. */
+ base = DECL_CONTEXT (fn);
+ base_binfo = lookup_base (vid->derived, base, ba_any, NULL);
+
+ /* Compute the vcall offset. */
+ /* As mentioned above, the vbase we're working on is a
+ primary base of vid->binfo. But it might be a lost
+ primary, so its BINFO_OFFSET might be wrong, so we just
+ use the BINFO_OFFSET from vid->binfo. */
+ vcall_offset = BINFO_OFFSET (vid->binfo);
+ vcall_offset = size_diffop (BINFO_OFFSET (base_binfo),
+ 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);
+ }
}
}
/* Return vtbl initializers for the RTTI entries coresponding to the
BINFO's vtable. The RTTI entries should indicate the object given
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.768
diff -c -5 -p -r1.768 cp-tree.h
*** cp/cp-tree.h 31 Oct 2002 21:38:38 -0000 1.768
--- cp/cp-tree.h 4 Nov 2002 01:34:27 -0000
*************** struct diagnostic_context;
*** 45,55 ****
TREE_INDIRECT_USING (in NAMESPACE_DECL).
LOCAL_BINDING_P (in CPLUS_BINDING)
ICS_USER_FLAG (in _CONV)
CLEANUP_P (in TRY_BLOCK)
AGGR_INIT_VIA_CTOR_P (in AGGR_INIT_EXPR)
- BV_USE_VCALL_INDEX_P (in the BINFO_VIRTUALS TREE_LIST)
PTRMEM_OK_P (in ADDR_EXPR, OFFSET_REF)
PARMLIST_ELLIPSIS_P (in PARMLIST)
1: IDENTIFIER_VIRTUAL_P.
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
--- 45,54 ----
*************** struct diagnostic_context;
*** 131,143 ****
overriden version of a base class method, then it is assumed
that, prior to adjustment, the this pointer points to an object
of the base class.
The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable
! index of the vcall offset for this entry. If
! BV_USE_VCALL_INDEX_P then the corresponding vtable entry should
! use a virtual thunk, as opposed to an ordinary thunk.
The BV_FN is the declaration for the virtual function itself.
BINFO_VTABLE
This is an expression with POINTER_TYPE that gives the value
--- 130,140 ----
overriden version of a base class method, then it is assumed
that, prior to adjustment, the this pointer points to an object
of the base class.
The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable
! index of the vcall offset for this entry.
The BV_FN is the declaration for the virtual function itself.
BINFO_VTABLE
This is an expression with POINTER_TYPE that gives the value
*************** enum cp_tree_index
*** 613,622 ****
--- 610,621 ----
CPTI_CALL_UNEXPECTED,
CPTI_ATEXIT,
CPTI_DSO_HANDLE,
CPTI_DCAST,
+ CPTI_DYNAMIC_CLASSES,
+
CPTI_MAX
};
extern GTY(()) tree cp_global_trees[CPTI_MAX];
*************** extern GTY(()) tree cp_global_trees[CPTI
*** 743,752 ****
--- 742,755 ----
/* The type of the vtt parameter passed to subobject constructors and
destructors. */
#define vtt_parm_type cp_global_trees[CPTI_VTT_PARM_TYPE]
+ /* A TREE_LIST of all of the dynamic classes in the program. */
+
+ #define dynamic_classes cp_global_trees[CPTI_DYNAMIC_CLASSES]
+
/* Global state. */
struct saved_scope GTY(())
{
tree old_bindings;
*************** struct lang_type_class GTY(())
*** 1151,1166 ****
remove a flag. */
unsigned dummy : 4;
tree primary_base;
tree vfields;
tree vbases;
tree tags;
tree as_base;
tree pure_virtuals;
tree friend_classes;
- tree rtti;
tree methods;
tree decl_list;
tree template_info;
tree befriending_classes;
};
--- 1154,1170 ----
remove a flag. */
unsigned dummy : 4;
tree primary_base;
tree vfields;
+ tree vcall_indices;
+ tree vtables;
tree vbases;
tree tags;
tree as_base;
tree pure_virtuals;
tree friend_classes;
tree methods;
tree decl_list;
tree template_info;
tree befriending_classes;
};
*************** struct lang_type GTY(())
*** 1255,1267 ****
#define TYPE_BEING_DEFINED(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->being_defined)
/* Nonzero means that this type has been redefined. In this case, if
convenient, don't reprocess any methods that appear in its redefinition. */
#define TYPE_REDEFINED(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->redefined)
- /* The is the basetype that contains NODE's rtti. */
- #define CLASSTYPE_RTTI(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->rtti)
-
/* Nonzero means that this _CLASSTYPE node overloads operator(). */
#define TYPE_OVERLOADS_CALL_EXPR(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->has_call_overloaded)
/* Nonzero means that this _CLASSTYPE node overloads operator[]. */
--- 1259,1268 ----
*************** struct lang_type GTY(())
*** 1429,1445 ****
#define CLASSTYPE_PURE_VIRTUALS(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->pure_virtuals)
/* Nonzero means that this aggr type has been `closed' by a semicolon. */
#define CLASSTYPE_GOT_SEMICOLON(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->got_semicolon)
- /* Nonzero means that the main virtual function table pointer needs to be
- set because base constructors have placed the wrong value there.
- If this is zero, it means that they placed the right value there,
- and there is no need to change it. */
- #define CLASSTYPE_NEEDS_VIRTUAL_REINIT(NODE) \
- (LANG_TYPE_CLASS_CHECK (NODE)->needs_virtual_reinit)
-
/* Nonzero means that this type has an X() constructor. */
#define TYPE_HAS_DEFAULT_CONSTRUCTOR(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->h.has_default_ctor)
/* Nonzero means that this type contains a mutable member */
--- 1430,1439 ----
*************** struct lang_type GTY(())
*** 1627,1636 ****
--- 1621,1645 ----
#define BINFO_INDIRECT_PRIMARY_P(NODE) TREE_USED (NODE)
/* Used by various search routines. */
#define IDENTIFIER_MARKED(NODE) TREE_LANG_FLAG_0 (NODE)
+ /* A TREE_LIST of the vcall indices associated with the class NODE.
+ The TREE_PURPOSE of each node is a FUNCTION_DECL for a virtual
+ function. The TREE_VALUE is the index into the virtual table where
+ the vcall offset for that function is stored, when NODE is a
+ virtual base. If NODE has a direct or indirect primary base that
+ is also virtual, the entries for that class are not present on this
+ list. */
+ #define CLASSTYPE_VCALL_INDICES(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->vcall_indices)
+
+ /* The various vtables for the class NODE. The primary vtable will be
+ first, followed by the construction vtables and VTT, if any. */
+ #define CLASSTYPE_VTABLES(NODE) \
+ (LANG_TYPE_CLASS_CHECK (NODE)->vtables)
+
/* Accessor macros for the vfield slots in structures. */
/* List of virtual table fields that this type contains (both the primary
and secondaries). The TREE_VALUE is the class type where the vtable
field was introduced. For a vtable field inherited from the primary
*************** struct lang_type GTY(())
*** 1662,1673 ****
#define BV_VCALL_INDEX(NODE) (TREE_TYPE (NODE))
/* The function to call. */
#define BV_FN(NODE) (TREE_VALUE (NODE))
- /* Nonzero if we should use a virtual thunk for this entry. */
- #define BV_USE_VCALL_INDEX_P(NODE) (TREE_LANG_FLAG_0 (NODE))
/* Nonzero for TREE_LIST node means that this list of things
is a list of parameters, as opposed to a list of expressions. */
#define TREE_PARMLIST(NODE) (TREE_LANG_FLAG_2 (NODE))
--- 1671,1680 ----
*************** extern tree strip_top_quals
*** 3544,3554 ****
extern tree perform_implicit_conversion PARAMS ((tree, tree));
/* in class.c */
extern tree build_base_path PARAMS ((enum tree_code, tree, tree, int));
extern tree convert_to_base (tree, tree, bool);
- extern tree build_vbase_path PARAMS ((enum tree_code, tree, tree, tree, int));
extern tree build_vtbl_ref PARAMS ((tree, tree));
extern tree build_vfn_ref PARAMS ((tree, tree));
extern tree get_vtable_decl PARAMS ((tree, int));
extern void add_method PARAMS ((tree, tree, int));
extern int currently_open_class PARAMS ((tree));
--- 3551,3560 ----
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.570
diff -c -5 -p -r1.570 decl2.c
*** cp/decl2.c 2 Nov 2002 02:17:39 -0000 1.570
--- cp/decl2.c 4 Nov 2002 01:34:27 -0000
*************** typedef struct priority_info_s {
*** 58,68 ****
int destructions_p;
} *priority_info;
static void mark_vtable_entries PARAMS ((tree));
static void grok_function_init PARAMS ((tree, tree));
! static int finish_vtable_vardecl PARAMS ((tree *, void *));
static int is_namespace_ancestor PARAMS ((tree, tree));
static void add_using_namespace PARAMS ((tree, tree, int));
static tree ambiguous_decl PARAMS ((tree, tree, tree,int));
static tree build_anon_union_vars PARAMS ((tree, tree*, int, int));
static int acceptable_java_type PARAMS ((tree));
--- 58,68 ----
int destructions_p;
} *priority_info;
static void mark_vtable_entries PARAMS ((tree));
static void grok_function_init PARAMS ((tree, tree));
! static int maybe_emit_vtables (tree);
static int is_namespace_ancestor PARAMS ((tree, tree));
static void add_using_namespace PARAMS ((tree, tree, int));
static tree ambiguous_decl PARAMS ((tree, tree, tree,int));
static tree build_anon_union_vars PARAMS ((tree, tree*, int, int));
static int acceptable_java_type PARAMS ((tree));
*************** key_method (type)
*** 1656,1671 ****
for (method = TYPE_METHODS (type); method != NULL_TREE;
method = TREE_CHAIN (method))
if (DECL_VINDEX (method) != NULL_TREE
&& ! DECL_DECLARED_INLINE_P (method)
! && (! DECL_PURE_VIRTUAL_P (method)
! #if 0
! /* This would be nice, but we didn't think of it in time. */
! || DECL_DESTRUCTOR_P (method)
! #endif
! ))
return method;
return NULL_TREE;
}
--- 1656,1666 ----
for (method = TYPE_METHODS (type); method != NULL_TREE;
method = TREE_CHAIN (method))
if (DECL_VINDEX (method) != NULL_TREE
&& ! DECL_DECLARED_INLINE_P (method)
! && ! DECL_PURE_VIRTUAL_P (method))
return method;
return NULL_TREE;
}
*************** output_vtable_inherit (vars)
*** 1803,1834 ****
abort ();
assemble_vtable_inherit (child_rtx, parent_rtx);
}
static int
! finish_vtable_vardecl (t, data)
! tree *t;
! void *data ATTRIBUTE_UNUSED;
{
! tree vars = *t;
! tree ctype = DECL_CONTEXT (vars);
import_export_class (ctype);
! import_export_vtable (vars, ctype, 1);
! if (! DECL_EXTERNAL (vars)
! && DECL_NEEDED_P (vars)
! && ! TREE_ASM_WRITTEN (vars))
! {
! if (TREE_TYPE (vars) == void_type_node)
! /* It is a dummy vtable made by get_vtable_decl. Ignore it. */
! return 0;
!
/* Write it out. */
! mark_vtable_entries (vars);
! if (TREE_TYPE (DECL_INITIAL (vars)) == 0)
! store_init_value (vars, DECL_INITIAL (vars));
if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
{
/* Mark the VAR_DECL node representing the vtable itself as a
"gratuitous" one, thereby forcing dwarfout.c to ignore it.
--- 1798,1853 ----
abort ();
assemble_vtable_inherit (child_rtx, parent_rtx);
}
+ /* If necessary, write out the vtables for the dynamic class CTYPE.
+ Returns non-zero if any vtables were emitted. */
+
static int
! maybe_emit_vtables (tree ctype)
{
! tree vtbl;
! tree primary_vtbl;
!
! /* If the vtables for this class have already been emitted there is
! nothing more to do. */
! primary_vtbl = CLASSTYPE_VTABLES (ctype);
! if (TREE_ASM_WRITTEN (primary_vtbl))
! return 0;
! /* Ignore dummy vtables made by get_vtable_decl. */
! if (TREE_TYPE (primary_vtbl) == void_type_node)
! return 0;
!
import_export_class (ctype);
! import_export_vtable (primary_vtbl, ctype, 1);
! /* See if any of the vtables are needed. */
! for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl))
! if (!DECL_EXTERNAL (vtbl) && DECL_NEEDED_P (vtbl))
! break;
!
! if (!vtbl)
! {
! /* If the references to this class' vtables are optimized away,
! still emit the appropriate debugging information. See
! dfs_debug_mark. */
! if (DECL_COMDAT (primary_vtbl)
! && CLASSTYPE_DEBUG_REQUESTED (ctype))
! note_debug_info_needed (ctype);
! return 0;
! }
!
! /* The ABI requires that we emit all of the vtables if we emit any
! of them. */
! for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl))
! {
/* Write it out. */
! import_export_vtable (vtbl, ctype, 1);
! mark_vtable_entries (vtbl);
! if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)
! store_init_value (vtbl, DECL_INITIAL (vtbl));
if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
{
/* Mark the VAR_DECL node representing the vtable itself as a
"gratuitous" one, thereby forcing dwarfout.c to ignore it.
*************** finish_vtable_vardecl (t, data)
*** 1849,1889 ****
We might be able to arrange to have the "vtable static member"
attached to the member list for `S' before the debug info for
`S' get written (which would solve the problem) but that would
require more intrusive changes to the g++ front end. */
! DECL_IGNORED_P (vars) = 1;
}
/* Always make vtables weak. */
if (flag_weak)
! comdat_linkage (vars);
! rest_of_decl_compilation (vars, NULL, 1, 1);
if (flag_vtable_gc)
! output_vtable_inherit (vars);
/* Because we're only doing syntax-checking, we'll never end up
actually marking the variable as written. */
if (flag_syntax_only)
! TREE_ASM_WRITTEN (vars) = 1;
!
! /* Since we're writing out the vtable here, also write the debug
! info. */
! note_debug_info_needed (ctype);
!
! return 1;
}
! /* If the references to this class' vtables were optimized away, still
! emit the appropriate debugging information. See dfs_debug_mark. */
! if (DECL_COMDAT (vars)
! && CLASSTYPE_DEBUG_REQUESTED (ctype))
! note_debug_info_needed (ctype);
! return 0;
}
/* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an
inline function or template instantiation at end-of-file. */
--- 1868,1900 ----
We might be able to arrange to have the "vtable static member"
attached to the member list for `S' before the debug info for
`S' get written (which would solve the problem) but that would
require more intrusive changes to the g++ front end. */
! DECL_IGNORED_P (vtbl) = 1;
}
/* Always make vtables weak. */
if (flag_weak)
! comdat_linkage (vtbl);
! rest_of_decl_compilation (vtbl, NULL, 1, 1);
if (flag_vtable_gc)
! output_vtable_inherit (vtbl);
/* Because we're only doing syntax-checking, we'll never end up
actually marking the variable as written. */
if (flag_syntax_only)
! TREE_ASM_WRITTEN (vtbl) = 1;
}
! /* Since we're writing out the vtable here, also write the debug
! info. */
! note_debug_info_needed (ctype);
! return 1;
}
/* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an
inline function or template instantiation at end-of-file. */
*************** finish_file ()
*** 2753,2775 ****
emit_support_tinfos ();
do
{
reconsider = 0;
/* If there are templates that we've put off instantiating, do
them now. */
instantiate_pending_templates ();
/* Write out virtual tables as required. Note that writing out
the virtual table for a template class may cause the
instantiation of members of that class. */
! if (walk_vtables (vtable_decl_p,
! finish_vtable_vardecl,
! /*data=*/0))
! reconsider = 1;
/* Write out needed type info variables. Writing out one variable
might cause others to be needed. */
if (walk_globals (unemitted_tinfo_decl_p, emit_tinfo_decl, /*data=*/0))
reconsider = 1;
--- 2764,2787 ----
emit_support_tinfos ();
do
{
+ tree t;
+
reconsider = 0;
/* If there are templates that we've put off instantiating, do
them now. */
instantiate_pending_templates ();
/* Write out virtual tables as required. Note that writing out
the virtual table for a template class may cause the
instantiation of members of that class. */
! for (t = dynamic_classes; t; t = TREE_CHAIN (t))
! if (maybe_emit_vtables (TREE_VALUE (t)))
! reconsider = 1;
/* Write out needed type info variables. Writing out one variable
might cause others to be needed. */
if (walk_globals (unemitted_tinfo_decl_p, emit_tinfo_decl, /*data=*/0))
reconsider = 1;
Index: cp/search.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/search.c,v
retrieving revision 1.239
diff -c -5 -p -r1.239 search.c
*** cp/search.c 30 Sep 2002 16:52:14 -0000 1.239
--- cp/search.c 4 Nov 2002 01:34:28 -0000
*************** look_for_overrides (type, fndecl)
*** 1953,1965 ****
found += look_for_overrides_r (basetype, fndecl);
}
return found;
}
! /* Look in TYPE for virtual functions with the same signature as FNDECL.
! This differs from get_matching_virtual in that it will only return
! a function from TYPE. */
tree
look_for_overrides_here (type, fndecl)
tree type, fndecl;
{
--- 1953,1964 ----
found += look_for_overrides_r (basetype, fndecl);
}
return found;
}
! /* Look in TYPE for virtual functions with the same signature as
! FNDECL. */
tree
look_for_overrides_here (type, fndecl)
tree type, fndecl;
{
Index: testsuite/g++.dg/abi/thunk1.C
===================================================================
RCS file: testsuite/g++.dg/abi/thunk1.C
diff -N testsuite/g++.dg/abi/thunk1.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/thunk1.C 4 Nov 2002 01:34:29 -0000
***************
*** 0 ****
--- 1,22 ----
+ // { dg-do compile { target i?86-*-* } }
+
+ struct A {
+ virtual void f ();
+ };
+
+ struct B : public virtual A {
+ virtual void f ();
+ };
+
+ struct C {
+ virtual void g ();
+ };
+
+ struct D : public C, public B {
+ virtual void f ();
+ };
+
+ void D::f () {}
+
+ // { dg-final { scan-assembler _ZThn4_N1D1fEv } }
+ // { dg-final { scan-assembler _ZTv0_n12_N1D1fEv } }
Index: testsuite/g++.dg/abi/thunk2.C
===================================================================
RCS file: testsuite/g++.dg/abi/thunk2.C
diff -N testsuite/g++.dg/abi/thunk2.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/thunk2.C 4 Nov 2002 01:34:29 -0000
***************
*** 0 ****
--- 1,26 ----
+ // { dg-do compile { target i?86-*-* } }
+ // { dg-options -w }
+
+ struct A {
+ virtual void f2 ();
+ virtual void f3 ();
+ };
+
+ struct B : virtual public A {
+ virtual void f3 ();
+ };
+
+ struct C : public A, public B {
+ virtual void f4 ();
+ };
+
+ struct D : virtual public B, virtual public C, virtual public A
+ {
+ virtual void f5 ();
+ virtual void f6 ();
+ virtual void f3 ();
+ };
+
+ void D::f3 () {}
+
+ // { dg-final { scan-assembler _ZTvn4_n20_N1D2f3Ev } }
Index: testsuite/g++.dg/abi/vtt1.C
===================================================================
RCS file: testsuite/g++.dg/abi/vtt1.C
diff -N testsuite/g++.dg/abi/vtt1.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/vtt1.C 4 Nov 2002 01:34:29 -0000
***************
*** 0 ****
--- 1,11 ----
+ // { dg-do compile }
+
+ struct A {
+ };
+
+ struct B : virtual public A {
+ };
+
+ B b;
+
+ // { dg-final { scan-assembler _ZTT1B } }