Commit 548502d3 by Mark Mitchell Committed by Mark Mitchell

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
parent 55376e41
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> 2002-11-01 Zack Weinberg <zack@codesourcery.com>
PR c/7353 redux PR c/7353 redux
......
...@@ -4712,7 +4712,7 @@ build_special_member_call (tree instance, tree name, tree args, ...@@ -4712,7 +4712,7 @@ build_special_member_call (tree instance, tree name, tree args,
/* If the current function is a complete object constructor /* If the current function is a complete object constructor
or destructor, then we fetch the VTT directly. or destructor, then we fetch the VTT directly.
Otherwise, we look it up using the VTT we were given. */ 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 = decay_conversion (vtt);
vtt = build (COND_EXPR, TREE_TYPE (vtt), vtt = build (COND_EXPR, TREE_TYPE (vtt),
build (EQ_EXPR, boolean_type_node, build (EQ_EXPR, boolean_type_node,
......
...@@ -87,6 +87,9 @@ typedef struct vtbl_init_data_s ...@@ -87,6 +87,9 @@ typedef struct vtbl_init_data_s
/* Nonzero if we are building the initializer for a construction /* Nonzero if we are building the initializer for a construction
vtable. */ vtable. */
int ctor_vtbl_p; 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; } vtbl_init_data;
/* The type of a function passed to walk_subobject_offsets. */ /* The type of a function passed to walk_subobject_offsets. */
...@@ -209,6 +212,7 @@ static tree dfs_base_derived_from (tree, void *); ...@@ -209,6 +212,7 @@ static tree dfs_base_derived_from (tree, void *);
static bool base_derived_from (tree, tree); static bool base_derived_from (tree, tree);
static int empty_base_at_nonzero_offset_p (tree, tree, splay_tree); static int empty_base_at_nonzero_offset_p (tree, tree, splay_tree);
static tree end_of_base (tree); static tree end_of_base (tree);
static tree get_vcall_index (tree, tree);
/* Macros for dfs walking during vtt construction. See /* Macros for dfs walking during vtt construction. See
dfs_ctor_vtable_bases_queue_p, dfs_build_secondary_vptr_vtt_inits dfs_ctor_vtable_bases_queue_p, dfs_build_secondary_vptr_vtt_inits
...@@ -540,21 +544,14 @@ get_vtable_decl (type, complete) ...@@ -540,21 +544,14 @@ get_vtable_decl (type, complete)
tree type; tree type;
int complete; int complete;
{ {
tree name = get_vtable_name (type); tree decl;
tree decl = IDENTIFIER_GLOBAL_VALUE (name);
if (CLASSTYPE_VTABLES (type))
if (decl) return CLASSTYPE_VTABLES (type);
{
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);
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 /* At one time the vtable info was grabbed 2 words at a time. This
fails on sparc unless you have 8-byte alignment. (tiemann) */ fails on sparc unless you have 8-byte alignment. (tiemann) */
DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node), DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),
...@@ -581,10 +578,7 @@ copy_virtuals (binfo) ...@@ -581,10 +578,7 @@ copy_virtuals (binfo)
copies = copy_list (BINFO_VIRTUALS (binfo)); copies = copy_list (BINFO_VIRTUALS (binfo));
for (t = copies; t; t = TREE_CHAIN (t)) for (t = copies; t; t = TREE_CHAIN (t))
{ BV_VCALL_INDEX (t) = NULL_TREE;
BV_VCALL_INDEX (t) = NULL_TREE;
BV_USE_VCALL_INDEX_P (t) = 0;
}
return copies; return copies;
} }
...@@ -1559,7 +1553,6 @@ set_primary_base (t, binfo) ...@@ -1559,7 +1553,6 @@ set_primary_base (t, binfo)
TYPE_BINFO_VTABLE (t) = TYPE_BINFO_VTABLE (basetype); TYPE_BINFO_VTABLE (t) = TYPE_BINFO_VTABLE (basetype);
TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS (basetype); TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS (basetype);
TYPE_VFIELD (t) = TYPE_VFIELD (basetype); TYPE_VFIELD (t) = TYPE_VFIELD (basetype);
CLASSTYPE_RTTI (t) = CLASSTYPE_RTTI (basetype);
} }
/* Determine the primary class for T. */ /* Determine the primary class for T. */
...@@ -1585,12 +1578,6 @@ determine_primary_base (t) ...@@ -1585,12 +1578,6 @@ determine_primary_base (t)
if (TYPE_CONTAINS_VPTR_P (basetype)) 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 /* We prefer a non-virtual base, although a virtual one will
do. */ do. */
if (TREE_VIA_VIRTUAL (base_binfo)) if (TREE_VIA_VIRTUAL (base_binfo))
...@@ -2325,21 +2312,23 @@ find_final_overrider (t, binfo, fn) ...@@ -2325,21 +2312,23 @@ find_final_overrider (t, binfo, fn)
return ffod.candidates; return ffod.candidates;
} }
/* Returns the function from the BINFO_VIRTUALS entry in T which matches /* Return the index of the vcall offset for FN when TYPE is used as a
the signature of FUNCTION_DECL FN, or NULL_TREE if none. In other words, virtual base. */
the function that the slot in T's primary vtable points to. */
static tree get_matching_virtual PARAMS ((tree, tree));
static tree static tree
get_matching_virtual (t, fn) get_vcall_index (tree fn, tree type)
tree t, fn;
{ {
tree f; tree v;
for (f = BINFO_VIRTUALS (TYPE_BINFO (t)); f; f = TREE_CHAIN (f)) for (v = CLASSTYPE_VCALL_INDICES (type); v; v = TREE_CHAIN (v))
if (same_signature_p (BV_FN (f), fn)) if ((DECL_DESTRUCTOR_P (fn) && DECL_DESTRUCTOR_P (TREE_PURPOSE (v)))
return BV_FN (f); || same_signature_p (fn, TREE_PURPOSE (v)))
return NULL_TREE; 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 /* 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) ...@@ -2407,7 +2396,6 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
/* Compute the constant adjustment to the `this' pointer. The /* Compute the constant adjustment to the `this' pointer. The
`this' pointer, when this function is called, will point at BINFO `this' pointer, when this function is called, will point at BINFO
(or one of its primary bases, which are at the same offset). */ (or one of its primary bases, which are at the same offset). */
if (virtual_base) if (virtual_base)
/* The `this' pointer needs to be adjusted from the declaration to /* The `this' pointer needs to be adjusted from the declaration to
the nearest virtual base. */ the nearest virtual base. */
...@@ -2420,36 +2408,11 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals) ...@@ -2420,36 +2408,11 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
will be zero, as it will be a primary base. */ will be zero, as it will be a primary base. */
delta = size_zero_node; delta = size_zero_node;
else else
{ /* The `this' pointer needs to be adjusted from pointing to
/* The `this' pointer needs to be adjusted from pointing to BINFO to pointing at the base where the final overrider
BINFO to pointing at the base where the final overrider appears. */
appears. */ delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)),
delta = size_diffop (BINFO_OFFSET (TREE_VALUE (overrider)), BINFO_OFFSET (binfo));
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, modify_vtable_entry (t,
binfo, binfo,
...@@ -2458,7 +2421,9 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals) ...@@ -2458,7 +2421,9 @@ update_vtable_entry_for_fn (t, binfo, fn, virtuals)
virtuals); virtuals);
if (virtual_base) 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. */ /* Called from modify_all_vtables via dfs_walk. */
...@@ -5101,32 +5066,8 @@ layout_class_type (tree t, tree *virtuals_p) ...@@ -5101,32 +5066,8 @@ layout_class_type (tree t, tree *virtuals_p)
splay_tree_delete (empty_base_offsets); splay_tree_delete (empty_base_offsets);
} }
/* Create a RECORD_TYPE or UNION_TYPE node for a C struct or union declaration /* Perform processing required when the definition of T (a class type)
(or C++ class declaration). is complete. */
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 void
finish_struct_1 (t) finish_struct_1 (t)
...@@ -5153,7 +5094,6 @@ finish_struct_1 (t) ...@@ -5153,7 +5094,6 @@ finish_struct_1 (t)
TYPE_SIZE (t) = NULL_TREE; TYPE_SIZE (t) = NULL_TREE;
CLASSTYPE_GOT_SEMICOLON (t) = 0; CLASSTYPE_GOT_SEMICOLON (t) = 0;
CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE; CLASSTYPE_PRIMARY_BINFO (t) = NULL_TREE;
CLASSTYPE_RTTI (t) = NULL_TREE;
fixup_inline_methods (t); fixup_inline_methods (t);
...@@ -5210,24 +5150,6 @@ finish_struct_1 (t) ...@@ -5210,24 +5150,6 @@ finish_struct_1 (t)
/* Here we know enough to change the type of our virtual /* Here we know enough to change the type of our virtual
function table, but we will wait until later this function. */ function table, but we will wait until later this function. */
build_primary_vtable (CLASSTYPE_PRIMARY_BINFO (t), t); 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)) if (TYPE_CONTAINS_VPTR_P (t))
...@@ -5253,6 +5175,9 @@ finish_struct_1 (t) ...@@ -5253,6 +5175,9 @@ finish_struct_1 (t)
? TARGET_VTABLE_USES_DESCRIPTORS : 1)) ? TARGET_VTABLE_USES_DESCRIPTORS : 1))
if (TREE_CODE (DECL_VINDEX (BV_FN (fn))) != INTEGER_CST) if (TREE_CODE (DECL_VINDEX (BV_FN (fn))) != INTEGER_CST)
DECL_VINDEX (BV_FN (fn)) = build_shared_int_cst (vindex); 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); finish_struct_bits (t);
...@@ -7068,8 +6993,10 @@ build_vtt (t) ...@@ -7068,8 +6993,10 @@ build_vtt (t)
/* Now, build the VTT object itself. */ /* Now, build the VTT object itself. */
vtt = build_vtable (t, get_vtt_name (t), type); vtt = build_vtable (t, get_vtt_name (t), type);
pushdecl_top_level (vtt);
initialize_array (vtt, inits); 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); dump_vtt (t, vtt);
} }
...@@ -7404,7 +7331,7 @@ build_ctor_vtbl_group (binfo, t) ...@@ -7404,7 +7331,7 @@ build_ctor_vtbl_group (binfo, t)
TREE_TYPE (vtbl) = type; TREE_TYPE (vtbl) = type;
/* Initialize the construction vtable. */ /* Initialize the construction vtable. */
pushdecl_top_level (vtbl); CLASSTYPE_VTABLES (t) = chainon (CLASSTYPE_VTABLES (t), vtbl);
initialize_array (vtbl, inits); initialize_array (vtbl, inits);
dump_vtable (t, binfo, vtbl); dump_vtable (t, binfo, vtbl);
} }
...@@ -7621,6 +7548,7 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p) ...@@ -7621,6 +7548,7 @@ build_vtbl_initializer (binfo, orig_binfo, t, rtti_binfo, non_fn_entries_p)
vid.last_init = &vid.inits; vid.last_init = &vid.inits;
vid.primary_vtbl_p = (binfo == TYPE_BINFO (t)); vid.primary_vtbl_p = (binfo == TYPE_BINFO (t));
vid.ctor_vtbl_p = !same_type_p (BINFO_TYPE (rtti_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. */ /* The first vbase or vcall offset is at index -3 in the vtable. */
vid.index = ssize_int (-3 * TARGET_VTABLE_DATA_ENTRY_DISTANCE); 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) ...@@ -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 /* Pull the offset for `this', and the function to call, out of
the list. */ the list. */
delta = BV_DELTA (v); delta = BV_DELTA (v);
vcall_index = BV_VCALL_INDEX (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 (delta) == INTEGER_CST, 19990727);
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727); my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
...@@ -7900,31 +7821,37 @@ build_vcall_offset_vtbl_entries (binfo, vid) ...@@ -7900,31 +7821,37 @@ build_vcall_offset_vtbl_entries (binfo, vid)
tree binfo; tree binfo;
vtbl_init_data *vid; vtbl_init_data *vid;
{ {
/* We only need these entries if this base is a virtual base. */ /* We only need these entries if this base is a virtual base. We
if (!TREE_VIA_VIRTUAL (binfo)) compute the indices -- but do not add to the vtable -- when
return; 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 A { virtual void f (); };
class B1 : virtual public A { virtual void f (); }; class B1 : virtual public A { virtual void f (); };
class B2 : virtual public A { virtual void f (); }; class B2 : virtual public A { virtual void f (); };
class C: public B1, public B2 { 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 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 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 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 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, 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 so we store this "vcall offset" in the A sub-vtable and look it up in
a "virtual thunk" for B2::f. a "virtual thunk" for B2::f.
We need entries for all the functions in our primary vtable and We need entries for all the functions in our primary vtable and
in our non-virtual bases' secondary vtables. */ in our non-virtual bases' secondary vtables. */
vid->vbase = binfo; vid->vbase = binfo;
/* Now, walk through the non-virtual bases, adding vcall offsets. */ /* If we are just computing the vcall indices -- but do not need
add_vcall_offset_vtbl_entries_r (binfo, vid); 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. */ /* Build vcall offsets, starting with those for BINFO. */
...@@ -8025,8 +7952,6 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid) ...@@ -8025,8 +7952,6 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid)
{ {
tree orig_fn; tree orig_fn;
tree fn; tree fn;
tree base;
tree base_binfo;
size_t i; size_t i;
tree vcall_offset; tree vcall_offset;
...@@ -8057,42 +7982,17 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid) ...@@ -8057,42 +7982,17 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid)
even though there are two virtual table entries. */ even though there are two virtual table entries. */
|| (DECL_DESTRUCTOR_P (BV_FN (derived_entry)) || (DECL_DESTRUCTOR_P (BV_FN (derived_entry))
&& DECL_DESTRUCTOR_P (fn))) && DECL_DESTRUCTOR_P (fn)))
{ break;
if (!vid->ctor_vtbl_p)
BV_VCALL_INDEX (derived_virtuals)
= BV_VCALL_INDEX (derived_entry);
break;
}
} }
if (i != VARRAY_ACTIVE_SIZE (vid->fns)) if (i != VARRAY_ACTIVE_SIZE (vid->fns))
continue; continue;
/* The FN comes from BASE. So, we must calculate the adjustment from /* If we are building these vcall offsets as part of building
vid->vbase to BASE. We can just look for BASE in the complete the vtable for the most derived class, remember the vcall
object because we are converting from a virtual base, so if there offset. */
were multiple copies, there would not be a unique final overrider if (vid->binfo == TYPE_BINFO (vid->derived))
and vid->derived would be ill-formed. */ CLASSTYPE_VCALL_INDICES (vid->derived)
base = DECL_CONTEXT (fn); = tree_cons (fn, vid->index, CLASSTYPE_VCALL_INDICES (vid->derived));
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 /* The next vcall offset will be found at a more negative
offset. */ offset. */
...@@ -8101,6 +8001,35 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid) ...@@ -8101,6 +8001,35 @@ add_vcall_offset_vtbl_entries_1 (binfo, vid)
/* Keep track of this function. */ /* Keep track of this function. */
VARRAY_PUSH_TREE (vid->fns, derived_virtuals); 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; ...@@ -47,7 +47,6 @@ struct diagnostic_context;
ICS_USER_FLAG (in _CONV) ICS_USER_FLAG (in _CONV)
CLEANUP_P (in TRY_BLOCK) CLEANUP_P (in TRY_BLOCK)
AGGR_INIT_VIA_CTOR_P (in AGGR_INIT_EXPR) 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) PTRMEM_OK_P (in ADDR_EXPR, OFFSET_REF)
PARMLIST_ELLIPSIS_P (in PARMLIST) PARMLIST_ELLIPSIS_P (in PARMLIST)
1: IDENTIFIER_VIRTUAL_P. 1: IDENTIFIER_VIRTUAL_P.
...@@ -133,9 +132,7 @@ struct diagnostic_context; ...@@ -133,9 +132,7 @@ struct diagnostic_context;
of the base class. of the base class.
The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable
index of the vcall offset for this entry. If index of the vcall offset for this entry.
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. The BV_FN is the declaration for the virtual function itself.
...@@ -615,6 +612,8 @@ enum cp_tree_index ...@@ -615,6 +612,8 @@ enum cp_tree_index
CPTI_DSO_HANDLE, CPTI_DSO_HANDLE,
CPTI_DCAST, CPTI_DCAST,
CPTI_DYNAMIC_CLASSES,
CPTI_MAX CPTI_MAX
}; };
...@@ -745,6 +744,10 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; ...@@ -745,6 +744,10 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
destructors. */ destructors. */
#define vtt_parm_type cp_global_trees[CPTI_VTT_PARM_TYPE] #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. */ /* Global state. */
struct saved_scope GTY(()) struct saved_scope GTY(())
...@@ -1153,12 +1156,13 @@ struct lang_type_class GTY(()) ...@@ -1153,12 +1156,13 @@ struct lang_type_class GTY(())
tree primary_base; tree primary_base;
tree vfields; tree vfields;
tree vcall_indices;
tree vtables;
tree vbases; tree vbases;
tree tags; tree tags;
tree as_base; tree as_base;
tree pure_virtuals; tree pure_virtuals;
tree friend_classes; tree friend_classes;
tree rtti;
tree methods; tree methods;
tree decl_list; tree decl_list;
tree template_info; tree template_info;
...@@ -1257,9 +1261,6 @@ struct lang_type GTY(()) ...@@ -1257,9 +1261,6 @@ struct lang_type GTY(())
convenient, don't reprocess any methods that appear in its redefinition. */ convenient, don't reprocess any methods that appear in its redefinition. */
#define TYPE_REDEFINED(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->redefined) #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(). */ /* Nonzero means that this _CLASSTYPE node overloads operator(). */
#define TYPE_OVERLOADS_CALL_EXPR(NODE) \ #define TYPE_OVERLOADS_CALL_EXPR(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->has_call_overloaded) (LANG_TYPE_CLASS_CHECK (NODE)->has_call_overloaded)
...@@ -1431,13 +1432,6 @@ struct lang_type GTY(()) ...@@ -1431,13 +1432,6 @@ struct lang_type GTY(())
/* Nonzero means that this aggr type has been `closed' by a semicolon. */ /* Nonzero means that this aggr type has been `closed' by a semicolon. */
#define CLASSTYPE_GOT_SEMICOLON(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->got_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. */ /* Nonzero means that this type has an X() constructor. */
#define TYPE_HAS_DEFAULT_CONSTRUCTOR(NODE) \ #define TYPE_HAS_DEFAULT_CONSTRUCTOR(NODE) \
(LANG_TYPE_CLASS_CHECK (NODE)->h.has_default_ctor) (LANG_TYPE_CLASS_CHECK (NODE)->h.has_default_ctor)
...@@ -1629,6 +1623,19 @@ struct lang_type GTY(()) ...@@ -1629,6 +1623,19 @@ struct lang_type GTY(())
/* Used by various search routines. */ /* Used by various search routines. */
#define IDENTIFIER_MARKED(NODE) TREE_LANG_FLAG_0 (NODE) #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. */ /* Accessor macros for the vfield slots in structures. */
/* List of virtual table fields that this type contains (both the primary /* List of virtual table fields that this type contains (both the primary
...@@ -1664,8 +1671,6 @@ struct lang_type GTY(()) ...@@ -1664,8 +1671,6 @@ struct lang_type GTY(())
/* The function to call. */ /* The function to call. */
#define BV_FN(NODE) (TREE_VALUE (NODE)) #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 /* Nonzero for TREE_LIST node means that this list of things
is a list of parameters, as opposed to a list of expressions. */ is a list of parameters, as opposed to a list of expressions. */
...@@ -3546,7 +3551,6 @@ extern tree perform_implicit_conversion PARAMS ((tree, tree)); ...@@ -3546,7 +3551,6 @@ extern tree perform_implicit_conversion PARAMS ((tree, tree));
/* in class.c */ /* in class.c */
extern tree build_base_path PARAMS ((enum tree_code, tree, tree, int)); extern tree build_base_path PARAMS ((enum tree_code, tree, tree, int));
extern tree convert_to_base (tree, tree, bool); 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_vtbl_ref PARAMS ((tree, tree));
extern tree build_vfn_ref PARAMS ((tree, tree)); extern tree build_vfn_ref PARAMS ((tree, tree));
extern tree get_vtable_decl PARAMS ((tree, int)); extern tree get_vtable_decl PARAMS ((tree, int));
......
...@@ -60,7 +60,7 @@ typedef struct priority_info_s { ...@@ -60,7 +60,7 @@ typedef struct priority_info_s {
static void mark_vtable_entries PARAMS ((tree)); static void mark_vtable_entries PARAMS ((tree));
static void grok_function_init PARAMS ((tree, 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 int is_namespace_ancestor PARAMS ((tree, tree));
static void add_using_namespace PARAMS ((tree, tree, int)); static void add_using_namespace PARAMS ((tree, tree, int));
static tree ambiguous_decl PARAMS ((tree, tree, tree,int)); static tree ambiguous_decl PARAMS ((tree, tree, tree,int));
...@@ -1658,12 +1658,7 @@ key_method (type) ...@@ -1658,12 +1658,7 @@ key_method (type)
method = TREE_CHAIN (method)) method = TREE_CHAIN (method))
if (DECL_VINDEX (method) != NULL_TREE if (DECL_VINDEX (method) != NULL_TREE
&& ! DECL_DECLARED_INLINE_P (method) && ! DECL_DECLARED_INLINE_P (method)
&& (! DECL_PURE_VIRTUAL_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 method;
return NULL_TREE; return NULL_TREE;
...@@ -1805,28 +1800,52 @@ output_vtable_inherit (vars) ...@@ -1805,28 +1800,52 @@ output_vtable_inherit (vars)
assemble_vtable_inherit (child_rtx, parent_rtx); 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 static int
finish_vtable_vardecl (t, data) maybe_emit_vtables (tree ctype)
tree *t;
void *data ATTRIBUTE_UNUSED;
{ {
tree vars = *t; tree vtbl;
tree ctype = DECL_CONTEXT (vars); 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_class (ctype);
import_export_vtable (vars, ctype, 1); import_export_vtable (primary_vtbl, ctype, 1);
if (! DECL_EXTERNAL (vars) /* See if any of the vtables are needed. */
&& DECL_NEEDED_P (vars) for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl))
&& ! TREE_ASM_WRITTEN (vars)) 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. */ /* Write it out. */
mark_vtable_entries (vars); import_export_vtable (vtbl, ctype, 1);
if (TREE_TYPE (DECL_INITIAL (vars)) == 0) mark_vtable_entries (vtbl);
store_init_value (vars, DECL_INITIAL (vars)); if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)
store_init_value (vtbl, DECL_INITIAL (vtbl));
if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG) if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
{ {
...@@ -1851,37 +1870,29 @@ finish_vtable_vardecl (t, data) ...@@ -1851,37 +1870,29 @@ finish_vtable_vardecl (t, data)
`S' get written (which would solve the problem) but that would `S' get written (which would solve the problem) but that would
require more intrusive changes to the g++ front end. */ require more intrusive changes to the g++ front end. */
DECL_IGNORED_P (vars) = 1; DECL_IGNORED_P (vtbl) = 1;
} }
/* Always make vtables weak. */ /* Always make vtables weak. */
if (flag_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) if (flag_vtable_gc)
output_vtable_inherit (vars); output_vtable_inherit (vtbl);
/* Because we're only doing syntax-checking, we'll never end up /* Because we're only doing syntax-checking, we'll never end up
actually marking the variable as written. */ actually marking the variable as written. */
if (flag_syntax_only) if (flag_syntax_only)
TREE_ASM_WRITTEN (vars) = 1; 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;
} }
/* If the references to this class' vtables were optimized away, still /* Since we're writing out the vtable here, also write the debug
emit the appropriate debugging information. See dfs_debug_mark. */ info. */
if (DECL_COMDAT (vars) note_debug_info_needed (ctype);
&& CLASSTYPE_DEBUG_REQUESTED (ctype))
note_debug_info_needed (ctype);
return 0; return 1;
} }
/* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an /* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an
...@@ -2755,6 +2766,8 @@ finish_file () ...@@ -2755,6 +2766,8 @@ finish_file ()
do do
{ {
tree t;
reconsider = 0; reconsider = 0;
/* If there are templates that we've put off instantiating, do /* If there are templates that we've put off instantiating, do
...@@ -2764,10 +2777,9 @@ finish_file () ...@@ -2764,10 +2777,9 @@ finish_file ()
/* Write out virtual tables as required. Note that writing out /* Write out virtual tables as required. Note that writing out
the virtual table for a template class may cause the the virtual table for a template class may cause the
instantiation of members of that class. */ instantiation of members of that class. */
if (walk_vtables (vtable_decl_p, for (t = dynamic_classes; t; t = TREE_CHAIN (t))
finish_vtable_vardecl, if (maybe_emit_vtables (TREE_VALUE (t)))
/*data=*/0)) reconsider = 1;
reconsider = 1;
/* Write out needed type info variables. Writing out one variable /* Write out needed type info variables. Writing out one variable
might cause others to be needed. */ might cause others to be needed. */
......
...@@ -1955,9 +1955,8 @@ look_for_overrides (type, fndecl) ...@@ -1955,9 +1955,8 @@ look_for_overrides (type, fndecl)
return found; return found;
} }
/* Look in TYPE for virtual functions with the same signature as FNDECL. /* Look in TYPE for virtual functions with the same signature as
This differs from get_matching_virtual in that it will only return FNDECL. */
a function from TYPE. */
tree tree
look_for_overrides_here (type, fndecl) look_for_overrides_here (type, fndecl)
......
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> 2002-11-02 Diego Novillo <dnovillo@redhat.com>
PR optimization/8423 PR optimization/8423
......
// { 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 } }
// { 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 } }
// { dg-do compile }
struct A {
};
struct B : virtual public A {
};
B b;
// { dg-final { scan-assembler _ZTT1B } }
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