diff options
author | Mark Mitchell <mark@codesourcery.com> | 2000-01-31 21:00:01 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 2000-01-31 21:00:01 +0000 |
commit | 5e19c0539080471ad7097fa5c441031334f12bdd (patch) | |
tree | 9d11b66fb3519c817dc45d1c1ad7fdca554ed8ed | |
parent | d4cf5733ee1a1e5efded2df9800e6edd64a944bd (diff) | |
download | gcc-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
-rw-r--r-- | gcc/cp/ChangeLog | 37 | ||||
-rw-r--r-- | gcc/cp/class.c | 688 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 32 | ||||
-rw-r--r-- | gcc/cp/tree.c | 27 |
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 |