From 59751e6c1cc8803f1e572c6dc135a65da1ccc5c4 Mon Sep 17 00:00:00 2001 From: mmitchel Date: Tue, 4 Apr 2000 18:13:22 +0000 Subject: [PATCH] Correct many new ABI issues regarding vbase and vcall offset layout. * cp-tree.h (BINFO_VTABLE): Document. (struct lang_type): Tweak formatting. (BINFO_PRIMARY_BINFO): Add to documentation. (CLASSTYPE_VSIZE): Fix typo in comment. (CLASSTYPE_VBASECLASSES): Update documentation. (BINFO_VBASE_MARKED): Remove. (SET_BINFO_VBASE_MARKED): Likewise. (CLEAR_BINFO_VBASE_MARKED): Likewise. (BINFO_FIELDS_MARKED): Remove. (SET_BINFO_FIELDS_MARKED): Likewise. (CLEAR_BINFO_FIELDS_MARKED): Likewise. (enum access_kind): New enumeration. (num_extra_vtbl_entries): Remove declaration. (size_extra_vtbl_entries): Likewise. (get_vtbl_decl_for_binfo): New function. (dfs_vbase_unmark): Remove declaration. (mark_primary_bases): Likewise. * class.c (SAME_FN): Remove. (struct vcall_offset_data_s): Move definition. (build_vbase_pointer): Use `build', not `build_binary_op', to access the vbase pointer under the new ABI. (build_vtable_entry_ref): Use get_vtbl_decl_for_binfo. (build_primary_vtable): Likewise. (dfs_mark_primary_bases): Move here from search.c. (mark_primary_bases): Likewise. (determine_primary_bases): Under the new ABI, don't make a base class a primary base just because we don't yet have any virtual functions. (layout_vtable_decl): Use get_vtbl_decl_for_binfo. (num_vfun_entries): Remove. (dfs_count_virtuals): Likewise. (num_extra_vtbl_entries): Likewise. (size_extra_vtbl_entries): Likewise. (layout_virtual_bases): Iterate in inheritance graph order under the new ABI. (finish_struct_1): Use TYPE_VFIELD, not CLASSTYPE_VSIZE, to indicate that a vfield is present. (init_class_processing): Initialize access_public_node, etc., from ak_public, etc. (get_vtbl_decl_for_binfo): New function. (dump_class_hierarchy_r): Likewise. (dump_class_hierarchy): Use it. (finish_vtbls): Build the vtbls in inheritance graph order. (dfs_finish_vtbls): Adjust call to build_vtbl_initializer. (initialize_vtable): Use get_vtbl_decl_for_binfo. (accumulate_vtbl_inits): Add comments explaining why a pre-order walk is required. (dfs_accumulate_vtbl_inits): Set BINFO_VTABLE to the location where the vptr points, even for primary vtables. (build_vtbl_initializer): Adjust handling of vbase and vcall offsets. (build_vcall_and_vbase_vtable_entries): New function. (dfs_build_vbase_offset_vtbl_entries): Remove. (build_vbase_offset_vtbl_entries): Reimplement. (dfs_build_vcall_offset_vtbl_entries): Don't include virtuals that were already handled in a primary base class vtable. (build_vcall_offset_vtbl_entries): Adjust. (build_rtti_vtbl_entries): Adjust. * decl2.c (output_vtable_inherit): Use get_vtbl_decl_for_binfo. * init.c (expand_virtual_init): Simplify. * repo.c (repo_get_id): Use get_vtbl_decl_for_binfo. * rtti.c (create_pseudo_type_info): Adjust calculation of vptr. * search.c (BINFO_ACCESS): New macro. (SET_BINFO_ACCESS): Likewise. (dfs_access_in_type): Manipulate access_kinds, not access nodes. (access_in_type): Likewise. (dfs_accessible_p): Likewise. (protected_accessible_p): Likewise. (lookup_fnfields_1): Adjust documentation. (dfs_mark_primary_bases): Move to class.c (mark_primary_bases): Likewise. (dfs_vbase_unmark): Remove. (virtual_context): Use BINFO_FOR_VBASE. (dfs_get_vbase_types): Simplify. (dfs_build_inheritance_graph_order): New function. (get_vbase_types): Use it. * tree.c (debug_binfo): Use get_vtbl_decl_for_binfo. * tinfo.cc (get_vbase_offset): New function. (__vmi_class_type_info::do_find_public_src): Use it. (__vmi_class_type_info::do_dyncast): Likewise. (__vmi_class_type_info::do_upcast): Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@32905 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 87 +++ gcc/cp/class.c | 865 +++++++++++++++----------- gcc/cp/cp-tree.h | 88 +-- gcc/cp/decl2.c | 2 +- gcc/cp/init.c | 30 +- gcc/cp/repo.c | 2 +- gcc/cp/rtti.c | 9 +- gcc/cp/search.c | 225 +++---- gcc/cp/tinfo.cc | 21 +- gcc/cp/tree.c | 2 +- gcc/testsuite/g++.old-deja/g++.abi/layout1.C | 51 ++ gcc/testsuite/g++.old-deja/g++.abi/vtable.C | 2 +- gcc/testsuite/g++.old-deja/g++.abi/vtable2.C | 179 ++++++ gcc/testsuite/g++.old-deja/g++.jason/dcast3.C | 2 +- 14 files changed, 979 insertions(+), 586 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.abi/layout1.C create mode 100644 gcc/testsuite/g++.old-deja/g++.abi/vtable2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1a74fea1c43..8fcacd2720e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,90 @@ +2000-04-04 Mark Mitchell + + Correct many new ABI issues regarding vbase and vcall offset + layout. + * cp-tree.h (BINFO_VTABLE): Document. + (struct lang_type): Tweak formatting. + (BINFO_PRIMARY_BINFO): Add to documentation. + (CLASSTYPE_VSIZE): Fix typo in comment. + (CLASSTYPE_VBASECLASSES): Update documentation. + (BINFO_VBASE_MARKED): Remove. + (SET_BINFO_VBASE_MARKED): Likewise. + (CLEAR_BINFO_VBASE_MARKED): Likewise. + (BINFO_FIELDS_MARKED): Remove. + (SET_BINFO_FIELDS_MARKED): Likewise. + (CLEAR_BINFO_FIELDS_MARKED): Likewise. + (enum access_kind): New enumeration. + (num_extra_vtbl_entries): Remove declaration. + (size_extra_vtbl_entries): Likewise. + (get_vtbl_decl_for_binfo): New function. + (dfs_vbase_unmark): Remove declaration. + (mark_primary_bases): Likewise. + * class.c (SAME_FN): Remove. + (struct vcall_offset_data_s): Move definition. + (build_vbase_pointer): Use `build', not `build_binary_op', to + access the vbase pointer under the new ABI. + (build_vtable_entry_ref): Use get_vtbl_decl_for_binfo. + (build_primary_vtable): Likewise. + (dfs_mark_primary_bases): Move here from search.c. + (mark_primary_bases): Likewise. + (determine_primary_bases): Under the new ABI, don't make a base + class a primary base just because we don't yet have any virtual + functions. + (layout_vtable_decl): Use get_vtbl_decl_for_binfo. + (num_vfun_entries): Remove. + (dfs_count_virtuals): Likewise. + (num_extra_vtbl_entries): Likewise. + (size_extra_vtbl_entries): Likewise. + (layout_virtual_bases): Iterate in inheritance graph order under + the new ABI. + (finish_struct_1): Use TYPE_VFIELD, not CLASSTYPE_VSIZE, to + indicate that a vfield is present. + (init_class_processing): Initialize access_public_node, etc., from + ak_public, etc. + (get_vtbl_decl_for_binfo): New function. + (dump_class_hierarchy_r): Likewise. + (dump_class_hierarchy): Use it. + (finish_vtbls): Build the vtbls in inheritance graph order. + (dfs_finish_vtbls): Adjust call to build_vtbl_initializer. + (initialize_vtable): Use get_vtbl_decl_for_binfo. + (accumulate_vtbl_inits): Add comments explaining why a pre-order + walk is required. + (dfs_accumulate_vtbl_inits): Set BINFO_VTABLE to the location + where the vptr points, even for primary vtables. + (build_vtbl_initializer): Adjust handling of vbase and vcall + offsets. + (build_vcall_and_vbase_vtable_entries): New function. + (dfs_build_vbase_offset_vtbl_entries): Remove. + (build_vbase_offset_vtbl_entries): Reimplement. + (dfs_build_vcall_offset_vtbl_entries): Don't include virtuals that + were already handled in a primary base class vtable. + (build_vcall_offset_vtbl_entries): Adjust. + (build_rtti_vtbl_entries): Adjust. + * decl2.c (output_vtable_inherit): Use get_vtbl_decl_for_binfo. + * init.c (expand_virtual_init): Simplify. + * repo.c (repo_get_id): Use get_vtbl_decl_for_binfo. + * rtti.c (create_pseudo_type_info): Adjust calculation of vptr. + * search.c (BINFO_ACCESS): New macro. + (SET_BINFO_ACCESS): Likewise. + (dfs_access_in_type): Manipulate access_kinds, not access nodes. + (access_in_type): Likewise. + (dfs_accessible_p): Likewise. + (protected_accessible_p): Likewise. + (lookup_fnfields_1): Adjust documentation. + (dfs_mark_primary_bases): Move to class.c + (mark_primary_bases): Likewise. + (dfs_vbase_unmark): Remove. + (virtual_context): Use BINFO_FOR_VBASE. + (dfs_get_vbase_types): Simplify. + (dfs_build_inheritance_graph_order): New function. + (get_vbase_types): Use it. + * tree.c (debug_binfo): Use get_vtbl_decl_for_binfo. + + * tinfo.cc (get_vbase_offset): New function. + (__vmi_class_type_info::do_find_public_src): Use it. + (__vmi_class_type_info::do_dyncast): Likewise. + (__vmi_class_type_info::do_upcast): Likewise. + 2000-04-03 Zack Weinberg * lang-specs.h: Pass -fno-show-column to the preprocessor. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index f3a94dc065c..a9f35951375 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -38,12 +38,6 @@ Boston, MA 02111-1307, USA. */ #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free -/* This is how we tell when two virtual member functions are really the - same. */ -#define SAME_FN(FN1DECL, FN2DECL) (DECL_ASSEMBLER_NAME (FN1DECL) == DECL_ASSEMBLER_NAME (FN2DECL)) - -extern void set_class_shadows PARAMS ((tree)); - /* The number of nested classes being processed. If we are not in the scope of any class, this is zero. */ @@ -68,6 +62,22 @@ typedef struct class_stack_node { splay_tree names_used; }* class_stack_node_t; +typedef struct vcall_offset_data_s +{ + /* The binfo for the most-derived type. */ + tree derived; + /* The binfo for the virtual base for which we're building + initializers. */ + tree vbase; + /* The vcall offset initializers built up so far. */ + tree inits; + /* The vtable index of the next vcall or vbase offset. */ + tree index; + /* Nonzero if we are building the initializer for the primary + vtable. */ + int primary_p; +} vcall_offset_data; + /* The stack itself. This is an dynamically resized array. The number of elements allocated is CURRENT_CLASS_STACK_SIZE. */ static int current_class_stack_size; @@ -108,7 +118,7 @@ static tree fixed_type_or_null PARAMS ((tree, int *)); static tree resolve_address_of_overloaded_function PARAMS ((tree, tree, int, int, tree)); static void build_vtable_entry_ref PARAMS ((tree, tree, tree)); -static tree build_vtbl_initializer PARAMS ((tree, tree)); +static tree build_vtbl_initializer PARAMS ((tree, tree, int *)); static int count_fields PARAMS ((tree)); static int add_fields_to_vec PARAMS ((tree, tree, int)); static void check_bitfield_decl PARAMS ((tree)); @@ -135,19 +145,17 @@ static void propagate_binfo_offsets PARAMS ((tree, tree)); static void layout_virtual_bases PARAMS ((tree, varray_type *)); static tree dfs_set_offset_for_shared_vbases PARAMS ((tree, void *)); static tree dfs_set_offset_for_unshared_vbases PARAMS ((tree, void *)); -static tree dfs_build_vbase_offset_vtbl_entries PARAMS ((tree, void *)); -static tree build_vbase_offset_vtbl_entries PARAMS ((tree, tree)); +static void build_vbase_offset_vtbl_entries PARAMS ((tree, vcall_offset_data *)); static tree dfs_vcall_offset_queue_p PARAMS ((tree, void *)); static tree dfs_build_vcall_offset_vtbl_entries PARAMS ((tree, void *)); -static tree build_vcall_offset_vtbl_entries PARAMS ((tree, tree)); -static tree dfs_count_virtuals PARAMS ((tree, void *)); +static void build_vcall_offset_vtbl_entries PARAMS ((tree, vcall_offset_data *)); 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)); -extern void dump_class_hierarchy PARAMS ((tree, int)); +static void dump_class_hierarchy_r PARAMS ((tree, tree, int)); +extern void dump_class_hierarchy PARAMS ((tree)); static tree build_vtable PARAMS ((tree, tree, tree)); static void initialize_vtable PARAMS ((tree, tree)); static void layout_nonempty_base_or_field PARAMS ((record_layout_info, @@ -162,6 +170,10 @@ static void layout_empty_base PARAMS ((tree, tree, varray_type)); static void accumulate_vtbl_inits PARAMS ((tree, tree)); static void set_vindex PARAMS ((tree, tree, int *)); static tree build_rtti_vtbl_entries PARAMS ((tree, tree)); +static void build_vcall_and_vbase_vtbl_entries PARAMS ((tree, + vcall_offset_data *)); +static tree dfs_mark_primary_bases PARAMS ((tree, void *)); +static void mark_primary_bases PARAMS ((tree)); /* Variables shared between class.c and call.c. */ @@ -274,9 +286,10 @@ build_vbase_pointer (exp, type) /* Find the virtual function table pointer. */ vbase_ptr = build_vfield_ref (exp, TREE_TYPE (exp)); /* Compute the location where the offset will lie. */ - vbase_ptr = build_binary_op (PLUS_EXPR, - vbase_ptr, - BINFO_VPTR_FIELD (vbase)); + vbase_ptr = build (PLUS_EXPR, + TREE_TYPE (vbase_ptr), + vbase_ptr, + BINFO_VPTR_FIELD (vbase)); vbase_ptr = build1 (NOP_EXPR, build_pointer_type (ptrdiff_type_node), vbase_ptr); @@ -462,7 +475,7 @@ build_vtable_entry_ref (basetype, vtbl, idx) static char asm_stmt[] = ".vtable_entry %c0, %c1"; tree s, i, i2; - s = build_unary_op (ADDR_EXPR, TYPE_BINFO_VTABLE (basetype), 0); + s = build_unary_op (ADDR_EXPR, get_vtbl_decl_for_binfo (basetype), 0); s = build_tree_list (build_string (1, "s"), s); i = build_array_ref (vtbl, idx); @@ -533,7 +546,23 @@ build_vtbl_ref (instance, idx) && (TREE_CODE (instance) == RESULT_DECL || TREE_CODE (instance) == PARM_DECL || TREE_CODE (instance) == VAR_DECL)) - vtbl = TYPE_BINFO_VTABLE (basetype); + { + vtbl = TYPE_BINFO_VTABLE (basetype); + /* Knowing the dynamic type of INSTANCE we can easily obtain + the correct vtable entry. In the new ABI, we resolve + this back to be in terms of the primary vtable. */ + if (TREE_CODE (vtbl) == PLUS_EXPR) + { + idx = fold (build (PLUS_EXPR, + TREE_TYPE (idx), + idx, + build (EXACT_DIV_EXPR, + TREE_TYPE (idx), + TREE_OPERAND (vtbl, 1), + TYPE_SIZE_UNIT (vtable_entry_type)))); + vtbl = get_vtbl_decl_for_binfo (TYPE_BINFO (basetype)); + } + } else vtbl = build_vfield_ref (instance, basetype); } @@ -733,10 +762,9 @@ build_primary_vtable (binfo, type) return 0; virtuals = copy_list (BINFO_VIRTUALS (binfo)); - TREE_TYPE (decl) = TREE_TYPE (BINFO_VTABLE (binfo)); - DECL_SIZE (decl) = TYPE_SIZE (TREE_TYPE (BINFO_VTABLE (binfo))); - DECL_SIZE_UNIT (decl) - = TYPE_SIZE_UNIT (TREE_TYPE (BINFO_VTABLE (binfo))); + TREE_TYPE (decl) = TREE_TYPE (get_vtbl_decl_for_binfo (binfo)); + DECL_SIZE (decl) = TYPE_SIZE (TREE_TYPE (decl)); + DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (TREE_TYPE (decl)); } else { @@ -1623,6 +1651,97 @@ check_bases (t, cant_have_default_ctor_p, cant_have_const_ctor_p, } } +/* Called via dfs_walk from mark_primary_bases. Sets + BINFO_PRIMARY_MARKED_P for BINFO, if appropriate. */ + +static tree +dfs_mark_primary_bases (binfo, data) + tree binfo; + void *data; +{ + int i; + tree base_binfo; + + if (!CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (binfo))) + return NULL_TREE; + + i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo)); + base_binfo = BINFO_BASETYPE (binfo, i); + + if (!TREE_VIA_VIRTUAL (base_binfo)) + /* Non-virtual base classes are easy. */ + BINFO_PRIMARY_MARKED_P (base_binfo) = 1; + else + { + tree shared_binfo; + + shared_binfo + = BINFO_FOR_VBASE (BINFO_TYPE (base_binfo), (tree) data); + + /* If this virtual base is not already primary somewhere else in + the hiearchy, then we'll be using this copy. */ + if (!BINFO_VBASE_PRIMARY_P (shared_binfo)) + { + BINFO_VBASE_PRIMARY_P (shared_binfo) = 1; + BINFO_PRIMARY_MARKED_P (base_binfo) = 1; + } + } + + return NULL_TREE; +} + +/* Set BINFO_PRIMARY_MARKED_P for all binfos in the hierarchy + dominated by BINFO that are primary bases. */ + +static void +mark_primary_bases (type) + tree type; +{ + tree vbases; + + /* 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 in inheritance graph + order. Any that are not already primary will need to be + allocated in TYPE, and so we need to mark their primary bases. */ + for (vbases = TYPE_BINFO (type); vbases; vbases = TREE_CHAIN (vbases)) + { + tree vbase; + + /* Make sure that only BINFOs appear on this list. + Historically, the TREE_CHAIN was used for other purposes, and + we want to make sure that none of those uses remain. */ + my_friendly_assert (TREE_CODE (vbases) == TREE_VEC, 20000402); + + if (!TREE_VIA_VIRTUAL (vbases)) + continue; + + vbase = BINFO_FOR_VBASE (BINFO_TYPE (vbases), type); + if (BINFO_VBASE_PRIMARY_P (vbase)) + /* This virtual base was already included in the hierarchy, so + there's nothing to do here. */ + continue; + + /* Temporarily pretend that VBASE is primary so that its bases + will be walked; this is the real copy of VBASE. */ + BINFO_PRIMARY_MARKED_P (vbase) = 1; + + /* Now, walk its bases. */ + dfs_walk_real (vbase, dfs_mark_primary_bases, NULL, + dfs_skip_nonprimary_vbases_unmarkedp, type); + + /* VBASE wasn't really primary. */ + BINFO_PRIMARY_MARKED_P (vbase) = 0; + } +} + /* Make the Ith baseclass of T its primary base. */ static void @@ -1696,7 +1815,7 @@ determine_primary_base (t, vfuns_p) VF_BASETYPE_VALUE (vfields), CLASSTYPE_VFIELDS (t)); - if (*vfuns_p == 0) + if (!flag_new_abi && *vfuns_p == 0) set_primary_base (t, i, vfuns_p); } } @@ -2184,6 +2303,7 @@ layout_vtable_decl (binfo, n) { tree itype; tree atype; + tree vtable; itype = size_int (n); atype = build_cplus_array_type (vtable_entry_type, @@ -2191,12 +2311,11 @@ layout_vtable_decl (binfo, n) layout_type (atype); /* We may have to grow the vtable. */ - if (!same_type_p (TREE_TYPE (BINFO_VTABLE (binfo)), atype)) + vtable = get_vtbl_decl_for_binfo (binfo); + if (!same_type_p (TREE_TYPE (vtable), atype)) { - tree vtable = BINFO_VTABLE (binfo); - TREE_TYPE (vtable) = atype; - DECL_SIZE (vtable) = DECL_SIZE_UNIT (vtable) = 0; + DECL_SIZE (vtable) = DECL_SIZE_UNIT (vtable) = NULL_TREE; layout_decl (vtable, 0); /* At one time the vtable info was grabbed 2 words at a time. This @@ -2206,104 +2325,6 @@ layout_vtable_decl (binfo, n) } } -/* Returns the number of virtual function table entries (excluding - RTTI information, vbase and vcall offests, etc.) in the vtable for - BINFO. */ - -static int -num_vfun_entries (binfo) - tree binfo; -{ - return list_length (BINFO_VIRTUALS (binfo)); -} - -typedef struct vcall_offset_data_s -{ - /* The binfo for the most-derived type. */ - tree derived; - /* The binfo for the virtual base for which we're building - initializers. */ - tree vbase; - /* The vcall offset initializers built up so far. */ - tree inits; - /* The number of vcall offsets accumulated. */ - int offsets; -} vcall_offset_data; - -/* Called from num_extra_vtbl_entries via dfs_walk. */ - -static tree -dfs_count_virtuals (binfo, data) - tree binfo; - void *data; -{ - /* Non-primary bases are not interesting; all of the virtual - function table entries have been overridden. */ - if (!BINFO_PRIMARY_MARKED_P (binfo)) - ((vcall_offset_data *) data)->offsets += num_vfun_entries (binfo); - - return NULL_TREE; -} - -/* Returns the number of extra entries (at negative indices) required - for BINFO's vtable. */ - -tree -num_extra_vtbl_entries (binfo) - tree binfo; -{ - tree type; - int entries; - - type = BINFO_TYPE (binfo); - entries = 0; - - /* There is an entry for the offset to each virtual base. */ - if (vbase_offsets_in_vtable_p ()) - entries += list_length (CLASSTYPE_VBASECLASSES (type)); - - /* If this is a virtual base, there are entries for each virtual - function defined in this class or its bases. */ - if (vcall_offsets_in_vtable_p () && TREE_VIA_VIRTUAL (binfo)) - { - vcall_offset_data vod; - - vod.vbase = binfo; - vod.offsets = 0; - dfs_walk (binfo, - dfs_count_virtuals, - dfs_vcall_offset_queue_p, - &vod); - entries += vod.offsets; - } - - /* When laying out COM-compatible classes, there are no RTTI - entries. */ - if (CLASSTYPE_COM_INTERFACE (type)) - ; - /* When using vtable thunks, there are two RTTI entries: the "offset - to top" value and the RTTI entry itself. */ - else if (flag_vtable_thunks) - entries += 2; - /* When not using vtable thunks there is only a single entry. */ - else - entries += 1; - - return size_int (entries); -} - -/* Returns the offset (in bytes) from the beginning of BINFO's vtable - where the vptr should actually point. */ - -tree -size_extra_vtbl_entries (binfo) - tree binfo; -{ - tree offset = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (vtable_entry_type), - num_extra_vtbl_entries (binfo)); - return fold (offset); -} - /* True if we should override the given BASE_FNDECL with the given FNDECL. */ @@ -3989,7 +4010,7 @@ check_bases_and_members (t, empty_p) /* If T needs a pointer to its virtual function table, set TYPE_VFIELD accordingly. If a new vfield was created (because T doesn't have a primary base class), then the newly created field is returned. It - is not added to the TYPE_FIELDS list; it is the callers + is not added to the TYPE_FIELDS list; it is the caller's responsibility to do that. */ static tree @@ -4205,7 +4226,7 @@ layout_virtual_bases (t, base_offsets) tree t; varray_type *base_offsets; { - tree vbase; + tree vbases; unsigned HOST_WIDE_INT dsize; unsigned HOST_WIDE_INT eoc; @@ -4225,53 +4246,70 @@ layout_virtual_bases (t, base_offsets) TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), BITS_PER_UNIT); /* Go through the virtual bases, allocating space for each virtual - base that is not already a primary base class. */ - for (vbase = CLASSTYPE_VBASECLASSES (t); - vbase; - vbase = TREE_CHAIN (vbase)) - if (!BINFO_VBASE_PRIMARY_P (vbase)) - { - /* This virtual base is not a primary base of any class in the - hierarchy, so we have to add space for it. */ - tree basetype; - unsigned int desired_align; + base that is not already a primary base class. Under the new + ABI, these are allocated according to a depth-first left-to-right + postorder traversal; in the new ABI, inheritance graph order is + used instead. */ + for (vbases = (flag_new_abi + ? TYPE_BINFO (t) + : CLASSTYPE_VBASECLASSES (t)); + vbases; + vbases = TREE_CHAIN (vbases)) + { + tree vbase; + + if (!TREE_VIA_VIRTUAL (vbases)) + continue; + + if (flag_new_abi) + vbase = BINFO_FOR_VBASE (BINFO_TYPE (vbases), t); + else + vbase = vbases; + + if (!BINFO_VBASE_PRIMARY_P (vbase)) + { + /* This virtual base is not a primary base of any class in the + hierarchy, so we have to add space for it. */ + tree basetype; + unsigned int desired_align; - basetype = BINFO_TYPE (vbase); + basetype = BINFO_TYPE (vbase); - if (flag_new_abi) - desired_align = CLASSTYPE_ALIGN (basetype); - else - /* Under the old ABI, virtual bases were aligned as for the + if (flag_new_abi) + desired_align = CLASSTYPE_ALIGN (basetype); + else + /* Under the old ABI, virtual bases were aligned as for the entire base object (including its virtual bases). That's wasteful, in general. */ - desired_align = TYPE_ALIGN (basetype); - TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), desired_align); - - /* Add padding so that we can put the virtual base class at an - appropriately aligned offset. */ - dsize = CEIL (dsize, desired_align) * desired_align; - - /* Under the new ABI, we try to squish empty virtual bases in - just like ordinary empty bases. */ - if (flag_new_abi && is_empty_class (basetype)) - layout_empty_base (vbase, - size_int (CEIL (dsize, BITS_PER_UNIT)), - *base_offsets); - else - { - /* And compute the offset of the virtual base. */ - propagate_binfo_offsets (vbase, - ssize_int (CEIL (dsize, BITS_PER_UNIT))); - /* Every virtual baseclass takes a least a UNIT, so that - we can take it's address and get something different - for each base. */ - dsize += MAX (BITS_PER_UNIT, - tree_low_cst (CLASSTYPE_SIZE (basetype), 0)); - } + desired_align = TYPE_ALIGN (basetype); + TYPE_ALIGN (t) = MAX (TYPE_ALIGN (t), desired_align); + + /* Add padding so that we can put the virtual base class at an + appropriately aligned offset. */ + dsize = CEIL (dsize, desired_align) * desired_align; + + /* Under the new ABI, we try to squish empty virtual bases in + just like ordinary empty bases. */ + if (flag_new_abi && is_empty_class (basetype)) + layout_empty_base (vbase, + size_int (CEIL (dsize, BITS_PER_UNIT)), + *base_offsets); + else + { + /* And compute the offset of the virtual base. */ + propagate_binfo_offsets (vbase, + ssize_int (CEIL (dsize, BITS_PER_UNIT))); + /* Every virtual baseclass takes a least a UNIT, so that + we can take it's address and get something different + for each base. */ + dsize += MAX (BITS_PER_UNIT, + tree_low_cst (CLASSTYPE_SIZE (basetype), 0)); + } - /* Keep track of the offsets assigned to this virtual base. */ - record_base_offsets (vbase, base_offsets); - } + /* Keep track of the offsets assigned to this virtual base. */ + record_base_offsets (vbase, base_offsets); + } + } /* Make sure that all of the CLASSTYPE_VBASECLASSES have their BINFO_OFFSET set correctly. Those we just allocated certainly @@ -4288,10 +4326,10 @@ layout_virtual_bases (t, base_offsets) 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); + for (vbases = CLASSTYPE_VBASECLASSES (t); + vbases; + vbases = TREE_CHAIN (vbases)) + dfs_walk (vbases, dfs_set_offset_for_unshared_vbases, NULL, t); /* If we had empty base classes that protruded beyond the end of the class, we didn't update DSIZE above; we were hoping to overlay @@ -4310,11 +4348,11 @@ layout_virtual_bases (t, base_offsets) /* Check for ambiguous virtual bases. */ if (extra_warnings) - for (vbase = CLASSTYPE_VBASECLASSES (t); - vbase; - vbase = TREE_CHAIN (vbase)) + for (vbases = CLASSTYPE_VBASECLASSES (t); + vbases; + vbases = TREE_CHAIN (vbases)) { - tree basetype = BINFO_TYPE (vbase); + tree basetype = BINFO_TYPE (vbases); if (get_base_distance (basetype, t, 0, (tree*)0) == -2) cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity", basetype, t); @@ -4572,7 +4610,7 @@ layout_class_type (t, empty_p, vfuns_p, /* Clean up. */ VARRAY_FREE (v); } - + /* Create a RECORD_TYPE or UNION_TYPE node for a C struct or union declaration (or C++ class declaration). @@ -4791,7 +4829,7 @@ finish_struct_1 (t) the base types we marked. */ finish_vtbls (t); - if (CLASSTYPE_VSIZE (t) != 0) + if (TYPE_VFIELD (t)) { /* In addition to this one, all the other vfields should be listed. */ /* Before that can be done, we have to have FIELD_DECLs for them, and @@ -5030,13 +5068,13 @@ init_class_processing () * sizeof (struct class_stack_node)); access_default_node = build_int_2 (0, 0); - access_public_node = build_int_2 (1, 0); - access_protected_node = build_int_2 (2, 0); - access_private_node = build_int_2 (3, 0); + access_public_node = build_int_2 (ak_public, 0); + access_protected_node = build_int_2 (ak_protected, 0); + access_private_node = build_int_2 (ak_private, 0); access_default_virtual_node = build_int_2 (4, 0); - access_public_virtual_node = build_int_2 (5, 0); - access_protected_virtual_node = build_int_2 (6, 0); - access_private_virtual_node = build_int_2 (7, 0); + access_public_virtual_node = build_int_2 (4 | ak_public, 0); + access_protected_virtual_node = build_int_2 (4 | ak_protected, 0); + access_private_virtual_node = build_int_2 (4 | ak_private, 0); } /* Set current scope to NAME. CODE tells us if this is a @@ -6047,12 +6085,36 @@ note_name_declared_in_class (name, decl) } } -/* Dump the offsets of all the bases rooted at BINFO to stderr. - INDENT should be zero when called from the top level; it is - incremented recursively. */ +/* Returns the VAR_DECL for the complete vtable associated with + BINFO. (Under the new ABI, secondary vtables are merged with + primary vtables; this function will return the VAR_DECL for the + primary vtable.) */ -void -dump_class_hierarchy (binfo, indent) +tree +get_vtbl_decl_for_binfo (binfo) + tree binfo; +{ + tree decl; + + decl = BINFO_VTABLE (binfo); + if (decl && TREE_CODE (decl) == PLUS_EXPR) + { + my_friendly_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR, + 2000403); + decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0); + } + if (decl) + my_friendly_assert (TREE_CODE (decl) == VAR_DECL, 20000403); + return decl; +} + +/* Dump the offsets of all the bases rooted at BINFO (in the hierarchy + dominated by T) to stderr. INDENT should be zero when called from + the top level; it is incremented recursively. */ + +static void +dump_class_hierarchy_r (t, binfo, indent) + tree t; tree binfo; int indent; { @@ -6063,11 +6125,31 @@ dump_class_hierarchy (binfo, indent) type_as_string (binfo, TS_PLAIN)); fprintf (stderr, HOST_WIDE_INT_PRINT_DEC, tree_low_cst (BINFO_OFFSET (binfo), 0)); - fprintf (stderr, " %s\n", - BINFO_PRIMARY_MARKED_P (binfo) ? "primary" : ""); + if (TREE_VIA_VIRTUAL (binfo)) + fprintf (stderr, " virtual"); + if (BINFO_PRIMARY_MARKED_P (binfo) + || (TREE_VIA_VIRTUAL (binfo) + && BINFO_VBASE_PRIMARY_P (BINFO_FOR_VBASE (BINFO_TYPE (binfo), + t)))) + fprintf (stderr, " primary"); + fprintf (stderr, "\n"); for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i) - dump_class_hierarchy (BINFO_BASETYPE (binfo, i), indent + 2); + dump_class_hierarchy_r (t, BINFO_BASETYPE (binfo, i), indent + 2); +} + +/* Dump the BINFO hierarchy for T. */ + +void +dump_class_hierarchy (t) + tree t; +{ + tree vbase; + + dump_class_hierarchy_r (t, TYPE_BINFO (t), 0); + fprintf (stderr, "virtual bases\n"); + for (vbase = CLASSTYPE_VBASECLASSES (t); vbase; vbase = TREE_CHAIN (vbase)) + dump_class_hierarchy_r (t, vbase, 0); } /* Virtual function table initialization. */ @@ -6087,14 +6169,18 @@ finish_vtbls (t) vtables in one contiguous vtable. The primary vtable is first, followed by the non-virtual secondary vtables in inheritance graph order. */ - list = build_tree_list (t, NULL_TREE); + list = build_tree_list (TYPE_BINFO_VTABLE (t), NULL_TREE); + TREE_TYPE (list) = t; accumulate_vtbl_inits (TYPE_BINFO (t), list); /* Then come the virtual bases, also in inheritance graph order. */ - for (vbase = CLASSTYPE_VBASECLASSES (t); - vbase; - vbase = TREE_CHAIN (vbase)) - accumulate_vtbl_inits (vbase, list); + for (vbase = TYPE_BINFO (t); vbase; vbase = TREE_CHAIN (vbase)) + { + if (!TREE_VIA_VIRTUAL (vbase)) + continue; + accumulate_vtbl_inits (BINFO_FOR_VBASE (BINFO_TYPE (vbase), t), + list); + } if (TYPE_BINFO_VTABLE (t)) initialize_vtable (TYPE_BINFO (t), TREE_VALUE (list)); @@ -6121,7 +6207,7 @@ dfs_finish_vtbls (binfo, data) && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)) && BINFO_NEW_VTABLE_MARKED (binfo, t)) initialize_vtable (binfo, - build_vtbl_initializer (binfo, t)); + build_vtbl_initializer (binfo, t, NULL)); CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t); SET_BINFO_MARKED (binfo); @@ -6140,7 +6226,7 @@ initialize_vtable (binfo, inits) tree decl; layout_vtable_decl (binfo, list_length (inits)); - decl = BINFO_VTABLE (binfo); + decl = get_vtbl_decl_for_binfo (binfo); context = DECL_CONTEXT (decl); DECL_CONTEXT (decl) = 0; DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE, inits); @@ -6156,10 +6242,12 @@ accumulate_vtbl_inits (binfo, inits) tree binfo; tree inits; { - /* Walk the BINFO and its bases. */ + /* Walk the BINFO and its bases. We walk in preorder so that as we + initialize each vtable we can figure out at what offset the + secondary vtable lies from the primary vtable. */ dfs_walk_real (binfo, dfs_accumulate_vtbl_inits, - NULL, + NULL, dfs_skip_vbases, inits); } @@ -6177,33 +6265,37 @@ dfs_accumulate_vtbl_inits (binfo, data) tree t; l = (tree) data; - t = TREE_PURPOSE (l); + t = TREE_TYPE (l); if (!BINFO_PRIMARY_MARKED_P (binfo) && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)) && BINFO_NEW_VTABLE_MARKED (binfo, t)) { - /* If this is a secondary vtable, record its location. */ - if (binfo != TYPE_BINFO (t)) - { - tree vtbl; - - vtbl = TYPE_BINFO_VTABLE (t); - vtbl = build1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (vtbl)), - vtbl); - BINFO_VTABLE (binfo) - = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, - size_binop (MULT_EXPR, - TYPE_SIZE_UNIT (TREE_TYPE (vtbl)), - size_int (list_length (TREE_VALUE (l))))); - } + tree inits; + tree vtbl; + tree index; + int non_fn_entries; + + /* Compute the initializer for this vtable. */ + inits = build_vtbl_initializer (binfo, t, &non_fn_entries); + + /* Set BINFO_VTABLE to the address where the VPTR should point. */ + vtbl = TREE_PURPOSE (l); + vtbl = build1 (ADDR_EXPR, + build_pointer_type (TREE_TYPE (vtbl)), + vtbl); + index = size_binop (PLUS_EXPR, + size_int (non_fn_entries), + size_int (list_length (TREE_VALUE (l)))); + BINFO_VTABLE (binfo) + = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, + size_binop (MULT_EXPR, + TYPE_SIZE_UNIT (TREE_TYPE (vtbl)), + index)); /* Add the initializers for this vtable to the initializers for the other vtables we've already got. */ - TREE_VALUE (l) - = chainon (TREE_VALUE (l), - build_vtbl_initializer (binfo, t)); + TREE_VALUE (l) = chainon (TREE_VALUE (l), inits); } CLEAR_BINFO_NEW_VTABLE_MARKED (binfo, t); @@ -6214,29 +6306,48 @@ dfs_accumulate_vtbl_inits (binfo, data) /* Construct the initializer for BINFOs virtual function table. BINFO is part of the hierarchy dominated by T. The value returned is a TREE_LIST suitable for wrapping in a CONSTRUCTOR to use as the - DECL_INITIAL for a vtable. */ + DECL_INITIAL for a vtable. If NON_FN_ENTRIES_P is not NULL, + *NON_FN_ENTRIES_P is set to the number of non-function entries in + the vtable. */ static tree -build_vtbl_initializer (binfo, t) +build_vtbl_initializer (binfo, t, non_fn_entries_p) tree binfo; tree t; + int *non_fn_entries_p; { tree v = BINFO_VIRTUALS (binfo); tree inits = NULL_TREE; + tree vfun_inits; + tree vbase; + vcall_offset_data vod; - /* Add entries to the vtable that indicate how to adjust the this - pointer when calling a virtual function in this class. */ - inits = build_vcall_offset_vtbl_entries (binfo, t); - - /* Add entries to the vtable for offsets to our virtual bases. */ - inits = chainon (build_vbase_offset_vtbl_entries (binfo, t), - inits); + /* Initialize those parts of VOD that matter. */ + vod.derived = t; + vod.inits = NULL_TREE; + vod.primary_p = (binfo == TYPE_BINFO (t)); + /* The first vbase or vcall offset is at index -3 in the vtable. */ + vod.index = build_int_2 (-3, -1); + + /* Add the vcall and vbase offset entries. */ + build_vcall_and_vbase_vtbl_entries (binfo, &vod); + inits = vod.inits; + /* Clear BINFO_VTABLE_PAATH_MARKED; it's set by + build_vbase_offset_vtbl_entries. */ + for (vbase = CLASSTYPE_VBASECLASSES (t); + vbase; + vbase = TREE_CHAIN (vbase)) + CLEAR_BINFO_VTABLE_PATH_MARKED (vbase); /* Add entries to the vtable for RTTI. */ - inits = chainon (build_rtti_vtbl_entries (binfo, t), inits); + inits = chainon (inits, build_rtti_vtbl_entries (binfo, t)); + + if (non_fn_entries_p) + *non_fn_entries_p = list_length (inits); /* Go through all the ordinary virtual functions, building up initializers. */ + vfun_inits = NULL_TREE; while (v) { tree delta; @@ -6266,118 +6377,133 @@ build_vtbl_initializer (binfo, t) /* Enter it in the vtable. */ init = build_vtable_entry (delta, vcall_index, pfn); /* And add it to the chain of initializers. */ - inits = tree_cons (NULL_TREE, init, inits); + vfun_inits = tree_cons (NULL_TREE, init, vfun_inits); /* Keep going. */ v = TREE_CHAIN (v); } - /* The initializers were built up in reverse order; straighten them - out now. */ - return nreverse (inits); + /* The initializers for virtual functions were built up in reverse + order; straighten them out now. */ + vfun_inits = nreverse (vfun_inits); + + /* The complete initializer is the INITS, followed by the + VFUN_INITS. */ + return chainon (inits, vfun_inits); } -/* Called from build_vbase_offset_vtbl_entries via dfs_walk. */ +/* Sets vod->inits to be the initializers for the vbase and vcall + offsets in BINFO, which is in the hierarchy dominated by T. */ -static tree -dfs_build_vbase_offset_vtbl_entries (binfo, data) +static void +build_vcall_and_vbase_vtbl_entries (binfo, vod) tree binfo; - void *data; + vcall_offset_data *vod; { - tree list = (tree) data; - - if (TREE_TYPE (list) == binfo) - /* The TREE_TYPE of LIST is the base class from which we started - walking. If that BINFO is virtual it's not a virtual baseclass - of itself. */ - ; - else if (TREE_VIA_VIRTUAL (binfo)) - { - tree init; - tree vbase; - - /* Remember the index to the vbase offset for this virtual - base. */ - vbase = BINFO_FOR_VBASE (BINFO_TYPE (binfo), TREE_PURPOSE (list)); - if (!TREE_VALUE (list)) - BINFO_VPTR_FIELD (vbase) = build_int_2 (-3, 0); - else - { - BINFO_VPTR_FIELD (vbase) = TREE_PURPOSE (TREE_VALUE (list)); - BINFO_VPTR_FIELD (vbase) - = fold (build (MINUS_EXPR, integer_type_node, - BINFO_VPTR_FIELD (vbase), integer_one_node)); - } - - /* And record the offset at which this virtual base lies in the - vtable. */ - init = BINFO_OFFSET (binfo); - TREE_VALUE (list) = tree_cons (BINFO_VPTR_FIELD (vbase), - init, TREE_VALUE (list)); - } + tree b; + tree inits; - SET_BINFO_VTABLE_PATH_MARKED (binfo); - - return NULL_TREE; + /* If this is a derived class, we must first create entries + corresponding to the base class. These entries must go closer to + the vptr, so we save them up and add them to the end of the list + later. */ + inits = vod->inits; + vod->inits = NULL_TREE; + b = BINFO_PRIMARY_BINFO (binfo); + if (b) + build_vcall_and_vbase_vtbl_entries (b, vod); + + /* Add the vbase entries for this base. */ + build_vbase_offset_vtbl_entries (binfo, vod); + /* Add the vcall entries for this base. */ + build_vcall_offset_vtbl_entries (binfo, vod); + + vod->inits = chainon (vod->inits, inits); } /* Returns the initializers for the vbase offset entries in the vtable for BINFO (which is part of the class hierarchy dominated by T), in - reverse order. */ + reverse order. VBASE_OFFSET_INDEX gives the vtable index + where the next vbase offset will go. */ -static tree -build_vbase_offset_vtbl_entries (binfo, t) +static void +build_vbase_offset_vtbl_entries (binfo, vod) tree binfo; - tree t; + vcall_offset_data *vod; { - tree inits; - tree init; - tree list; + tree vbase; + tree t; /* Under the old ABI, pointers to virtual bases are stored in each object. */ if (!vbase_offsets_in_vtable_p ()) - return NULL_TREE; + return; /* If there are no virtual baseclasses, then there is nothing to do. */ if (!TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo))) - return NULL_TREE; + return; - inits = NULL_TREE; + t = vod->derived; - /* The offsets are allocated in the reverse order of a - depth-first left-to-right traversal of the hierarchy. We use - BINFO_VTABLE_PATH_MARKED because we are ourselves during a - dfs_walk, and so BINFO_MARKED is already in use. */ - list = build_tree_list (t, NULL_TREE); - TREE_TYPE (list) = binfo; - dfs_walk (binfo, - dfs_build_vbase_offset_vtbl_entries, - unmarked_vtable_pathp, - list); - dfs_walk (binfo, - dfs_vtable_path_unmark, - marked_vtable_pathp, - list); - inits = nreverse (TREE_VALUE (list)); - - /* We've now got offsets in the right order. However, the offsets - we've stored are offsets from the beginning of the complete - object, and we need offsets from this BINFO. */ - for (init = inits; init; init = TREE_CHAIN (init)) - { - /* The dfs_build_vbase_offset_vtbl_entries routine uses the - TREE_PURPOSE to scribble in. But, we need to clear it now so - that the values are not perceived as labeled initializers. */ - TREE_PURPOSE (init) = NULL_TREE; - TREE_VALUE (init) - = fold (build1 (NOP_EXPR, vtable_entry_type, - size_diffop (TREE_VALUE (init), - BINFO_OFFSET (binfo)))); - } + /* Go through the virtual bases, adding the offsets. */ + for (vbase = TYPE_BINFO (BINFO_TYPE (binfo)); + vbase; + vbase = TREE_CHAIN (vbase)) + { + tree b; + tree delta; + + if (!TREE_VIA_VIRTUAL (vbase)) + continue; - return inits; + /* Find the instance of this virtual base in the complete + object. */ + b = BINFO_FOR_VBASE (BINFO_TYPE (vbase), t); + + /* If we've already got an offset for this virtual base, we + don't need another one. */ + if (BINFO_VTABLE_PATH_MARKED (b)) + continue; + SET_BINFO_VTABLE_PATH_MARKED (b); + + /* Figure out where we can find this vbase offset. */ + delta = size_binop (MULT_EXPR, + convert (ssizetype, vod->index), + convert (ssizetype, + TYPE_SIZE_UNIT (vtable_entry_type))); + if (vod->primary_p) + BINFO_VPTR_FIELD (b) = delta; + + if (binfo != TYPE_BINFO (t)) + { + tree orig_vbase; + + /* Find the instance of this virtual base in the type of BINFO. */ + orig_vbase = BINFO_FOR_VBASE (BINFO_TYPE (vbase), + BINFO_TYPE (binfo)); + + /* The vbase offset had better be the same. */ + if (!tree_int_cst_equal (delta, + BINFO_VPTR_FIELD (orig_vbase))) + my_friendly_abort (20000403); + } + + /* The next vbase will come at a more negative offset. */ + vod->index = fold (build (MINUS_EXPR, integer_type_node, + vod->index, integer_one_node)); + + /* The initializer is the delta from BINFO to this virtual base. + The vbase offsets go in reverse inheritance-graph order, and + we are walking in inheritance graph order so these end up in + the right order. */ + delta = size_diffop (BINFO_OFFSET (b), BINFO_OFFSET (binfo)); + vod->inits = tree_cons (NULL_TREE, + fold (build1 (NOP_EXPR, + vtable_entry_type, + delta)), + vod->inits); + } } /* Called from build_vcall_offset_vtbl_entries via dfs_walk. */ @@ -6402,20 +6528,22 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data) vcall_offset_data* vod; tree virtuals; tree binfo_inits; - - /* Primary bases are not interesting; all of the virtual - function table entries have been overridden. */ - if (BINFO_PRIMARY_MARKED_P (binfo)) - return NULL_TREE; + tree b; + int i; vod = (vcall_offset_data *) data; binfo_inits = NULL_TREE; + + /* Skip virtuals that we have already handled in a primary base + class. */ + virtuals = BINFO_VIRTUALS (binfo); + b = BINFO_PRIMARY_BINFO (binfo); + if (b) + for (i = 0; i < CLASSTYPE_VSIZE (BINFO_TYPE (b)); ++i) + virtuals = TREE_CHAIN (virtuals); - /* We chain the offsets on in reverse order. That's correct -- - build_vtbl_initializer will straighten them out. */ - for (virtuals = BINFO_VIRTUALS (binfo); - virtuals; - virtuals = TREE_CHAIN (virtuals)) + /* Make entries for the rest of the virtuals. */ + while (virtuals) { /* Figure out what function we're looking at. */ tree fn = TREE_VALUE (virtuals); @@ -6430,34 +6558,48 @@ dfs_build_vcall_offset_vtbl_entries (binfo, data) size_diffop (BINFO_OFFSET (base_binfo), BINFO_OFFSET (vod->vbase)))), binfo_inits); + vod->index = fold (build (MINUS_EXPR, integer_type_node, + vod->index, integer_one_node)); + virtuals = TREE_CHAIN (virtuals); } - /* Now add the initializers we've just created to the list that will - be returned to our caller. */ - vod->inits = chainon (vod->inits, binfo_inits); + /* The offests are built up in reverse order, so we straighten them + here. We simultaneously add them to VOD->INITS; we're walking + the bases in inheritance graph order, and the initializers are + supposed to appear in reverse inheritance order, so that's + correct. */ + while (binfo_inits) + { + tree next; + + next = TREE_CHAIN (binfo_inits); + TREE_CHAIN (binfo_inits) = vod->inits; + vod->inits = binfo_inits; + binfo_inits = next; + } return NULL_TREE; } -/* Returns the initializers for the vcall offset entries in the vtable - for BINFO (which is part of the class hierarchy dominated by T), in - reverse order. */ +/* Adds the initializers for the vcall offset entries in the vtable + for BINFO (which is part of the class hierarchy dominated by T) to + VOD->INITS. */ -static tree -build_vcall_offset_vtbl_entries (binfo, t) +static void +build_vcall_offset_vtbl_entries (binfo, vod) tree binfo; - tree t; + vcall_offset_data *vod; { - vcall_offset_data vod; + tree inits; /* Under the old ABI, the adjustments to the `this' pointer were made elsewhere. */ if (!vcall_offsets_in_vtable_p ()) - return NULL_TREE; + return; /* We only need these entries if this base is a virtual base. */ if (!TREE_VIA_VIRTUAL (binfo)) - return NULL_TREE; + return; /* We need a vcall offset for each of the virtual functions in this vtable. For example: @@ -6481,15 +6623,15 @@ build_vcall_offset_vtbl_entries (binfo, t) in our non-virtual bases vtables. For each base, the entries appear in the same order as in the base; but the bases themselves appear in reverse depth-first, left-to-right order. */ - vod.derived = t; - vod.vbase = binfo; - vod.inits = NULL_TREE; - dfs_walk (binfo, - dfs_build_vcall_offset_vtbl_entries, - dfs_vcall_offset_queue_p, - &vod); - - return vod.inits; + vod->vbase = binfo; + inits = vod->inits; + vod->inits = NULL_TREE; + dfs_walk_real (binfo, + dfs_build_vcall_offset_vtbl_entries, + NULL, + dfs_vcall_offset_queue_p, + vod); + vod->inits = chainon (vod->inits, inits); } /* Return vtbl initializers for the RTTI entries coresponding to the @@ -6503,10 +6645,10 @@ build_rtti_vtbl_entries (binfo, t) { tree b; tree basetype; - tree inits; tree offset; tree decl; tree init; + tree inits; basetype = BINFO_TYPE (binfo); inits = NULL_TREE; @@ -6519,19 +6661,15 @@ build_rtti_vtbl_entries (binfo, t) primary base, and then add the offset in the vtbl to that value. */ b = binfo; while (CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (b))) - b = BINFO_BASETYPE (b, - CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (b))); - offset = size_diffop (size_zero_node, BINFO_OFFSET (b)); - - /* Add the offset-to-top entry. */ - if (flag_vtable_thunks) { - /* Convert the offset to look like a function pointer, so that - we can put it in the vtable. */ - init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset); - TREE_CONSTANT (init) = 1; - inits = tree_cons (NULL_TREE, init, inits); + tree primary_base; + + primary_base = BINFO_PRIMARY_BINFO (b); + if (!BINFO_PRIMARY_MARKED_P (primary_base)) + break; + b = primary_base; } + offset = size_diffop (size_zero_node, BINFO_OFFSET (b)); /* The second entry is, in the case of the new ABI, the address of the typeinfo object, or, in the case of the old ABI, a function @@ -6561,10 +6699,19 @@ build_rtti_vtbl_entries (binfo, t) TREE_CONSTANT (init) = 1; init = build_vtable_entry (offset, integer_zero_node, init); } - - /* Hook the RTTI declaration onto the list. */ inits = tree_cons (NULL_TREE, init, inits); + /* Add the offset-to-top entry. It comes earlier in the vtable that + the the typeinfo entry. */ + if (flag_vtable_thunks) + { + /* Convert the offset to look like a function pointer, so that + we can put it in the vtable. */ + init = build1 (NOP_EXPR, vfunc_ptr_type_node, offset); + TREE_CONSTANT (init) = 1; + inits = tree_cons (NULL_TREE, init, inits); + } + return inits; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 0433135fc1c..07b867567e4 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -55,8 +55,6 @@ Boston, MA 02111-1307, USA. */ ICS_ELLIPSIS_FLAG (in _CONV) STMT_IS_FULL_EXPR_P (in _STMT) 2: IDENTIFIER_OPNAME_P. - BINFO_VBASE_MARKED. - BINFO_FIELDS_MARKED. TYPE_POLYMORHPIC_P (in _TYPE) ICS_THIS_FLAG (in _CONV) STMT_LINENO_FOR_FN_P (in _STMT) @@ -130,6 +128,13 @@ Boston, MA 02111-1307, USA. */ this function. (This binfo's BINFO_TYPE will always be the same as the DECL_CLASS_CONTEXT for the function.) + BINFO_VTABLE + Sometimes this is a VAR_DECL. Under the new ABI, it is instead + an expression with POINTER_TYPE pointing that gives the value + to which the vptr should be initialized. Use get_vtbl_decl_for_binfo + to extract the VAR_DECL for the complete vtable; that macro works + in both ABIs. + DECL_ARGUMENTS For a VAR_DECL this is DECL_ANON_UNION_ELEMS. @@ -1356,24 +1361,17 @@ struct lang_type int vsize; int vfield_parent; - union tree_node *vfields; - union tree_node *vbases; - - union tree_node *tags; - - union tree_node *search_slot; - - union tree_node *size; - union tree_node *size_unit; - - union tree_node *pure_virtuals; - union tree_node *friend_classes; - - union tree_node *rtti; - - union tree_node *methods; - - union tree_node *template_info; + tree vfields; + tree vbases; + tree tags; + tree search_slot; + tree size; + tree size_unit; + tree pure_virtuals; + tree friend_classes; + tree rtti; + tree methods; + tree template_info; tree befriending_classes; }; @@ -1538,21 +1536,29 @@ struct lang_type #define CLASSTYPE_PRIMARY_BINFO(NODE) \ (BINFO_PRIMARY_BINFO (TYPE_BINFO (NODE))) -/* If non-NULL, this is the binfo for the primary base of BINFO. */ +/* If non-NULL, this is the binfo for the primary base of BINFO. Note + that in a complex hierarchy the resulting BINFO may not actually + *be* primary. In particular if the resulting BINFO is a virtual + base, and it occurs elsewhere in the hierarchy, then this + occurrence may not actually be a primary base in the complete + object. Check BINFO_PRIMARY_MARKED_P to be sure. */ #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 present in this classes virtual +/* The number of virtual functions present in this class' virtual function table. */ #define CLASSTYPE_VSIZE(NODE) (TYPE_LANG_SPECIFIC(NODE)->vsize) /* A chain of BINFOs for the direct and indirect virtual base classes - that this type uses in depth-first left-to-right order. These - BINFOs are distinct from those in the TYPE_BINFO hierarchy. So, - given: + that this type uses in a post-order depth-first left-to-right + order. (In other words, these bases appear in the order that they + should be initialized.) + + These BINFOs are distinct from those in the TYPE_BINFO hierarchy. + So, given: struct A {}; struct B : public A {}; @@ -1683,9 +1689,7 @@ struct lang_type We use TREE_VIA_PROTECTED and TREE_VIA_PUBLIC, but private inheritance is indicated by the absence of the other two flags, not - by TREE_VIA_PRIVATE, which is unused. - - The TREE_CHAIN is for scratch space in search.c. */ + by TREE_VIA_PRIVATE, which is unused. */ /* Nonzero means marked by DFS or BFS search, including searches by `get_binfo' and `get_base_distance'. */ @@ -1695,18 +1699,6 @@ struct lang_type #define SET_BINFO_MARKED(NODE) (TREE_VIA_VIRTUAL(NODE)?SET_CLASSTYPE_MARKED(BINFO_TYPE(NODE)):(TREE_LANG_FLAG_0(NODE)=1)) #define CLEAR_BINFO_MARKED(NODE) (TREE_VIA_VIRTUAL(NODE)?CLEAR_CLASSTYPE_MARKED(BINFO_TYPE(NODE)):(TREE_LANG_FLAG_0(NODE)=0)) -/* Nonzero means marked in search through virtual inheritance hierarchy. */ -#define BINFO_VBASE_MARKED(NODE) CLASSTYPE_MARKED2 (BINFO_TYPE (NODE)) -/* Modifier macros */ -#define SET_BINFO_VBASE_MARKED(NODE) SET_CLASSTYPE_MARKED2 (BINFO_TYPE (NODE)) -#define CLEAR_BINFO_VBASE_MARKED(NODE) CLEAR_CLASSTYPE_MARKED2 (BINFO_TYPE (NODE)) - -/* Nonzero means marked in search for members or member functions. */ -#define BINFO_FIELDS_MARKED(NODE) \ - (TREE_VIA_VIRTUAL(NODE)?CLASSTYPE_MARKED2 (BINFO_TYPE (NODE)):TREE_LANG_FLAG_2(NODE)) -#define SET_BINFO_FIELDS_MARKED(NODE) (TREE_VIA_VIRTUAL(NODE)?SET_CLASSTYPE_MARKED2(BINFO_TYPE(NODE)):(TREE_LANG_FLAG_2(NODE)=1)) -#define CLEAR_BINFO_FIELDS_MARKED(NODE) (TREE_VIA_VIRTUAL(NODE)?CLEAR_CLASSTYPE_MARKED2(BINFO_TYPE(NODE)):(TREE_LANG_FLAG_2(NODE)=0)) - /* Nonzero means that this class is on a path leading to a new vtable. */ #define BINFO_VTABLE_PATH_MARKED(NODE) \ (TREE_VIA_VIRTUAL(NODE)?CLASSTYPE_MARKED3(BINFO_TYPE(NODE)):TREE_LANG_FLAG_3(NODE)) @@ -3081,6 +3073,17 @@ typedef enum tmpl_spec_kind { tsk_expl_inst /* An explicit instantiation. */ } tmpl_spec_kind; +/* The various kinds of access. BINFO_ACCESS depends on these being + two bit quantities. The numerical values are important; they are + used to initialize RTTI data structures, so chaning them changes + the ABI. */ +typedef enum access_kind { + ak_none = 0, /* Inaccessible. */ + ak_public = 1, /* Accessible, as a `public' thing. */ + ak_protected = 2, /* Accessible, as a `protected' thing. */ + ak_private = 3 /* Accessible, as a `private' thing. */ +} access_kind; + /* Zero means prototype weakly, as in ANSI C (no args means nothing). Each language context defines how this variable should be set. */ extern int strict_prototype; @@ -3694,8 +3697,7 @@ extern void unreverse_member_declarations PARAMS ((tree)); extern void invalidate_class_lookup_cache PARAMS ((void)); extern void maybe_note_name_used_in_class PARAMS ((tree, tree)); extern void note_name_declared_in_class PARAMS ((tree, tree)); -extern tree num_extra_vtbl_entries PARAMS ((tree)); -extern tree size_extra_vtbl_entries PARAMS ((tree)); +extern tree get_vtbl_decl_for_binfo PARAMS ((tree)); /* in cvt.c */ extern tree convert_to_reference PARAMS ((tree, tree, int, int, tree)); @@ -4203,7 +4205,6 @@ extern tree dfs_walk_real PARAMS ((tree, tree (*) (tree, void *), void *)); extern tree dfs_unmark PARAMS ((tree, void *)); -extern tree dfs_vbase_unmark PARAMS ((tree, void *)); extern tree dfs_vtable_path_unmark PARAMS ((tree, void *)); extern tree markedp PARAMS ((tree, void *)); extern tree unmarkedp PARAMS ((tree, void *)); @@ -4214,7 +4215,6 @@ extern tree dfs_marked_real_bases_queue_p PARAMS ((tree, void *)); extern tree dfs_skip_vbases PARAMS ((tree, void *)); extern tree marked_vtable_pathp PARAMS ((tree, void *)); extern tree unmarked_vtable_pathp PARAMS ((tree, void *)); -extern void mark_primary_bases PARAMS ((tree)); extern tree convert_pointer_to_vbase PARAMS ((tree, tree)); extern tree find_vbase_instance PARAMS ((tree, tree)); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 37a352ed385..be51512e266 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -2544,7 +2544,7 @@ output_vtable_inherit (vars) op[1] = const0_rtx; else if (parent) { - parent = TYPE_BINFO_VTABLE (BINFO_TYPE (parent)); + parent = get_vtbl_decl_for_binfo (TYPE_BINFO (BINFO_TYPE (parent))); op[1] = XEXP (DECL_RTL (parent), 0); /* strip the mem ref */ } else diff --git a/gcc/cp/init.c b/gcc/cp/init.c index ff8e0583434..4623abf6fa9 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -653,31 +653,23 @@ expand_virtual_init (binfo, decl) tree type = BINFO_TYPE (binfo); tree vtbl, vtbl_ptr; tree vtype, vtype_binfo; + tree b; /* Compute the location of the vtable. */ vtype = DECL_CONTEXT (TYPE_VFIELD (type)); vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0); - vtbl = BINFO_VTABLE (binfo_value (DECL_FIELD_CONTEXT (TYPE_VFIELD (type)), binfo)); + b = binfo_value (DECL_FIELD_CONTEXT (TYPE_VFIELD (type)), binfo); + /* Figure out what vtable BINFO's vtable is based on, and mark it as + used. */ + vtbl = get_vtbl_decl_for_binfo (b); + assemble_external (vtbl); + TREE_USED (vtbl) = 1; + + /* Now compute the address to use when initializing the vptr. */ + vtbl = BINFO_VTABLE (b); if (TREE_CODE (vtbl) == VAR_DECL) - { - assemble_external (vtbl); - TREE_USED (vtbl) = 1; - vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl); - } - else - /* Under the new ABI, secondary vtables are stored with the - primary vtable. So, the BINFO_VTABLE may be an expression for - computing the secondary vtable, rather than the secondary - vtable itself. */ - my_friendly_assert (merge_primary_and_secondary_vtables_p (), - 20000220); - - /* Under the new ABI, we need to point into the middle of the - vtable. */ - if (vbase_offsets_in_vtable_p ()) - vtbl = build (PLUS_EXPR, TREE_TYPE (vtbl), vtbl, - size_extra_vtbl_entries (binfo)); + vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl); /* Compute the location of the vtpr. */ decl = convert_pointer_to_real (vtype_binfo, decl); diff --git a/gcc/cp/repo.c b/gcc/cp/repo.c index 99d53f089d1..0d3879eebb2 100644 --- a/gcc/cp/repo.c +++ b/gcc/cp/repo.c @@ -103,7 +103,7 @@ repo_get_id (t) if (!COMPLETE_TYPE_P (t) || TYPE_BEING_DEFINED (t)) my_friendly_abort (981113); - t = TYPE_BINFO_VTABLE (t); + t = get_vtbl_decl_for_binfo (TYPE_BINFO (t)); if (t == NULL_TREE) return t; } diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index e9873ba9718..a5429ecfcc6 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -1640,11 +1640,14 @@ create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...)) /* Under the new ABI, we need to point into the middle of the vtable. */ - if (vbase_offsets_in_vtable_p ()) + if (flag_new_abi) { - vtable_decl = build (PLUS_EXPR, TREE_TYPE (vtable_decl), + vtable_decl = build (PLUS_EXPR, + TREE_TYPE (vtable_decl), vtable_decl, - size_extra_vtbl_entries (TYPE_BINFO (real_type))); + size_binop (MULT_EXPR, + size_int (2), + TYPE_SIZE_UNIT (vtable_entry_type))); TREE_CONSTANT (vtable_decl) = 1; } diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 14ceff28982..4c4b600659f 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -143,7 +143,7 @@ static int dependent_base_p PARAMS ((tree)); static tree dfs_accessible_queue_p PARAMS ((tree, void *)); static tree dfs_accessible_p PARAMS ((tree, void *)); static tree dfs_access_in_type PARAMS ((tree, void *)); -static tree access_in_type PARAMS ((tree, tree)); +static access_kind access_in_type PARAMS ((tree, tree)); static tree dfs_canonical_queue PARAMS ((tree, void *)); static tree dfs_assert_unmarked_p PARAMS ((tree, void *)); static void assert_canonical_unmarked PARAMS ((tree)); @@ -152,7 +152,6 @@ static int friend_accessible_p PARAMS ((tree, tree, tree)); static void setup_class_bindings PARAMS ((tree, int)); static int template_self_reference_p PARAMS ((tree, tree)); static void fixup_all_virtual_upcast_offsets PARAMS ((tree, tree)); -static tree dfs_mark_primary_bases PARAMS ((tree, void *)); static tree get_shared_vbase_if_not_primary PARAMS ((tree, void *)); static tree dfs_find_vbase_instance PARAMS ((tree, void *)); static tree dfs_get_pure_virtuals PARAMS ((tree, void *)); @@ -811,6 +810,18 @@ shared_unmarked_p (binfo, data) return unmarkedp (binfo, data); } +/* The accessibility routines use BINFO_ACCESS for scratch space + during the computation of the accssibility of some declaration. */ + +#define BINFO_ACCESS(NODE) \ + ((access_kind) ((TREE_LANG_FLAG_1 (NODE) << 1) | TREE_LANG_FLAG_6 (NODE))) + +/* Set the access associated with NODE to ACCESS. */ + +#define SET_BINFO_ACCESS(NODE, ACCESS) \ + ((TREE_LANG_FLAG_1 (NODE) = (ACCESS & 2) != 0), \ + (TREE_LANG_FLAG_6 (NODE) = (ACCESS & 1) != 0)) + /* Called from access_in_type via dfs_walk. Calculate the access to DATA (which is really a DECL) in BINFO. */ @@ -821,18 +832,18 @@ dfs_access_in_type (binfo, data) { tree decl = (tree) data; tree type = BINFO_TYPE (binfo); - tree access = NULL_TREE; + access_kind access = ak_none; if (context_for_name_lookup (decl) == type) { /* If we have desceneded to the scope of DECL, just note the appropriate access. */ if (TREE_PRIVATE (decl)) - access = access_private_node; + access = ak_private; else if (TREE_PROTECTED (decl)) - access = access_protected_node; + access = ak_protected; else - access = access_public_node; + access = ak_public; } else { @@ -842,9 +853,10 @@ dfs_access_in_type (binfo, data) DECL_ACCESS. */ if (DECL_LANG_SPECIFIC (decl)) { - access = purpose_member (type, DECL_ACCESS (decl)); - if (access) - access = TREE_VALUE (access); + tree decl_access = purpose_member (type, DECL_ACCESS (decl)); + if (decl_access) + access = ((access_kind) + TREE_INT_CST_LOW (TREE_VALUE (decl_access))); } if (!access) @@ -860,35 +872,36 @@ dfs_access_in_type (binfo, data) for (i = 0; i < n_baselinks; ++i) { tree base_binfo = TREE_VEC_ELT (binfos, i); - tree base_access = TREE_CHAIN (canonical_binfo (base_binfo)); + access_kind base_access + = BINFO_ACCESS (canonical_binfo (base_binfo)); - if (!base_access || base_access == access_private_node) + if (base_access == ak_none || base_access == ak_private) /* If it was not accessible in the base, or only accessible as a private member, we can't access it all. */ - base_access = NULL_TREE; + base_access = ak_none; else if (TREE_VIA_PROTECTED (base_binfo)) /* Public and protected members in the base are protected here. */ - base_access = access_protected_node; + base_access = ak_protected; else if (!TREE_VIA_PUBLIC (base_binfo)) /* Public and protected members in the base are private here. */ - base_access = access_private_node; + base_access = ak_private; /* See if the new access, via this base, gives more access than our previous best access. */ - if (base_access && - (base_access == access_public_node - || (base_access == access_protected_node - && access != access_public_node) - || (base_access == access_private_node - && !access))) + if (base_access != ak_none + && (base_access == ak_public + || (base_access == ak_protected + && access != ak_public) + || (base_access == ak_private + && access == ak_none))) { access = base_access; /* If the new access is public, we can't do better. */ - if (access == access_public_node) + if (access == ak_public) break; } } @@ -896,7 +909,7 @@ dfs_access_in_type (binfo, data) } /* Note the access to DECL in TYPE. */ - TREE_CHAIN (binfo) = access; + SET_BINFO_ACCESS (binfo, access); /* Mark TYPE as visited so that if we reach it again we do not duplicate our efforts here. */ @@ -907,7 +920,7 @@ dfs_access_in_type (binfo, data) /* Return the access to DECL in TYPE. */ -static tree +static access_kind access_in_type (type, decl) tree type; tree decl; @@ -929,7 +942,7 @@ access_in_type (type, decl) dfs_walk (binfo, dfs_unmark, shared_marked_p, 0); assert_canonical_unmarked (binfo); - return TREE_CHAIN (binfo); + return BINFO_ACCESS (binfo); } /* Called from dfs_accessible_p via dfs_walk. */ @@ -960,17 +973,14 @@ dfs_accessible_p (binfo, data) void *data; { int protected_ok = data != 0; - tree access; + access_kind access; - /* We marked the binfos while computing the access in each type. - So, we unmark as we go now. */ SET_BINFO_MARKED (binfo); - - access = TREE_CHAIN (binfo); - if (access == access_public_node - || (access == access_protected_node && protected_ok)) + access = BINFO_ACCESS (binfo); + if (access == ak_public || (access == ak_protected && protected_ok)) return binfo; - else if (access && is_friend (BINFO_TYPE (binfo), current_scope ())) + else if (access != ak_none + && is_friend (BINFO_TYPE (binfo), current_scope ())) return binfo; return NULL_TREE; @@ -985,7 +995,7 @@ protected_accessible_p (decl, derived, binfo) tree derived; tree binfo; { - tree access; + access_kind access; /* We're checking this clause from [class.access.base] @@ -1010,7 +1020,7 @@ protected_accessible_p (decl, derived, binfo) access = access_in_type (derived, decl); /* If m is inaccessible in DERIVED, then it's not a P. */ - if (access == NULL_TREE) + if (access == ak_none) return 0; /* [class.protected] @@ -1752,12 +1762,11 @@ lookup_fnfields_1 (type, name) If it ever returns a non-NULL value, that value is immediately returned and the walk is terminated. At each node FN, is passed a BINFO indicating the path from the curently visited base-class to - TYPE. The TREE_CHAINs of the BINFOs may be used for scratch space; - they are otherwise unused. Before each base-class is walked QFN is - called. If the value returned is non-zero, the base-class is - walked; otherwise it is not. If QFN is NULL, it is treated as a - function which always returns 1. Both FN and QFN are passed the - DATA whenever they are called. */ + TYPE. Before each base-class is walked QFN is called. If the + value returned is non-zero, the base-class is walked; otherwise it + is not. If QFN is NULL, it is treated as a function which always + returns 1. Both FN and QFN are passed the DATA whenever they are + called. */ static tree bfs_walk (binfo, fn, qfn, data) @@ -2194,97 +2203,6 @@ dfs_skip_nonprimary_vbases_markedp (binfo, data) return markedp (binfo, NULL); } -/* Called via dfs_walk from mark_primary_bases. */ - -static tree -dfs_mark_primary_bases (binfo, data) - tree binfo; - void *data; -{ - int i; - tree base_binfo; - - if (!CLASSTYPE_HAS_PRIMARY_BASE_P (BINFO_TYPE (binfo))) - return NULL_TREE; - - i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo)); - base_binfo = BINFO_BASETYPE (binfo, i); - - if (!TREE_VIA_VIRTUAL (base_binfo)) - /* Non-virtual base classes are easy. */ - BINFO_PRIMARY_MARKED_P (base_binfo) = 1; - else - { - tree shared_binfo; - - shared_binfo - = BINFO_FOR_VBASE (BINFO_TYPE (base_binfo), (tree) data); - - /* If this virtual base is not already primary somewhere else in - the hiearchy, then we'll be using this copy. */ - if (!BINFO_VBASE_PRIMARY_P (shared_binfo) - && !BINFO_VBASE_MARKED (shared_binfo)) - { - BINFO_VBASE_PRIMARY_P (shared_binfo) = 1; - BINFO_PRIMARY_MARKED_P (base_binfo) = 1; - } - } - - return NULL_TREE; -} - -/* Set BINFO_PRIMARY_MARKED_P for all binfos in the hierarchy - dominated by BINFO that are primary bases. */ - -void -mark_primary_bases (type) - tree type; -{ - tree vbase; - - /* 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 - to mark their primary bases. */ - for (vbase = CLASSTYPE_VBASECLASSES (type); - vbase; - vbase = TREE_CHAIN (vbase)) - { - if (BINFO_VBASE_PRIMARY_P (vbase)) - /* This virtual base was already included in the hierarchy, so - there's nothing to do here. */ - continue; - - /* Temporarily pretend that VBASE is primary so that its bases - will be walked; this is the real copy of VBASE. */ - BINFO_PRIMARY_MARKED_P (vbase) = 1; - - /* Now, walk its bases. */ - dfs_walk (vbase, dfs_mark_primary_bases, - dfs_skip_nonprimary_vbases_unmarkedp, type); - - /* VBASE wasn't really primary. */ - BINFO_PRIMARY_MARKED_P (vbase) = 0; - /* And we don't want to allow it to *become* primary if it is a - base of some subsequent base class. */ - SET_BINFO_VBASE_MARKED (vbase); - } - - /* Clear the VBASE_MARKED bits we set above. */ - for (vbase = CLASSTYPE_VBASECLASSES (type); - vbase; - vbase = TREE_CHAIN (vbase)) - CLEAR_BINFO_VBASE_MARKED (vbase); -} - /* If BINFO is a non-primary virtual baseclass (in the hierarchy dominated by TYPE), and no primary copy appears anywhere in the hierarchy, return the shared copy. If a primary copy appears @@ -2577,17 +2495,6 @@ dfs_unmark (binfo, data) return NULL_TREE; } -/* Clear both BINFO_MARKED and BINFO_VBASE_MARKED. */ - -tree -dfs_vbase_unmark (binfo, data) - tree binfo; - void *data ATTRIBUTE_UNUSED; -{ - CLEAR_BINFO_VBASE_MARKED (binfo); - return dfs_unmark (binfo, data); -} - /* Clear BINFO_VTABLE_PATH_MARKED. */ tree @@ -2781,7 +2688,7 @@ virtual_context (fndecl, t, vbase) while (path) { if (TREE_VIA_VIRTUAL (path)) - return binfo_member (BINFO_TYPE (path), CLASSTYPE_VBASECLASSES (t)); + return BINFO_FOR_VBASE (BINFO_TYPE (path), t); path = BINFO_INHERITANCE_CHAIN (path); } return 0; @@ -3072,7 +2979,7 @@ dfs_get_vbase_types (binfo, data) { tree type = (tree) data; - if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo)) + if (TREE_VIA_VIRTUAL (binfo)) { tree new_vbase = make_binfo (size_zero_node, BINFO_TYPE (binfo), @@ -3083,24 +2990,50 @@ dfs_get_vbase_types (binfo, data) BINFO_INHERITANCE_CHAIN (new_vbase) = TYPE_BINFO (type); TREE_CHAIN (new_vbase) = CLASSTYPE_VBASECLASSES (type); CLASSTYPE_VBASECLASSES (type) = new_vbase; - SET_BINFO_VBASE_MARKED (binfo); } SET_BINFO_MARKED (binfo); return NULL_TREE; } +/* Called via dfs_walk from mark_primary_bases. Builds the + inheritance graph order list of BINFOs. */ + +static tree +dfs_build_inheritance_graph_order (binfo, data) + tree binfo; + void *data; +{ + tree *last_binfo = (tree *) data; + + if (*last_binfo) + TREE_CHAIN (*last_binfo) = binfo; + *last_binfo = binfo; + SET_BINFO_MARKED (binfo); + return NULL_TREE; +} + /* Set CLASSTYPE_VBASECLASSES for TYPE. */ void get_vbase_types (type) tree type; { + tree last_binfo; + CLASSTYPE_VBASECLASSES (type) = NULL_TREE; dfs_walk (TYPE_BINFO (type), dfs_get_vbase_types, unmarkedp, type); /* Rely upon the reverse dfs ordering from dfs_get_vbase_types, and now reverse it so that we get normal dfs ordering. */ CLASSTYPE_VBASECLASSES (type) = nreverse (CLASSTYPE_VBASECLASSES (type)); - dfs_walk (TYPE_BINFO (type), dfs_vbase_unmark, markedp, 0); + dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, 0); + /* Thread the BINFOs in inheritance-graph order. */ + last_binfo = NULL; + dfs_walk_real (TYPE_BINFO (type), + dfs_build_inheritance_graph_order, + NULL, + unmarkedp, + &last_binfo); + dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp, NULL); } /* Called from find_vbase_instance via dfs_walk. */ diff --git a/gcc/cp/tinfo.cc b/gcc/cp/tinfo.cc index 71e5c2847c4..fbc498b5d7d 100644 --- a/gcc/cp/tinfo.cc +++ b/gcc/cp/tinfo.cc @@ -590,6 +590,14 @@ adjust_pointer (const void *base, ptrdiff_t offset) (reinterpret_cast (base) + offset); } +inline ptrdiff_t +get_vbase_offset (const void *object, ptrdiff_t offset) +{ + const char *vtable = *reinterpret_cast (object); + vtable += offset; + return *reinterpret_cast (vtable); +} + // some predicate functions for __class_type_info::sub_kind inline bool contained_p (__class_type_info::sub_kind access_path) { @@ -718,9 +726,7 @@ do_find_public_src (ptrdiff_t src2dst, { if (src2dst == -3) continue; // Not a virtual base, so can't be here. - const ptrdiff_t *vtable = *static_cast (base); - - offset = vtable[offset]; + offset = get_vbase_offset (base, offset); } base = adjust_pointer (base, offset); @@ -841,9 +847,7 @@ do_dyncast (ptrdiff_t src2dst, if (base_list[i].is_virtual_p ()) { base_access = sub_kind (base_access | contained_virtual_mask); - const ptrdiff_t *vtable = *static_cast (base); - - offset = vtable[offset]; + offset = get_vbase_offset (base, offset); } base = adjust_pointer (base, offset); @@ -1041,10 +1045,7 @@ do_upcast (sub_kind access_path, sub_access = sub_kind (sub_access | contained_virtual_mask); if (base) - { - const ptrdiff_t *vtable = *static_cast (base); - offset = vtable[offset]; - } + offset = get_vbase_offset (base, offset); } if (base) base = adjust_pointer (base, offset); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index e27ff7b71e2..d5e0a5d667a 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -921,7 +921,7 @@ debug_binfo (elem) debug_tree (BINFO_TYPE (elem)); if (BINFO_VTABLE (elem)) fprintf (stderr, "vtable decl \"%s\"\n", - IDENTIFIER_POINTER (DECL_NAME (BINFO_VTABLE (elem)))); + IDENTIFIER_POINTER (DECL_NAME (get_vtbl_decl_for_binfo (elem)))); else fprintf (stderr, "no vtable decl yet\n"); fprintf (stderr, "virtuals:\n"); diff --git a/gcc/testsuite/g++.old-deja/g++.abi/layout1.C b/gcc/testsuite/g++.old-deja/g++.abi/layout1.C new file mode 100644 index 00000000000..a37ef07e75f --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.abi/layout1.C @@ -0,0 +1,51 @@ +// Origin: Mark Mitchell + +#if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 + +struct R +{ + virtual void r (); +}; + +struct S +{ + virtual void f (); +}; + +struct T : virtual public S +{ + virtual void g (); +}; + +struct U : public R, virtual public T +{ + virtual void h (); +}; + +struct V : public R, virtual public S, virtual public T +{ + virtual void v (); +}; + +struct U1 +{ + R r; + T t; +}; + +int main () +{ + if (sizeof (U) != sizeof (U1)) + return 1; + if (sizeof (V) != sizeof (U1)) + return 2; +} + +#else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */ + +int main () +{ +} + +#endif /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */ + diff --git a/gcc/testsuite/g++.old-deja/g++.abi/vtable.C b/gcc/testsuite/g++.old-deja/g++.abi/vtable.C index aafcad8d19c..4c811a8c5ab 100644 --- a/gcc/testsuite/g++.old-deja/g++.abi/vtable.C +++ b/gcc/testsuite/g++.old-deja/g++.abi/vtable.C @@ -65,7 +65,7 @@ int main () if (vtable (&s4) != vtable (s2)) return 1; - if (vtable (s2) >= vtable (s3)) + if (vtable (s2) >= vtable (s3)) return 2; if (vtable (s3) >= vtable (s1)) return 3; diff --git a/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C b/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C new file mode 100644 index 00000000000..5d8cf9d0197 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C @@ -0,0 +1,179 @@ +// Origin: Mark Mitchell + +#if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 + +#include + +struct S0 +{ + virtual void s0 (); +}; + +struct S1 : virtual public S0 +{ + virtual void s1 (); +}; + +struct S2 : virtual public S1 +{ + virtual void s1 (); + virtual void s0 (); +}; + +struct S3 +{ + virtual void s3 (); +}; + +struct S4 : public S3, virtual public S2 +{ + virtual void s1 (); +}; + +void S0::s0 () +{ +} + +void S1::s1 () +{ +} + +void S2::s1 () +{ +} + +void S2::s0 () +{ +} + +void S3::s3 () +{ +} + +void S4::s1 () +{ +} + +/* The vtables should look like: + + S0 primary vtable + + S0 offset to top + S0 RTTI + S0::s0 + + ================= + + S1 primary vtable + + S0::s0 vcall offset + S0 vbase offset + S1 offset to top + S1 RTTI + S0::s0 + S1::s1 + + ================= + + S2 primary vtable + + S2::s1 vcall offset + S1 vbase offset + S2::s0 vcall offset + S0 vbase offset + S2 offset to top + S2 RTTI + S2::s0 + S2::s1 + + ================= + + S3 primary vtable + + S3 offset to top + S3 RTTI + S3::s3 + + ================= + + S4 primary vtable + + vbase offset for S0 + vbase offset for S1 + vbase offset for S2 + S4 offset to top + S4 RTTI + S3::s3 + S4::s1 + + S2-in-S4 secondary vtable + + S4::s1 vcall offset + S1 vbase offset + S2:s0 vcall offset + S0 vbase offset + S2 offset to top + S4 RTTI + S2::s0 + S4::s1 + +*/ + +// These are tricks to allow us to get raw function pointers for +// member functions. +extern "C" { +void s3__2S3 (); +void s1__2S4 (); +} + +int main () +{ + S4 s4; + ptrdiff_t **vptr; + ptrdiff_t *vtbl; + + // Set vtbl to point at the beginning of S4's primary vtable. + vptr = (ptrdiff_t **) &s4; + vtbl = *vptr; + vtbl -= 5; + + if (*vtbl++ != ((char*) (S0*) &s4) - (char*) &s4) + return 1; + if (*vtbl++ != ((char*) (S1*) &s4) - (char*) &s4) + return 2; + if (*vtbl++ != ((char*) (S2*) &s4) - (char*) &s4) + return 3; + if (*vtbl++ != 0) + return 4; + // Skip the RTTI entry. + vtbl++; + if (*vtbl++ != (ptrdiff_t) &s3__2S3) + return 5; + if (*vtbl++ != (ptrdiff_t) &s1__2S4) + return 6; + // All the vcall and vbase offsets should be zero. + if (*vtbl++ != 0) + return 7; + if (*vtbl++ != 0) + return 8; + if (*vtbl++ != 0) + return 9; + if (*vtbl++ != 0) + return 10; + // Now we're at the S2 offset to top entry. + if (*vtbl++ != ((char*) &s4 - (char*) (S2*) &s4)) + return 11; + // Skip the RTTI entry. + vtbl++; + // Skip the remaining virtual functions -- they are thunks. + vtbl++; + vtbl++; +} + +#else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */ + +int main () +{ +} + +#endif /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */ diff --git a/gcc/testsuite/g++.old-deja/g++.jason/dcast3.C b/gcc/testsuite/g++.old-deja/g++.jason/dcast3.C index 6d333f098bc..a67a1ddc9dc 100644 --- a/gcc/testsuite/g++.old-deja/g++.jason/dcast3.C +++ b/gcc/testsuite/g++.old-deja/g++.jason/dcast3.C @@ -28,5 +28,5 @@ int main () ap = (C2*)&e2; // ap points to base subobject shared by two Bs; fails if (dynamic_cast (ap) != 0) - return 1; + return 2; } -- 2.11.0