cp-tree.h (BINFO_VIRTUALS): Tweak documentation.

* cp-tree.h (BINFO_VIRTUALS): Tweak documentation.
	(CLASSTYPE_PRIMARY_BINFO): Use BINFO_PRIMARY_BINFO.
	(BINFO_PRIMARY_BINFO): New macro.
	(BF_DELTA): Rename to ...
	(BV_DELTA): ... this.
	(BF_VCALL_INDEX): Rename to ...
	(BV_VCALL_INDEX): ... this.
	(BF_FN): Rename to ...
	(BV_FN): ... this.
	* class.c (build_vbase_path): Adjust for changes to reverse_path.
	(set_rtti_entry): Rename BF_ macros to BV_ variants.
	(modify_vtable_entry): Simplify.
	(add_virtual_function): Rename BF_ macros to BV_ variants.
	(build_vtable_initializer): Likewise.
	(get_class_offset_1): Remove.
	(dfs_get_class_offset): Likewise.
	(get_class_offset): Likewise.
	(dfs_find_final_overrider): New function.
	(find_final_overrider): Likewise.
	(modify_one_vtable): Remove.
	(dfs_find_base): New function.
	(dfs_modify_vtables): Fold modify_one_vtable in here.  Use
	find_final_overrider.
	(modify_all_vtables): Adjust.  Set BV_VCALL_INDEX on new
	virtuals.
	(dfs_fixup_vtable_deltas): Remove.
	(override_one_vtable): Remove.
	(merge_overrides): Likewise.
	(layout_virtual_bases): Make sure BINFO_OFFSET is set right for
	unreal chilren of virtual bases.
	(finish_struct_1): Don't use merge_overrides.  Don't use
	dfs_fixup_vtable_deltas.
	* tree.c (reverse_path): Return a TREE_LIST, not a chain of
	BINFOs.

From-SVN: r31724
This commit is contained in:
Mark Mitchell 2000-01-31 21:00:01 +00:00 committed by Mark Mitchell
parent d4cf5733ee
commit 5e19c05390
4 changed files with 313 additions and 475 deletions

View File

@ -1,3 +1,40 @@
2000-01-31 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (BINFO_VIRTUALS): Tweak documentation.
(CLASSTYPE_PRIMARY_BINFO): Use BINFO_PRIMARY_BINFO.
(BINFO_PRIMARY_BINFO): New macro.
(BF_DELTA): Rename to ...
(BV_DELTA): ... this.
(BF_VCALL_INDEX): Rename to ...
(BV_VCALL_INDEX): ... this.
(BF_FN): Rename to ...
(BV_FN): ... this.
* class.c (build_vbase_path): Adjust for changes to reverse_path.
(set_rtti_entry): Rename BF_ macros to BV_ variants.
(modify_vtable_entry): Simplify.
(add_virtual_function): Rename BF_ macros to BV_ variants.
(build_vtable_initializer): Likewise.
(get_class_offset_1): Remove.
(dfs_get_class_offset): Likewise.
(get_class_offset): Likewise.
(dfs_find_final_overrider): New function.
(find_final_overrider): Likewise.
(modify_one_vtable): Remove.
(dfs_find_base): New function.
(dfs_modify_vtables): Fold modify_one_vtable in here. Use
find_final_overrider.
(modify_all_vtables): Adjust. Set BV_VCALL_INDEX on new
virtuals.
(dfs_fixup_vtable_deltas): Remove.
(override_one_vtable): Remove.
(merge_overrides): Likewise.
(layout_virtual_bases): Make sure BINFO_OFFSET is set right for
unreal chilren of virtual bases.
(finish_struct_1): Don't use merge_overrides. Don't use
dfs_fixup_vtable_deltas.
* tree.c (reverse_path): Return a TREE_LIST, not a chain of
BINFOs.
2000-01-31 Herman A.J. ten Brugge <Haj.Ten.Brugge@net.HCC.nl> 2000-01-31 Herman A.J. ten Brugge <Haj.Ten.Brugge@net.HCC.nl>
Jason Merrill <jason@yorick.cygnus.com> Jason Merrill <jason@yorick.cygnus.com>

View File

