Commit c35cce41 by Mark Mitchell Committed by Mark Mitchell

Correct many new ABI issues regarding vbase and vcall offset layout.

	Correct many new ABI issues regarding vbase and vcall offset
	layout.
	* cp-tree.h (BINFO_VTABLE): Document.
	(struct lang_type): Tweak formatting.
	(BINFO_PRIMARY_BINFO): Add to documentation.
	(CLASSTYPE_VSIZE): Fix typo in comment.
	(CLASSTYPE_VBASECLASSES): Update documentation.
	(BINFO_VBASE_MARKED): Remove.
	(SET_BINFO_VBASE_MARKED): Likewise.
	(CLEAR_BINFO_VBASE_MARKED): Likewise.
	(BINFO_FIELDS_MARKED): Remove.
	(SET_BINFO_FIELDS_MARKED): Likewise.
	(CLEAR_BINFO_FIELDS_MARKED): Likewise.
	(enum access_kind): New enumeration.
	(num_extra_vtbl_entries): Remove declaration.
	(size_extra_vtbl_entries): Likewise.
	(get_vtbl_decl_for_binfo): New function.
	(dfs_vbase_unmark): Remove declaration.
	(mark_primary_bases): Likewise.
	* class.c (SAME_FN): Remove.
	(struct vcall_offset_data_s): Move definition.
	(build_vbase_pointer): Use `build', not `build_binary_op', to
	access the vbase pointer under the new ABI.
	(build_vtable_entry_ref): Use get_vtbl_decl_for_binfo.
	(build_primary_vtable): Likewise.
	(dfs_mark_primary_bases): Move here from search.c.
	(mark_primary_bases): Likewise.
	(determine_primary_bases): Under the new ABI, don't make a base
	class a primary base just because we don't yet have any virtual
	functions.
	(layout_vtable_decl): Use get_vtbl_decl_for_binfo.
	(num_vfun_entries): Remove.
	(dfs_count_virtuals): Likewise.
	(num_extra_vtbl_entries): Likewise.
	(size_extra_vtbl_entries): Likewise.
	(layout_virtual_bases): Iterate in inheritance graph order under
	the new ABI.
	(finish_struct_1): Use TYPE_VFIELD, not CLASSTYPE_VSIZE, to
	indicate that a vfield is present.
	(init_class_processing): Initialize access_public_node, etc., from
	ak_public, etc.
	(get_vtbl_decl_for_binfo): New function.
	(dump_class_hierarchy_r): Likewise.
	(dump_class_hierarchy): Use it.
	(finish_vtbls): Build the vtbls in inheritance graph order.
	(dfs_finish_vtbls): Adjust call to build_vtbl_initializer.
	(initialize_vtable): Use get_vtbl_decl_for_binfo.
	(accumulate_vtbl_inits): Add comments explaining why a pre-order
	walk is required.
	(dfs_accumulate_vtbl_inits): Set BINFO_VTABLE to the location
	where the vptr points, even for primary vtables.
	(build_vtbl_initializer): Adjust handling of vbase and vcall
	offsets.
	(build_vcall_and_vbase_vtable_entries): New function.
	(dfs_build_vbase_offset_vtbl_entries): Remove.
	(build_vbase_offset_vtbl_entries): Reimplement.
	(dfs_build_vcall_offset_vtbl_entries): Don't include virtuals that
	were already handled in a primary base class vtable.
	(build_vcall_offset_vtbl_entries): Adjust.
	(build_rtti_vtbl_entries): Adjust.
	* decl2.c (output_vtable_inherit): Use get_vtbl_decl_for_binfo.
	* init.c (expand_virtual_init): Simplify.
	* repo.c (repo_get_id): Use get_vtbl_decl_for_binfo.
	* rtti.c (create_pseudo_type_info): Adjust calculation of vptr.
	* search.c (BINFO_ACCESS): New macro.
	(SET_BINFO_ACCESS): Likewise.
	(dfs_access_in_type): Manipulate access_kinds, not access nodes.
	(access_in_type): Likewise.
	(dfs_accessible_p): Likewise.
	(protected_accessible_p): Likewise.
	(lookup_fnfields_1): Adjust documentation.
	(dfs_mark_primary_bases): Move to class.c
	(mark_primary_bases): Likewise.
	(dfs_vbase_unmark): Remove.
	(virtual_context): Use BINFO_FOR_VBASE.
	(dfs_get_vbase_types): Simplify.
	(dfs_build_inheritance_graph_order): New function.
	(get_vbase_types): Use it.
	* tree.c (debug_binfo): Use get_vtbl_decl_for_binfo.

	* tinfo.cc (get_vbase_offset): New function.
	(__vmi_class_type_info::do_find_public_src): Use it.
	(__vmi_class_type_info::do_dyncast): Likewise.
	(__vmi_class_type_info::do_upcast): Likewise.

