cp-tree.h (dfs_skip_vbases): New function.

* cp-tree.h (dfs_skip_vbases): New function.
	(find_vbase_instance): Likewise.
	* class.c (determine_primary_base): Allow a nearly empty base to
	serve as a primary base class under the new ABI.
	(get_class_offset_1): Rename to ...
	(dfs_get_class_offset): ... this.  Simplify.  Don't issue error
	messages here.
	(get_class_offset): Use it.  Issue error messages here.
	(dfs_modify_vtables): Rely on dfs_unmarked_real_bases_queue_p to
	find the right copies of virtual bases.
	(fixup_vtable_deltas1): Rename to ...
	(dfs_fixup_vtable_deltas): ... this.  Adjust to handle virtual
	bases as primary bases.
	(fixup_vtable_deltas): Remove.
	(override_one_vtable): Handle virtual bases as primary bases.
	(merge_overrides): Likewise.
	(finish_struct_1): Likewise.
	(dump_class_hierarchy): Dump primary-ness of bases as well.
	* search.c (mark_primary_bases): Use a pre-order traversal to
	handle primary virtual bases.
	(dfs_skip_vbases): New fiunction.
	(expand_upcast_fixups): Adjust to handle primary virtual bases.
	(fixup_virtual_upcast_offsets): Likewise.
	(fixup_all_virtual_upcast_offsets): Likewise.
	(dfs_find_vbase_instances): New function.
	(find_vbase_instance): Likewise.

From-SVN: r31360
This commit is contained in:
Mark Mitchell 2000-01-12 20:56:15 +00:00 committed by Mark Mitchell
parent e5778b1e84
commit dd42e13519
4 changed files with 231 additions and 64 deletions

View File

@ -1,3 +1,32 @@
2000-01-12 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (dfs_skip_vbases): New function.
(find_vbase_instance): Likewise.
* class.c (determine_primary_base): Allow a nearly empty base to
serve as a primary base class under the new ABI.
(get_class_offset_1): Rename to ...
(dfs_get_class_offset): ... this. Simplify. Don't issue error
messages here.
(get_class_offset): Use it. Issue error messages here.
(dfs_modify_vtables): Rely on dfs_unmarked_real_bases_queue_p to
find the right copies of virtual bases.
(fixup_vtable_deltas1): Rename to ...
(dfs_fixup_vtable_deltas): ... this. Adjust to handle virtual
bases as primary bases.
(fixup_vtable_deltas): Remove.
(override_one_vtable): Handle virtual bases as primary bases.
(merge_overrides): Likewise.
(finish_struct_1): Likewise.
(dump_class_hierarchy): Dump primary-ness of bases as well.
* search.c (mark_primary_bases): Use a pre-order traversal to
handle primary virtual bases.
(dfs_skip_vbases): New fiunction.
(expand_upcast_fixups): Adjust to handle primary virtual bases.
(fixup_virtual_upcast_offsets): Likewise.
(fixup_all_virtual_upcast_offsets): Likewise.
(dfs_find_vbase_instances): New function.
(find_vbase_instance): Likewise.
2000-01-11 Mumit Khan <khan@xraylith.wisc.edu>
* lex.c (DIR_SEPARATOR): Delete macro.

View File