@ -82,10 +82,9 @@ static tree get_basefndecls PARAMS ((tree, tree));
static void set_rtti_entry PARAMS ((tree, tree, tree)); static void set_rtti_entry PARAMS ((tree, tree, tree));
static int build_primary_vtable PARAMS ((tree, tree)); static int build_primary_vtable PARAMS ((tree, tree));
static int build_secondary_vtable PARAMS ((tree, tree)); static int build_secondary_vtable PARAMS ((tree, tree));
static tree dfs_fixup_vtable_deltas PARAMS ((tree, void *));
static tree dfs_finish_vtbls PARAMS ((tree, void *)); static tree dfs_finish_vtbls PARAMS ((tree, void *));
static void finish_vtbls PARAMS ((tree)); static void finish_vtbls PARAMS ((tree));
static void modify_vtable_entry PARAMS ((tree, tree, tree, tree *)); static void modify_vtable_entry PARAMS ((tree, tree, tree, tree, tree *));
static void add_virtual_function PARAMS ((tree *, tree *, int *, tree, tree)); static void add_virtual_function PARAMS ((tree *, tree *, int *, tree, tree));
static tree delete_duplicate_fields_1 PARAMS ((tree, tree)); static tree delete_duplicate_fields_1 PARAMS ((tree, tree));
static void delete_duplicate_fields PARAMS ((tree)); static void delete_duplicate_fields PARAMS ((tree));
@ -94,13 +93,8 @@ static int alter_access PARAMS ((tree, tree, tree, tree));
static void handle_using_decl PARAMS ((tree, tree)); static void handle_using_decl PARAMS ((tree, tree));
static int overrides PARAMS ((tree, tree)); static int overrides PARAMS ((tree, tree));
static int strictly_overrides PARAMS ((tree, tree)); static int strictly_overrides PARAMS ((tree, tree));
static void merge_overrides PARAMS ((tree, tree, int, tree));
static void override_one_vtable PARAMS ((tree, tree, tree));
static void mark_overriders PARAMS ((tree, tree)); static void mark_overriders PARAMS ((tree, tree));
static void check_for_override PARAMS ((tree, tree)); static void check_for_override PARAMS ((tree, tree));
static tree dfs_get_class_offset PARAMS ((tree, void *));
static tree get_class_offset PARAMS ((tree, tree, tree, tree));
static void modify_one_vtable PARAMS ((tree, tree, tree));
static tree dfs_modify_vtables PARAMS ((tree, void *)); static tree dfs_modify_vtables PARAMS ((tree, void *));
static tree modify_all_vtables PARAMS ((tree, int *, tree)); static tree modify_all_vtables PARAMS ((tree, int *, tree));
static void determine_primary_base PARAMS ((tree, int *)); static void determine_primary_base PARAMS ((tree, int *));
@ -151,6 +145,9 @@ static tree dfs_count_virtuals PARAMS ((tree, void *));
static void start_vtable PARAMS ((tree, int *)); static void start_vtable PARAMS ((tree, int *));
static void layout_vtable_decl PARAMS ((tree, int)); static void layout_vtable_decl PARAMS ((tree, int));
static int num_vfun_entries PARAMS ((tree)); static int num_vfun_entries PARAMS ((tree));
static tree dfs_find_final_overrider PARAMS ((tree, void *));
static tree find_final_overrider PARAMS ((tree, tree, tree));
static tree dfs_find_base PARAMS ((tree, void *));
static int make_new_vtable PARAMS ((tree, tree)); static int make_new_vtable PARAMS ((tree, tree));
/* Variables shared between class.c and call.c. */ /* Variables shared between class.c and call.c. */
@ -558,16 +555,15 @@ build_vbase_path (code, type, expr, path, nonnull)
expr = save_expr (expr); expr = save_expr (expr);
nonnull_expr = expr; nonnull_expr = expr;
if (BINFO_INHERITANCE_CHAIN (path)) path = reverse_path (path);
path = reverse_path (path);
basetype = BINFO_TYPE (path); basetype = BINFO_TYPE (path);
while (path) while (path)
{ {
if (TREE_VIA_VIRTUAL (path)) if (TREE_VIA_VIRTUAL (TREE_VALUE (path)))
{ {
last_virtual = BINFO_TYPE (path); last_virtual = BINFO_TYPE (TREE_VALUE (path));
if (code == PLUS_EXPR) if (code == PLUS_EXPR)
{ {
changed = ! fixed_type_p; changed = ! fixed_type_p;
@ -609,8 +605,8 @@ build_vbase_path (code, type, expr, path, nonnull)
return error_mark_node; return error_mark_node;
} }
} }
last = path; last = TREE_VALUE (path);
path = BINFO_INHERITANCE_CHAIN (path); path = TREE_CHAIN (path);
} }
/* LAST is now the last basetype assoc on the path. */ /* LAST is now the last basetype assoc on the path. */
@ -981,8 +977,8 @@ set_rtti_entry (virtuals, offset, type)
if (flag_vtable_thunks) if (flag_vtable_thunks)
{ {
/* The first slot holds the offset. */ /* The first slot holds the offset. */
BF_DELTA (virtuals) = offset; BV_DELTA (virtuals) = offset;
BF_VCALL_INDEX (virtuals) = integer_zero_node; BV_VCALL_INDEX (virtuals) = integer_zero_node;
/* The next node holds the decl. */ /* The next node holds the decl. */
virtuals = TREE_CHAIN (virtuals); virtuals = TREE_CHAIN (virtuals);
@ -990,9 +986,9 @@ set_rtti_entry (virtuals, offset, type)
} }
/* This slot holds the function to call. */ /* This slot holds the function to call. */
BF_DELTA (virtuals) = offset; BV_DELTA (virtuals) = offset;
BF_VCALL_INDEX (virtuals) = integer_zero_node; BV_VCALL_INDEX (virtuals) = integer_zero_node;
BF_FN (virtuals) = decl; BV_FN (virtuals) = decl;
} }
/* Get the VAR_DECL of the vtable for TYPE. TYPE need not be polymorphic, /* Get the VAR_DECL of the vtable for TYPE. TYPE need not be polymorphic,
@ -1289,44 +1285,27 @@ make_new_vtable (t, binfo)
/* Make *VIRTUALS, an entry on the BINFO_VIRTUALS list for BINFO /* Make *VIRTUALS, an entry on the BINFO_VIRTUALS list for BINFO
(which is in the hierarchy dominated by T) list FNDECL as its (which is in the hierarchy dominated by T) list FNDECL as its
BF_FN. */ BV_FN. DELTA is the required adjustment from the `this' pointer
where the vtable entry appears to the `this' required when the
function is actually called. */
static void static void
modify_vtable_entry (t, binfo, fndecl, virtuals) modify_vtable_entry (t, binfo, fndecl, delta, virtuals)
tree t; tree t;
tree binfo; tree binfo;
tree fndecl; tree fndecl;
tree delta;
tree *virtuals; tree *virtuals;
{ {
tree base_offset;
tree offset;
tree context;
tree this_offset;
tree vcall_index; tree vcall_index;
tree v; tree v;
v = *virtuals; v = *virtuals;
context = DECL_CLASS_CONTEXT (fndecl);
offset = get_class_offset (context, t, binfo, fndecl);
/* Find the right offset for ythe this pointer based on the
base class we just found. We have to take into
consideration the virtual base class pointers that we
stick in before the virtual function table pointer.
Also, we want just the delta between the most base class
that we derived this vfield from and us. */
base_offset
= size_binop (PLUS_EXPR,
get_derived_offset (binfo,
DECL_VIRTUAL_CONTEXT (BF_FN (v))),
BINFO_OFFSET (binfo));
this_offset = ssize_binop (MINUS_EXPR, offset, base_offset);
vcall_index = integer_zero_node; vcall_index = integer_zero_node;
if (fndecl != BF_FN (v) if (fndecl != BV_FN (v)
|| !tree_int_cst_equal (this_offset, BF_DELTA (v)) || !tree_int_cst_equal (delta, BV_DELTA (v))
|| !tree_int_cst_equal (vcall_index, BF_VCALL_INDEX (v))) || !tree_int_cst_equal (vcall_index, BV_VCALL_INDEX (v)))
{ {
tree base_fndecl; tree base_fndecl;
@ -1337,15 +1316,15 @@ modify_vtable_entry (t, binfo, fndecl, virtuals)
of the BINFO_VIRTUALS list. Now, we have to find the of the BINFO_VIRTUALS list. Now, we have to find the
corresponding entry in that list. */ corresponding entry in that list. */
*virtuals = BINFO_VIRTUALS (binfo); *virtuals = BINFO_VIRTUALS (binfo);
while (BF_FN (*virtuals) != BF_FN (v)) while (BV_FN (*virtuals) != BV_FN (v))
*virtuals = TREE_CHAIN (*virtuals); *virtuals = TREE_CHAIN (*virtuals);
v = *virtuals; v = *virtuals;
} }
base_fndecl = BF_FN (v); base_fndecl = BV_FN (v);
BF_DELTA (v) = this_offset; BV_DELTA (v) = delta;
BF_VCALL_INDEX (v) = vcall_index; BV_VCALL_INDEX (v) = vcall_index;
BF_FN (v) = fndecl; BV_FN (v) = fndecl;
/* Now assign virtual dispatch information, if unset. We can /* Now assign virtual dispatch information, if unset. We can
dispatch this, through any overridden base function. */ dispatch this, through any overridden base function. */
@ -1407,7 +1386,7 @@ add_virtual_function (new_virtuals_p, overridden_virtuals_p,
return; return;
new_virtual = build_tree_list (integer_zero_node, fndecl); new_virtual = build_tree_list (integer_zero_node, fndecl);
BF_VCALL_INDEX (new_virtual) = integer_zero_node; BV_VCALL_INDEX (new_virtual) = integer_zero_node;
if (DECL_VINDEX (fndecl) == error_mark_node) if (DECL_VINDEX (fndecl) == error_mark_node)
{ {
@ -2713,9 +2692,9 @@ build_vtbl_initializer (binfo, t)
/* Pull the offset for `this', and the function to call, out of /* Pull the offset for `this', and the function to call, out of
the list. */ the list. */
delta = BF_DELTA (v); delta = BV_DELTA (v);
vcall_index = BF_VCALL_INDEX (v); vcall_index = BV_VCALL_INDEX (v);
fn = BF_FN (v); fn = BV_FN (v);
my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727); my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727); my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
@ -2812,127 +2791,151 @@ overrides (fndecl, base_fndecl)
return 0; return 0;
} }
/* Returns the BINFO_OFFSET for the base of BINFO that has the same typedef struct find_final_overrider_data_s {
type as CONTEXT. */ /* The function for which we are trying to find a final overrider. */
tree fn;
/* The base class in which the function was declared. */
tree declaring_base;
/* The most derived class in the hierarchy. */
tree most_derived_type;
/* The final overriding function. */
tree overriding_fn;
/* The BINFO for the class in which the final overriding function
appears. */
tree overriding_base;
} find_final_overrider_data;
/* Called from find_final_overrider via dfs_walk. */
static tree static tree
get_class_offset_1 (parent, binfo, context, t, fndecl) dfs_find_final_overrider (binfo, data)
tree parent, binfo, context, t, fndecl;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
tree rval = NULL_TREE;
if (binfo == parent)
return error_mark_node;
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree nrval;
if (TREE_VIA_VIRTUAL (base_binfo))
base_binfo = BINFO_FOR_VBASE (BINFO_TYPE (base_binfo), t);
nrval = get_class_offset_1 (parent, base_binfo, context, t, fndecl);
/* See if we have a new value */
if (nrval && (nrval != error_mark_node || rval==0))
{
/* Only compare if we have two offsets */
if (rval && rval != error_mark_node
&& ! tree_int_cst_equal (nrval, rval))
{
/* Only give error if the two offsets are different */
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);
return rval;
}
rval = nrval;
}
if (rval && BINFO_TYPE (binfo) == context)
{
my_friendly_assert (rval == error_mark_node
|| tree_int_cst_equal (rval, BINFO_OFFSET (binfo)), 999);
rval = BINFO_OFFSET (binfo);
}
}
return rval;
}
/* Called from get_class_offset via dfs_walk. */
static tree
dfs_get_class_offset (binfo, data)
tree binfo; tree binfo;
void *data; void *data;
{ {
tree list = (tree) data; find_final_overrider_data *ffod = (find_final_overrider_data *) data;
tree context = TREE_TYPE (list);
if (same_type_p (BINFO_TYPE (binfo), context)) if (same_type_p (BINFO_TYPE (binfo),
BINFO_TYPE (ffod->declaring_base))
&& tree_int_cst_equal (BINFO_OFFSET (binfo),
BINFO_OFFSET (ffod->declaring_base)))
{ {
if (TREE_VALUE (list)) tree path;
return error_mark_node; tree method;
else
TREE_VALUE (list) = BINFO_OFFSET (binfo); /* We've found a path to the declaring base. Walk down the path
looking for an overrider for FN. */
for (path = reverse_path (binfo);
path;
path = TREE_CHAIN (path))
{
for (method = TYPE_METHODS (BINFO_TYPE (TREE_VALUE (path)));
method;
method = TREE_CHAIN (method))
if (DECL_VIRTUAL_P (method) && overrides (method, ffod->fn))
break;
if (method)
break;
}
/* If we found an overrider, record the overriding function, and
the base from which it came. */
if (path)
{
if (ffod->overriding_fn && ffod->overriding_fn != method)
{
/* We've found a different overrider along a different
path. That can be OK if the new one overrides the
old one. Consider:
struct S { virtual void f(); };
struct T : public virtual S { virtual void f(); };
struct U : public virtual S, public virtual T {};
Here `T::f' is the final overrider for `S::f'. */
if (strictly_overrides (method, ffod->overriding_fn))
{
ffod->overriding_fn = method;
ffod->overriding_base = TREE_VALUE (path);
}
else if (!strictly_overrides (ffod->overriding_fn, method))
{
cp_error ("no unique final overrider for `%D' in `%T'",
ffod->most_derived_type,
ffod->fn);
cp_error ("candidates are: `%#D'", ffod->overriding_fn);
cp_error (" `%#D'", method);
return error_mark_node;
}
}
else if (ffod->overriding_base
&& (!tree_int_cst_equal
(BINFO_OFFSET (TREE_VALUE (path)),
BINFO_OFFSET (ffod->overriding_base))))
{
/* We've found two instances of the same base that
provide overriders. */
cp_error ("no unique final overrider for `%D' since there two instances of `%T' in `%T'",
ffod->fn,
BINFO_TYPE (ffod->overriding_base),
ffod->most_derived_type);
return error_mark_node;
}
else
{
ffod->overriding_fn = method;
ffod->overriding_base = TREE_VALUE (path);
}
}
} }
SET_BINFO_MARKED (binfo);
return NULL_TREE; return NULL_TREE;
} }
/* Returns the BINFO_OFFSET for the subobject of BINFO that has the /* Returns a TREE_LIST whose TREE_PURPOSE is the final overrider for
type given by CONTEXT. */ FN and whose TREE_VALUE is the binfo for the base where the
overriding occurs. BINFO (in the hierarchy dominated by T) is the
base object in which FN is declared. */
static tree static tree
get_class_offset (context, t, binfo, fndecl) find_final_overrider (t, binfo, fn)
tree context, t, binfo, fndecl; tree t;
tree binfo;
tree fn;
{ {
tree list; find_final_overrider_data ffod;
tree offset;
int i;
if (context == t) /* Getting this right is a little tricky. This is legal:
return integer_zero_node;
if (BINFO_TYPE (binfo) == context) struct S { virtual void f (); };
return BINFO_OFFSET (binfo); struct T { virtual void f (); };
struct U : public S, public T { };
/* Check less derived binfos first. */ even though calling `f' in `U' is ambiguous. But,
while (BINFO_BASETYPES (binfo)
&& (i=CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
{
tree binfos = BINFO_BASETYPES (binfo);
binfo = TREE_VEC_ELT (binfos, i);
if (BINFO_TYPE (binfo) == context)
return BINFO_OFFSET (binfo);
}
list = build_tree_list (t, NULL_TREE); struct R { virtual void f(); };
TREE_TYPE (list) = context; struct S : virtual public R { virtual void f (); };
offset = dfs_walk (TYPE_BINFO (t), struct T : virtual public R { virtual void f (); };
dfs_get_class_offset, struct U : public S, public T { };
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) is not -- there's no way to decide whether to put `S::f' or
{ `T::f' in the vtable for `R'.
error ("every virtual function must have a unique final overrider");
cp_error (" found two (or more) `%T' class subobjects in `%T'", The solution is to look at all paths to BINFO. If we find
context, t); different overriders along any two, then there is a problem. */
cp_error (" with virtual `%D' from virtual base class", fndecl); ffod.fn = fn;
offset = integer_zero_node; ffod.declaring_base = binfo;
} ffod.most_derived_type = t;
else ffod.overriding_fn = NULL_TREE;
offset = TREE_VALUE (list); ffod.overriding_base = NULL_TREE;
my_friendly_assert (offset != NULL_TREE, 999); if (dfs_walk (TYPE_BINFO (t),
my_friendly_assert (TREE_CODE (offset) == INTEGER_CST, 999); dfs_find_final_overrider,
NULL,
&ffod))
return error_mark_node;
return offset; return build_tree_list (ffod.overriding_fn, ffod.overriding_base);
} }
/* Return the BINFO_VIRTUALS list for BINFO, without the RTTI stuff at /* Return the BINFO_VIRTUALS list for BINFO, without the RTTI stuff at
@ -2972,37 +2975,16 @@ skip_rtti_stuff (binfo, t, n)
return virtuals; return virtuals;
} }
static void /* Called via dfs_walk. Returns BINFO if BINFO has the same type as
modify_one_vtable (binfo, t, fndecl) DATA (which is really an _TYPE node). */
tree binfo, t, fndecl;
static tree
dfs_find_base (binfo, data)
tree binfo;
void *data;
{ {
tree virtuals; return (same_type_p (BINFO_TYPE (binfo), (tree) data)
? binfo : NULL_TREE);
/* If we're support RTTI then we always need a new vtable to point
to the RTTI information. Under the new ABI we may need a new
vtable to contain vcall and vbase offsets. */
if (flag_rtti || flag_new_abi)
make_new_vtable (t, binfo);
if (fndecl == NULL_TREE)
return;
for (virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), NULL);
virtuals;
virtuals = TREE_CHAIN (virtuals))
{
tree current_fndecl = BF_FN (virtuals);
/* We should never have an instance of __pure_virtual on the
BINFO_VIRTUALS list. If we do, then we will never notice
that the function that should have been there instead has
been overridden. */
my_friendly_assert (current_fndecl != abort_fndecl,
19990727);
if (current_fndecl && overrides (fndecl, current_fndecl))
modify_vtable_entry (t, binfo, fndecl, &virtuals);
}
} }
/* Called from modify_all_vtables via dfs_walk. */ /* Called from modify_all_vtables via dfs_walk. */
@ -3018,8 +3000,70 @@ dfs_modify_vtables (binfo, data)
/* Similarly, a base without a vtable needs no modification. */ /* Similarly, a base without a vtable needs no modification. */
&& CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))) && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
{ {
tree list = (tree) data; tree t;
modify_one_vtable (binfo, TREE_PURPOSE (list), TREE_VALUE (list)); tree virtuals;
tree old_virtuals;
t = (tree) data;
/* If we're support RTTI then we always need a new vtable to point
to the RTTI information. Under the new ABI we may need a new
vtable to contain vcall and vbase offsets. */
if (flag_rtti || flag_new_abi)
make_new_vtable (t, binfo);
/* Now, go through each of the virtual functions in the virtual
function table for BINFO. Find the final overrider, and
update the BINFO_VIRTUALS list appropriately. */
for (virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), NULL),
old_virtuals = skip_rtti_stuff (TYPE_BINFO (BINFO_TYPE (binfo)),
BINFO_TYPE (binfo),
NULL);
virtuals;
virtuals = TREE_CHAIN (virtuals),
old_virtuals = TREE_CHAIN (old_virtuals))
{
tree b;
tree fn;
tree overrider;
tree vindex;
tree delta;
/* Find the function which originally caused this vtable
entry to be present. */
fn = BV_FN (old_virtuals);
vindex = DECL_VINDEX (fn);
b = dfs_walk (binfo, dfs_find_base, NULL, DECL_VIRTUAL_CONTEXT (fn));
fn = skip_rtti_stuff (TYPE_BINFO (BINFO_TYPE (b)),
BINFO_TYPE (b),
NULL);
while (!tree_int_cst_equal (DECL_VINDEX (BV_FN (fn)), vindex))
fn = TREE_CHAIN (fn);
fn = BV_FN (fn);
/* Handle the case of a virtual function defined in BINFO
itself. */
overrider = find_final_overrider (t, b, fn);
if (overrider == error_mark_node)
continue;
/* The `this' pointer needs to be adjusted from pointing to
BINFO to pointing at the base where the final overrider
appears. */
delta = size_binop (PLUS_EXPR,
get_derived_offset (binfo,
DECL_VIRTUAL_CONTEXT (fn)),
BINFO_OFFSET (binfo));
delta = ssize_binop (MINUS_EXPR,
BINFO_OFFSET (TREE_VALUE (overrider)),
delta);
modify_vtable_entry (t,
binfo,
TREE_PURPOSE (overrider),
delta,
&virtuals);
}
} }
SET_BINFO_MARKED (binfo); SET_BINFO_MARKED (binfo);
@ -3042,26 +3086,16 @@ modify_all_vtables (t, has_virtual_p, overridden_virtuals)
int *has_virtual_p; int *has_virtual_p;
tree overridden_virtuals; tree overridden_virtuals;
{ {
tree fns;
tree binfo; tree binfo;
binfo = TYPE_BINFO (t); binfo = TYPE_BINFO (t);
/* Even if there are no overridden virtuals, we want to go through /* Update all of the vtables. */
the hierarchy updating RTTI information. */ dfs_walk (binfo,
if (!overridden_virtuals && TYPE_CONTAINS_VPTR_P (t) && flag_rtti) dfs_modify_vtables,
overridden_virtuals = build_tree_list (NULL_TREE, NULL_TREE); dfs_unmarked_real_bases_queue_p,
t);
/* Iterate through each of the overriding functions, updating the dfs_walk (binfo, dfs_unmark, dfs_marked_real_bases_queue_p, t);
base vtables. */
for (fns = overridden_virtuals; fns; fns = TREE_CHAIN (fns))
{
tree list;
list = build_tree_list (t, TREE_VALUE (fns));
dfs_walk (binfo, dfs_modify_vtables,
dfs_unmarked_real_bases_queue_p, list);
dfs_walk (binfo, dfs_unmark, dfs_marked_real_bases_queue_p, t);
}
/* If we should include overriding functions for secondary vtables /* If we should include overriding functions for secondary vtables
in our primary vtable, add them now. */ in our primary vtable, add them now. */
@ -3086,7 +3120,8 @@ modify_all_vtables (t, has_virtual_p, overridden_virtuals)
DECL_VIRTUAL_CONTEXT (fn) = t; DECL_VIRTUAL_CONTEXT (fn) = t;
/* We don't need to adjust the `this' pointer when /* We don't need to adjust the `this' pointer when
calling this function. */ calling this function. */
TREE_PURPOSE (*fnsp) = integer_zero_node; BV_DELTA (*fnsp) = integer_zero_node;
BV_VCALL_INDEX (*fnsp) = integer_zero_node;
/* This is an overridden function not already in our /* This is an overridden function not already in our
vtable. Keep it. */ vtable. Keep it. */
@ -3104,37 +3139,6 @@ modify_all_vtables (t, has_virtual_p, overridden_virtuals)
return overridden_virtuals; return overridden_virtuals;
} }
/* Fixup all the delta entries in this one vtable that need updating. */
static tree
dfs_fixup_vtable_deltas (binfo, data)
tree binfo;
void *data;
{
tree virtuals;
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;
}
for (virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), NULL);
virtuals;
virtuals = TREE_CHAIN (virtuals))
{
tree fndecl = BF_FN (virtuals);
if (fndecl)
modify_vtable_entry (t, binfo, fndecl, &virtuals);
}
return NULL_TREE;
}
/* Here, we already know that they match in every respect. /* Here, we already know that they match in every respect.
All we have to check is where they had their declarations. */ All we have to check is where they had their declarations. */
@ -3150,169 +3154,6 @@ strictly_overrides (fndecl1, fndecl2)
return 0; return 0;
} }
/* Merge overrides for one vtable.
If we want to merge in same function, we are fine.
else
if one has a DECL_CLASS_CONTEXT that is a parent of the
other, than choose the more derived one
else
potentially ill-formed (see 10.3 [class.virtual])
we have to check later to see if there was an
override in this class. If there was ok, if not
then it is ill-formed. (mrs)
We take special care to reuse a vtable, if we can. */
static void
override_one_vtable (binfo, old, t)
tree 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))
choose = NEITHER;
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 (orig_virtuals)
{
tree fndecl = BF_FN (virtuals);
tree old_fndecl = BF_FN (old_virtuals);
/* First check to see if they are the same. */
if (DECL_ASSEMBLER_NAME (fndecl) == DECL_ASSEMBLER_NAME (old_fndecl))
{
/* No need to do anything. */
}
else if (strictly_overrides (fndecl, old_fndecl))
{
if (choose == UNDECIDED)
choose = REUSE_NEW;
else if (choose == REUSE_OLD)
{
choose = NEITHER;
if (! BINFO_NEW_VTABLE_MARKED (binfo))
{
build_secondary_vtable (binfo, t);
override_one_vtable (binfo, old, t);
return;
}
}
}
else if (strictly_overrides (old_fndecl, fndecl))
{
if (choose == UNDECIDED)
choose = REUSE_OLD;
else if (choose == REUSE_NEW)
{
choose = NEITHER;
if (! BINFO_NEW_VTABLE_MARKED (binfo))
{
build_secondary_vtable (binfo, t);
override_one_vtable (binfo, old, t);
return;
}
TREE_VALUE (virtuals) = TREE_VALUE (old_virtuals);
}
else if (choose == NEITHER)
{
TREE_VALUE (virtuals) = TREE_VALUE (old_virtuals);
}
}
else
{
choose = NEITHER;
if (! BINFO_NEW_VTABLE_MARKED (binfo))
{
build_secondary_vtable (binfo, t);
override_one_vtable (binfo, old, t);
return;
}
{
/* This MUST be overridden, or the class is ill-formed. */
tree fndecl = BF_FN (virtuals);
fndecl = copy_node (fndecl);
copy_lang_decl (fndecl);
DECL_NEEDS_FINAL_OVERRIDER_P (fndecl) = 1;
/* Make sure we search for it later. */
if (! CLASSTYPE_PURE_VIRTUALS (t))
CLASSTYPE_PURE_VIRTUALS (t) = error_mark_node;
/* We can use integer_zero_node, as we will core dump
if this is used anyway. */
BF_DELTA (virtuals) = integer_zero_node;
BF_FN (virtuals) = fndecl;
}
}
virtuals = TREE_CHAIN (virtuals);
old_virtuals = TREE_CHAIN (old_virtuals);
orig_virtuals = TREE_CHAIN (orig_virtuals);
}
/* Let's reuse the old vtable. */
if (choose == REUSE_OLD)
{
BINFO_VTABLE (binfo) = BINFO_VTABLE (old);
BINFO_VIRTUALS (binfo) = BINFO_VIRTUALS (old);
}
}
/* Merge in overrides for virtual bases.
BINFO is the hierarchy we want to modify, and OLD has the potential
overrides. */
static void
merge_overrides (binfo, old, do_self, t)
tree binfo, old;
int do_self;
tree t;
{
tree binfos = BINFO_BASETYPES (binfo);
tree old_binfos = BINFO_BASETYPES (old);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
/* Should we use something besides CLASSTYPE_VFIELDS? */
if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
{
override_one_vtable (binfo, old, t);
}
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree old_base_binfo = TREE_VEC_ELT (old_binfos, i);
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);
}
}
/* Get the base virtual function declarations in T that are either /* Get the base virtual function declarations in T that are either
overridden or hidden by FNDECL as a list. We set TREE_PURPOSE with overridden or hidden by FNDECL as a list. We set TREE_PURPOSE with
the overrider/hider. */ the overrider/hider. */
@ -4842,6 +4683,10 @@ layout_virtual_bases (t)
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);
vbase;
vbase = TREE_CHAIN (vbase))
dfs_walk (vbase, dfs_set_offset_for_unshared_vbases, NULL, t);
/* Now, make sure that the total size of the type is a multiple of /* Now, make sure that the total size of the type is a multiple of
its alignment. */ its alignment. */
@ -5065,42 +4910,6 @@ finish_struct_1 (t)
layout_class_type (t, &empty, &has_virtual, layout_class_type (t, &empty, &has_virtual,
&new_virtuals, &overridden_virtuals); &new_virtuals, &overridden_virtuals);
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
{
tree vbases;
vbases = CLASSTYPE_VBASECLASSES (t);
{
/* Now fixup overrides of all functions in vtables from all
direct or indirect virtual base classes. */
tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
for (i = 0; i < n_baseclasses; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree basetype = BINFO_TYPE (base_binfo);
tree vbases;
vbases = CLASSTYPE_VBASECLASSES (basetype);
while (vbases)
{
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);
}
}
}
}
/* Set up the DECL_FIELD_BITPOS of the vfield if we need to, as we /* Set up the DECL_FIELD_BITPOS of the vfield if we need to, as we
might need to know it for setting up the offsets in the vtable might need to know it for setting up the offsets in the vtable
(or in thunks) below. */ (or in thunks) below. */
@ -5126,28 +4935,7 @@ finish_struct_1 (t)
overridden_virtuals overridden_virtuals
= modify_all_vtables (t, &has_virtual, nreverse (overridden_virtuals)); = modify_all_vtables (t, &has_virtual, nreverse (overridden_virtuals));
if (TYPE_USES_VIRTUAL_BASECLASSES (t)) /* If necessary, create the primary vtable for this class. */
{
tree vbases;
/* Now fixup any virtual function entries from virtual bases
that have different deltas. This has to come after we do the
overridden virtuals. */
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. */
vbase = find_vbase_instance (BINFO_TYPE (vbases), t);
dfs_walk (vbase, dfs_fixup_vtable_deltas, dfs_skip_vbases, t);
vbases = TREE_CHAIN (vbases);
}
}
/* If necessary, create the vtable for this class. */
if (new_virtuals if (new_virtuals
|| overridden_virtuals || overridden_virtuals
|| (TYPE_CONTAINS_VPTR_P (t) && vptrs_present_everywhere_p ())) || (TYPE_CONTAINS_VPTR_P (t) && vptrs_present_everywhere_p ()))