From-SVN: r32905
parent f2d33f13
2000-04-04 Mark Mitchell <mark@codesourcery.com>
Correct many new ABI issues regarding vbase and vcall offset
layout.
* cp-tree.h (BINFO_VTABLE): Document.
(struct lang_type): Tweak formatting.
(BINFO_PRIMARY_BINFO): Add to documentation.
(CLASSTYPE_VSIZE): Fix typo in comment.
(CLASSTYPE_VBASECLASSES): Update documentation.
(BINFO_VBASE_MARKED): Remove.
(SET_BINFO_VBASE_MARKED): Likewise.
(CLEAR_BINFO_VBASE_MARKED): Likewise.
(BINFO_FIELDS_MARKED): Remove.
(SET_BINFO_FIELDS_MARKED): Likewise.
(CLEAR_BINFO_FIELDS_MARKED): Likewise.
(enum access_kind): New enumeration.
(num_extra_vtbl_entries): Remove declaration.
(size_extra_vtbl_entries): Likewise.
(get_vtbl_decl_for_binfo): New function.
(dfs_vbase_unmark): Remove declaration.
(mark_primary_bases): Likewise.
* class.c (SAME_FN): Remove.
(struct vcall_offset_data_s): Move definition.
(build_vbase_pointer): Use `build', not `build_binary_op', to
access the vbase pointer under the new ABI.
(build_vtable_entry_ref): Use get_vtbl_decl_for_binfo.
(build_primary_vtable): Likewise.
(dfs_mark_primary_bases): Move here from search.c.
(mark_primary_bases): Likewise.
(determine_primary_bases): Under the new ABI, don't make a base
class a primary base just because we don't yet have any virtual
functions.
(layout_vtable_decl): Use get_vtbl_decl_for_binfo.
(num_vfun_entries): Remove.
(dfs_count_virtuals): Likewise.
(num_extra_vtbl_entries): Likewise.
(size_extra_vtbl_entries): Likewise.
(layout_virtual_bases): Iterate in inheritance graph order under
the new ABI.
(finish_struct_1): Use TYPE_VFIELD, not CLASSTYPE_VSIZE, to
indicate that a vfield is present.
(init_class_processing): Initialize access_public_node, etc., from
ak_public, etc.
(get_vtbl_decl_for_binfo): New function.
(dump_class_hierarchy_r): Likewise.
(dump_class_hierarchy): Use it.
(finish_vtbls): Build the vtbls in inheritance graph order.
(dfs_finish_vtbls): Adjust call to build_vtbl_initializer.
(initialize_vtable): Use get_vtbl_decl_for_binfo.
(accumulate_vtbl_inits): Add comments explaining why a pre-order
walk is required.
(dfs_accumulate_vtbl_inits): Set BINFO_VTABLE to the location
where the vptr points, even for primary vtables.
(build_vtbl_initializer): Adjust handling of vbase and vcall
offsets.
(build_vcall_and_vbase_vtable_entries): New function.
(dfs_build_vbase_offset_vtbl_entries): Remove.
(build_vbase_offset_vtbl_entries): Reimplement.
(dfs_build_vcall_offset_vtbl_entries): Don't include virtuals that
were already handled in a primary base class vtable.
(build_vcall_offset_vtbl_entries): Adjust.
(build_rtti_vtbl_entries): Adjust.
* decl2.c (output_vtable_inherit): Use get_vtbl_decl_for_binfo.
* init.c (expand_virtual_init): Simplify.
* repo.c (repo_get_id): Use get_vtbl_decl_for_binfo.
* rtti.c (create_pseudo_type_info): Adjust calculation of vptr.
* search.c (BINFO_ACCESS): New macro.
(SET_BINFO_ACCESS): Likewise.
(dfs_access_in_type): Manipulate access_kinds, not access nodes.
(access_in_type): Likewise.
(dfs_accessible_p): Likewise.
(protected_accessible_p): Likewise.
(lookup_fnfields_1): Adjust documentation.
(dfs_mark_primary_bases): Move to class.c
(mark_primary_bases): Likewise.
(dfs_vbase_unmark): Remove.
(virtual_context): Use BINFO_FOR_VBASE.
(dfs_get_vbase_types): Simplify.
(dfs_build_inheritance_graph_order): New function.
(get_vbase_types): Use it.
* tree.c (debug_binfo): Use get_vtbl_decl_for_binfo.
* tinfo.cc (get_vbase_offset): New function.
(__vmi_class_type_info::do_find_public_src): Use it.
(__vmi_class_type_info::do_dyncast): Likewise.
(__vmi_class_type_info::do_upcast): Likewise.
2000-04-03 Zack Weinberg <zack@wolery.cumb.org> 2000-04-03 Zack Weinberg <zack@wolery.cumb.org>
* lang-specs.h: Pass -fno-show-column to the preprocessor. * lang-specs.h: Pass -fno-show-column to the preprocessor.
......
...@@ -38,12 +38,6 @@ Boston, MA 02111-1307, USA. */ ...@@ -38,12 +38,6 @@ Boston, MA 02111-1307, USA. */
#define obstack_chunk_alloc xmalloc #define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free #define obstack_chunk_free free
/* This is how we tell when two virtual member functions are really the
same. */
#define SAME_FN(FN1DECL, FN2DECL) (DECL_ASSEMBLER_NAME (FN1DECL) == DECL_ASSEMBLER_NAME (FN2DECL))
extern void set_class_shadows PARAMS ((tree));
/* The number of nested classes being processed. If we are not in the /* The number of nested classes being processed. If we are not in the
scope of any class, this is zero. */ scope of any class, this is zero. */
...@@ -68,6 +62,22 @@ typedef struct class_stack_node { ...@@ -68,6 +62,22 @@ typedef struct class_stack_node {
splay_tree names_used; splay_tree names_used;
}* class_stack_node_t; }* class_stack_node_t;
typedef struct vcall_offset_data_s
{
/* The binfo for the most-derived type. */
tree derived;
/* The binfo for the virtual base for which we're building
initializers. */
tree vbase;
/* The vcall offset initializers built up so far. */
tree inits;
/* The vtable index of the next vcall or vbase offset. */
tree index;
/* Nonzero if we are building the initializer for the primary
vtable. */
int primary_p;
} vcall_offset_data;
/* The stack itself. This is an dynamically resized array. The /* The stack itself. This is an dynamically resized array. The
number of elements allocated is CURRENT_CLASS_STACK_SIZE. */ number of elements allocated is CURRENT_CLASS_STACK_SIZE. */
static int current_class_stack_size; static int current_class_stack_size;
...@@ -108,7 +118,7 @@ static tree fixed_type_or_null PARAMS ((tree, int *)); ...@@ -108,7 +118,7 @@ static tree fixed_type_or_null PARAMS ((tree, int *));
static tree resolve_address_of_overloaded_function PARAMS ((tree, tree, int, static tree resolve_address_of_overloaded_function PARAMS ((tree, tree, int,
int, tree)); int, tree));
static void build_vtable_entry_ref PARAMS ((tree, tree, tree)); static void build_vtable_entry_ref PARAMS ((tree, tree, tree));
static tree build_vtbl_initializer PARAMS ((tree, tree)); static tree build_vtbl_initializer PARAMS ((tree, tree, int *));
static int count_fields PARAMS ((tree)); static int count_fields PARAMS ((tree));
static int add_fields_to_vec PARAMS ((tree, tree, int)); static int add_fields_to_vec PARAMS ((tree, tree, int));
static void check_bitfield_decl PARAMS ((tree)); static void check_bitfield_decl PARAMS ((tree));
...@@ -135,19 +145,17 @@ static void propagate_binfo_offsets PARAMS ((tree, tree)); ...@@ -135,19 +145,17 @@ static void propagate_binfo_offsets PARAMS ((tree, tree));
static void layout_virtual_bases PARAMS ((tree, varray_type *)); static void layout_virtual_bases PARAMS ((tree, varray_type *));
static tree dfs_set_offset_for_shared_vbases PARAMS ((tree, void *)); static tree dfs_set_offset_for_shared_vbases PARAMS ((tree, void *));
static tree dfs_set_offset_for_unshared_vbases PARAMS ((tree, void *)); static tree dfs_set_offset_for_unshared_vbases PARAMS ((tree, void *));
static tree dfs_build_vbase_offset_vtbl_entries PARAMS ((tree, void *)); static void build_vbase_offset_vtbl_entries PARAMS ((tree, vcall_offset_data *));
static tree build_vbase_offset_vtbl_entries PARAMS ((tree, tree));
static tree dfs_vcall_offset_queue_p PARAMS ((tree, void *)); static tree dfs_vcall_offset_queue_p PARAMS ((tree, void *));
static tree dfs_build_vcall_offset_vtbl_entries PARAMS ((tree, void *)); static tree dfs_build_vcall_offset_vtbl_entries PARAMS ((tree, void *));
static tree build_vcall_offset_vtbl_entries PARAMS ((tree, tree)); static void build_vcall_offset_vtbl_entries PARAMS ((tree, vcall_offset_data *));
static tree dfs_count_virtuals PARAMS ((tree, void *));
static void layout_vtable_decl PARAMS ((tree, int)); static void layout_vtable_decl PARAMS ((tree, int));
static int num_vfun_entries PARAMS ((tree));
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));
static tree dfs_find_base PARAMS ((tree, void *)); static tree dfs_find_base PARAMS ((tree, void *));
static int make_new_vtable PARAMS ((tree, tree)); static int make_new_vtable PARAMS ((tree, tree));
extern void dump_class_hierarchy PARAMS ((tree, int)); static void dump_class_hierarchy_r PARAMS ((tree, tree, int));
extern void dump_class_hierarchy PARAMS ((tree));
static tree build_vtable PARAMS ((tree, tree, tree)); static tree build_vtable PARAMS ((tree, tree, tree));
static void initialize_vtable PARAMS ((tree, tree)); static void initialize_vtable PARAMS ((tree, tree));
static void layout_nonempty_base_or_field PARAMS ((record_layout_info, static void layout_nonempty_base_or_field PARAMS ((record_layout_info,
...@@ -162,6 +170,10 @@ static void layout_empty_base PARAMS ((tree, tree, varray_type)); ...@@ -162,6 +170,10 @@ static void layout_empty_base PARAMS ((tree, tree, varray_type));
static void accumulate_vtbl_inits PARAMS ((tree, tree)); static void accumulate_vtbl_inits PARAMS ((tree, tree));
static void set_vindex PARAMS ((tree, tree, int *)); static void set_vindex PARAMS ((tree, tree, int *));
static tree build_rtti_vtbl_entries PARAMS ((tree, tree)); static tree build_rtti_vtbl_entries PARAMS ((tree, tree));
static void build_vcall_and_vbase_vtbl_entries PARAMS ((tree,
vcall_offset_data *));
static tree dfs_mark_primary_bases PARAMS ((tree, void *));
static void mark_primary_bases PARAMS ((tree));
/* Variables shared between class.c and call.c. */ /* Variables shared between class.c and call.c. */
...@@ -274,7 +286,8 @@ build_vbase_pointer (exp, type) ...@@ -274,7 +286,8 @@ build_vbase_pointer (exp, type)
/* Find the virtual function table pointer. */ /* Find the virtual function table pointer. */
vbase_ptr = build_vfield_ref (exp, TREE_TYPE (exp)); vbase_ptr = build_vfield_ref (exp, TREE_TYPE (exp));
/* Compute the location where the offset will lie. */ /* Compute the location where the offset will lie. */
vbase_ptr = build_binary_op (PLUS_EXPR, vbase_ptr = build (PLUS_EXPR,
TREE_TYPE (vbase_ptr),
vbase_ptr, vbase_ptr,
BINFO_VPTR_FIELD (vbase)); BINFO_VPTR_FIELD (vbase));
vbase_ptr = build1 (NOP_EXPR, vbase_ptr = build1 (NOP_EXPR,
...@@ -462,7 +475,7 @@ build_vtable_entry_ref (basetype, vtbl, idx) ...@@ -462,7 +475,7 @@ build_vtable_entry_ref (basetype, vtbl, idx)
static char asm_stmt[] = ".vtable_entry %c0, %c1"; static char asm_stmt[] = ".vtable_entry %c0, %c1";
tree s, i, i2; tree s, i, i2;
s = build_unary_op (ADDR_EXPR, TYPE_BINFO_VTABLE (basetype), 0); s = build_unary_op (ADDR_EXPR, get_vtbl_decl_for_binfo (basetype), 0);
s = build_tree_list (build_string (1, "s"), s); s = build_tree_list (build_string (1, "s"), s);
i = build_array_ref (vtbl, idx); i = build_array_ref (vtbl, idx);
...@@ -533,7 +546,23 @@ build_vtbl_ref (instance, idx) ...@@ -533,7 +546,23 @@ build_vtbl_ref (instance, idx)
&& (TREE_CODE (instance) == RESULT_DECL && (TREE_CODE (instance) == RESULT_DECL
|| TREE_CODE (instance) == PARM_DECL || TREE_CODE (instance) == PARM_DECL
|| TREE_CODE (instance) == VAR_DECL)) || TREE_CODE (instance) == VAR_DECL))
{
vtbl = TYPE_BINFO_VTABLE (basetype); vtbl = TYPE_BINFO_VTABLE (basetype);
/* Knowing the dynamic type of INSTANCE we can easily obtain
the correct vtable entry. In the new ABI, we resolve
this back to be in terms of the primary vtable. */
if (TREE_CODE (vtbl) == PLUS_EXPR)
{
idx = fold (build (PLUS_EXPR,
TREE_TYPE (idx),
idx,
build (EXACT_DIV_EXPR,
TREE_TYPE (idx),
TREE_OPERAND (vtbl, 1),
TYPE_SIZE_UNIT (vtable_entry_type))));
vtbl = get_vtbl_decl_for_binfo (TYPE_BINFO (basetype));
}
}
else else
vtbl = build_vfield_ref (instance, basetype); vtbl = build_vfield_ref (instance, basetype);
} }
...@@ -733,10 +762,9 @@ build_primary_vtable (binfo, type) ...@@ -733,10 +762,9 @@ build_primary_vtable (binfo, type)
return 0; return 0;
virtuals = copy_list (BINFO_VIRTUALS (binfo)); virtuals = copy_list (BINFO_VIRTUALS (binfo));
TREE_TYPE (decl) = TREE_TYPE (BINFO_VTABLE (binfo)); TREE_TYPE (decl) = TREE_TYPE (get_vtbl_decl_for_binfo (binfo));
DECL_SIZE (decl) = TYPE_SIZE (TREE_TYPE (BINFO_VTABLE (binfo))); DECL_SIZE (decl) = TYPE_SIZE (TREE_TYPE (decl));
DECL_SIZE_UNIT (decl) DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (TREE_TYPE (decl));
= TYPE_SIZE_UNIT (TREE_TYPE (BINFO_VTABLE (binfo)));
} }
else else
{ {
...@@ -1623,6 +1651,97 @@ check_bases (t, cant_have_default_ctor_p, cant_have_const_ctor_p, ...@@ -1623,6 +1651,97 @@ check_bases (t, cant_have_default_ctor_p, cant_have_const_ctor_p,
} }
} }
/* Called via dfs_walk from mark_primary_bases. Sets
BINFO_PRIMARY_MARKED_P for BINFO, if appropriate. */
static tree
dfs_mark_primary_bases (binfo, data)
tree binfo;
void *data;
{
int i;
tree base_binfo;
if (!CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (binfo)))
return NULL_TREE;
i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
base_binfo = BINFO_BASETYPE (binfo, i);
if (!TREE_VIA_VIRTUAL (base_binfo))
/* Non-virtual base classes are easy. */
BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
else
{
tree shared_binfo;
shared_binfo
= BINFO_FOR_VBASE (BINFO_TYPE (base_binfo), (tree) data);
/* If this virtual base is not already primary somewhere else in
the hiearchy, then we'll be using this copy. */
if (!BINFO_VBASE_PRIMARY_P (shared_binfo))
{
BINFO_VBASE_PRIMARY_P (shared_binfo) = 1;
BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
}
}
return NULL_TREE;
}
/* Set BINFO_PRIMARY_MARKED_P for all binfos in the hierarchy
dominated by BINFO that are primary bases. */
static void
mark_primary_bases (type)
tree type;
{
tree vbases;
/* Mark the TYPE_BINFO hierarchy. We need to mark primary bases in
pre-order to deal with primary virtual bases. (The virtual base
would be skipped if it were not marked as primary, and that
requires getting to dfs_mark_primary_bases before
dfs_skip_nonprimary_vbases_unmarkedp has a chance to skip the
virtual base.) */
dfs_walk_real (TYPE_BINFO (type), dfs_mark_primary_bases, NULL,
dfs_skip_nonprimary_vbases_unmarkedp, type);
/* Now go through the virtual base classes in inheritance graph
order. Any that are not already primary will need to be
allocated in TYPE, and so we need to mark their primary bases. */
for (vbases = TYPE_BINFO (type); vbases; vbases = TREE_CHAIN (vbases))
{
tree vbase;
/* Make sure that only BINFOs appear on this list.
Historically, the TREE_CHAIN was used for other purposes, and
we want to make sure that none of those uses remain. */
my_friendly_assert (TREE_CODE (vbases) == TREE_VEC, 20000402);
if (!TREE_VIA_VIRTUAL (vbases))
continue;
vbase = BINFO_FOR_VBASE (BINFO_TYPE (vbases), type);
if (BINFO_VBASE_PRIMARY_P (vbase))
/* This virtual base was already included in the hierarchy, so
there's nothing to do here. */
continue;
/* Temporarily pretend that VBASE is primary so that its bases
will be walked; this is the real copy of VBASE. */
BINFO_PRIMARY_MARKED_P (vbase) = 1;
/* Now, walk its bases. */
dfs_walk_real (vbase, dfs_mark_primary_bases, NULL,
dfs_skip_nonprimary_vbases_unmarkedp, type);
/* VBASE wasn't really primary. */
BINFO_PRIMARY_MARKED_P (vbase) = 0;
}
}
/* Make the Ith baseclass of T its primary base. */ /* Make the Ith baseclass of T its primary base. */
static void static void
...@@ -1696,7 +1815,7 @@ determine_primary_base (t, vfuns_p) ...@@ -1696,7 +1815,7 @@ determine_primary_base (t, vfuns_p)
VF_BASETYPE_VALUE (vfields), VF_BASETYPE_VALUE (vfields),
CLASSTYPE_VFIELDS (t)); CLASSTYPE_VFIELDS (t));
if (*vfuns_p == 0) if (!flag_new_abi && *vfuns_p == 0)
set_primary_base (t, i, vfuns_p); set_primary_base (t, i, vfuns_p);
} }
} }
...@@ -2184,6 +2303,7 @@ layout_vtable_decl (binfo, n) ...@@ -2184,6 +2303,7 @@ layout_vtable_decl (binfo, n)
{ {
tree itype; tree itype;
tree atype; tree atype;
tree vtable;
itype = size_int (n); itype = size_int (n);
atype = build_cplus_array_type (vtable_entry_type, atype = build_cplus_array_type (vtable_entry_type,
...@@ -2191,12 +2311,11 @@ layout_vtable_decl (binfo, n) ...@@ -2191,12 +2311,11 @@ layout_vtable_decl (binfo, n)
layout_type (atype); layout_type (atype);
/* We may have to grow the vtable. */ /* We may have to grow the vtable. */
if (!same_type_p (TREE_TYPE (BINFO_VTABLE (binfo)), atype)) vtable = get_vtbl_decl_for_binfo (binfo);
if (!same_type_p (TREE_TYPE (vtable), atype))
{ {
tree vtable = BINFO_VTABLE (binfo);
TREE_TYPE (vtable) = atype; TREE_TYPE (vtable) = atype;
DECL_SIZE (vtable) = DECL_SIZE_UNIT (vtable) = 0; DECL_SIZE (vtable) = DECL_SIZE_UNIT (vtable) = NULL_TREE;
layout_decl (vtable, 0); layout_decl (vtable, 0);
/* 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
...@@ -2206,104 +2325,6 @@ layout_vtable_decl (binfo, n) ...@@ -2206,104 +2325,6 @@ layout_vtable_decl (binfo, n)
} }
} }
/* Returns the number of virtual function table entries (excluding
RTTI information, vbase and vcall offests, etc.) in the vtable for
BINFO. */
static int
num_vfun_entries (binfo)
tree binfo;
{
return list_length (BINFO_VIRTUALS (binfo));
}
typedef struct vcall_offset_data_s
{
/* The binfo for the most-derived type. */
tree derived;
/* The binfo for the virtual base for which we're building
initializers. */
tree vbase;
/* The vcall offset initializers built up so far. */
tree inits;
/* The number of vcall offsets accumulated. */
int offsets;
} vcall_offset_data;
/* Called from num_extra_vtbl_entries via dfs_walk. */
static tree
dfs_count_virtuals (binfo, data)
tree binfo;
void *data;
{
/* Non-primary bases are not interesting; all of the virtual
function table entries have been overridden. */
if (!BINFO_PRIMARY_MARKED_P (binfo))
((vcall_offset_data *) data)->offsets += num_vfun_entries (binfo);
return NULL_TREE;
}
/* Returns the number of extra entries (at negative indices) required
for BINFO's vtable. */
tree
num_extra_vtbl_entries (binfo)
tree binfo;
{
tree type;
int entries;
type = BINFO_TYPE (binfo);
entries = 0;
/* There is an entry for the offset to each virtual base. */
if (vbase_offsets_in_vtable_p ())
entries += list_length (CLASSTYPE_VBASECLASSES (type));
/* If this is a virtual base, there are entries for each virtual
function defined in this class or its bases. */
if (vcall_offsets_in_vtable_p () && TREE_VIA_VIRTUAL (binfo))
{
vcall_offset_data vod;
vod.vbase = binfo;
vod.offsets = 0;
dfs_walk (binfo,
dfs_count_virtuals,
dfs_vcall_offset_queue_p,
&vod);
entries += vod.offsets;
}
/* When laying out COM-compatible classes, there are no RTTI
entries. */
if (CLASSTYPE_COM_INTERFACE (type))
;
/* When using vtable thunks, there are two RTTI entries: the "offset
to top" value and the RTTI entry itself. */
else if (flag_vtable_thunks)
entries += 2;
/* When not using vtable thunks there is only a single entry. */
else
entries += 1;
return size_int (entries);
}
/* Returns the offset (in bytes) from the beginning of BINFO's vtable
where the vptr should actually point. */
tree
size_extra_vtbl_entries (binfo)
tree binfo;
{
tree offset = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (vtable_entry_type),
num_extra_vtbl_entries (binfo));
return fold (offset);
}
/* True if we should override the given BASE_FNDECL with the given /* True if we should override the given BASE_FNDECL with the given
FNDECL. */ FNDECL. */
...@@ -3989,7 +4010,7 @@ check_bases_and_members (t, empty_p) ...@@ -3989,7 +4010,7 @@ check_bases_and_members (t, empty_p)
/* If T needs a pointer to its virtual function table, set TYPE_VFIELD /* If T needs a pointer to its virtual function table, set TYPE_VFIELD
accordingly. If a new vfield was created (because T doesn't have a accordingly. If a new vfield was created (because T doesn't have a
primary base class), then the newly created field is returned. It primary base class), then the newly created field is returned. It
is not added to the TYPE_FIELDS list; it is the callers is not added to the TYPE_FIELDS list; it is the caller's
responsibility to do that. */ responsibility to do that. */
static tree static tree
...@@ -4205,7 +4226,7 @@ layout_virtual_bases (t, base_offsets) ...@@ -4205,7 +4226,7 @@ layout_virtual_bases (t, base_offsets)
tree t; tree t;
varray_type *base_offsets; varray_type *base_offsets;
{ {
tree vbase; tree vbases;
unsigned HOST_WIDE_INT dsize; unsigned HOST_WIDE_INT dsize;
unsigned HOST_WIDE_INT eoc; unsigned HOST_WIDE_INT eoc;
...@@ -4225,10 +4246,26 @@ layout_virtual_bases (t, base_offsets) ...@@ -4225,10 +4246,26 @@ layout_virtual_bases (t, base_offsets)
TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), BITS_PER_UNIT); TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), BITS_PER_UNIT);
/* Go through the virtual bases, allocating space for each virtual /* Go through the virtual bases, allocating space for each virtual
base that is not already a primary base class. */ base that is not already a primary base class. Under the new
for (vbase = CLASSTYPE_VBASECLASSES (t); ABI, these are allocated according to a depth-first left-to-right
vbase; postorder traversal; in the new ABI, inheritance graph order is
vbase = TREE_CHAIN (vbase)) used instead. */
for (vbases = (flag_new_abi
? TYPE_BINFO (t)
: CLASSTYPE_VBASECLASSES (t));
vbases;
vbases = TREE_CHAIN (vbases))
{
tree vbase;
if (!TREE_VIA_VIRTUAL (vbases))
continue;
if (flag_new_abi)
vbase = BINFO_FOR_VBASE (BINFO_TYPE (vbases), t);
else
vbase = vbases;
if (!BINFO_VBASE_PRIMARY_P (vbase)) if (!BINFO_VBASE_PRIMARY_P (vbase))
{ {
/* This virtual base is not a primary base of any class in the /* This virtual base is not a primary base of any class in the
...@@ -4272,6 +4309,7 @@ layout_virtual_bases (t, base_offsets) ...@@ -4272,6 +4309,7 @@ layout_virtual_bases (t, base_offsets)
/* Keep track of the offsets assigned to this virtual base. */ /* Keep track of the offsets assigned to this virtual base. */
record_base_offsets (vbase, base_offsets); record_base_offsets (vbase, base_offsets);
} }
}
/* Make sure that all of the CLASSTYPE_VBASECLASSES have their /* Make sure that all of the CLASSTYPE_VBASECLASSES have their
BINFO_OFFSET set correctly. Those we just allocated certainly BINFO_OFFSET set correctly. Those we just allocated certainly
...@@ -4288,10 +4326,10 @@ layout_virtual_bases (t, base_offsets) ...@@ -4288,10 +4326,10 @@ layout_virtual_bases (t, base_offsets)
in get_base_distance depend on the BINFO_OFFSETs being set in get_base_distance depend on the BINFO_OFFSETs being set
correctly. */ correctly. */
dfs_walk (TYPE_BINFO (t), dfs_set_offset_for_unshared_vbases, NULL, t); dfs_walk (TYPE_BINFO (t), dfs_set_offset_for_unshared_vbases, NULL, t);
for (vbase = CLASSTYPE_VBASECLASSES (t); for (vbases = CLASSTYPE_VBASECLASSES (t);
vbase; vbases;
vbase = TREE_CHAIN (vbase)) vbases = TREE_CHAIN (vbases))
dfs_walk (vbase, dfs_set_offset_for_unshared_vbases, NULL, t); dfs_walk (vbases, dfs_set_offset_for_unshared_vbases, NULL, t);
/* If we had empty base classes that protruded beyond the end of the /* If we had empty base classes that protruded beyond the end of the
class, we didn't update DSIZE above; we were hoping to overlay class, we didn't update DSIZE above; we were hoping to overlay
...@@ -4310,11 +4348,11 @@ layout_virtual_bases (t, base_offsets) ...@@ -4310,11 +4348,11 @@ layout_virtual_bases (t, base_offsets)
/* Check for ambiguous virtual bases. */ /* Check for ambiguous virtual bases. */
if (extra_warnings) if (extra_warnings)
for (vbase = CLASSTYPE_VBASECLASSES (t); for (vbases = CLASSTYPE_VBASECLASSES (t);
vbase; vbases;
vbase = TREE_CHAIN (vbase)) vbases = TREE_CHAIN (vbases))
{ {
tree basetype = BINFO_TYPE (vbase); tree basetype = BINFO_TYPE (vbases);
if (get_base_distance (basetype, t, 0, (tree*)0) == -2) if (get_base_distance (basetype, t, 0, (tree*)0) == -2)
cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity", cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
basetype, t); basetype, t);
...@@ -4791,7 +4829,7 @@ finish_struct_1 (t) ...@@ -4791,7 +4829,7 @@ finish_struct_1 (t)
the base types we marked. */ the base types we marked. */
finish_vtbls (t); finish_vtbls (t);
if (CLASSTYPE_VSIZE (t) != 0) if (TYPE_VFIELD (t))
{ {
/* In addition to this one, all the other vfields should be listed. */ /* In addition to this one, all the other vfields should be listed. */
/* Before that can be done, we have to have FIELD_DECLs for them, and /* Before that can be done, we have to have FIELD_DECLs for them, and
...@@ -5030,13 +5068,13 @@ init_class_processing () ...@@ -5030,13 +5068,13 @@ init_class_processing ()
* sizeof (struct class_stack_node)); * sizeof (struct class_stack_node));
access_default_node = build_int_2 (0, 0); access_default_node = build_int_2 (0, 0);
access_public_node = build_int_2 (1, 0); access_public_node = build_int_2 (ak_public, 0);
access_protected_node = build_int_2 (2, 0); access_protected_node = build_int_2 (ak_protected, 0);
access_private_node = build_int_2 (3, 0); access_private_node = build_int_2 (ak_private, 0);
access_default_virtual_node = build_int_2 (4, 0); access_default_virtual_node = build_int_2 (4, 0);
access_public_virtual_node = build_int_2 (5, 0); access_public_virtual_node = build_int_2 (4 | ak_public, 0);
access_protected_virtual_node = build_int_2 (6, 0); access_protected_virtual_node = build_int_2 (4 | ak_protected, 0);
access_private_virtual_node = build_int_2 (7, 0); access_private_virtual_node = build_int_2 (4 | ak_private, 0);
} }
/* Set current scope to NAME. CODE tells us if this is a /* Set current scope to NAME. CODE tells us if this is a
...@@ -6047,12 +6085,36 @@ note_name_declared_in_class (name, decl) ...@@ -6047,12 +6085,36 @@ note_name_declared_in_class (name, decl)
} }
} }
/* Dump the offsets of all the bases rooted at BINFO to stderr. /* Returns the VAR_DECL for the complete vtable associated with
INDENT should be zero when called from the top level; it is BINFO. (Under the new ABI, secondary vtables are merged with
incremented recursively. */ primary vtables; this function will return the VAR_DECL for the
primary vtable.) */
void tree
dump_class_hierarchy (binfo, indent) get_vtbl_decl_for_binfo (binfo)
tree binfo;
{
tree decl;
decl = BINFO_VTABLE (binfo);
if (decl && TREE_CODE (decl) == PLUS_EXPR)
{
my_friendly_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR,
2000403);
decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
}
if (decl)
my_friendly_assert (TREE_CODE (decl) == VAR_DECL, 20000403);
return decl;
}
/* Dump the offsets of all the bases rooted at BINFO (in the hierarchy
dominated by T) to stderr. INDENT should be zero when called from
the top level; it is incremented recursively. */
static void
dump_class_hierarchy_r (t, binfo, indent)
tree t;
tree binfo; tree binfo;
int indent; int indent;
{ {
...@@ -6063,11 +6125,31 @@ dump_class_hierarchy (binfo, indent) ...@@ -6063,11 +6125,31 @@ dump_class_hierarchy (binfo, indent)
type_as_string (binfo, TS_PLAIN)); type_as_string (binfo, TS_PLAIN));
fprintf (stderr, HOST_WIDE_INT_PRINT_DEC, fprintf (stderr, HOST_WIDE_INT_PRINT_DEC,
tree_low_cst (BINFO_OFFSET (binfo), 0)); tree_low_cst (BINFO_OFFSET (binfo), 0));
fprintf (stderr, " %s\n", if (TREE_VIA_VIRTUAL (binfo))
BINFO_PRIMARY_MARKED_P (binfo) ? "primary" : ""); fprintf (stderr, " virtual");
if (BINFO_PRIMARY_MARKED_P (binfo)
|| (TREE_VIA_VIRTUAL (binfo)
&& BINFO_VBASE_PRIMARY_P (BINFO_FOR_VBASE (BINFO_TYPE (binfo),
t))))
fprintf (stderr, " primary");
fprintf (stderr, "\n");
for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i) for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
dump_class_hierarchy (BINFO_BASETYPE (binfo, i), indent + 2); dump_class_hierarchy_r (t, BINFO_BASETYPE (binfo, i), indent + 2);
}
/* Dump the BINFO hierarchy for T. */
void
dump_class_hierarchy (t)
tree t;
{
tree vbase;
dump_class_hierarchy_r (t, TYPE_BINFO (t), 0);
fprintf (stderr, "virtual bases\n");
for (vbase = CLASSTYPE_VBASECLASSES (t); vbase; vbase = TREE_CHAIN (vbase))
dump_class_hierarchy_r (t, vbase, 0);
} }
/* Virtual function table initialization. */ /* Virtual function table initialization. */
...@@ -6087,14 +6169,18 @@ finish_vtbls (t) ...@@ -6087,14 +6169,18 @@ finish_vtbls (t)
vtables in one contiguous vtable. The primary vtable is vtables in one contiguous vtable. The primary vtable is
first, followed by the non-virtual secondary vtables in first, followed by the non-virtual secondary vtables in
inheritance graph order. */ inheritance graph order. */
list = build_tree_list (t, NULL_TREE); list = build_tree_list (TYPE_BINFO_VTABLE (t), NULL_TREE);
TREE_TYPE (list) = t;
accumulate_vtbl_inits (TYPE_BINFO (t), list); accumulate_vtbl_inits (TYPE_BINFO (t), list);
/* Then come the virtual bases, also in inheritance graph /* Then come the virtual bases, also in inheritance graph
order. */ order. */
for (vbase = CLASSTYPE_VBASECLASSES (t); for (vbase = TYPE_BINFO (t); vbase; vbase = TREE_CHAIN (vbase))
vbase; {
vbase = TREE_CHAIN (vbase)) if (!TREE_VIA_VIRTUAL (vbase))
accumulate_vtbl_inits (vbase, list); continue;
accumulate_vtbl_inits (BINFO_FOR_VBASE (BINFO_TYPE (vbase), t),
list);
}
if (TYPE_BINFO_VTABLE (t)) if (TYPE_BINFO_VTABLE (t))
initialize_vtable (TYPE_BINFO (t), TREE_VALUE (list)); initialize_vtable (TYPE_BINFO (t), TREE_VALUE (list));
...@@ -6121,7 +6207,7 @@ dfs_finish_vtbls (binfo, data) ...@@ -6121,7 +6207,7 @@ dfs_finish_vtbls (binfo, data)
&& CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)) && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
&& BINFO_NEW_VTABLE_MARKED (binfo, t)) && BINFO_NEW_VTABLE_MARKED (binfo, t))
initialize_vtable (binfo, initialize_vtable (binfo,
build_vtbl_initializer (binfo, t)); build_vtbl_initializer (binfo, t, NULL));
CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t); CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
SET_BINFO_MARKED (binfo); SET_BINFO_MARKED (binfo);
...@@ -6140,7 +6226,7 @@ initialize_vtable (binfo, inits) ...@@ -6140,7 +6226,7 @@ initialize_vtable (binfo, inits)
tree decl; tree decl;
layout_vtable_decl (binfo, list_length (inits)); layout_vtable_decl (binfo, list_length (inits));
decl = BINFO_VTABLE (binfo); decl = get_vtbl_decl_for_binfo (binfo);
context = DECL_CONTEXT (decl); context = DECL_CONTEXT (decl);
DECL_CONTEXT (decl) = 0; DECL_CONTEXT (decl) = 0;
DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE, inits); DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE, inits);
...@@ -6156,7 +6242,9 @@ accumulate_vtbl_inits (binfo, inits) ...@@ -6156,7 +6242,9 @@ accumulate_vtbl_inits (binfo, inits)
tree binfo; tree binfo;
tree inits; tree inits;
{ {
/* Walk the BINFO and its bases. */ /* Walk the BINFO and its bases. We walk in preorder so that as we
initialize each vtable we can figure out at what offset the
secondary vtable lies from the primary vtable. */
dfs_walk_real (binfo, dfs_walk_real (binfo,
dfs_accumulate_vtbl_inits, dfs_accumulate_vtbl_inits,
NULL, NULL,
...@@ -6177,33 +6265,37 @@ dfs_accumulate_vtbl_inits (binfo, data) ...@@ -6177,33 +6265,37 @@ dfs_accumulate_vtbl_inits (binfo, data)
tree t; tree t;
l = (tree) data; l = (tree) data;
t = TREE_PURPOSE (l); t = TREE_TYPE (l);
if (!BINFO_PRIMARY_MARKED_P (binfo) if (!BINFO_PRIMARY_MARKED_P (binfo)
&& CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)) && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))
&& BINFO_NEW_VTABLE_MARKED (binfo, t)) && BINFO_NEW_VTABLE_MARKED (binfo, t))
{ {
/* If this is a secondary vtable, record its location. */ tree inits;
if (binfo != TYPE_BINFO (t))
{
tree vtbl; tree vtbl;
tree index;
int non_fn_entries;
/* Compute the initializer for this vtable. */
inits = build_vtbl_initializer (binfo, t, &non_fn_entries);
vtbl = TYPE_BINFO_VTABLE (t); /* Set BINFO_VTABLE to the address where the VPTR should point. */
vtbl = TREE_PURPOSE (l);
vtbl = build1 (ADDR_EXPR, vtbl = build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (vtbl)), build_pointer_type (TREE_TYPE (vtbl)),
vtbl); vtbl);
index = size_binop (PLUS_EXPR,
size_int (non_fn_entries),
size_int (list_length (TREE_VALUE (l))));
BINFO_VTABLE (binfo) BINFO_VTABLE (binfo)
= build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl,
size_binop (MULT_EXPR, size_binop (MULT_EXPR,
TYPE_SIZE_UNIT (TREE_TYPE (vtbl)), TYPE_SIZE_UNIT (TREE_TYPE (vtbl)),
size_int (list_length (TREE_VALUE (l))))); index));
}
/* Add the initializers for this vtable to the initializers for /* Add the initializers for this vtable to the initializers for
the other vtables we've already got. */ the other vtables we've already got. */
TREE_VALUE (l) TREE_VALUE (l) = chainon (TREE_VALUE (l), inits);
= chainon (TREE_VALUE (l),
build_vtbl_initializer (binfo, t));
} }
CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t); CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t);
...@@ -6214,29 +6306,48 @@ dfs_accumulate_vtbl_inits (binfo, data) ...@@ -6214,29 +6306,48 @@ dfs_accumulate_vtbl_inits (binfo, data)
/* Construct the initializer for BINFOs virtual function table. BINFO /* Construct the initializer for BINFOs virtual function table. BINFO
is part of the hierarchy dominated by T. The value returned is a is part of the hierarchy dominated by T. The value returned is a
TREE_LIST suitable for wrapping in a CONSTRUCTOR to use as the TREE_LIST suitable for wrapping in a CONSTRUCTOR to use as the
DECL_INITIAL for a vtable. */ DECL_INITIAL for a vtable. If NON_FN_ENTRIES_P is not NULL,
*NON_FN_ENTRIES_P is set to the number of non-function entries in
the vtable. */
static tree static tree
build_vtbl_initializer (binfo, t) build_vtbl_initializer (binfo, t, non_fn_entries_p)
tree binfo; tree binfo;
tree t; tree t;
int *non_fn_entries_p;
{ {
tree v = BINFO_VIRTUALS (binfo); tree v = BINFO_VIRTUALS (binfo);
tree inits = NULL_TREE; tree inits = NULL_TREE;
tree vfun_inits;
tree vbase;
vcall_offset_data vod;
/* Add entries to the vtable that indicate how to adjust the this /* Initialize those parts of VOD that matter. */
pointer when calling a virtual function in this class. */ vod.derived = t;
inits = build_vcall_offset_vtbl_entries (binfo, t); vod.inits = NULL_TREE;
vod.primary_p = (binfo == TYPE_BINFO (t));
/* Add entries to the vtable for offsets to our virtual bases. */ /* The first vbase or vcall offset is at index -3 in the vtable. */
inits = chainon (build_vbase_offset_vtbl_entries (binfo, t), vod.index = build_int_2 (-3, -1);
inits);
/* Add the vcall and vbase offset entries. */
build_vcall_and_vbase_vtbl_entries (binfo, &vod);
inits = vod.inits;
/* Clear BINFO_VTABLE_PAATH_MARKED; it's set by
build_vbase_offset_vtbl_entries. */
for (vbase = CLASSTYPE_VBASECLASSES (t);
vbase;
vbase = TREE_CHAIN (vbase))
CLEAR_BINFO_VTABLE_PATH_MARKED (vbase);
/* Add entries to the vtable for RTTI. */ /* Add entries to the vtable for RTTI. */
inits = chainon (build_rtti_vtbl_entries (binfo, t), inits); inits = chainon (inits, build_rtti_vtbl_entries (binfo, t));
if (non_fn_entries_p)
*non_fn_entries_p = list_length (inits);
/* Go through all the ordinary virtual functions, building up /* Go through all the ordinary virtual functions, building up
initializers. */ initializers. */
vfun_inits = NULL_TREE;
while (v) while (v)
{ {
tree delta; tree delta;
...@@ -6266,118 +6377,133 @@ build_vtbl_initializer (binfo, t) ...@@ -6266,118 +6377,133 @@ build_vtbl_initializer (binfo, t)
/* Enter it in the vtable. */ /* Enter it in the vtable. */
init = build_vtable_entry (delta, vcall_index, pfn); init = build_vtable_entry (delta, vcall_index, pfn);
/* And add it to the chain of initializers. */ /* And add it to the chain of initializers. */
inits = tree_cons (NULL_TREE, init, inits); vfun_inits = tree_cons (NULL_TREE, init, vfun_inits);
/* Keep going. */ /* Keep going. */
v = TREE_CHAIN (v); v = TREE_CHAIN (v);
} }
/* The initializers were built up in reverse order; straighten them /* The initializers for virtual functions were built up in reverse
out now. */ order; straighten them out now. */
return nreverse (inits); vfun_inits = nreverse (vfun_inits);
/* The complete initializer is the INITS, followed by the
VFUN_INITS. */
return chainon (inits, vfun_inits);
} }
/* Called from build_vbase_offset_vtbl_entries via dfs_walk. */ /* Sets vod->inits to be the initializers for the vbase and vcall
offsets in BINFO, which is in the hierarchy dominated by T. */
static tree static void
dfs_build_vbase_offset_vtbl_entries (binfo, data) build_vcall_and_vbase_vtbl_entries (binfo, vod)
tree binfo; tree binfo;
void *data; vcall_offset_data *vod;
{ {
tree list = (tree) data; tree b;
tree inits;
if (TREE_TYPE (list) == binfo)
/* The TREE_TYPE of LIST is the base class from which we started
walking. If that BINFO is virtual it's not a virtual baseclass
of itself. */
;
else if (TREE_VIA_VIRTUAL (binfo))
{
tree init;
tree vbase;
/* Remember the index to the vbase offset for this virtual
base. */
vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), TREE_PURPOSE (list));
if (!TREE_VALUE (list))
BINFO_VPTR_FIELD (vbase) = build_int_2 (-3, 0);
else
{
BINFO_VPTR_FIELD (vbase) = TREE_PURPOSE (TREE_VALUE (list));
BINFO_VPTR_FIELD (vbase)
= fold (build (MINUS_EXPR, integer_type_node,
BINFO_VPTR_FIELD (vbase), integer_one_node));
}
/* And record the offset at which this virtual base lies in the
vtable. */
init = BINFO_OFFSET (binfo);
TREE_VALUE (list) = tree_cons (BINFO_VPTR_FIELD (vbase),
init, TREE_VALUE (list));
}
SET_BINFO_VTABLE_PATH_MARKED (binfo);
return NULL_TREE; /* If this is a derived class, we must first create entries
corresponding to the base class. These entries must go closer to
the vptr, so we save them up and add them to the end of the list
later. */
inits = vod->inits;
vod->inits = NULL_TREE;
b = BINFO_PRIMARY_BINFO (binfo);
if (b)
build_vcall_and_vbase_vtbl_entries (b, vod);
/* Add the vbase entries for this base. */
build_vbase_offset_vtbl_entries (binfo, vod);
/* Add the vcall entries for this base. */
build_vcall_offset_vtbl_entries (binfo, vod);
vod->inits = chainon (vod->inits, inits);
} }
/* Returns the initializers for the vbase offset entries in the vtable /* Returns the initializers for the vbase offset entries in the vtable
for BINFO (which is part of the class hierarchy dominated by T), in for BINFO (which is part of the class hierarchy dominated by T), in
reverse order. */ reverse order. VBASE_OFFSET_INDEX gives the vtable index
where the next vbase offset will go. */
static tree static void
build_vbase_offset_vtbl_entries (binfo, t) build_vbase_offset_vtbl_entries (binfo, vod)
tree binfo; tree binfo;
tree t; vcall_offset_data *vod;
{ {
tree inits; tree vbase;
tree init; tree t;
tree list;
/* Under the old ABI, pointers to virtual bases are stored in each /* Under the old ABI, pointers to virtual bases are stored in each
object. */ object. */
if (!vbase_offsets_in_vtable_p ()) if (!vbase_offsets_in_vtable_p ())
return NULL_TREE; return;
/* If there are no virtual baseclasses, then there is nothing to /* If there are no virtual baseclasses, then there is nothing to
do. */ do. */
if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))) if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
return NULL_TREE; return;
inits = NULL_TREE; t = vod->derived;
/* The offsets are allocated in the reverse order of a /* Go through the virtual bases, adding the offsets. */
depth-first left-to-right traversal of the hierarchy. We use for (vbase = TYPE_BINFO (BINFO_TYPE (binfo));
BINFO_VTABLE_PATH_MARKED because we are ourselves during a vbase;
dfs_walk, and so BINFO_MARKED is already in use. */ vbase = TREE_CHAIN (vbase))
list = build_tree_list (t, NULL_TREE); {
TREE_TYPE (list) = binfo; tree b;
dfs_walk (binfo, tree delta;
dfs_build_vbase_offset_vtbl_entries,
unmarked_vtable_pathp,
list);
dfs_walk (binfo,
dfs_vtable_path_unmark,
marked_vtable_pathp,
list);
inits = nreverse (TREE_VALUE (list));
/* We've now got offsets in the right order. However, the offsets if (!TREE_VIA_VIRTUAL (vbase))
we've stored are offsets from the beginning of the complete continue;
object, and we need offsets from this BINFO. */
for (init = inits; init; init = TREE_CHAIN (init)) /* Find the instance of this virtual base in the complete
object. */
b = BINFO_FOR_VBASE (BINFO_TYPE (vbase), t);
/* If we've already got an offset for this virtual base, we
don't need another one. */
if (BINFO_VTABLE_PATH_MARKED (b))
continue;
SET_BINFO_VTABLE_PATH_MARKED (b);
/* Figure out where we can find this vbase offset. */
delta = size_binop (MULT_EXPR,
convert (ssizetype, vod->index),
convert (ssizetype,
TYPE_SIZE_UNIT (vtable_entry_type)));
if (vod->primary_p)
BINFO_VPTR_FIELD (b) = delta;
if (binfo != TYPE_BINFO (t))
{ {
/* The dfs_build_vbase_offset_vtbl_entries routine uses the tree orig_vbase;
TREE_PURPOSE to scribble in. But, we need to clear it now so
that the values are not perceived as labeled initializers. */ /* Find the instance of this virtual base in the type of BINFO. */
TREE_PURPOSE (init) = NULL_TREE; orig_vbase = BINFO_FOR_VBASE (BINFO_TYPE (vbase),
TREE_VALUE (init) BINFO_TYPE (binfo));
= fold (build1 (NOP_EXPR, vtable_entry_type,
size_diffop (TREE_VALUE (init), /* The vbase offset had better be the same. */
BINFO_OFFSET (binfo)))); if (!tree_int_cst_equal (delta,
BINFO_VPTR_FIELD (orig_vbase)))
my_friendly_abort (20000403);
} }
return inits; /* The next vbase will come at a more negative offset. */
vod->index = fold (build (MINUS_EXPR, integer_type_node,
vod->index, integer_one_node));
/* The initializer is the delta from BINFO to this virtual base.
The vbase offsets go in reverse inheritance-graph order, and
we are walking in inheritance graph order so these end up in
the right order. */
delta = size_diffop (BINFO_OFFSET (b), BINFO_OFFSET (binfo));
vod->inits = tree_cons (NULL_TREE,
fold (build1 (NOP_EXPR,
vtable_entry_type,
delta)),
vod->inits);
}
} }
/* Called from build_vcall_offset_vtbl_entries via dfs_walk. */ /* Called from build_vcall_offset_vtbl_entries via dfs_walk. */
...@@ -6402,20 +6528,22 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data) ...@@ -6402,20 +6528,22 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data)
vcall_offset_data* vod; vcall_offset_data* vod;
tree virtuals; tree virtuals;
tree binfo_inits; tree binfo_inits;
tree b;
/* Primary bases are not interesting; all of the virtual int i;
function table entries have been overridden. */
if (BINFO_PRIMARY_MARKED_P (binfo))
return NULL_TREE;
vod = (vcall_offset_data *) data; vod = (vcall_offset_data *) data;
binfo_inits = NULL_TREE; binfo_inits = NULL_TREE;
/* We chain the offsets on in reverse order. That's correct -- /* Skip virtuals that we have already handled in a primary base
build_vtbl_initializer will straighten them out. */ class. */
for (virtuals = BINFO_VIRTUALS (binfo); virtuals = BINFO_VIRTUALS (binfo);
virtuals; b = BINFO_PRIMARY_BINFO (binfo);
virtuals = TREE_CHAIN (virtuals)) if (b)
for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (b)); ++i)
virtuals = TREE_CHAIN (virtuals);
/* Make entries for the rest of the virtuals. */
while (virtuals)
{ {
/* Figure out what function we're looking at. */ /* Figure out what function we're looking at. */
tree fn = TREE_VALUE (virtuals); tree fn = TREE_VALUE (virtuals);
...@@ -6430,34 +6558,48 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data) ...@@ -6430,34 +6558,48 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data)
size_diffop (BINFO_OFFSET (base_binfo), size_diffop (BINFO_OFFSET (base_binfo),
BINFO_OFFSET (vod->vbase)))), BINFO_OFFSET (vod->vbase)))),
binfo_inits); binfo_inits);
vod->index = fold (build (MINUS_EXPR, integer_type_node,
vod->index, integer_one_node));
virtuals = TREE_CHAIN (virtuals);
} }
/* Now add the initializers we've just created to the list that will /* The offests are built up in reverse order, so we straighten them
be returned to our caller. */ here. We simultaneously add them to VOD->INITS; we're walking
vod->inits = chainon (vod->inits, binfo_inits); the bases in inheritance graph order, and the initializers are
supposed to appear in reverse inheritance order, so that's
correct. */
while (binfo_inits)
{
tree next;
next = TREE_CHAIN (binfo_inits);
TREE_CHAIN (binfo_inits) = vod->inits;
vod->inits = binfo_inits;
binfo_inits = next;
}
return NULL_TREE; return NULL_TREE;
} }
/* Returns the initializers for the vcall offset entries in the vtable /* Adds the initializers for the vcall offset entries in the vtable
for BINFO (which is part of the class hierarchy dominated by T), in for BINFO (which is part of the class hierarchy dominated by T) to
reverse order. */ VOD->INITS. */
static tree static void
build_vcall_offset_vtbl_entries (binfo, t) build_vcall_offset_vtbl_entries (binfo, vod)
tree binfo; tree binfo;
tree t; vcall_offset_data *vod;
{ {
vcall_offset_data vod; tree inits;
/* Under the old ABI, the adjustments to the `this' pointer were made /* Under the old ABI, the adjustments to the `this' pointer were made
elsewhere. */ elsewhere. */
if (!vcall_offsets_in_vtable_p ()) if (!vcall_offsets_in_vtable_p ())
return NULL_TREE; return;
/* We only need these entries if this base is a virtual base. */ /* We only need these entries if this base is a virtual base. */
if (!TREE_VIA_VIRTUAL (binfo)) if (!TREE_VIA_VIRTUAL (binfo))
return NULL_TREE; return;
/* We need a vcall offset for each of the virtual functions in this /* We need a vcall offset for each of the virtual functions in this
vtable. For example: vtable. For example:
...@@ -6481,15 +6623,15 @@ build_vcall_offset_vtbl_entries (binfo, t) ...@@ -6481,15 +6623,15 @@ build_vcall_offset_vtbl_entries (binfo, t)
in our non-virtual bases vtables. For each base, the entries in our non-virtual bases vtables. For each base, the entries
appear in the same order as in the base; but the bases themselves appear in the same order as in the base; but the bases themselves
appear in reverse depth-first, left-to-right order. */ appear in reverse depth-first, left-to-right order. */
vod.derived = t; vod->vbase = binfo;
vod.vbase = binfo; inits = vod->inits;
vod.inits = NULL_TREE; vod->inits = NULL_TREE;
dfs_walk (binfo, dfs_walk_real (binfo,
dfs_build_vcall_offset_vtbl_entries, dfs_build_vcall_offset_vtbl_entries,
NULL,
dfs_vcall_offset_queue_p, dfs_vcall_offset_queue_p,
&vod); vod);
vod->inits = chainon (vod->inits, inits);
return vod.inits;
} }
/* Return vtbl initializers for the RTTI entries coresponding to the /* Return vtbl initializers for the RTTI entries coresponding to the
...@@ -6503,10 +6645,10 @@ build_rtti_vtbl_entries (binfo, t) ...@@ -6503,10 +6645,10 @@ build_rtti_vtbl_entries (binfo, t)
{ {
tree b; tree b;
tree basetype; tree basetype;
tree inits;
tree offset; tree offset;
tree decl; tree decl;
tree init; tree init;
tree inits;
basetype = BINFO_TYPE (binfo); basetype = BINFO_TYPE (binfo);
inits = NULL_TREE; inits = NULL_TREE;
...@@ -6519,19 +6661,15 @@ build_rtti_vtbl_entries (binfo, t) ...@@ -6519,19 +6661,15 @@ build_rtti_vtbl_entries (binfo, t)
primary base, and then add the offset in the vtbl to that value. */ primary base, and then add the offset in the vtbl to that value. */
b = binfo; b = binfo;
while (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (b))) while (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (b)))
b = BINFO_BASETYPE (b,
CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (b)));
offset = size_diffop (size_zero_node, BINFO_OFFSET (b));
/* Add the offset-to-top entry. */
if (flag_vtable_thunks)
{ {
/* Convert the offset to look like a function pointer, so that tree primary_base;
we can put it in the vtable. */
init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset); primary_base = BINFO_PRIMARY_BINFO (b);
TREE_CONSTANT (init) = 1; if (!BINFO_PRIMARY_MARKED_P (primary_base))
inits = tree_cons (NULL_TREE, init, inits); break;
b = primary_base;
} }
offset = size_diffop (size_zero_node, BINFO_OFFSET (b));
/* The second entry is, in the case of the new ABI, the address of /* The second entry is, in the case of the new ABI, the address of
the typeinfo object, or, in the case of the old ABI, a function the typeinfo object, or, in the case of the old ABI, a function
...@@ -6561,9 +6699,18 @@ build_rtti_vtbl_entries (binfo, t) ...@@ -6561,9 +6699,18 @@ build_rtti_vtbl_entries (binfo, t)
TREE_CONSTANT (init) = 1; TREE_CONSTANT (init) = 1;
init = build_vtable_entry (offset, integer_zero_node, init); init = build_vtable_entry (offset, integer_zero_node, init);
} }
inits = tree_cons (NULL_TREE, init, inits);
/* Hook the RTTI declaration onto the list. */ /* Add the offset-to-top entry. It comes earlier in the vtable that
the the typeinfo entry. */
if (flag_vtable_thunks)
{
/* Convert the offset to look like a function pointer, so that
we can put it in the vtable. */
init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
TREE_CONSTANT (init) = 1;
inits = tree_cons (NULL_TREE, init, inits); inits = tree_cons (NULL_TREE, init, inits);
}
return inits; return inits;
} }
......
...@@ -55,8 +55,6 @@ Boston, MA 02111-1307, USA. */ ...@@ -55,8 +55,6 @@ Boston, MA 02111-1307, USA. */
ICS_ELLIPSIS_FLAG (in _CONV) ICS_ELLIPSIS_FLAG (in _CONV)
STMT_IS_FULL_EXPR_P (in _STMT) STMT_IS_FULL_EXPR_P (in _STMT)
2: IDENTIFIER_OPNAME_P. 2: IDENTIFIER_OPNAME_P.
BINFO_VBASE_MARKED.
BINFO_FIELDS_MARKED.
TYPE_POLYMORHPIC_P (in _TYPE) TYPE_POLYMORHPIC_P (in _TYPE)
ICS_THIS_FLAG (in _CONV) ICS_THIS_FLAG (in _CONV)
STMT_LINENO_FOR_FN_P (in _STMT) STMT_LINENO_FOR_FN_P (in _STMT)
...@@ -130,6 +128,13 @@ Boston, MA 02111-1307, USA. */ ...@@ -130,6 +128,13 @@ Boston, MA 02111-1307, USA. */
this function. (This binfo's BINFO_TYPE will always be the same this function. (This binfo's BINFO_TYPE will always be the same
as the DECL_CLASS_CONTEXT for the function.) as the DECL_CLASS_CONTEXT for the function.)
BINFO_VTABLE
Sometimes this is a VAR_DECL. Under the new ABI, it is instead
an expression with POINTER_TYPE pointing that gives the value
to which the vptr should be initialized. Use get_vtbl_decl_for_binfo
to extract the VAR_DECL for the complete vtable; that macro works
in both ABIs.
DECL_ARGUMENTS DECL_ARGUMENTS
For a VAR_DECL this is DECL_ANON_UNION_ELEMS. For a VAR_DECL this is DECL_ANON_UNION_ELEMS.
...@@ -1356,24 +1361,17 @@ struct lang_type ...@@ -1356,24 +1361,17 @@ struct lang_type
int vsize; int vsize;
int vfield_parent; int vfield_parent;
union tree_node *vfields; tree vfields;
union tree_node *vbases; tree vbases;
tree tags;
union tree_node *tags; tree search_slot;
tree size;
union tree_node *search_slot; tree size_unit;
tree pure_virtuals;
union tree_node *size; tree friend_classes;
union tree_node *size_unit; tree rtti;
tree methods;
union tree_node *pure_virtuals; tree template_info;
union tree_node *friend_classes;
union tree_node *rtti;
union tree_node *methods;
union tree_node *template_info;
tree befriending_classes; tree befriending_classes;
}; };
...@@ -1538,21 +1536,29 @@ struct lang_type ...@@ -1538,21 +1536,29 @@ struct lang_type
#define CLASSTYPE_PRIMARY_BINFO(NODE) \ #define CLASSTYPE_PRIMARY_BINFO(NODE) \
(BINFO_PRIMARY_BINFO (TYPE_BINFO (NODE))) (BINFO_PRIMARY_BINFO (TYPE_BINFO (NODE)))
/* If non-NULL, this is the binfo for the primary base of BINFO. */ /* If non-NULL, this is the binfo for the primary base of BINFO. Note
that in a complex hierarchy the resulting BINFO may not actually
*be* primary. In particular if the resulting BINFO is a virtual
base, and it occurs elsewhere in the hierarchy, then this
occurrence may not actually be a primary base in the complete
object. Check BINFO_PRIMARY_MARKED_P to be sure. */
#define BINFO_PRIMARY_BINFO(NODE) \ #define BINFO_PRIMARY_BINFO(NODE) \
(CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (NODE)) \ (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (NODE)) \
? BINFO_BASETYPE (NODE, \ ? BINFO_BASETYPE (NODE, \
CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (NODE))) \ CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (NODE))) \
: NULL_TREE) : NULL_TREE)
/* The number of virtual functions present in this classes virtual /* The number of virtual functions present in this class' virtual
function table. */ function table. */
#define CLASSTYPE_VSIZE(NODE) (TYPE_LANG_SPECIFIC(NODE)->vsize) #define CLASSTYPE_VSIZE(NODE) (TYPE_LANG_SPECIFIC(NODE)->vsize)
/* A chain of BINFOs for the direct and indirect virtual base classes /* A chain of BINFOs for the direct and indirect virtual base classes
that this type uses in depth-first left-to-right order. These that this type uses in a post-order depth-first left-to-right
BINFOs are distinct from those in the TYPE_BINFO hierarchy. So, order. (In other words, these bases appear in the order that they
given: should be initialized.)
These BINFOs are distinct from those in the TYPE_BINFO hierarchy.
So, given:
struct A {}; struct A {};
struct B : public A {}; struct B : public A {};
...@@ -1683,9 +1689,7 @@ struct lang_type ...@@ -1683,9 +1689,7 @@ struct lang_type
We use TREE_VIA_PROTECTED and TREE_VIA_PUBLIC, but private We use TREE_VIA_PROTECTED and TREE_VIA_PUBLIC, but private
inheritance is indicated by the absence of the other two flags, not inheritance is indicated by the absence of the other two flags, not
by TREE_VIA_PRIVATE, which is unused. by TREE_VIA_PRIVATE, which is unused. */
The TREE_CHAIN is for scratch space in search.c. */
/* Nonzero means marked by DFS or BFS search, including searches /* Nonzero means marked by DFS or BFS search, including searches
by `get_binfo' and `get_base_distance'. */ by `get_binfo' and `get_base_distance'. */
...@@ -1695,18 +1699,6 @@ struct lang_type ...@@ -1695,18 +1699,6 @@ struct lang_type
#define SET_BINFO_MARKED(NODE) (TREE_VIA_VIRTUAL(NODE)?SET_CLASSTYPE_MARKED(BINFO_TYPE(NODE)):(TREE_LANG_FLAG_0(NODE)=1)) #define SET_BINFO_MARKED(NODE) (TREE_VIA_VIRTUAL(NODE)?SET_CLASSTYPE_MARKED(BINFO_TYPE(NODE)):(TREE_LANG_FLAG_0(NODE)=1))
#define CLEAR_BINFO_MARKED(NODE) (TREE_VIA_VIRTUAL(NODE)?CLEAR_CLASSTYPE_MARKED(BINFO_TYPE(NODE)):(TREE_LANG_FLAG_0(NODE)=0)) #define CLEAR_BINFO_MARKED(NODE) (TREE_VIA_VIRTUAL(NODE)?CLEAR_CLASSTYPE_MARKED(BINFO_TYPE(NODE)):(TREE_LANG_FLAG_0(NODE)=0))
/* Nonzero means marked in search through virtual inheritance hierarchy. */
#define BINFO_VBASE_MARKED(NODE) CLASSTYPE_MARKED2 (BINFO_TYPE (NODE))
/* Modifier macros */
#define SET_BINFO_VBASE_MARKED(NODE) SET_CLASSTYPE_MARKED2 (BINFO_TYPE (NODE))
#define CLEAR_BINFO_VBASE_MARKED(NODE) CLEAR_CLASSTYPE_MARKED2 (BINFO_TYPE (NODE))
/* Nonzero means marked in search for members or member functions. */
#define BINFO_FIELDS_MARKED(NODE) \
(TREE_VIA_VIRTUAL(NODE)?CLASSTYPE_MARKED2 (BINFO_TYPE (NODE)):TREE_LANG_FLAG_2(NODE))
#define SET_BINFO_FIELDS_MARKED(NODE) (TREE_VIA_VIRTUAL(NODE)?SET_CLASSTYPE_MARKED2(BINFO_TYPE(NODE)):(TREE_LANG_FLAG_2(NODE)=1))
#define CLEAR_BINFO_FIELDS_MARKED(NODE) (TREE_VIA_VIRTUAL(NODE)?CLEAR_CLASSTYPE_MARKED2(BINFO_TYPE(NODE)):(TREE_LANG_FLAG_2(NODE)=0))
/* Nonzero means that this class is on a path leading to a new vtable. */ /* Nonzero means that this class is on a path leading to a new vtable. */
#define BINFO_VTABLE_PATH_MARKED(NODE) \ #define BINFO_VTABLE_PATH_MARKED(NODE) \
(TREE_VIA_VIRTUAL(NODE)?CLASSTYPE_MARKED3(BINFO_TYPE(NODE)):TREE_LANG_FLAG_3(NODE)) (TREE_VIA_VIRTUAL(NODE)?CLASSTYPE_MARKED3(BINFO_TYPE(NODE)):TREE_LANG_FLAG_3(NODE))
...@@ -3081,6 +3073,17 @@ typedef enum tmpl_spec_kind { ...@@ -3081,6 +3073,17 @@ typedef enum tmpl_spec_kind {
tsk_expl_inst /* An explicit instantiation. */ tsk_expl_inst /* An explicit instantiation. */
} tmpl_spec_kind; } tmpl_spec_kind;
/* The various kinds of access. BINFO_ACCESS depends on these being
two bit quantities. The numerical values are important; they are
used to initialize RTTI data structures, so chaning them changes
the ABI. */
typedef enum access_kind {
ak_none = 0, /* Inaccessible. */
ak_public = 1, /* Accessible, as a `public' thing. */
ak_protected = 2, /* Accessible, as a `protected' thing. */
ak_private = 3 /* Accessible, as a `private' thing. */
} access_kind;
/* Zero means prototype weakly, as in ANSI C (no args means nothing). /* Zero means prototype weakly, as in ANSI C (no args means nothing).
Each language context defines how this variable should be set. */ Each language context defines how this variable should be set. */
extern int strict_prototype; extern int strict_prototype;
...@@ -3694,8 +3697,7 @@ extern void unreverse_member_declarations PARAMS ((tree)); ...@@ -3694,8 +3697,7 @@ extern void unreverse_member_declarations PARAMS ((tree));
extern void invalidate_class_lookup_cache PARAMS ((void)); extern void invalidate_class_lookup_cache PARAMS ((void));
extern void maybe_note_name_used_in_class PARAMS ((tree, tree)); extern void maybe_note_name_used_in_class PARAMS ((tree, tree));
extern void note_name_declared_in_class PARAMS ((tree, tree)); extern void note_name_declared_in_class PARAMS ((tree, tree));
extern tree num_extra_vtbl_entries PARAMS ((tree)); extern tree get_vtbl_decl_for_binfo PARAMS ((tree));
extern tree size_extra_vtbl_entries PARAMS ((tree));
/* in cvt.c */ /* in cvt.c */
extern tree convert_to_reference PARAMS ((tree, tree, int, int, tree)); extern tree convert_to_reference PARAMS ((tree, tree, int, int, tree));
...@@ -4203,7 +4205,6 @@ extern tree dfs_walk_real PARAMS ((tree, ...@@ -4203,7 +4205,6 @@ extern tree dfs_walk_real PARAMS ((tree,
tree (*) (tree, void *), tree (*) (tree, void *),
void *)); void *));
extern tree dfs_unmark PARAMS ((tree, void *)); extern tree dfs_unmark PARAMS ((tree, void *));
extern tree dfs_vbase_unmark PARAMS ((tree, void *));
extern tree dfs_vtable_path_unmark PARAMS ((tree, void *)); extern tree dfs_vtable_path_unmark PARAMS ((tree, void *));
extern tree markedp PARAMS ((tree, void *)); extern tree markedp PARAMS ((tree, void *));
extern tree unmarkedp PARAMS ((tree, void *)); extern tree unmarkedp PARAMS ((tree, void *));
...@@ -4214,7 +4215,6 @@ extern tree dfs_marked_real_bases_queue_p PARAMS ((tree, void *)); ...@@ -4214,7 +4215,6 @@ extern tree dfs_marked_real_bases_queue_p PARAMS ((tree, void *));
extern tree dfs_skip_vbases PARAMS ((tree, void *)); extern tree dfs_skip_vbases PARAMS ((tree, void *));
extern tree marked_vtable_pathp PARAMS ((tree, void *)); extern tree marked_vtable_pathp PARAMS ((tree, void *));
extern tree unmarked_vtable_pathp PARAMS ((tree, void *)); extern tree unmarked_vtable_pathp PARAMS ((tree, void *));
extern void mark_primary_bases PARAMS ((tree));
extern tree convert_pointer_to_vbase PARAMS ((tree, tree)); extern tree convert_pointer_to_vbase PARAMS ((tree, tree));
extern tree find_vbase_instance PARAMS ((tree, tree)); extern tree find_vbase_instance PARAMS ((tree, tree));
......
...@@ -2544,7 +2544,7 @@ output_vtable_inherit (vars) ...@@ -2544,7 +2544,7 @@ output_vtable_inherit (vars)
op[1] = const0_rtx; op[1] = const0_rtx;
else if (parent) else if (parent)
{ {
parent = TYPE_BINFO_VTABLE (BINFO_TYPE (parent)); parent = get_vtbl_decl_for_binfo (TYPE_BINFO (BINFO_TYPE (parent)));
op[1] = XEXP (DECL_RTL (parent), 0); /* strip the mem ref */ op[1] = XEXP (DECL_RTL (parent), 0); /* strip the mem ref */
} }
else else
......
...@@ -653,31 +653,23 @@ expand_virtual_init (binfo, decl) ...@@ -653,31 +653,23 @@ expand_virtual_init (binfo, decl)
tree type = BINFO_TYPE (binfo); tree type = BINFO_TYPE (binfo);
tree vtbl, vtbl_ptr; tree vtbl, vtbl_ptr;
tree vtype, vtype_binfo; tree vtype, vtype_binfo;
tree b;
/* Compute the location of the vtable. */ /* Compute the location of the vtable. */
vtype = DECL_CONTEXT (TYPE_VFIELD (type)); vtype = DECL_CONTEXT (TYPE_VFIELD (type));
vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0); vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0);
vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (TYPE_VFIELD (type)), binfo)); b = binfo_value (DECL_FIELD_CONTEXT (TYPE_VFIELD (type)), binfo);
if (TREE_CODE (vtbl) == VAR_DECL) /* Figure out what vtable BINFO's vtable is based on, and mark it as
{ used. */
vtbl = get_vtbl_decl_for_binfo (b);
assemble_external (vtbl); assemble_external (vtbl);
TREE_USED (vtbl) = 1; TREE_USED (vtbl) = 1;
vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
}
else
/* Under the new ABI, secondary vtables are stored with the
primary vtable. So, the BINFO_VTABLE may be an expression for
computing the secondary vtable, rather than the secondary
vtable itself. */
my_friendly_assert (merge_primary_and_secondary_vtables_p (),
20000220);
/* Under the new ABI, we need to point into the middle of the /* Now compute the address to use when initializing the vptr. */
vtable. */ vtbl = BINFO_VTABLE (b);
if (vbase_offsets_in_vtable_p ()) if (TREE_CODE (vtbl) == VAR_DECL)
vtbl = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
size_extra_vtbl_entries (binfo));
/* Compute the location of the vtpr. */ /* Compute the location of the vtpr. */
decl = convert_pointer_to_real (vtype_binfo, decl); decl = convert_pointer_to_real (vtype_binfo, decl);
......
...@@ -103,7 +103,7 @@ repo_get_id (t) ...@@ -103,7 +103,7 @@ repo_get_id (t)
if (!COMPLETE_TYPE_P (t) || TYPE_BEING_DEFINED (t)) if (!COMPLETE_TYPE_P (t) || TYPE_BEING_DEFINED (t))
my_friendly_abort (981113); my_friendly_abort (981113);
t = TYPE_BINFO_VTABLE (t); t = get_vtbl_decl_for_binfo (TYPE_BINFO (t));
if (t == NULL_TREE) if (t == NULL_TREE)
return t; return t;
} }
......
...@@ -1640,11 +1640,14 @@ create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...)) ...@@ -1640,11 +1640,14 @@ create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
/* Under the new ABI, we need to point into the middle of the /* Under the new ABI, we need to point into the middle of the
vtable. */ vtable. */
if (vbase_offsets_in_vtable_p ()) if (flag_new_abi)
{ {
vtable_decl = build (PLUS_EXPR, TREE_TYPE (vtable_decl), vtable_decl = build (PLUS_EXPR,
TREE_TYPE (vtable_decl),
vtable_decl, vtable_decl,
size_extra_vtbl_entries (TYPE_BINFO (real_type))); size_binop (MULT_EXPR,
size_int (2),
TYPE_SIZE_UNIT (vtable_entry_type)));
TREE_CONSTANT (vtable_decl) = 1; TREE_CONSTANT (vtable_decl) = 1;
} }
......
...@@ -143,7 +143,7 @@ static int dependent_base_p PARAMS ((tree)); ...@@ -143,7 +143,7 @@ static int dependent_base_p PARAMS ((tree));
static tree dfs_accessible_queue_p PARAMS ((tree, void *)); static tree dfs_accessible_queue_p PARAMS ((tree, void *));
static tree dfs_accessible_p PARAMS ((tree, void *)); static tree dfs_accessible_p PARAMS ((tree, void *));
static tree dfs_access_in_type PARAMS ((tree, void *)); static tree dfs_access_in_type PARAMS ((tree, void *));
static tree access_in_type PARAMS ((tree, tree)); static access_kind access_in_type PARAMS ((tree, tree));
static tree dfs_canonical_queue PARAMS ((tree, void *)); static tree dfs_canonical_queue PARAMS ((tree, void *));
static tree dfs_assert_unmarked_p PARAMS ((tree, void *)); static tree dfs_assert_unmarked_p PARAMS ((tree, void *));
static void assert_canonical_unmarked PARAMS ((tree)); static void assert_canonical_unmarked PARAMS ((tree));
...@@ -152,7 +152,6 @@ static int friend_accessible_p PARAMS ((tree, tree, tree)); ...@@ -152,7 +152,6 @@ static int friend_accessible_p PARAMS ((tree, tree, tree));
static void setup_class_bindings PARAMS ((tree, int)); static void setup_class_bindings PARAMS ((tree, int));
static int template_self_reference_p PARAMS ((tree, tree)); static int template_self_reference_p PARAMS ((tree, tree));
static void fixup_all_virtual_upcast_offsets PARAMS ((tree, tree)); static void fixup_all_virtual_upcast_offsets PARAMS ((tree, tree));
static tree dfs_mark_primary_bases PARAMS ((tree, void *));
static tree get_shared_vbase_if_not_primary PARAMS ((tree, void *)); static tree get_shared_vbase_if_not_primary PARAMS ((tree, void *));
static tree dfs_find_vbase_instance PARAMS ((tree, void *)); static tree dfs_find_vbase_instance PARAMS ((tree, void *));
static tree dfs_get_pure_virtuals PARAMS ((tree, void *)); static tree dfs_get_pure_virtuals PARAMS ((tree, void *));
...@@ -811,6 +810,18 @@ shared_unmarked_p (binfo, data) ...@@ -811,6 +810,18 @@ shared_unmarked_p (binfo, data)
return unmarkedp (binfo, data); return unmarkedp (binfo, data);
} }
/* The accessibility routines use BINFO_ACCESS for scratch space
during the computation of the accssibility of some declaration. */
#define BINFO_ACCESS(NODE) \
((access_kind) ((TREE_LANG_FLAG_1 (NODE) << 1) | TREE_LANG_FLAG_6 (NODE)))
/* Set the access associated with NODE to ACCESS. */
#define SET_BINFO_ACCESS(NODE, ACCESS) \
((TREE_LANG_FLAG_1 (NODE) = (ACCESS & 2) != 0), \
(TREE_LANG_FLAG_6 (NODE) = (ACCESS & 1) != 0))
/* Called from access_in_type via dfs_walk. Calculate the access to /* Called from access_in_type via dfs_walk. Calculate the access to
DATA (which is really a DECL) in BINFO. */ DATA (which is really a DECL) in BINFO. */
...@@ -821,18 +832,18 @@ dfs_access_in_type (binfo, data) ...@@ -821,18 +832,18 @@ dfs_access_in_type (binfo, data)
{ {
tree decl = (tree) data; tree decl = (tree) data;
tree type = BINFO_TYPE (binfo); tree type = BINFO_TYPE (binfo);
tree access = NULL_TREE; access_kind access = ak_none;
if (context_for_name_lookup (decl) == type) if (context_for_name_lookup (decl) == type)
{ {
/* If we have desceneded to the scope of DECL, just note the /* If we have desceneded to the scope of DECL, just note the
appropriate access. */ appropriate access. */
if (TREE_PRIVATE (decl)) if (TREE_PRIVATE (decl))
access = access_private_node; access = ak_private;
else if (TREE_PROTECTED (decl)) else if (TREE_PROTECTED (decl))
access = access_protected_node; access = ak_protected;
else else
access = access_public_node; access = ak_public;
} }
else else
{ {
...@@ -842,9 +853,10 @@ dfs_access_in_type (binfo, data) ...@@ -842,9 +853,10 @@ dfs_access_in_type (binfo, data)
DECL_ACCESS. */ DECL_ACCESS. */
if (DECL_LANG_SPECIFIC (decl)) if (DECL_LANG_SPECIFIC (decl))
{ {
access = purpose_member (type, DECL_ACCESS (decl)); tree decl_access = purpose_member (type, DECL_ACCESS (decl));
if (access) if (decl_access)
access = TREE_VALUE (access); access = ((access_kind)
TREE_INT_CST_LOW (TREE_VALUE (decl_access)));
} }
if (!access) if (!access)
...@@ -860,35 +872,36 @@ dfs_access_in_type (binfo, data) ...@@ -860,35 +872,36 @@ dfs_access_in_type (binfo, data)
for (i = 0; i < n_baselinks; ++i) for (i = 0; i < n_baselinks; ++i)
{ {
tree base_binfo = TREE_VEC_ELT (binfos, i); tree base_binfo = TREE_VEC_ELT (binfos, i);
tree base_access = TREE_CHAIN (canonical_binfo (base_binfo)); access_kind base_access
= BINFO_ACCESS (canonical_binfo (base_binfo));
if (!base_access || base_access == access_private_node) if (base_access == ak_none || base_access == ak_private)
/* If it was not accessible in the base, or only /* If it was not accessible in the base, or only
accessible as a private member, we can't access it accessible as a private member, we can't access it
all. */ all. */
base_access = NULL_TREE; base_access = ak_none;
else if (TREE_VIA_PROTECTED (base_binfo)) else if (TREE_VIA_PROTECTED (base_binfo))
/* Public and protected members in the base are /* Public and protected members in the base are
protected here. */ protected here. */
base_access = access_protected_node; base_access = ak_protected;
else if (!TREE_VIA_PUBLIC (base_binfo)) else if (!TREE_VIA_PUBLIC (base_binfo))
/* Public and protected members in the base are /* Public and protected members in the base are
private here. */ private here. */
base_access = access_private_node; base_access = ak_private;
/* See if the new access, via this base, gives more /* See if the new access, via this base, gives more
access than our previous best access. */ access than our previous best access. */
if (base_access && if (base_access != ak_none
(base_access == access_public_node && (base_access == ak_public
|| (base_access == access_protected_node || (base_access == ak_protected
&& access != access_public_node) && access != ak_public)
|| (base_access == access_private_node || (base_access == ak_private
&& !access))) && access == ak_none)))
{ {
access = base_access; access = base_access;
/* If the new access is public, we can't do better. */ /* If the new access is public, we can't do better. */
if (access == access_public_node) if (access == ak_public)
break; break;
} }
} }
...@@ -896,7 +909,7 @@ dfs_access_in_type (binfo, data) ...@@ -896,7 +909,7 @@ dfs_access_in_type (binfo, data)
} }
/* Note the access to DECL in TYPE. */ /* Note the access to DECL in TYPE. */
TREE_CHAIN (binfo) = access; SET_BINFO_ACCESS (binfo, access);
/* Mark TYPE as visited so that if we reach it again we do not /* Mark TYPE as visited so that if we reach it again we do not
duplicate our efforts here. */ duplicate our efforts here. */
...@@ -907,7 +920,7 @@ dfs_access_in_type (binfo, data) ...@@ -907,7 +920,7 @@ dfs_access_in_type (binfo, data)
/* Return the access to DECL in TYPE. */ /* Return the access to DECL in TYPE. */
static tree static access_kind
access_in_type (type, decl) access_in_type (type, decl)
tree type; tree type;
tree decl; tree decl;
...@@ -929,7 +942,7 @@ access_in_type (type, decl) ...@@ -929,7 +942,7 @@ access_in_type (type, decl)
dfs_walk (binfo, dfs_unmark, shared_marked_p, 0); dfs_walk (binfo, dfs_unmark, shared_marked_p, 0);
assert_canonical_unmarked (binfo); assert_canonical_unmarked (binfo);
return TREE_CHAIN (binfo); return BINFO_ACCESS (binfo);
} }
/* Called from dfs_accessible_p via dfs_walk. */ /* Called from dfs_accessible_p via dfs_walk. */
...@@ -960,17 +973,14 @@ dfs_accessible_p (binfo, data) ...@@ -960,17 +973,14 @@ dfs_accessible_p (binfo, data)
void *data; void *data;
{ {
int protected_ok = data != 0; int protected_ok = data != 0;
tree access; access_kind access;
/* We marked the binfos while computing the access in each type.
So, we unmark as we go now. */
SET_BINFO_MARKED (binfo); SET_BINFO_MARKED (binfo);
access = BINFO_ACCESS (binfo);
access = TREE_CHAIN (binfo); if (access == ak_public || (access == ak_protected && protected_ok))
if (access == access_public_node
|| (access == access_protected_node && protected_ok))
return binfo; return binfo;
else if (access && is_friend (BINFO_TYPE (binfo), current_scope ())) else if (access != ak_none
&& is_friend (BINFO_TYPE (binfo), current_scope ()))
return binfo; return binfo;
return NULL_TREE; return NULL_TREE;
...@@ -985,7 +995,7 @@ protected_accessible_p (decl, derived, binfo) ...@@ -985,7 +995,7 @@ protected_accessible_p (decl, derived, binfo)
tree derived; tree derived;
tree binfo; tree binfo;
{ {
tree access; access_kind access;
/* We're checking this clause from [class.access.base] /* We're checking this clause from [class.access.base]
...@@ -1010,7 +1020,7 @@ protected_accessible_p (decl, derived, binfo) ...@@ -1010,7 +1020,7 @@ protected_accessible_p (decl, derived, binfo)
access = access_in_type (derived, decl); access = access_in_type (derived, decl);
/* If m is inaccessible in DERIVED, then it's not a P. */ /* If m is inaccessible in DERIVED, then it's not a P. */
if (access == NULL_TREE) if (access == ak_none)
return 0; return 0;
/* [class.protected] /* [class.protected]
...@@ -1752,12 +1762,11 @@ lookup_fnfields_1 (type, name) ...@@ -1752,12 +1762,11 @@ lookup_fnfields_1 (type, name)
If it ever returns a non-NULL value, that value is immediately If it ever returns a non-NULL value, that value is immediately
returned and the walk is terminated. At each node FN, is passed a returned and the walk is terminated. At each node FN, is passed a
BINFO indicating the path from the curently visited base-class to BINFO indicating the path from the curently visited base-class to
TYPE. The TREE_CHAINs of the BINFOs may be used for scratch space; TYPE. Before each base-class is walked QFN is called. If the
they are otherwise unused. Before each base-class is walked QFN is value returned is non-zero, the base-class is walked; otherwise it
called. If the value returned is non-zero, the base-class is is not. If QFN is NULL, it is treated as a function which always
walked; otherwise it is not. If QFN is NULL, it is treated as a returns 1. Both FN and QFN are passed the DATA whenever they are
function which always returns 1. Both FN and QFN are passed the called. */
DATA whenever they are called. */
static tree static tree
bfs_walk (binfo, fn, qfn, data) bfs_walk (binfo, fn, qfn, data)
...@@ -2194,97 +2203,6 @@ dfs_skip_nonprimary_vbases_markedp (binfo, data) ...@@ -2194,97 +2203,6 @@ dfs_skip_nonprimary_vbases_markedp (binfo, data)
return markedp (binfo, NULL); return markedp (binfo, NULL);
} }
/* Called via dfs_walk from mark_primary_bases. */
static tree
dfs_mark_primary_bases (binfo, data)
tree binfo;
void *data;
{
int i;
tree base_binfo;
if (!CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (binfo)))
return NULL_TREE;
i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
base_binfo = BINFO_BASETYPE (binfo, i);
if (!TREE_VIA_VIRTUAL (base_binfo))
/* Non-virtual base classes are easy. */
BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
else
{
tree shared_binfo;
shared_binfo
= BINFO_FOR_VBASE (BINFO_TYPE (base_binfo), (tree) data);
/* If this virtual base is not already primary somewhere else in
the hiearchy, then we'll be using this copy. */
if (!BINFO_VBASE_PRIMARY_P (shared_binfo)
&& !BINFO_VBASE_MARKED (shared_binfo))
{
BINFO_VBASE_PRIMARY_P (shared_binfo) = 1;
BINFO_PRIMARY_MARKED_P (base_binfo) = 1;
}
}
return NULL_TREE;
}
/* Set BINFO_PRIMARY_MARKED_P for all binfos in the hierarchy
dominated by BINFO that are primary bases. */
void
mark_primary_bases (type)
tree type;
{
tree vbase;
/* Mark the TYPE_BINFO hierarchy. We need to mark primary bases in
pre-order to deal with primary virtual bases. (The virtual base
would be skipped if it were not marked as primary, and that
requires getting to dfs_mark_primary_bases before
dfs_skip_nonprimary_vbases_unmarkedp has a chance to skip the
virtual base.) */
dfs_walk_real (TYPE_BINFO (type), dfs_mark_primary_bases, NULL,
dfs_skip_nonprimary_vbases_unmarkedp, type);
/* Now go through the virtual base classes. Any that are not
already primary will need to be allocated in TYPE, and so we need
to mark their primary bases. */
for (vbase = CLASSTYPE_VBASECLASSES (type);
vbase;
vbase = TREE_CHAIN (vbase))
{
if (BINFO_VBASE_PRIMARY_P (vbase))
/* This virtual base was already included in the hierarchy, so
there's nothing to do here. */
continue;
/* Temporarily pretend that VBASE is primary so that its bases
will be walked; this is the real copy of VBASE. */
BINFO_PRIMARY_MARKED_P (vbase) = 1;
/* Now, walk its bases. */
dfs_walk (vbase, dfs_mark_primary_bases,
dfs_skip_nonprimary_vbases_unmarkedp, type);
/* VBASE wasn't really primary. */
BINFO_PRIMARY_MARKED_P (vbase) = 0;
/* And we don't want to allow it to *become* primary if it is a
base of some subsequent base class. */
SET_BINFO_VBASE_MARKED (vbase);
}
/* Clear the VBASE_MARKED bits we set above. */
for (vbase = CLASSTYPE_VBASECLASSES (type);
vbase;
vbase = TREE_CHAIN (vbase))
CLEAR_BINFO_VBASE_MARKED (vbase);
}
/* If BINFO is a non-primary virtual baseclass (in the hierarchy /* If BINFO is a non-primary virtual baseclass (in the hierarchy
dominated by TYPE), and no primary copy appears anywhere in the dominated by TYPE), and no primary copy appears anywhere in the
hierarchy, return the shared copy. If a primary copy appears hierarchy, return the shared copy. If a primary copy appears
...@@ -2577,17 +2495,6 @@ dfs_unmark (binfo, data) ...@@ -2577,17 +2495,6 @@ dfs_unmark (binfo, data)
return NULL_TREE; return NULL_TREE;
} }
/* Clear both BINFO_MARKED and BINFO_VBASE_MARKED. */
tree
dfs_vbase_unmark (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
CLEAR_BINFO_VBASE_MARKED (binfo);
return dfs_unmark (binfo, data);
}
/* Clear BINFO_VTABLE_PATH_MARKED. */ /* Clear BINFO_VTABLE_PATH_MARKED. */
tree tree
...@@ -2781,7 +2688,7 @@ virtual_context (fndecl, t, vbase) ...@@ -2781,7 +2688,7 @@ virtual_context (fndecl, t, vbase)
while (path) while (path)
{ {
if (TREE_VIA_VIRTUAL (path)) if (TREE_VIA_VIRTUAL (path))
return binfo_member (BINFO_TYPE (path), CLASSTYPE_VBASECLASSES (t)); return BINFO_FOR_VBASE (BINFO_TYPE (path), t);
path = BINFO_INHERITANCE_CHAIN (path); path = BINFO_INHERITANCE_CHAIN (path);
} }
return 0; return 0;
...@@ -3072,7 +2979,7 @@ dfs_get_vbase_types (binfo, data) ...@@ -3072,7 +2979,7 @@ dfs_get_vbase_types (binfo, data)
{ {
tree type = (tree) data; tree type = (tree) data;
if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo)) if (TREE_VIA_VIRTUAL (binfo))
{ {
tree new_vbase = make_binfo (size_zero_node, tree new_vbase = make_binfo (size_zero_node,
BINFO_TYPE (binfo), BINFO_TYPE (binfo),
...@@ -3083,24 +2990,50 @@ dfs_get_vbase_types (binfo, data) ...@@ -3083,24 +2990,50 @@ dfs_get_vbase_types (binfo, data)
BINFO_INHERITANCE_CHAIN (new_vbase) = TYPE_BINFO (type); BINFO_INHERITANCE_CHAIN (new_vbase) = TYPE_BINFO (type);
TREE_CHAIN (new_vbase) = CLASSTYPE_VBASECLASSES (type); TREE_CHAIN (new_vbase) = CLASSTYPE_VBASECLASSES (type);
CLASSTYPE_VBASECLASSES (type) = new_vbase; CLASSTYPE_VBASECLASSES (type) = new_vbase;
SET_BINFO_VBASE_MARKED (binfo);
} }
SET_BINFO_MARKED (binfo); SET_BINFO_MARKED (binfo);
return NULL_TREE; return NULL_TREE;
} }
/* Called via dfs_walk from mark_primary_bases. Builds the
inheritance graph order list of BINFOs. */
static tree
dfs_build_inheritance_graph_order (binfo, data)
tree binfo;
void *data;
{
tree *last_binfo = (tree *) data;
if (*last_binfo)
TREE_CHAIN (*last_binfo) = binfo;
*last_binfo = binfo;
SET_BINFO_MARKED (binfo);
return NULL_TREE;
}
/* Set CLASSTYPE_VBASECLASSES for TYPE. */ /* Set CLASSTYPE_VBASECLASSES for TYPE. */
void void
get_vbase_types (type) get_vbase_types (type)
tree type; tree type;
{ {
tree last_binfo;
CLASSTYPE_VBASECLASSES (type) = NULL_TREE; CLASSTYPE_VBASECLASSES (type) = NULL_TREE;
dfs_walk (TYPE_BINFO (type), dfs_get_vbase_types, unmarkedp, type); dfs_walk (TYPE_BINFO (type), dfs_get_vbase_types, unmarkedp, type);
/* Rely upon the reverse dfs ordering from dfs_get_vbase_types, and now /* Rely upon the reverse dfs ordering from dfs_get_vbase_types, and now
reverse it so that we get normal dfs ordering. */ reverse it so that we get normal dfs ordering. */
CLASSTYPE_VBASECLASSES (type) = nreverse (CLASSTYPE_VBASECLASSES (type)); CLASSTYPE_VBASECLASSES (type) = nreverse (CLASSTYPE_VBASECLASSES (type));
dfs_walk (TYPE_BINFO (type), dfs_vbase_unmark, markedp, 0); dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, 0);
/* Thread the BINFOs in inheritance-graph order. */
last_binfo = NULL;
dfs_walk_real (TYPE_BINFO (type),
dfs_build_inheritance_graph_order,
NULL,
unmarkedp,
&last_binfo);
dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, NULL);
} }
/* Called from find_vbase_instance via dfs_walk. */ /* Called from find_vbase_instance via dfs_walk. */
......
...@@ -590,6 +590,14 @@ adjust_pointer (const void *base, ptrdiff_t offset) ...@@ -590,6 +590,14 @@ adjust_pointer (const void *base, ptrdiff_t offset)
(reinterpret_cast <const char *> (base) + offset); (reinterpret_cast <const char *> (base) + offset);
} }
inline ptrdiff_t
get_vbase_offset (const void *object, ptrdiff_t offset)
{
const char *vtable = *reinterpret_cast <const char *const *> (object);
vtable += offset;
return *reinterpret_cast <const ptrdiff_t *> (vtable);
}
// some predicate functions for __class_type_info::sub_kind // some predicate functions for __class_type_info::sub_kind
inline bool contained_p (__class_type_info::sub_kind access_path) inline bool contained_p (__class_type_info::sub_kind access_path)
{ {
...@@ -718,9 +726,7 @@ do_find_public_src (ptrdiff_t src2dst, ...@@ -718,9 +726,7 @@ do_find_public_src (ptrdiff_t src2dst,
{ {
if (src2dst == -3) if (src2dst == -3)
continue; // Not a virtual base, so can't be here. continue; // Not a virtual base, so can't be here.
const ptrdiff_t *vtable = *static_cast <const ptrdiff_t *const *> (base); offset = get_vbase_offset (base, offset);
offset = vtable[offset];
} }
base = adjust_pointer <void> (base, offset); base = adjust_pointer <void> (base, offset);
...@@ -841,9 +847,7 @@ do_dyncast (ptrdiff_t src2dst, ...@@ -841,9 +847,7 @@ do_dyncast (ptrdiff_t src2dst,
if (base_list[i].is_virtual_p ()) if (base_list[i].is_virtual_p ())
{ {
base_access = sub_kind (base_access | contained_virtual_mask); base_access = sub_kind (base_access | contained_virtual_mask);
const ptrdiff_t *vtable = *static_cast <const ptrdiff_t *const *> (base); offset = get_vbase_offset (base, offset);
offset = vtable[offset];
} }
base = adjust_pointer <void> (base, offset); base = adjust_pointer <void> (base, offset);
...@@ -1041,10 +1045,7 @@ do_upcast (sub_kind access_path, ...@@ -1041,10 +1045,7 @@ do_upcast (sub_kind access_path,
sub_access = sub_kind (sub_access | contained_virtual_mask); sub_access = sub_kind (sub_access | contained_virtual_mask);
if (base) if (base)
{ offset = get_vbase_offset (base, offset);
const ptrdiff_t *vtable = *static_cast <const ptrdiff_t *const *> (base);
offset = vtable[offset];
}
} }
if (base) if (base)
base = adjust_pointer <void> (base, offset); base = adjust_pointer <void> (base, offset);
......
...@@ -921,7 +921,7 @@ debug_binfo (elem) ...@@ -921,7 +921,7 @@ debug_binfo (elem)
debug_tree (BINFO_TYPE (elem)); debug_tree (BINFO_TYPE (elem));
if (BINFO_VTABLE (elem)) if (BINFO_VTABLE (elem))
fprintf (stderr, "vtable decl \"%s\"\n", fprintf (stderr, "vtable decl \"%s\"\n",
IDENTIFIER_POINTER (DECL_NAME (BINFO_VTABLE (elem)))); IDENTIFIER_POINTER (DECL_NAME (get_vtbl_decl_for_binfo (elem))));
else else
fprintf (stderr, "no vtable decl yet\n"); fprintf (stderr, "no vtable decl yet\n");
fprintf (stderr, "virtuals:\n"); fprintf (stderr, "virtuals:\n");
......
// Origin: Mark Mitchell <mark@codesourcery.com>
#if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
struct R
{
virtual void r ();
};
struct S
{
virtual void f ();
};
struct T : virtual public S
{
virtual void g ();
};
struct U : public R, virtual public T
{
virtual void h ();
};
struct V : public R, virtual public S, virtual public T
{
virtual void v ();
};
struct U1
{
R r;
T t;
};
int main ()
{
if (sizeof (U) != sizeof (U1))
return 1;
if (sizeof (V) != sizeof (U1))
return 2;
}
#else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
int main ()
{
}
#endif /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
// Origin: Mark Mitchell <mark@codesourcery.com>
#if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
#include <stddef.h>
struct S0
{
virtual void s0 ();
};
struct S1 : virtual public S0
{
virtual void s1 ();
};
struct S2 : virtual public S1
{
virtual void s1 ();
virtual void s0 ();
};
struct S3
{
virtual void s3 ();
};
struct S4 : public S3, virtual public S2
{
virtual void s1 ();
};
void S0::s0 ()
{
}
void S1::s1 ()
{
}
void S2::s1 ()
{
}
void S2::s0 ()
{
}
void S3::s3 ()
{
}
void S4::s1 ()
{
}
/* The vtables should look like:
S0 primary vtable
S0 offset to top
S0 RTTI
S0::s0
=================
S1 primary vtable
S0::s0 vcall offset
S0 vbase offset
S1 offset to top
S1 RTTI
S0::s0
S1::s1
=================
S2 primary vtable
S2::s1 vcall offset
S1 vbase offset
S2::s0 vcall offset
S0 vbase offset
S2 offset to top
S2 RTTI
S2::s0
S2::s1
=================
S3 primary vtable
S3 offset to top
S3 RTTI
S3::s3
=================
S4 primary vtable
vbase offset for S0
vbase offset for S1
vbase offset for S2
S4 offset to top
S4 RTTI
S3::s3
S4::s1
S2-in-S4 secondary vtable
S4::s1 vcall offset
S1 vbase offset
S2:s0 vcall offset
S0 vbase offset
S2 offset to top
S4 RTTI
S2::s0
S4::s1
*/
// These are tricks to allow us to get raw function pointers for
// member functions.
extern "C" {
void s3__2S3 ();
void s1__2S4 ();
}
int main ()
{
S4 s4;
ptrdiff_t **vptr;
ptrdiff_t *vtbl;
// Set vtbl to point at the beginning of S4's primary vtable.
vptr = (ptrdiff_t **) &s4;
vtbl = *vptr;
vtbl -= 5;
if (*vtbl++ != ((char*) (S0*) &s4) - (char*) &s4)
return 1;
if (*vtbl++ != ((char*) (S1*) &s4) - (char*) &s4)
return 2;
if (*vtbl++ != ((char*) (S2*) &s4) - (char*) &s4)
return 3;
if (*vtbl++ != 0)
return 4;
// Skip the RTTI entry.
vtbl++;
if (*vtbl++ != (ptrdiff_t) &s3__2S3)
return 5;
if (*vtbl++ != (ptrdiff_t) &s1__2S4)
return 6;
// All the vcall and vbase offsets should be zero.
if (*vtbl++ != 0)
return 7;
if (*vtbl++ != 0)
return 8;
if (*vtbl++ != 0)
return 9;
if (*vtbl++ != 0)
return 10;
// Now we're at the S2 offset to top entry.
if (*vtbl++ != ((char*) &s4 - (char*) (S2*) &s4))
return 11;
// Skip the RTTI entry.
vtbl++;
// Skip the remaining virtual functions -- they are thunks.
vtbl++;
vtbl++;
}
#else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
int main ()
{
}
#endif /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
...@@ -28,5 +28,5 @@ int main () ...@@ -28,5 +28,5 @@ int main ()
ap = (C2*)&e2; ap = (C2*)&e2;
// ap points to base subobject shared by two Bs; fails // ap points to base subobject shared by two Bs; fails
if (dynamic_cast <B2*> (ap) != 0) if (dynamic_cast <B2*> (ap) != 0)
return 1; return 2;
} }
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