From dd42e13519fd78d873e5aeb4528162a499a299eb Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Wed, 12 Jan 2000 20:56:15 +0000 Subject: [PATCH] cp-tree.h (dfs_skip_vbases): New function. * cp-tree.h (dfs_skip_vbases): New function. (find_vbase_instance): Likewise. * class.c (determine_primary_base): Allow a nearly empty base to serve as a primary base class under the new ABI. (get_class_offset_1): Rename to ... (dfs_get_class_offset): ... this. Simplify. Don't issue error messages here. (get_class_offset): Use it. Issue error messages here. (dfs_modify_vtables): Rely on dfs_unmarked_real_bases_queue_p to find the right copies of virtual bases. (fixup_vtable_deltas1): Rename to ... (dfs_fixup_vtable_deltas): ... this. Adjust to handle virtual bases as primary bases. (fixup_vtable_deltas): Remove. (override_one_vtable): Handle virtual bases as primary bases. (merge_overrides): Likewise. (finish_struct_1): Likewise. (dump_class_hierarchy): Dump primary-ness of bases as well. * search.c (mark_primary_bases): Use a pre-order traversal to handle primary virtual bases. (dfs_skip_vbases): New fiunction. (expand_upcast_fixups): Adjust to handle primary virtual bases. (fixup_virtual_upcast_offsets): Likewise. (fixup_all_virtual_upcast_offsets): Likewise. (dfs_find_vbase_instances): New function. (find_vbase_instance): Likewise. From-SVN: r31360 --- gcc/cp/ChangeLog | 29 ++++++++ gcc/cp/class.c | 182 ++++++++++++++++++++++++++++++++--------------- gcc/cp/cp-tree.h | 2 + gcc/cp/search.c | 82 ++++++++++++++++++--- 4 files changed, 231 insertions(+), 64 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 53bf525d248..89b74005ce0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,32 @@ +2000-01-12 Mark Mitchell + + * cp-tree.h (dfs_skip_vbases): New function. + (find_vbase_instance): Likewise. + * class.c (determine_primary_base): Allow a nearly empty base to + serve as a primary base class under the new ABI. + (get_class_offset_1): Rename to ... + (dfs_get_class_offset): ... this. Simplify. Don't issue error + messages here. + (get_class_offset): Use it. Issue error messages here. + (dfs_modify_vtables): Rely on dfs_unmarked_real_bases_queue_p to + find the right copies of virtual bases. + (fixup_vtable_deltas1): Rename to ... + (dfs_fixup_vtable_deltas): ... this. Adjust to handle virtual + bases as primary bases. + (fixup_vtable_deltas): Remove. + (override_one_vtable): Handle virtual bases as primary bases. + (merge_overrides): Likewise. + (finish_struct_1): Likewise. + (dump_class_hierarchy): Dump primary-ness of bases as well. + * search.c (mark_primary_bases): Use a pre-order traversal to + handle primary virtual bases. + (dfs_skip_vbases): New fiunction. + (expand_upcast_fixups): Adjust to handle primary virtual bases. + (fixup_virtual_upcast_offsets): Likewise. + (fixup_all_virtual_upcast_offsets): Likewise. + (dfs_find_vbase_instances): New function. + (find_vbase_instance): Likewise. + 2000-01-11 Mumit Khan * lex.c (DIR_SEPARATOR): Delete macro. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 023cf1a27c4..7d9ab931ee7 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -82,8 +82,7 @@ static tree get_basefndecls PROTO((tree, tree)); static void set_rtti_entry PROTO((tree, tree, tree)); static void build_vtable PROTO((tree, tree)); static void prepare_fresh_vtable PROTO((tree, tree)); -static void fixup_vtable_deltas1 PROTO((tree, tree)); -static void fixup_vtable_deltas PROTO((tree, int, tree)); +static tree dfs_fixup_vtable_deltas PROTO((tree, void *)); static tree dfs_finish_vtbls PROTO((tree, void *)); static void finish_vtbls PROTO((tree)); static void modify_vtable_entry PROTO((tree, tree, tree)); @@ -100,7 +99,7 @@ static void merge_overrides PROTO((tree, tree, int, tree)); static void override_one_vtable PROTO((tree, tree, tree)); static void mark_overriders PROTO((tree, tree)); static void check_for_override PROTO((tree, tree)); -static tree get_class_offset_1 PROTO((tree, tree, tree, tree, tree)); +static tree dfs_get_class_offset PROTO((tree, void *)); static tree get_class_offset PROTO((tree, tree, tree, tree)); static void modify_one_vtable PROTO((tree, tree, tree)); static tree dfs_modify_vtables PROTO((tree, void *)); @@ -1672,9 +1671,25 @@ determine_primary_base (t, has_virtual_p) if (!TYPE_VFIELD (t)) CLASSTYPE_VFIELD_PARENT (t) = -1; - /* Now that we know what the primary base class is, we can run - through the entire hierarchy marking the primary bases for future - reference. */ + /* The new ABI allows for the use of a "nearly-empty" virtual base + class as the primary base class if no non-virtual polymorphic + base can be found. */ + if (flag_new_abi && !CLASSTYPE_HAS_PRIMARY_BASE_P (t)) + for (i = 0; i < n_baseclasses; ++i) + { + tree base_binfo = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), i); + tree basetype = BINFO_TYPE (base_binfo); + + if (TREE_VIA_VIRTUAL (base_binfo) + && CLASSTYPE_NEARLY_EMPTY_P (basetype)) + { + set_primary_base (t, i, has_virtual_p); + CLASSTYPE_VFIELDS (t) = copy_list (CLASSTYPE_VFIELDS (basetype)); + break; + } + } + + /* Mark the primary base classes at this point. */ mark_primary_bases (t); } @@ -2266,6 +2281,9 @@ overrides (fndecl, base_fndecl) 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; @@ -2311,14 +2329,37 @@ get_class_offset_1 (parent, binfo, context, t, fndecl) return rval; } -/* Get the offset to the CONTEXT subobject that is related to the - given BINFO. */ +/* 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 first_binfo = binfo; + tree list; tree offset; int i; @@ -2338,11 +2379,28 @@ get_class_offset (context, t, binfo, fndecl) return BINFO_OFFSET (binfo); } - /* Ok, not found in the less derived binfos, now check the more - derived binfos. */ - offset = get_class_offset_1 (first_binfo, TYPE_BINFO (t), context, t, fndecl); - if (offset==0 || TREE_CODE (offset) != INTEGER_CST) - my_friendly_abort (999); /* we have to find it. */ + 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; } @@ -2473,9 +2531,6 @@ dfs_modify_vtables (binfo, data) && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))) { tree list = (tree) data; - - if (TREE_VIA_VIRTUAL (binfo)) - binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), TREE_PURPOSE (list)); modify_one_vtable (binfo, TREE_PURPOSE (list), TREE_VALUE (list)); } @@ -2499,13 +2554,23 @@ modify_all_vtables (t, fndecl) /* Fixup all the delta entries in this one vtable that need updating. */ -static void -fixup_vtable_deltas1 (binfo, t) - tree binfo, t; +static tree +dfs_fixup_vtable_deltas (binfo, data) + tree binfo; + void *data; { tree virtuals; unsigned HOST_WIDE_INT n; - + 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; + } + virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), &n); while (virtuals) @@ -2559,33 +2624,8 @@ fixup_vtable_deltas1 (binfo, t) ++n; virtuals = TREE_CHAIN (virtuals); } -} -/* Fixup all the delta entries in all the direct vtables that need updating. - This happens when we have non-overridden virtual functions from a - virtual base class, that are at a different offset, in the new - hierarchy, because the layout of the virtual bases has changed. */ - -static void -fixup_vtable_deltas (binfo, init_self, t) - tree binfo; - int init_self; - tree t; -{ - tree binfos = BINFO_BASETYPES (binfo); - int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; - - for (i = 0; i < n_baselinks; i++) - { - tree base_binfo = TREE_VEC_ELT (binfos, i); - int is_not_base_vtable - = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo)); - if (! TREE_VIA_VIRTUAL (base_binfo)) - fixup_vtable_deltas (base_binfo, is_not_base_vtable, t); - } - /* Should we use something besides CLASSTYPE_VFIELDS? */ - if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))) - fixup_vtable_deltas1 (binfo, t); + return NULL_TREE; } /* Here, we already know that they match in every respect. @@ -2622,8 +2662,26 @@ override_one_vtable (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)) @@ -2631,8 +2689,9 @@ override_one_vtable (binfo, old, t) 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 (virtuals) + while (orig_virtuals) { tree fndecl = TREE_VALUE (virtuals); tree old_fndecl = TREE_VALUE (old_virtuals); @@ -2705,6 +2764,7 @@ override_one_vtable (binfo, old, t) } virtuals = TREE_CHAIN (virtuals); old_virtuals = TREE_CHAIN (old_virtuals); + orig_virtuals = TREE_CHAIN (orig_virtuals); } /* Let's reuse the old vtable. */ @@ -2739,8 +2799,8 @@ merge_overrides (binfo, old, do_self, t) { tree base_binfo = TREE_VEC_ELT (binfos, i); tree old_base_binfo = TREE_VEC_ELT (old_binfos, i); - int is_not_base_vtable - = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo)); + 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); } @@ -4563,9 +4623,15 @@ finish_struct_1 (t) vbases = CLASSTYPE_VBASECLASSES (basetype); while (vbases) { - merge_overrides (binfo_member (BINFO_TYPE (vbases), - CLASSTYPE_VBASECLASSES (t)), - vbases, 1, t); + 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); } } @@ -4613,11 +4679,14 @@ finish_struct_1 (t) 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. */ - fixup_vtable_deltas (vbases, 1, t); + vbase = find_vbase_instance (BINFO_TYPE (vbases), t); + dfs_walk (vbase, dfs_fixup_vtable_deltas, dfs_skip_vbases, t); vbases = TREE_CHAIN (vbases); } } @@ -6015,10 +6084,11 @@ dump_class_hierarchy (binfo, indent) { int i; - fprintf (stderr, "%*s0x%x (%s) %d\n", indent, "", + fprintf (stderr, "%*s0x%x (%s) %d %s\n", indent, "", (unsigned int) binfo, type_as_string (binfo, TS_PLAIN), - TREE_INT_CST_LOW (BINFO_OFFSET (binfo))); + TREE_INT_CST_LOW (BINFO_OFFSET (binfo)), + BINFO_PRIMARY_MARKED_P (binfo) ? "primary" : ""); for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i) dump_class_hierarchy (BINFO_BASETYPE (binfo, i), indent + 2); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index beaa4168338..88b49a0fdda 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3954,8 +3954,10 @@ extern tree dfs_skip_nonprimary_vbases_unmarkedp PROTO((tree, void *)); extern tree dfs_skip_nonprimary_vbases_markedp PROTO((tree, void *)); extern tree dfs_unmarked_real_bases_queue_p PROTO((tree, void *)); extern tree dfs_marked_real_bases_queue_p PROTO((tree, void *)); +extern tree dfs_skip_vbases PROTO((tree, void *)); extern void mark_primary_bases PROTO((tree)); extern tree convert_pointer_to_vbase PROTO((tree, tree)); +extern tree find_vbase_instance PROTO((tree, tree)); /* in semantics.c */ extern void finish_expr_stmt PROTO((tree)); diff --git a/gcc/cp/search.c b/gcc/cp/search.c index abd6867a0f4..1d6efed889d 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -151,6 +151,7 @@ static int template_self_reference_p PROTO ((tree, tree)); static void fixup_all_virtual_upcast_offsets PROTO ((tree, tree)); static tree dfs_mark_primary_bases PROTO((tree, void *)); static tree get_shared_vbase_if_not_primary PROTO((tree, tree)); +static tree dfs_find_vbase_instance PROTO((tree, void *)); /* Allocate a level of searching. */ @@ -2189,9 +2190,14 @@ mark_primary_bases (type) { tree vbase; - /* Mark the TYPE_BINFO hierarchy. */ - dfs_walk (TYPE_BINFO (type), dfs_mark_primary_bases, - dfs_skip_nonprimary_vbases_unmarkedp, type); + /* Mark the TYPE_BINFO hierarchy. We need to mark primary bases in + pre-order to deal with primary virtual bases. (The virtual base + would be skipped if it were not marked as primary, and that + requires getting to dfs_mark_primary_bases before + dfs_skip_nonprimary_vbases_unmarkedp has a chance to skip the + virtual base.) */ + dfs_walk_real (TYPE_BINFO (type), dfs_mark_primary_bases, NULL, + dfs_skip_nonprimary_vbases_unmarkedp, type); /* Now go through the virtual base classes. Any that are not already primary will need to be allocated in TYPE, and so we need @@ -2289,6 +2295,20 @@ dfs_marked_real_bases_queue_p (binfo, data) return binfo ? markedp (binfo, NULL) : NULL_TREE; } +/* A queue function that skips all virtual bases (and their + bases). */ + +tree +dfs_skip_vbases (binfo, data) + tree binfo; + void *data ATTRIBUTE_UNUSED; +{ + if (TREE_VIA_VIRTUAL (binfo)) + return NULL_TREE; + + return binfo; +} + /* Called via dfs_walk from dfs_get_pure_virtuals. */ static tree @@ -2798,7 +2818,14 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t, tree vc; tree delta; unsigned HOST_WIDE_INT n; - + + while (BINFO_PRIMARY_MARKED_P (binfo)) + { + binfo = BINFO_INHERITANCE_CHAIN (binfo); + if (TREE_VIA_VIRTUAL (binfo)) + return; + } + delta = purpose_member (vbase, *vbase_offsets); if (! delta) { @@ -2925,7 +2952,7 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori tree real_base_binfo = TREE_VEC_ELT (real_binfos, i); tree base_binfo = TREE_VEC_ELT (binfos, i); int is_not_base_vtable - = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo)); + = !BINFO_PRIMARY_MARKED_P (real_base_binfo); if (! TREE_VIA_VIRTUAL (real_base_binfo)) fixup_virtual_upcast_offsets (real_base_binfo, base_binfo, is_not_base_vtable, can_elide, addr, @@ -2979,15 +3006,17 @@ fixup_all_virtual_upcast_offsets (type, decl_ptr) ; else { + tree vbase; tree vbase_offsets; tree addr; + vbase = find_vbase_instance (BINFO_TYPE (vbases), type); vbase_offsets = NULL_TREE; - addr = convert_pointer_to_vbase (TREE_TYPE (vbases), decl_ptr); - fixup_virtual_upcast_offsets (vbases, + addr = convert_pointer_to_vbase (BINFO_TYPE (vbases), decl_ptr); + fixup_virtual_upcast_offsets (vbase, TYPE_BINFO (BINFO_TYPE (vbases)), 1, 0, addr, decl_ptr, - type, vbases, &vbase_offsets); + type, vbase, &vbase_offsets); } } @@ -3074,6 +3103,43 @@ get_vbase_types (type) CLASSTYPE_VBASECLASSES (type) = nreverse (CLASSTYPE_VBASECLASSES (type)); dfs_walk (TYPE_BINFO (type), dfs_vbase_unmark, markedp, 0); } + +/* Called from find_vbase_instance via dfs_walk. */ + +static tree +dfs_find_vbase_instance (binfo, data) + tree binfo; + void *data; +{ + tree base = TREE_VALUE ((tree) data); + + if (BINFO_PRIMARY_MARKED_P (binfo) + && same_type_p (BINFO_TYPE (binfo), base)) + return binfo; + + return NULL_TREE; +} + +/* Find the real occurrence of the virtual BASE (a class type) in the + hierarchy dominated by TYPE. */ + +tree +find_vbase_instance (base, type) + tree base; + tree type; +{ + tree instance; + + instance = BINFO_FOR_VBASE (base, type); + if (!BINFO_VBASE_PRIMARY_P (instance)) + return instance; + + return dfs_walk (TYPE_BINFO (type), + dfs_find_vbase_instance, + NULL, + build_tree_list (type, base)); +} + /* Debug info for C++ classes can get very large; try to avoid emitting it everywhere.