aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2000-01-31 21:00:01 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2000-01-31 21:00:01 +0000
commit5e19c0539080471ad7097fa5c441031334f12bdd (patch)
tree9d11b66fb3519c817dc45d1c1ad7fdca554ed8ed /gcc
parentd4cf5733ee1a1e5efded2df9800e6edd64a944bd (diff)
downloadgcc-5e19c0539080471ad7097fa5c441031334f12bdd.zip
gcc-5e19c0539080471ad7097fa5c441031334f12bdd.tar.gz
gcc-5e19c0539080471ad7097fa5c441031334f12bdd.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog37
-rw-r--r--gcc/cp/class.c688
-rw-r--r--gcc/cp/cp-tree.h32
-rw-r--r--gcc/cp/tree.c27
4 files changed, 311 insertions, 473 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 2969fe4..50848be 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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>
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 81692f2..40f8383 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -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;
+dfs_find_final_overrider (binfo, data)
+ tree binfo;
+ void *data;
{
- 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;
+ find_final_overrider_data *ffod = (find_final_overrider_data *) data;
- for (i = 0; i < n_baselinks; i++)
+ 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 base_binfo = TREE_VEC_ELT (binfos, i);
- tree nrval;
+ tree path;
+ tree method;
- 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))
+ /* 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))
{
- /* 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;
+ 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 (rval && BINFO_TYPE (binfo) == context)
+
+ /* If we found an overrider, record the overriding function, and
+ the base from which it came. */
+ if (path)
{
- my_friendly_assert (rval == error_mark_node
- || tree_int_cst_equal (rval, BINFO_OFFSET (binfo)), 999);
- rval = BINFO_OFFSET (binfo);
+ 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 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. */
+/* 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);
-
- 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);
+ 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 { };
- my_friendly_assert (offset != NULL_TREE, 999);
- my_friendly_assert (TREE_CODE (offset) == INTEGER_CST, 999);
+ 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 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;
-{
- 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);
+/* Called via dfs_walk. Returns BINFO if BINFO has the same type as
+ DATA (which is really an _TYPE node). */
- /* 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);
- }
+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. */
@@ -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 ()))
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ae738d3..72d4b18 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 392ea54..a66a634 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -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