View File

@ -115,18 +115,22 @@ Boston, MA 02111-1307, USA. */
For a static VAR_DECL, this is DECL_INIT_PRIORITY. For a static VAR_DECL, this is DECL_INIT_PRIORITY.
BINFO_VIRTUALS BINFO_VIRTUALS
For a binfo, this is a TREE_LIST. The BF_DELTA of each node For a binfo, this is a TREE_LIST. The BV_DELTA of each node
gives the amount by which to adjust the `this' pointer when gives the amount by which to adjust the `this' pointer when
calling the function. If the method is an overriden version of a calling the function. If the method is an overriden version of a
base class method, then it is assumed that, prior to adjustment, base class method, then it is assumed that, prior to adjustment,
the this pointer points to an object of the base class. the this pointer points to an object of the base class.
The BF_VCALL_INDEX of each node, if non-NULL, gives the vtable The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable
index of the vcall offset for this entry. index of the vcall offset for this entry.
The BF_FN is the declaration for the virtual function itself. The BV_FN is the declaration for the virtual function itself.
When CLASSTYPE_COM_INTERFACE_P does not hold, the first entry When CLASSTYPE_COM_INTERFACE_P does not hold, the first entry
does not have a BF_FN; it is just an offset. does not have a BV_FN; it is just an offset.
The BV_OVERRIDING_BASE is the binfo for the final overrider for
this function. (This binfo's BINFO_TYPE will always be the same
as the DECL_CLASS_CONTEXT for the function.)
DECL_ARGUMENTS DECL_ARGUMENTS
For a VAR_DECL this is DECL_ANON_UNION_ELEMS. For a VAR_DECL this is DECL_ANON_UNION_ELEMS.
@ -1500,10 +1504,14 @@ struct lang_type
/* If non-NULL, this is the binfo for the primary base class, i.e., /* If non-NULL, this is the binfo for the primary base class, i.e.,
the base class which contains the virtual function table pointer the base class which contains the virtual function table pointer
for this class. */ for this class. */
#define CLASSTYPE_PRIMARY_BINFO(NODE) \ #define CLASSTYPE_PRIMARY_BINFO(NODE) \
(CLASSTYPE_HAS_PRIMARY_BASE_P (NODE) \ (BINFO_PRIMARY_BINFO (TYPE_BINFO (NODE)))
? TREE_VEC_ELT (TYPE_BINFO_BASETYPES (NODE), \
CLASSTYPE_VFIELD_PARENT (NODE)) \ /* If non-NULL, this is the binfo for the primary base of BINFO. */
#define BINFO_PRIMARY_BINFO(NODE) \
(CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (NODE)) \
? BINFO_BASETYPE (NODE, \
CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (NODE))) \
: NULL_TREE) : NULL_TREE)
/* The number of virtual functions defined for this /* The number of virtual functions defined for this
@ -1726,14 +1734,16 @@ struct lang_type
/* The number of bytes by which to adjust the `this' pointer when /* The number of bytes by which to adjust the `this' pointer when
calling this virtual function. */ calling this virtual function. */
#define BF_DELTA(NODE) (TREE_PURPOSE (NODE)) #define BV_DELTA(NODE) (TREE_PURPOSE (NODE))
/* If non-NULL, the vtable index at which to find the vcall offset /* If non-NULL, the vtable index at which to find the vcall offset
when calling this virtual function. */ when calling this virtual function. */
#define BF_VCALL_INDEX(NODE) (TREE_TYPE (NODE)) #define BV_VCALL_INDEX(NODE) (TREE_TYPE (NODE))
/* The function to call. */ /* The function to call. */
#define BF_FN(NODE) (TREE_VALUE (NODE)) #define BV_FN(NODE) (TREE_VALUE (NODE))
/* The most derived class. */
/* Nonzero for TREE_LIST node means that this list of things /* Nonzero for TREE_LIST node means that this list of things

View File

@ -883,23 +883,26 @@ binfo_value (elem, type)
return get_binfo (elem, type, 0); return get_binfo (elem, type, 0);
} }
/* Return a reversed copy of the BINFO-chain given by PATH. (If the /* Return a TREE_LIST whose TREE_VALUE nodes along the
BINFO_INHERITANCE_CHAIN points from base classes to derived BINFO_INHERITANCE_CHAIN for BINFO, but in the opposite order. In
classes, it will instead point from derived classes to base other words, while the BINFO_INHERITANCE_CHAIN goes from base
classes.) Returns the first node in the reversed chain. */ classes to derived classes, the reversed path goes from derived
classes to base classes. */
tree tree
reverse_path (path) reverse_path (binfo)
tree path; tree binfo;
{ {
register tree prev = NULL_TREE, cur; tree reversed_path;
for (cur = path; cur; cur = BINFO_INHERITANCE_CHAIN (cur))
reversed_path = NULL_TREE;
while (binfo)
{ {
tree r = copy_node (cur); reversed_path = tree_cons (NULL_TREE, binfo, reversed_path);
BINFO_INHERITANCE_CHAIN (r) = prev; binfo = BINFO_INHERITANCE_CHAIN (binfo);
prev = r;
} }
return prev;
return reversed_path;
} }
void void