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>
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 int build_primary_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 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 tree delete_duplicate_fields_1 PARAMS ((tree, 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 int 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 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 modify_all_vtables PARAMS ((tree, int *, tree));
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 layout_vtable_decl PARAMS ((tree, int));
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));
/* Variables shared between class.c and call.c. */
@ -558,16 +555,15 @@ build_vbase_path (code, type, expr, path, nonnull)
expr = save_expr (expr);
nonnull_expr = expr;
if (BINFO_INHERITANCE_CHAIN (path))
path = reverse_path (path);
path = reverse_path (path);
basetype = BINFO_TYPE (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)
{
changed = ! fixed_type_p;
@ -609,8 +605,8 @@ build_vbase_path (code, type, expr, path, nonnull)
return error_mark_node;
}
}
last = path;
path = BINFO_INHERITANCE_CHAIN (path);
last = TREE_VALUE (path);
path = TREE_CHAIN (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)
{
/* The first slot holds the offset. */
BF_DELTA (virtuals) = offset;
BF_VCALL_INDEX (virtuals) = integer_zero_node;
BV_DELTA (virtuals) = offset;
BV_VCALL_INDEX (virtuals) = integer_zero_node;
/* The next node holds the decl. */
virtuals = TREE_CHAIN (virtuals);
@ -990,9 +986,9 @@ set_rtti_entry (virtuals, offset, type)
}
/* This slot holds the function to call. */
BF_DELTA (virtuals) = offset;
BF_VCALL_INDEX (virtuals) = integer_zero_node;
BF_FN (virtuals) = decl;
BV_DELTA (virtuals) = offset;
BV_VCALL_INDEX (virtuals) = integer_zero_node;
BV_FN (virtuals) = decl;
}
/* 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
(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
modify_vtable_entry (t, binfo, fndecl, virtuals)
modify_vtable_entry (t, binfo, fndecl, delta, virtuals)
tree t;
tree binfo;
tree fndecl;
tree delta;
tree *virtuals;
{
tree base_offset;
tree offset;
tree context;
tree this_offset;
tree vcall_index;
tree v;
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;
if (fndecl != BF_FN (v)
|| !tree_int_cst_equal (this_offset, BF_DELTA (v))
|| !tree_int_cst_equal (vcall_index, BF_VCALL_INDEX (v)))
if (fndecl != BV_FN (v)
|| !tree_int_cst_equal (delta, BV_DELTA (v))
|| !tree_int_cst_equal (vcall_index, BV_VCALL_INDEX (v)))
{
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
corresponding entry in that list. */
*virtuals = BINFO_VIRTUALS (binfo);
while (BF_FN (*virtuals) != BF_FN (v))
while (BV_FN (*virtuals) != BV_FN (v))
*virtuals = TREE_CHAIN (*virtuals);
v = *virtuals;
}
base_fndecl = BF_FN (v);
BF_DELTA (v) = this_offset;
BF_VCALL_INDEX (v) = vcall_index;
BF_FN (v) = fndecl;
base_fndecl = BV_FN (v);
BV_DELTA (v) = delta;
BV_VCALL_INDEX (v) = vcall_index;
BV_FN (v) = fndecl;
/* Now assign virtual dispatch information, if unset. We can
dispatch this, through any overridden base function. */
@ -1407,7 +1386,7 @@ add_virtual_function (new_virtuals_p, overridden_virtuals_p,
return;
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)
{
@ -2713,9 +2692,9 @@ build_vtbl_initializer (binfo, t)
/* Pull the offset for `this', and the function to call, out of
the list. */
delta = BF_DELTA (v);
vcall_index = BF_VCALL_INDEX (v);
fn = BF_FN (v);
delta = BV_DELTA (v);
vcall_index = BV_VCALL_INDEX (v);
fn = BV_FN (v);
my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
@ -2812,127 +2791,151 @@ overrides (fndecl, base_fndecl)
return 0;
}
/* Returns the BINFO_OFFSET for the base of BINFO that has the same
type as CONTEXT. */
typedef struct find_final_overrider_data_s {
/* 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
get_class_offset_1 (parent, binfo, context, t, fndecl)
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)
dfs_find_final_overrider (binfo, data)
tree binfo;
void *data;
{
tree list = (tree) data;
tree context = TREE_TYPE (list);
find_final_overrider_data *ffod = (find_final_overrider_data *) data;
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))
return error_mark_node;
else
TREE_VALUE (list) = BINFO_OFFSET (binfo);
tree path;
tree method;
/* 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;
}
/* Returns the BINFO_OFFSET for the subobject of BINFO that has the
type given by CONTEXT. */
/* Returns a TREE_LIST whose TREE_PURPOSE is the final overrider for
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
get_class_offset (context, t, binfo, fndecl)
tree context, t, binfo, fndecl;
find_final_overrider (t, binfo, fn)
tree t;
tree binfo;
tree fn;
{
tree list;
tree offset;
int i;
find_final_overrider_data ffod;
if (context == t)
return integer_zero_node;
/* Getting this right is a little tricky. This is legal:
if (BINFO_TYPE (binfo) == context)
return BINFO_OFFSET (binfo);
struct S { virtual void f (); };
struct T { virtual void f (); };
struct U : public S, public T { };
/* Check less derived binfos first. */
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);
}
even though calling `f' in `U' is ambiguous. But,
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);
struct R { virtual void f(); };
struct S : virtual public R { virtual void f (); };
struct T : virtual public R { virtual void f (); };
struct U : public S, public 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);
is not -- there's no way to decide whether to put `S::f' or
`T::f' in the vtable for `R'.
The solution is to look at all paths to BINFO. If we find
different overriders along any two, then there is a problem. */
ffod.fn = fn;
ffod.declaring_base = binfo;
ffod.most_derived_type = t;
ffod.overriding_fn = NULL_TREE;
ffod.overriding_base = NULL_TREE;
my_friendly_assert (offset != NULL_TREE, 999);
my_friendly_assert (TREE_CODE (offset) == INTEGER_CST, 999);
if (dfs_walk (TYPE_BINFO (t),
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
@ -2972,37 +2975,16 @@ skip_rtti_stuff (binfo, t, n)
return virtuals;
}
static void
modify_one_vtable (binfo, t, fndecl)
tree binfo, t, fndecl;
/* Called via dfs_walk. Returns BINFO if BINFO has the same type as
DATA (which is really an _TYPE node). */
static tree
dfs_find_base (binfo, data)
tree binfo;
void *data;
{
tree virtuals;
/* 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);
}
return (same_type_p (BINFO_TYPE (binfo), (tree) data)
? binfo : NULL_TREE);
}
/* 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. */
&& CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
{
tree list = (tree) data;
modify_one_vtable (binfo, TREE_PURPOSE (list), TREE_VALUE (list));
tree t;
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);
@ -3042,26 +3086,16 @@ modify_all_vtables (t, has_virtual_p, overridden_virtuals)
int *has_virtual_p;
tree overridden_virtuals;
{
tree fns;
tree binfo;
binfo = TYPE_BINFO (t);
/* Even if there are no overridden virtuals, we want to go through
the hierarchy updating RTTI information. */
if (!overridden_virtuals && TYPE_CONTAINS_VPTR_P (t) && flag_rtti)
overridden_virtuals = build_tree_list (NULL_TREE, NULL_TREE);
/* Iterate through each of the overriding functions, updating the
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);
}
/* Update all of the vtables. */
dfs_walk (binfo,
dfs_modify_vtables,
dfs_unmarked_real_bases_queue_p,
t);
dfs_walk (binfo, dfs_unmark, dfs_marked_real_bases_queue_p, t);
/* If we should include overriding functions for secondary vtables
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;
/* We don't need to adjust the `this' pointer when
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
vtable. Keep it. */
@ -3104,37 +3139,6 @@ modify_all_vtables (t, has_virtual_p, 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.
All we have to check is where they had their declarations. */
@ -3150,169 +3154,6 @@ strictly_overrides (fndecl1, fndecl2)
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
overridden or hidden by FNDECL as a list. We set TREE_PURPOSE with
the overrider/hider. */
@ -4842,6 +4683,10 @@ layout_virtual_bases (t)
in get_base_distance depend on the BINFO_OFFSETs being set
correctly. */
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
its alignment. */
@ -5065,42 +4910,6 @@ finish_struct_1 (t)
layout_class_type (t, &empty, &has_virtual,
&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
might need to know it for setting up the offsets in the vtable
(or in thunks) below. */
@ -5126,28 +4935,7 @@ finish_struct_1 (t)
overridden_virtuals
= modify_all_vtables (t, &has_virtual, nreverse (overridden_virtuals));
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
{
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 necessary, create the primary vtable for this class. */
if (new_virtuals
|| overridden_virtuals
|| (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.
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
calling the function. If the method is an overriden version of a
base class method, then it is assumed that, prior to adjustment,
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.
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
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
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.,
the base class which contains the virtual function table pointer
for this class. */
#define CLASSTYPE_PRIMARY_BINFO(NODE) \
(CLASSTYPE_HAS_PRIMARY_BASE_P (NODE) \
? TREE_VEC_ELT (TYPE_BINFO_BASETYPES (NODE), \
CLASSTYPE_VFIELD_PARENT (NODE)) \
#define CLASSTYPE_PRIMARY_BINFO(NODE) \
(BINFO_PRIMARY_BINFO (TYPE_BINFO (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)
/* 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
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
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. */
#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

View File

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