@ -82,8 +82,7 @@ static tree get_basefndecls PROTO((tree, tree));
static void set_rtti_entry PROTO((tree, tree, tree));
static void build_vtable PROTO((tree, tree));
static void prepare_fresh_vtable PROTO((tree, tree));
static void fixup_vtable_deltas1 PROTO((tree, tree));
static void fixup_vtable_deltas PROTO((tree, int, tree));
static tree dfs_fixup_vtable_deltas PROTO((tree, void *));
static tree dfs_finish_vtbls PROTO((tree, void *));
static void finish_vtbls PROTO((tree));
static void modify_vtable_entry PROTO((tree, tree, tree));
@ -100,7 +99,7 @@ static void merge_overrides PROTO((tree, tree, int, tree));
static void override_one_vtable PROTO((tree, tree, tree));
static void mark_overriders PROTO((tree, tree));
static void check_for_override PROTO((tree, tree));
static tree get_class_offset_1 PROTO((tree, tree, tree, tree, tree));
static tree dfs_get_class_offset PROTO((tree, void *));
static tree get_class_offset PROTO((tree, tree, tree, tree));
static void modify_one_vtable PROTO((tree, tree, tree));
static tree dfs_modify_vtables PROTO((tree, void *));
@ -1672,9 +1671,25 @@ determine_primary_base (t, has_virtual_p)
if (!TYPE_VFIELD (t))
CLASSTYPE_VFIELD_PARENT (t) = -1;
/* Now that we know what the primary base class is, we can run
through the entire hierarchy marking the primary bases for future
reference. */
/* The new ABI allows for the use of a "nearly-empty" virtual base
class as the primary base class if no non-virtual polymorphic
base can be found. */
if (flag_new_abi && !CLASSTYPE_HAS_PRIMARY_BASE_P (t))
for (i = 0; i < n_baseclasses; ++i)
{
tree base_binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i);
tree basetype = BINFO_TYPE (base_binfo);
if (TREE_VIA_VIRTUAL (base_binfo)
&& CLASSTYPE_NEARLY_EMPTY_P (basetype))
{
set_primary_base (t, i, has_virtual_p);
CLASSTYPE_VFIELDS (t) = copy_list (CLASSTYPE_VFIELDS (basetype));
break;
}
}
/* Mark the primary base classes at this point. */
mark_primary_bases (t);
}
@ -2266,6 +2281,9 @@ overrides (fndecl, base_fndecl)
return 0;
}
/* Returns the BINFO_OFFSET for the base of BINFO that has the same
type as CONTEXT. */
static tree
get_class_offset_1 (parent, binfo, context, t, fndecl)
tree parent, binfo, context, t, fndecl;
@ -2311,14 +2329,37 @@ get_class_offset_1 (parent, binfo, context, t, fndecl)
return rval;
}
/* Get the offset to the CONTEXT subobject that is related to the
given BINFO. */
/* Called from get_class_offset via dfs_walk. */
static tree
dfs_get_class_offset (binfo, data)
tree binfo;
void *data;
{
tree list = (tree) data;
tree context = TREE_TYPE (list);
if (same_type_p (BINFO_TYPE (binfo), context))
{
if (TREE_VALUE (list))
return error_mark_node;
else
TREE_VALUE (list) = BINFO_OFFSET (binfo);
}
SET_BINFO_MARKED (binfo);
return NULL_TREE;
}
/* Returns the BINFO_OFFSET for the subobject of BINFO that has the
type given by CONTEXT. */
static tree
get_class_offset (context, t, binfo, fndecl)
tree context, t, binfo, fndecl;
{
tree first_binfo = binfo;
tree list;
tree offset;
int i;
@ -2338,11 +2379,28 @@ get_class_offset (context, t, binfo, fndecl)
return BINFO_OFFSET (binfo);
}
/* Ok, not found in the less derived binfos, now check the more
derived binfos. */
offset = get_class_offset_1 (first_binfo, TYPE_BINFO (t), context, t, fndecl);
if (offset==0 || TREE_CODE (offset) != INTEGER_CST)
my_friendly_abort (999); /* we have to find it. */
list = build_tree_list (t, NULL_TREE);
TREE_TYPE (list) = context;
offset = dfs_walk (TYPE_BINFO (t),
dfs_get_class_offset,
dfs_unmarked_real_bases_queue_p,
list);
dfs_walk (TYPE_BINFO (t), dfs_unmark, dfs_marked_real_bases_queue_p, t);
if (offset == error_mark_node)
{
error ("every virtual function must have a unique final overrider");
cp_error (" found two (or more) `%T' class subobjects in `%T'",
context, t);
cp_error (" with virtual `%D' from virtual base class", fndecl);
offset = integer_zero_node;
}
else
offset = TREE_VALUE (list);
my_friendly_assert (offset != NULL_TREE, 999);
my_friendly_assert (TREE_CODE (offset) == INTEGER_CST, 999);
return offset;
}
@ -2473,9 +2531,6 @@ dfs_modify_vtables (binfo, data)
&& CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
{
tree list = (tree) data;
if (TREE_VIA_VIRTUAL (binfo))
binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), TREE_PURPOSE (list));
modify_one_vtable (binfo, TREE_PURPOSE (list), TREE_VALUE (list));
}
@ -2499,13 +2554,23 @@ modify_all_vtables (t, fndecl)
/* Fixup all the delta entries in this one vtable that need updating. */
static void
fixup_vtable_deltas1 (binfo, t)
tree binfo, t;
static tree
dfs_fixup_vtable_deltas (binfo, data)
tree binfo;
void *data;
{
tree virtuals;
unsigned HOST_WIDE_INT n;
tree t = (tree) data;
while (BINFO_PRIMARY_MARKED_P (binfo))
{
binfo = BINFO_INHERITANCE_CHAIN (binfo);
/* If BINFO is virtual then we'll handle this base later. */
if (TREE_VIA_VIRTUAL (binfo))
return NULL_TREE;
}
virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), &n);
while (virtuals)
@ -2559,33 +2624,8 @@ fixup_vtable_deltas1 (binfo, t)
++n;
virtuals = TREE_CHAIN (virtuals);
}
}
/* Fixup all the delta entries in all the direct vtables that need updating.
This happens when we have non-overridden virtual functions from a
virtual base class, that are at a different offset, in the new
hierarchy, because the layout of the virtual bases has changed. */
static void
fixup_vtable_deltas (binfo, init_self, t)
tree binfo;
int init_self;
tree t;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
int is_not_base_vtable
= i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (! TREE_VIA_VIRTUAL (base_binfo))
fixup_vtable_deltas (base_binfo, is_not_base_vtable, t);
}
/* Should we use something besides CLASSTYPE_VFIELDS? */
if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
fixup_vtable_deltas1 (binfo, t);
return NULL_TREE;
}
/* Here, we already know that they match in every respect.
@ -2622,8 +2662,26 @@ override_one_vtable (binfo, old, t)
{
tree virtuals;
tree old_virtuals;
tree orig_binfo;
tree orig_virtuals;
enum { REUSE_NEW, REUSE_OLD, UNDECIDED, NEITHER } choose = UNDECIDED;
/* Either or both of BINFO or OLD might be primary base classes
because merge_overrides is called with a vbase from the class we
are definining and the corresponding vbase from one of its direct
bases. */
orig_binfo = binfo;
while (BINFO_PRIMARY_MARKED_P (binfo))
{
binfo = BINFO_INHERITANCE_CHAIN (binfo);
/* If BINFO is virtual, then we'll handle this virtual base when
later. */
if (TREE_VIA_VIRTUAL (binfo))
return;
}
while (BINFO_PRIMARY_MARKED_P (old))
old = BINFO_INHERITANCE_CHAIN (old);
/* If we have already committed to modifying it, then don't try and
reuse another vtable. */
if (BINFO_NEW_VTABLE_MARKED (binfo))
@ -2631,8 +2689,9 @@ override_one_vtable (binfo, old, t)
virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), NULL);
old_virtuals = skip_rtti_stuff (old, BINFO_TYPE (binfo), NULL);
orig_virtuals = skip_rtti_stuff (orig_binfo, BINFO_TYPE (binfo), NULL);
while (virtuals)
while (orig_virtuals)
{
tree fndecl = TREE_VALUE (virtuals);
tree old_fndecl = TREE_VALUE (old_virtuals);
@ -2705,6 +2764,7 @@ override_one_vtable (binfo, old, t)
}
virtuals = TREE_CHAIN (virtuals);
old_virtuals = TREE_CHAIN (old_virtuals);
orig_virtuals = TREE_CHAIN (orig_virtuals);
}
/* Let's reuse the old vtable. */
@ -2739,8 +2799,8 @@ merge_overrides (binfo, old, do_self, t)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree old_base_binfo = TREE_VEC_ELT (old_binfos, i);
int is_not_base_vtable
= i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
int is_not_base_vtable
= !BINFO_PRIMARY_MARKED_P (base_binfo);
if (! TREE_VIA_VIRTUAL (base_binfo))
merge_overrides (base_binfo, old_base_binfo, is_not_base_vtable, t);
}
@ -4563,9 +4623,15 @@ finish_struct_1 (t)
vbases = CLASSTYPE_VBASECLASSES (basetype);
while (vbases)
{
merge_overrides (binfo_member (BINFO_TYPE (vbases),
CLASSTYPE_VBASECLASSES (t)),
vbases, 1, t);
tree vbase;
tree basetype_vbase;
vbase
= find_vbase_instance (BINFO_TYPE (vbases), t);
basetype_vbase
= find_vbase_instance (BINFO_TYPE (vbases), basetype);
merge_overrides (vbase, basetype_vbase, 1, t);
vbases = TREE_CHAIN (vbases);
}
}
@ -4613,11 +4679,14 @@ finish_struct_1 (t)
vbases = CLASSTYPE_VBASECLASSES (t);
while (vbases)
{
tree vbase;
/* We might be able to shorten the amount of work we do by
only doing this for vtables that come from virtual bases
that have differing offsets, but don't want to miss any
entries. */
fixup_vtable_deltas (vbases, 1, t);
vbase = find_vbase_instance (BINFO_TYPE (vbases), t);
dfs_walk (vbase, dfs_fixup_vtable_deltas, dfs_skip_vbases, t);
vbases = TREE_CHAIN (vbases);
}
}
@ -6015,10 +6084,11 @@ dump_class_hierarchy (binfo, indent)
{
int i;
fprintf (stderr, "%*s0x%x (%s) %d\n", indent, "",
fprintf (stderr, "%*s0x%x (%s) %d %s\n", indent, "",
(unsigned int) binfo,
type_as_string (binfo, TS_PLAIN),
TREE_INT_CST_LOW (BINFO_OFFSET (binfo)));
TREE_INT_CST_LOW (BINFO_OFFSET (binfo)),
BINFO_PRIMARY_MARKED_P (binfo) ? "primary" : "");
for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
dump_class_hierarchy (BINFO_BASETYPE (binfo, i), indent + 2);

View File

@ -3954,8 +3954,10 @@ extern tree dfs_skip_nonprimary_vbases_unmarkedp PROTO((tree, void *));
extern tree dfs_skip_nonprimary_vbases_markedp PROTO((tree, void *));
extern tree dfs_unmarked_real_bases_queue_p PROTO((tree, void *));
extern tree dfs_marked_real_bases_queue_p PROTO((tree, void *));
extern tree dfs_skip_vbases PROTO((tree, void *));
extern void mark_primary_bases PROTO((tree));
extern tree convert_pointer_to_vbase PROTO((tree, tree));
extern tree find_vbase_instance PROTO((tree, tree));
/* in semantics.c */
extern void finish_expr_stmt PROTO((tree));

View File

@ -151,6 +151,7 @@ static int template_self_reference_p PROTO ((tree, tree));
static void fixup_all_virtual_upcast_offsets PROTO ((tree, tree));
static tree dfs_mark_primary_bases PROTO((tree, void *));
static tree get_shared_vbase_if_not_primary PROTO((tree, tree));
static tree dfs_find_vbase_instance PROTO((tree, void *));
/* Allocate a level of searching. */
@ -2189,9 +2190,14 @@ mark_primary_bases (type)
{
tree vbase;
/* Mark the TYPE_BINFO hierarchy. */
dfs_walk (TYPE_BINFO (type), dfs_mark_primary_bases,
dfs_skip_nonprimary_vbases_unmarkedp, type);
/* 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
@ -2289,6 +2295,20 @@ dfs_marked_real_bases_queue_p (binfo, data)
return binfo ? markedp (binfo, NULL) : NULL_TREE;
}
/* A queue function that skips all virtual bases (and their
bases). */
tree
dfs_skip_vbases (binfo, data)
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
if (TREE_VIA_VIRTUAL (binfo))
return NULL_TREE;
return binfo;
}
/* Called via dfs_walk from dfs_get_pure_virtuals. */
static tree
@ -2798,7 +2818,14 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
tree vc;
tree delta;
unsigned HOST_WIDE_INT n;
while (BINFO_PRIMARY_MARKED_P (binfo))
{
binfo = BINFO_INHERITANCE_CHAIN (binfo);
if (TREE_VIA_VIRTUAL (binfo))
return;
}
delta = purpose_member (vbase, *vbase_offsets);
if (! delta)
{
@ -2925,7 +2952,7 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori
tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
tree base_binfo = TREE_VEC_ELT (binfos, i);
int is_not_base_vtable
= i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
= !BINFO_PRIMARY_MARKED_P (real_base_binfo);
if (! TREE_VIA_VIRTUAL (real_base_binfo))
fixup_virtual_upcast_offsets (real_base_binfo, base_binfo,
is_not_base_vtable, can_elide, addr,
@ -2979,15 +3006,17 @@ fixup_all_virtual_upcast_offsets (type, decl_ptr)
;
else
{
tree vbase;
tree vbase_offsets;
tree addr;
vbase = find_vbase_instance (BINFO_TYPE (vbases), type);
vbase_offsets = NULL_TREE;
addr = convert_pointer_to_vbase (TREE_TYPE (vbases), decl_ptr);
fixup_virtual_upcast_offsets (vbases,
addr = convert_pointer_to_vbase (BINFO_TYPE (vbases), decl_ptr);
fixup_virtual_upcast_offsets (vbase,
TYPE_BINFO (BINFO_TYPE (vbases)),
1, 0, addr, decl_ptr,
type, vbases, &vbase_offsets);
type, vbase, &vbase_offsets);
}
}
@ -3074,6 +3103,43 @@ get_vbase_types (type)
CLASSTYPE_VBASECLASSES (type) = nreverse (CLASSTYPE_VBASECLASSES (type));
dfs_walk (TYPE_BINFO (type), dfs_vbase_unmark, markedp, 0);
}
/* Called from find_vbase_instance via dfs_walk. */
static tree
dfs_find_vbase_instance (binfo, data)
tree binfo;
void *data;
{
tree base = TREE_VALUE ((tree) data);
if (BINFO_PRIMARY_MARKED_P (binfo)
&& same_type_p (BINFO_TYPE (binfo), base))
return binfo;
return NULL_TREE;
}
/* Find the real occurrence of the virtual BASE (a class type) in the
hierarchy dominated by TYPE. */
tree
find_vbase_instance (base, type)
tree base;
tree type;
{
tree instance;
instance = BINFO_FOR_VBASE (base, type);
if (!BINFO_VBASE_PRIMARY_P (instance))
return instance;
return dfs_walk (TYPE_BINFO (type),
dfs_find_vbase_instance,
NULL,
build_tree_list (type, base));
}
/* Debug info for C++ classes can get very large; try to avoid
emitting it everywhere.