This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: Reorganize computation of vtable entries
- To: gcc-patches at gcc dot gnu dot org
- Subject: C++ PATCH: Reorganize computation of vtable entries
- From: Mark Mitchell <mark at codesourcery dot com>
- Date: Mon, 31 Jan 2000 13:00:56 -0800
- Organization: CodeSourcery, LLC
This patch changes the way in which we compute vtable entries, but not
the values computed. It fixes one new-ABI regression where we missed
an ambiguous declaration because our ambiguity detection code was
intimately tied up in our vtable layout code. Ugh.
I've deleted lots of code, and added code to compute "final
overriders" as defined by the standard. Much cleaner, and it will
facilitate the new ABI virtual calling convention as well.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
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.
Index: class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.250
diff -c -p -r1.250 class.c
*** class.c 2000/01/31 04:03:01 1.250
--- class.c 2000/01/31 20:52:43
*************** static tree get_basefndecls PARAMS ((tre
*** 82,91 ****
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 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));
--- 82,90 ----
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_finish_vtbls PARAMS ((tree, void *));
static void finish_vtbls PARAMS ((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));
*************** static int alter_access PARAMS ((tree, t
*** 94,106 ****
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 *));
--- 93,100 ----
*************** static tree dfs_count_virtuals PARAMS ((
*** 151,156 ****
--- 145,153 ----
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. */
*************** build_vbase_path (code, type, expr, path
*** 558,573 ****
expr = save_expr (expr);
nonnull_expr = expr;
! if (BINFO_INHERITANCE_CHAIN (path))
! path = reverse_path (path);
basetype = BINFO_TYPE (path);
while (path)
{
! if (TREE_VIA_VIRTUAL (path))
{
! last_virtual = BINFO_TYPE (path);
if (code == PLUS_EXPR)
{
changed = ! fixed_type_p;
--- 555,569 ----
expr = save_expr (expr);
nonnull_expr = expr;
! path = reverse_path (path);
basetype = BINFO_TYPE (path);
while (path)
{
! if (TREE_VIA_VIRTUAL (TREE_VALUE (path)))
{
! last_virtual = BINFO_TYPE (TREE_VALUE (path));
if (code == PLUS_EXPR)
{
changed = ! fixed_type_p;
*************** build_vbase_path (code, type, expr, path
*** 609,616 ****
return error_mark_node;
}
}
! last = path;
! path = BINFO_INHERITANCE_CHAIN (path);
}
/* LAST is now the last basetype assoc on the path. */
--- 605,612 ----
return error_mark_node;
}
}
! last = TREE_VALUE (path);
! path = TREE_CHAIN (path);
}
/* LAST is now the last basetype assoc on the path. */
*************** set_rtti_entry (virtuals, offset, type)
*** 981,988 ****
if (flag_vtable_thunks)
{
/* The first slot holds the offset. */
! BF_DELTA (virtuals) = offset;
! BF_VCALL_INDEX (virtuals) = integer_zero_node;
/* The next node holds the decl. */
virtuals = TREE_CHAIN (virtuals);
--- 977,984 ----
if (flag_vtable_thunks)
{
/* The first slot holds the offset. */
! BV_DELTA (virtuals) = offset;
! BV_VCALL_INDEX (virtuals) = integer_zero_node;
/* The next node holds the decl. */
virtuals = TREE_CHAIN (virtuals);
*************** set_rtti_entry (virtuals, offset, type)
*** 990,998 ****
}
/* This slot holds the function to call. */
! BF_DELTA (virtuals) = offset;
! BF_VCALL_INDEX (virtuals) = integer_zero_node;
! BF_FN (virtuals) = decl;
}
/* Get the VAR_DECL of the vtable for TYPE. TYPE need not be polymorphic,
--- 986,994 ----
}
/* This slot holds the function to call. */
! 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,
*************** make_new_vtable (t, binfo)
*** 1289,1332 ****
/* 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. */
static void
! modify_vtable_entry (t, binfo, fndecl, virtuals)
tree t;
tree binfo;
tree fndecl;
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)))
{
tree base_fndecl;
--- 1285,1311 ----
/* Make *VIRTUALS, an entry on the BINFO_VIRTUALS list for BINFO
(which is in the hierarchy dominated by T) list FNDECL as its
! 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, delta, virtuals)
tree t;
tree binfo;
tree fndecl;
+ tree delta;
tree *virtuals;
{
tree vcall_index;
tree v;
v = *virtuals;
vcall_index = integer_zero_node;
! 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;
*************** modify_vtable_entry (t, binfo, fndecl, v
*** 1337,1351 ****
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))
*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;
/* Now assign virtual dispatch information, if unset. We can
dispatch this, through any overridden base function. */
--- 1316,1330 ----
of the BINFO_VIRTUALS list. Now, we have to find the
corresponding entry in that list. */
*virtuals = BINFO_VIRTUALS (binfo);
! while (BV_FN (*virtuals) != BV_FN (v))
*virtuals = TREE_CHAIN (*virtuals);
v = *virtuals;
}
! 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. */
*************** add_virtual_function (new_virtuals_p, ov
*** 1407,1413 ****
return;
new_virtual = build_tree_list (integer_zero_node, fndecl);
! BF_VCALL_INDEX (new_virtual) = integer_zero_node;
if (DECL_VINDEX (fndecl) == error_mark_node)
{
--- 1386,1392 ----
return;
new_virtual = build_tree_list (integer_zero_node, fndecl);
! BV_VCALL_INDEX (new_virtual) = integer_zero_node;
if (DECL_VINDEX (fndecl) == error_mark_node)
{
*************** build_vtbl_initializer (binfo, t)
*** 2713,2721 ****
/* 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);
my_friendly_assert (TREE_CODE (delta) == INTEGER_CST, 19990727);
my_friendly_assert (TREE_CODE (fn) == FUNCTION_DECL, 19990727);
--- 2692,2700 ----
/* Pull the offset for `this', and the function to call, out of
the list. */
! 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);
*************** overrides (fndecl, base_fndecl)
*** 2811,2938 ****
}
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;
{
! 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;
- 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 list;
! tree offset;
! int i;
! if (context == t)
! return integer_zero_node;
! if (BINFO_TYPE (binfo) == context)
! return BINFO_OFFSET (binfo);
! /* 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);
! }
! 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;
}
/* Return the BINFO_VIRTUALS list for BINFO, without the RTTI stuff at
--- 2790,2941 ----
}
return 0;
}
+
+ 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
! dfs_find_final_overrider (binfo, data)
! tree binfo;
! void *data;
{
! find_final_overrider_data *ffod = (find_final_overrider_data *) data;
! if (same_type_p (BINFO_TYPE (binfo),
! BINFO_TYPE (ffod->declaring_base))
! && tree_int_cst_equal (BINFO_OFFSET (binfo),
! BINFO_OFFSET (ffod->declaring_base)))
! {
! 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);
! }
}
}
return NULL_TREE;
}
! /* 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
! find_final_overrider (t, binfo, fn)
! tree t;
! tree binfo;
! tree fn;
{
! find_final_overrider_data ffod;
! /* Getting this right is a little tricky. This is legal:
! struct S { virtual void f (); };
! struct T { virtual void f (); };
! struct U : public S, public T { };
! even though calling `f' in `U' is ambiguous. But,
! 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 { };
! 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;
!
! if (dfs_walk (TYPE_BINFO (t),
! dfs_find_final_overrider,
! NULL,
! &ffod))
! return error_mark_node;
! return build_tree_list (ffod.overriding_fn, ffod.overriding_base);
}
/* Return the BINFO_VIRTUALS list for BINFO, without the RTTI stuff at
*************** skip_rtti_stuff (binfo, t, n)
*** 2971,3008 ****
return virtuals;
}
-
- static void
- modify_one_vtable (binfo, t, fndecl)
- tree binfo, t, fndecl;
- {
- 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);
! }
}
/* Called from modify_all_vtables via dfs_walk. */
--- 2974,2990 ----
return virtuals;
}
! /* 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;
! {
! return (same_type_p (BINFO_TYPE (binfo), (tree) data)
! ? binfo : NULL_TREE);
}
/* Called from modify_all_vtables via dfs_walk. */
*************** dfs_modify_vtables (binfo, data)
*** 3018,3025 ****
/* 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));
}
SET_BINFO_MARKED (binfo);
--- 3000,3069 ----
/* Similarly, a base without a vtable needs no modification. */
&& CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))
{
! 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);
*************** modify_all_vtables (t, has_virtual_p, ov
*** 3042,3067 ****
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);
! }
/* If we should include overriding functions for secondary vtables
in our primary vtable, add them now. */
--- 3086,3101 ----
int *has_virtual_p;
tree overridden_virtuals;
{
tree binfo;
binfo = TYPE_BINFO (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. */
*************** modify_all_vtables (t, has_virtual_p, ov
*** 3086,3092 ****
DECL_VIRTUAL_CONTEXT (fn) = t;
/* We don't need to adjust the `this' pointer when
calling this function. */
! TREE_PURPOSE (*fnsp) = integer_zero_node;
/* This is an overridden function not already in our
vtable. Keep it. */
--- 3120,3127 ----
DECL_VIRTUAL_CONTEXT (fn) = t;
/* We don't need to adjust the `this' pointer when
calling this function. */
! 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. */
*************** modify_all_vtables (t, has_virtual_p, ov
*** 3104,3140 ****
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. */
--- 3139,3144 ----
*************** strictly_overrides (fndecl1, fndecl2)
*** 3150,3318 ****
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. */
--- 3154,3159 ----
*************** layout_virtual_bases (t)
*** 4842,4847 ****
--- 4683,4692 ----
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. */
*************** finish_struct_1 (t)
*** 5065,5106 ****
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. */
--- 4910,4915 ----
*************** finish_struct_1 (t)
*** 5125,5153 ****
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 (new_virtuals
|| overridden_virtuals
|| (TYPE_CONTAINS_VPTR_P (t) && vptrs_present_everywhere_p ()))
--- 4934,4941 ----
overridden_virtuals
= modify_all_vtables (t, &has_virtual, nreverse (overridden_virtuals));
! /* If necessary, create the primary vtable for this class. */
if (new_virtuals
|| overridden_virtuals
|| (TYPE_CONTAINS_VPTR_P (t) && vptrs_present_everywhere_p ()))
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.397
diff -c -p -r1.397 cp-tree.h
*** cp-tree.h 2000/01/29 03:59:09 1.397
--- cp-tree.h 2000/01/31 20:52:47
*************** Boston, MA 02111-1307, USA. */
*** 115,133 ****
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
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
index of the vcall offset for this entry.
! The BF_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.
DECL_ARGUMENTS
For a VAR_DECL this is DECL_ANON_UNION_ELEMS.
--- 115,137 ----
For a static VAR_DECL, this is DECL_INIT_PRIORITY.
BINFO_VIRTUALS
! 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 BV_VCALL_INDEX of each node, if non-NULL, gives the vtable
index of the vcall offset for this entry.
! 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 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.
*************** struct lang_type
*** 1500,1509 ****
/* 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)) \
: NULL_TREE)
/* The number of virtual functions defined for this
--- 1504,1517 ----
/* 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) \
! (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
*************** struct lang_type
*** 1726,1739 ****
/* The number of bytes by which to adjust the `this' pointer when
calling this virtual function. */
! #define BF_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))
/* The function to call. */
! #define BF_FN(NODE) (TREE_VALUE (NODE))
/* Nonzero for TREE_LIST node means that this list of things
--- 1734,1749 ----
/* The number of bytes by which to adjust the `this' pointer when
calling this virtual function. */
! #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 BV_VCALL_INDEX(NODE) (TREE_TYPE (NODE))
/* The function to call. */
! #define BV_FN(NODE) (TREE_VALUE (NODE))
!
! /* The most derived class. */
/* Nonzero for TREE_LIST node means that this list of things
Index: tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/tree.c,v
retrieving revision 1.180
diff -c -p -r1.180 tree.c
*** tree.c 2000/01/26 20:51:37 1.180
--- tree.c 2000/01/31 20:52:48
*************** binfo_value (elem, type)
*** 883,905 ****
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. */
tree
! reverse_path (path)
! tree path;
{
! register tree prev = NULL_TREE, cur;
! for (cur = path; cur; cur = BINFO_INHERITANCE_CHAIN (cur))
{
! tree r = copy_node (cur);
! BINFO_INHERITANCE_CHAIN (r) = prev;
! prev = r;
}
! return prev;
}
void
--- 883,908 ----
return get_binfo (elem, type, 0);
}
! /* 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 (binfo)
! tree binfo;
{
! tree reversed_path;
!
! reversed_path = NULL_TREE;
! while (binfo)
{
! reversed_path = tree_cons (NULL_TREE, binfo, reversed_path);
! binfo = BINFO_INHERITANCE_CHAIN (binfo);
}
!
! return reversed_path;
}
void