mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-26 22:41:23 +08:00
call.c (build_special_member_call): Do not try to lookup VTTs by name.
* 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. * g++.dg/abi/thunk1.C: New test. * g++.dg/abi/thunk2.C: Likewise. * g++.dg/abi/vtt1.C: Likewise. From-SVN: r58779
This commit is contained in:
parent
55376e4128
commit
548502d3b1
@ -1,3 +1,40 @@
|
||||
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-01 Zack Weinberg <zack@codesourcery.com>
|
||||
|
||||
PR c/7353 redux
|
||||
|
@ -4712,7 +4712,7 @@ build_special_member_call (tree instance, tree name, tree args,
|
||||
/* 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 = TREE_CHAIN (CLASSTYPE_VTABLES (current_class_type));
|
||||
vtt = decay_conversion (vtt);
|
||||
vtt = build (COND_EXPR, TREE_TYPE (vtt),
|
||||
build (EQ_EXPR, boolean_type_node,
|
||||
|
287
gcc/cp/class.c
287
gcc/cp/class.c
@ -87,6 +87,9 @@ typedef struct vtbl_init_data_s
|
||||
/* 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. */
|
||||
@ -209,6 +212,7 @@ 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
|
||||
@ -540,21 +544,14 @@ 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);
|
||||
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),
|
||||
@ -581,10 +578,7 @@ copy_virtuals (binfo)
|
||||
|
||||
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;
|
||||
}
|
||||
BV_VCALL_INDEX (t) = NULL_TREE;
|
||||
|
||||
return copies;
|
||||
}
|
||||
@ -1559,7 +1553,6 @@ set_primary_base (t, 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. */
|
||||
@ -1585,12 +1578,6 @@ determine_primary_base (t)
|
||||
|
||||
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))
|
||||
@ -2325,21 +2312,23 @@ find_final_overrider (t, binfo, fn)
|
||||
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. */
|
||||
/* Return the index of the vcall offset for FN when TYPE is used as a
|
||||
virtual base. */
|
||||
|
||||
static tree get_matching_virtual PARAMS ((tree, tree));
|
||||
static tree
|
||||
get_matching_virtual (t, fn)
|
||||
tree t, fn;
|
||||
get_vcall_index (tree fn, tree type)
|
||||
{
|
||||
tree f;
|
||||
tree v;
|
||||
|
||||
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;
|
||||
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
|
||||
@ -2407,7 +2396,6 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
|
||||
/* 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. */
|
||||
@ -2420,36 +2408,11 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 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,
|
||||
@ -2458,7 +2421,9 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
|
||||
virtuals);
|
||||
|
||||
if (virtual_base)
|
||||
BV_USE_VCALL_INDEX_P (*virtuals) = 1;
|
||||
BV_VCALL_INDEX (*virtuals)
|
||||
= get_vcall_index (TREE_PURPOSE (overrider),
|
||||
BINFO_TYPE (virtual_base));
|
||||
}
|
||||
|
||||
/* Called from modify_all_vtables via dfs_walk. */
|
||||
@ -5101,32 +5066,8 @@ layout_class_type (tree t, tree *virtuals_p)
|
||||
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. */
|
||||
/* Perform processing required when the definition of T (a class type)
|
||||
is complete. */
|
||||
|
||||
void
|
||||
finish_struct_1 (t)
|
||||
@ -5153,7 +5094,6 @@ finish_struct_1 (t)
|
||||
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);
|
||||
|
||||
@ -5210,24 +5150,6 @@ finish_struct_1 (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))
|
||||
@ -5253,6 +5175,9 @@ finish_struct_1 (t)
|
||||
? 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);
|
||||
@ -7068,8 +6993,10 @@ build_vtt (t)
|
||||
|
||||
/* Now, build the VTT object itself. */
|
||||
vtt = build_vtable (t, get_vtt_name (t), type);
|
||||
pushdecl_top_level (vtt);
|
||||
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);
|
||||
}
|
||||
@ -7404,7 +7331,7 @@ build_ctor_vtbl_group (binfo, t)
|
||||
TREE_TYPE (vtbl) = type;
|
||||
|
||||
/* Initialize the construction vtable. */
|
||||
pushdecl_top_level (vtbl);
|
||||
CLASSTYPE_VTABLES (t) = chainon (CLASSTYPE_VTABLES (t), vtbl);
|
||||
initialize_array (vtbl, inits);
|
||||
dump_vtable (t, binfo, vtbl);
|
||||
}
|
||||
@ -7621,6 +7548,7 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
|
||||
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);
|
||||
|
||||
@ -7704,14 +7632,7 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
|
||||
/* 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;
|
||||
vcall_index = BV_VCALL_INDEX (v);
|
||||
|
||||
my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
|
||||
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
|
||||
@ -7900,31 +7821,37 @@ 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 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:
|
||||
|
||||
/* 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 (); };
|
||||
|
||||
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.
|
||||
|
||||
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);
|
||||
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. */
|
||||
@ -8025,8 +7952,6 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid)
|
||||
{
|
||||
tree orig_fn;
|
||||
tree fn;
|
||||
tree base;
|
||||
tree base_binfo;
|
||||
size_t i;
|
||||
tree vcall_offset;
|
||||
|
||||
@ -8057,42 +7982,17 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid)
|
||||
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;
|
||||
}
|
||||
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;
|
||||
/* 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. */
|
||||
@ -8101,6 +8001,35 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid)
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,6 @@ struct diagnostic_context;
|
||||
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.
|
||||
@ -133,9 +132,7 @@ struct diagnostic_context;
|
||||
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.
|
||||
index of the vcall offset for this entry.
|
||||
|
||||
The BV_FN is the declaration for the virtual function itself.
|
||||
|
||||
@ -615,6 +612,8 @@ enum cp_tree_index
|
||||
CPTI_DSO_HANDLE,
|
||||
CPTI_DCAST,
|
||||
|
||||
CPTI_DYNAMIC_CLASSES,
|
||||
|
||||
CPTI_MAX
|
||||
};
|
||||
|
||||
@ -745,6 +744,10 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
|
||||
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(())
|
||||
@ -1153,12 +1156,13 @@ struct lang_type_class GTY(())
|
||||
|
||||
tree primary_base;
|
||||
tree vfields;
|
||||
tree vcall_indices;
|
||||
tree vtables;
|
||||
tree vbases;
|
||||
tree tags;
|
||||
tree as_base;
|
||||
tree pure_virtuals;
|
||||
tree friend_classes;
|
||||
tree rtti;
|
||||
tree methods;
|
||||
tree decl_list;
|
||||
tree template_info;
|
||||
@ -1257,9 +1261,6 @@ struct lang_type GTY(())
|
||||
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)
|
||||
@ -1431,13 +1432,6 @@ struct lang_type GTY(())
|
||||
/* 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)
|
||||
@ -1629,6 +1623,19 @@ struct lang_type GTY(())
|
||||
/* 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. */
|
||||
#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
|
||||
@ -1664,8 +1671,6 @@ struct lang_type GTY(())
|
||||
/* 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. */
|
||||
@ -3546,7 +3551,6 @@ 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));
|
||||
|
106
gcc/cp/decl2.c
106
gcc/cp/decl2.c
@ -60,7 +60,7 @@ typedef struct priority_info_s {
|
||||
|
||||
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 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));
|
||||
@ -1658,12 +1658,7 @@ key_method (type)
|
||||
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
|
||||
))
|
||||
&& ! DECL_PURE_VIRTUAL_P (method))
|
||||
return method;
|
||||
|
||||
return NULL_TREE;
|
||||
@ -1805,28 +1800,52 @@ output_vtable_inherit (vars)
|
||||
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 necessary, write out the vtables for the dynamic class CTYPE.
|
||||
Returns non-zero if any vtables were emitted. */
|
||||
|
||||
if (! DECL_EXTERNAL (vars)
|
||||
&& DECL_NEEDED_P (vars)
|
||||
&& ! TREE_ASM_WRITTEN (vars))
|
||||
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))
|
||||
{
|
||||
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));
|
||||
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)
|
||||
{
|
||||
@ -1851,37 +1870,29 @@ finish_vtable_vardecl (t, data)
|
||||
`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;
|
||||
DECL_IGNORED_P (vtbl) = 1;
|
||||
}
|
||||
|
||||
/* Always make vtables weak. */
|
||||
if (flag_weak)
|
||||
comdat_linkage (vars);
|
||||
comdat_linkage (vtbl);
|
||||
|
||||
rest_of_decl_compilation (vars, NULL, 1, 1);
|
||||
rest_of_decl_compilation (vtbl, NULL, 1, 1);
|
||||
|
||||
if (flag_vtable_gc)
|
||||
output_vtable_inherit (vars);
|
||||
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 (vars) = 1;
|
||||
|
||||
/* Since we're writing out the vtable here, also write the debug
|
||||
info. */
|
||||
note_debug_info_needed (ctype);
|
||||
|
||||
return 1;
|
||||
TREE_ASM_WRITTEN (vtbl) = 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);
|
||||
/* Since we're writing out the vtable here, also write the debug
|
||||
info. */
|
||||
note_debug_info_needed (ctype);
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an
|
||||
@ -2755,6 +2766,8 @@ finish_file ()
|
||||
|
||||
do
|
||||
{
|
||||
tree t;
|
||||
|
||||
reconsider = 0;
|
||||
|
||||
/* If there are templates that we've put off instantiating, do
|
||||
@ -2764,10 +2777,9 @@ finish_file ()
|
||||
/* 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;
|
||||
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. */
|
||||
|
@ -1955,9 +1955,8 @@ look_for_overrides (type, 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. */
|
||||
/* Look in TYPE for virtual functions with the same signature as
|
||||
FNDECL. */
|
||||
|
||||
tree
|
||||
look_for_overrides_here (type, fndecl)
|
||||
|
@ -1,3 +1,9 @@
|
||||
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.
|
||||
|
||||
2002-11-02 Diego Novillo <dnovillo@redhat.com>
|
||||
|
||||
PR optimization/8423
|
||||
|
22
gcc/testsuite/g++.dg/abi/thunk1.C
Normal file
22
gcc/testsuite/g++.dg/abi/thunk1.C
Normal file
@ -0,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 } }
|
26
gcc/testsuite/g++.dg/abi/thunk2.C
Normal file
26
gcc/testsuite/g++.dg/abi/thunk2.C
Normal file
@ -0,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 } }
|
11
gcc/testsuite/g++.dg/abi/vtt1.C
Normal file
11
gcc/testsuite/g++.dg/abi/vtt1.C
Normal file
@ -0,0 +1,11 @@
|
||||
// { dg-do compile }
|
||||
|
||||
struct A {
|
||||
};
|
||||
|
||||
struct B : virtual public A {
|
||||
};
|
||||
|
||||
B b;
|
||||
|
||||
// { dg-final { scan-assembler _ZTT1B } }
|
Loading…
x
Reference in New Issue
Block a user