Commit e6a66567 by Mark Mitchell Committed by Mark Mitchell

class.c (add_vcall_offset_vtbl_entries_1): Correct ordering of vcall offfsets.

	* class.c (add_vcall_offset_vtbl_entries_1): Correct ordering of
	vcall offfsets.  Split out ...
	(add_vcall_offset): ... new function.

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

From-SVN: r58912
parent 4f2c9d7e
2002-11-07 Mark Mitchell <mark@codesourcery.com> 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 PR c++/8338
* pt.c (for_each_template_parm): Add htab parameter. * pt.c (for_each_template_parm): Add htab parameter.
(process_partial_specialization): Adjust call. (process_partial_specialization): Adjust call.
......
...@@ -156,6 +156,7 @@ static void build_vbase_offset_vtbl_entries PARAMS ((tree, vtbl_init_data *)); ...@@ -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_r PARAMS ((tree, vtbl_init_data *));
static void add_vcall_offset_vtbl_entries_1 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 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 void layout_vtable_decl PARAMS ((tree, int));
static tree dfs_find_final_overrider PARAMS ((tree, void *)); static tree dfs_find_final_overrider PARAMS ((tree, void *));
static tree find_final_overrider PARAMS ((tree, tree, tree)); static tree find_final_overrider PARAMS ((tree, tree, tree));
...@@ -7908,116 +7909,154 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid) ...@@ -7908,116 +7909,154 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid)
tree binfo; tree binfo;
vtbl_init_data* vid; vtbl_init_data* vid;
{ {
tree derived_virtuals; tree binfo_in_rtti;
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;
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 /* Make entries for the rest of the virtuals. */
until we find the most derived class of which we are a primary base: if (abi_version_at_least (2))
it is the BINFO_VIRTUALS there that we need to consider. */
non_primary_binfo = binfo;
while (BINFO_INHERITANCE_CHAIN (non_primary_binfo))
{ {
tree b; tree orig_fn;
/* If we have reached a virtual base, then it must be vid->vbase, /* The ABI requires that the methods be processed in declaration
because we ignore other virtual bases in order. G++ 3.2 used the order in the vtable. */
add_vcall_offset_vtbl_entries_r. In turn, it must be a primary for (orig_fn = TYPE_METHODS (BINFO_TYPE (binfo));
base (possibly multi-level) of vid->binfo, or we wouldn't orig_fn;
have called build_vcall_and_vbase_vtbl_entries for it. But it orig_fn = TREE_CHAIN (orig_fn))
might be a lost primary, so just skip down to vid->binfo. */ if (DECL_VINDEX (orig_fn))
if (TREE_VIA_VIRTUAL (non_primary_binfo)) 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) tree b;
abort ();
non_primary_binfo = vid->binfo; /* If we have reached a virtual base, then it must be vid->vbase,
break; 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); b = BINFO_INHERITANCE_CHAIN (non_primary_binfo);
if (get_primary_binfo (b) != non_primary_binfo) if (get_primary_binfo (b) != non_primary_binfo)
break; break;
non_primary_binfo = b; non_primary_binfo = b;
} }
if (vid->ctor_vtbl_p) if (vid->ctor_vtbl_p)
/* For a ctor vtable we need the equivalent binfo within the hierarchy /* For a ctor vtable we need the equivalent binfo within the hierarchy
where rtti_binfo is the most derived type. */ where rtti_binfo is the most derived type. */
non_primary_binfo = get_original_base non_primary_binfo = get_original_base
(non_primary_binfo, TYPE_BINFO (BINFO_TYPE (vid->rtti_binfo))); (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. */ /* Find the declaration that originally caused this function to
for (base_virtuals = BINFO_VIRTUALS (binfo), be present in BINFO_TYPE (binfo). */
derived_virtuals = BINFO_VIRTUALS (non_primary_binfo), orig_fn = BV_FN (orig_virtuals);
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 /* When processing BINFO, we only want to generate vcall slots for
be present in BINFO_TYPE (binfo). */ function slots introduced in BINFO. So don't try to generate
orig_fn = BV_FN (orig_virtuals); 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 add_vcall_offset (orig_fn, binfo_in_rtti, vid);
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;
/* Find the overriding function. */ /* Add a vcall offset entry for ORIG_FN to the vtable. In a
fn = BV_FN (derived_virtuals); 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 static void
signature as FN, then we do not need a second vcall offset. add_vcall_offset (tree orig_fn, tree binfo_in_rtti,
Check the list of functions already present in the derived vtbl_init_data *vid)
class vtable. */ {
for (i = 0; i < VARRAY_ACTIVE_SIZE (vid->fns); ++i) size_t i;
{ tree vcall_offset;
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;
/* If we are building these vcall offsets as part of building /* If there is already an entry for a function with the same
the vtable for the most derived class, remember the vcall signature as FN, then we do not need a second vcall offset.
offset. */ Check the list of functions already present in the derived
if (vid->binfo == TYPE_BINFO (vid->derived)) class vtable. */
CLASSTYPE_VCALL_INDICES (vid->derived) for (i = 0; i < VARRAY_ACTIVE_SIZE (vid->fns); ++i)
= tree_cons (fn, vid->index, CLASSTYPE_VCALL_INDICES (vid->derived)); {
tree derived_entry;
/* The next vcall offset will be found at a more negative derived_entry = VARRAY_TREE (vid->fns, i);
offset. */ if (same_signature_p (derived_entry, orig_fn)
vid->index = size_binop (MINUS_EXPR, vid->index, /* We only use one vcall offset for virtual destructors,
ssize_int (TARGET_VTABLE_DATA_ENTRY_DISTANCE)); even though there are two virtual table entries. */
|| (DECL_DESTRUCTOR_P (derived_entry)
&& DECL_DESTRUCTOR_P (orig_fn)))
return;
}
/* Keep track of this function. */ /* If we are building these vcall offsets as part of building
VARRAY_PUSH_TREE (vid->fns, derived_virtuals); 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) /* The next vcall offset will be found at a more negative
{ offset. */
tree base; vid->index = size_binop (MINUS_EXPR, vid->index,
tree base_binfo; 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 /* The FN comes from BASE. So, we must calculate the
adjustment from vid->vbase to BASE. We can just look for adjustment from vid->vbase to BASE. We can just look for
BASE in the complete object because we are converting BASE in the complete object because we are converting
...@@ -8037,10 +8076,10 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid) ...@@ -8037,10 +8076,10 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid)
vcall_offset); vcall_offset);
vcall_offset = fold (build1 (NOP_EXPR, vtable_entry_type, vcall_offset = fold (build1 (NOP_EXPR, vtable_entry_type,
vcall_offset)); 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);
} }
} }
......
2002-11-07 Mark Mitchell <mark@codesourcery.com> 2002-11-07 Mark Mitchell <mark@codesourcery.com>
* g++.dg/abi/vthunk3.C: New test.
PR c++/8338 PR c++/8338
* g++.dg/template/crash2.C: New test. * g++.dg/template/crash2.C: New test.
......
// { 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 } }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment