diff options
-rw-r--r-- | gcc/cp/ChangeLog | 50 | ||||
-rw-r--r-- | gcc/cp/call.c | 26 | ||||
-rw-r--r-- | gcc/cp/class.c | 70 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 45 | ||||
-rw-r--r-- | gcc/cp/decl.c | 6 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 38 | ||||
-rw-r--r-- | gcc/cp/init.c | 81 | ||||
-rw-r--r-- | gcc/cp/optimize.c | 30 | ||||
-rw-r--r-- | gcc/cp/search.c | 24 | ||||
-rw-r--r-- | gcc/cp/semantics.c | 14 | ||||
-rw-r--r-- | gcc/cp/tree.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.other/vbase1.C | 51 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.other/vbase2.C | 36 |
13 files changed, 403 insertions, 70 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index db9cb15a..33d02be 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,53 @@ +2000-05-25 Mark Mitchell <mark@codesourcery.com> + + Finish implementation of VTTs. + * cp-tree.h (cp_tree_index): Add CPTI_VTT_PARM_TYPE and + CPTI_VTT_PARM_IDENTIFIER. + (vtt_parm_identifier): New macro. + (vtt_parm_type): Likewise. + (BINFO_SUBVTT_INDEX): Likewise. + (BINFO_VPTR_INDEX): Likewise. + (struct lang_decl): Add vtt_parm. + (DECL_VTT_PARM): New macro. + (DECL_USE_VTT_PARM): Likewise. + (DECL_NEEDS_VTT_PARM_P): Likewise. + (get_vtt_name): Declare. + (build_artifical_parm): Likewise. + (fixup_all_virtual_upcast_offsets): Likewise. + (expand_indirect_vtbls_init): Remove. + * call.c (build_new_method_call): Pass the vtt to subobject + constructors and destructors. + * class.c (get_vtt_name): Give it external linkage. + (build_clone): Handle the magic VTT parameters for clones. + (clone_function_decl): Fix typo in comment. + (build_vtt): Keep track of the indices in the VTTs where various + entities are stored. + (build_vtt_inits): Likewise. + (dfs_build_vtt_inits): Likewise. + (build_ctor_vtbl_group): Tweak type of construction vtables. + (dfs_accumulate_vtbl_inits): Build vtables for all bases, even + primary bases, when building construction vtables. + * decl.c (duplicate_decls): Handle DECL_VTT_PARM. + (initialize_predefined_identifiers): Add vtt_parm_identifier. + (init_decl_processing): Initialize vtt_parm_type. + (grokfndecl): Use DECL_OVERLOADED_OPERATOR_P. + (lang_mark_tree): Make vtt_parm. + * decl2.c (build_artificial_parm): New function. + (maybe_retrofit_in_chrg): Use it. Add VTT parameters. + (grokclassfn): Use build_artificial_parm. + * init.c (initialize_vtbl_ptrs): Call + fixup_all_virtual_upcast_offsets directly. + (perform_member_init): Use the complete subobject destructor for + member cleanups. + (build_vtbl_address): New function. + (expand_virtual_init): Handle VTTs. + * optimize (maybe_clone_body): Likewise. + * search.c (fixup_all_virtual_upcast_offsets): Give it external + linkage. + (expand_indirect_vtbls_init): Remove. + * semantics.c (setup_vtbl_ptr): Fix typos in comment. + * tree.c (make_binfo): Make them bigger. + 2000-05-25 Nathan Sidwell <nathan@codesourcery.com> * inc/cxxabi.h (__pbase_type_info): Define, based on diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 93feadd..a034f52 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4321,6 +4321,32 @@ build_new_method_call (instance, name, args, basetype_path, flags) old ABI. */ name = constructor_p ? ctor_identifier : dtor_identifier; } + /* If we're call a subobject constructor or destructor for a + subobject that uses virtual base classes, then we need to + pass down a pointer to a VTT for the subobject. */ + else if ((name == base_ctor_identifier + || name == base_dtor_identifier) + && TYPE_USES_VIRTUAL_BASECLASSES (basetype)) + { + tree vtt; + tree sub_vtt; + + /* If the current function is a complete object constructor + or destructor, then we fetch the VTT directly. + Otherwise, we look it up using the VTT we were given. */ + vtt = IDENTIFIER_GLOBAL_VALUE (get_vtt_name (current_class_type)); + vtt = build_unary_op (ADDR_EXPR, vtt, /*noconvert=*/1); + vtt = build (COND_EXPR, TREE_TYPE (vtt), + DECL_USE_VTT_PARM (current_function_decl), + DECL_VTT_PARM (current_function_decl), + vtt); + + sub_vtt = build (PLUS_EXPR, TREE_TYPE (vtt), vtt, + BINFO_SUBVTT_INDEX (basetype_path)); + sub_vtt = build_indirect_ref (sub_vtt, NULL); + + args = tree_cons (NULL_TREE, sub_vtt, args); + } } else pretty_name = name; diff --git a/gcc/cp/class.c b/gcc/cp/class.c index b86bac4..d865fba 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -181,7 +181,7 @@ static void update_vtable_entry_for_fn PARAMS ((tree, tree, tree, tree *)); static tree copy_virtuals PARAMS ((tree)); static void build_ctor_vtbl_group PARAMS ((tree, tree)); static void build_vtt PARAMS ((tree)); -static tree *build_vtt_inits PARAMS ((tree, tree, tree *)); +static tree *build_vtt_inits PARAMS ((tree, tree, tree *, tree *)); static tree dfs_build_vtt_inits PARAMS ((tree, void *)); static tree dfs_fixup_binfo_vtbls PARAMS ((tree, void *)); @@ -635,7 +635,7 @@ get_vtable_name (type) /* Return an IDENTIFIER_NODE for the name of the virtual table table for TYPE. */ -static tree +tree get_vtt_name (type) tree type; { @@ -3957,6 +3957,8 @@ build_clone (fn, name) DECL_PENDING_INLINE_P (clone) = 0; /* And it hasn't yet been deferred. */ DECL_DEFERRED_FN (clone) = 0; + /* There's no magic VTT parameter in the clone. */ + DECL_VTT_PARM (clone) = NULL_TREE; /* The base-class destructor is not virtual. */ if (name == base_dtor_identifier) @@ -3981,6 +3983,10 @@ build_clone (fn, name) parmtypes = TREE_CHAIN (parmtypes); /* Skip the in-charge parameter. */ parmtypes = TREE_CHAIN (parmtypes); + /* If this is subobject constructor or destructor, add the vtt + parameter. */ + if (DECL_NEEDS_VTT_PARM_P (clone)) + parmtypes = hash_tree_chain (vtt_parm_type, parmtypes); TREE_TYPE (clone) = build_cplus_method_type (basetype, TREE_TYPE (TREE_TYPE (clone)), @@ -4002,6 +4008,18 @@ build_clone (fn, name) = TREE_CHAIN (TREE_CHAIN (DECL_ARGUMENTS (clone))); DECL_HAS_IN_CHARGE_PARM_P (clone) = 0; } + + /* Add the VTT parameter. */ + if (DECL_NEEDS_VTT_PARM_P (clone)) + { + tree parm; + + parm = build_artificial_parm (vtt_parm_identifier, + vtt_parm_type); + TREE_CHAIN (parm) = TREE_CHAIN (DECL_ARGUMENTS (clone)); + TREE_CHAIN (DECL_ARGUMENTS (clone)) = parm; + } + for (parms = DECL_ARGUMENTS (clone); parms; parms = TREE_CHAIN (parms)) { DECL_CONTEXT (parms) = clone; @@ -4063,7 +4081,7 @@ clone_function_decl (fn, update_method_vec_p) { my_friendly_assert (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn), 20000411); - /* For each destructor, we need two variants: an in-charge + /* For each destructor, we need three variants: an in-charge version, a not-in-charge version, and an in-charge deleting version. We clone the deleting version first because that means it will go second on the TYPE_METHODS list -- and that @@ -6474,6 +6492,7 @@ build_vtt (t) tree inits; tree type; tree vtt; + tree index; /* Under the old ABI, we don't use VTTs. */ if (!flag_new_abi) @@ -6481,7 +6500,8 @@ build_vtt (t) /* Build up the initializers for the VTT. */ inits = NULL_TREE; - build_vtt_inits (TYPE_BINFO (t), t, &inits); + index = size_zero_node; + build_vtt_inits (TYPE_BINFO (t), t, &inits, &index); /* If we didn't need a VTT, we're done. */ if (!inits) @@ -6499,13 +6519,15 @@ build_vtt (t) /* Recursively build the VTT-initializer for BINFO (which is in the hierarchy dominated by T). INITS points to the end of the - initializer list to date. */ + initializer list to date. INDEX is the VTT index where the next + element will be placed. */ static tree * -build_vtt_inits (binfo, t, inits) +build_vtt_inits (binfo, t, inits, index) tree binfo; tree t; tree *inits; + tree *index; { int i; tree b; @@ -6521,7 +6543,12 @@ build_vtt_inits (binfo, t, inits) VTT. */ ctor_vtbl_p = !same_type_p (TREE_TYPE (binfo), t); if (ctor_vtbl_p) - build_ctor_vtbl_group (binfo, t); + { + build_ctor_vtbl_group (binfo, t); + + /* Record the offset in the VTT where this sub-VTT can be found. */ + BINFO_SUBVTT_INDEX (binfo) = *index; + } /* Add the address of the primary vtable for the complete object. */ init = BINFO_VTABLE (binfo); @@ -6529,20 +6556,24 @@ build_vtt_inits (binfo, t, inits) init = TREE_PURPOSE (init); *inits = build_tree_list (NULL_TREE, init); inits = &TREE_CHAIN (*inits); - + BINFO_VPTR_INDEX (binfo) = *index; + *index = size_binop (PLUS_EXPR, *index, TYPE_SIZE_UNIT (ptr_type_node)); + /* Recursively add the secondary VTTs for non-virtual bases. */ for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i) { b = BINFO_BASETYPE (binfo, i); if (!TREE_VIA_VIRTUAL (b)) - inits = build_vtt_inits (BINFO_BASETYPE (binfo, i), t, inits); + inits = build_vtt_inits (BINFO_BASETYPE (binfo, i), t, inits, + index); } - + /* Add secondary virtual pointers for all subobjects of BINFO with either virtual bases or virtual functions overridden along a virtual path between the declaration and D, except subobjects that are non-virtual primary bases. */ secondary_vptrs = build_tree_list (BINFO_TYPE (binfo), NULL_TREE); + TREE_TYPE (secondary_vptrs) = *index; dfs_walk_real (binfo, dfs_build_vtt_inits, NULL, @@ -6550,6 +6581,7 @@ build_vtt_inits (binfo, t, inits) secondary_vptrs); dfs_walk (binfo, dfs_fixup_binfo_vtbls, dfs_marked_real_bases_queue_p, BINFO_TYPE (binfo)); + *index = TREE_TYPE (secondary_vptrs); /* The secondary vptrs come back in reverse order. After we reverse them, and add the INITS, the last init will be the first element @@ -6571,7 +6603,7 @@ build_vtt_inits (binfo, t, inits) continue; vbase = binfo_for_vbase (BINFO_TYPE (b), t); - inits = build_vtt_inits (vbase, t, inits); + inits = build_vtt_inits (vbase, t, inits, index); } return inits; @@ -6587,6 +6619,7 @@ dfs_build_vtt_inits (binfo, data) tree l; tree t; tree init; + tree index; l = (tree) data; t = TREE_PURPOSE (l); @@ -6612,13 +6645,18 @@ dfs_build_vtt_inits (binfo, data) /* FIXME: Implement this. */ ; - /* Add the initializer for this secondary vptr. */ + /* Record the index where this secondary vptr can be found. */ + index = TREE_TYPE (l); + BINFO_VPTR_INDEX (binfo) = index; + TREE_TYPE (l) = size_binop (PLUS_EXPR, index, + TYPE_SIZE_UNIT (ptr_type_node)); + + /* Add the initializer for the secondary vptr itself. */ init = BINFO_VTABLE (binfo); if (TREE_CODE (init) == TREE_LIST) init = TREE_PURPOSE (init); - TREE_VALUE (l) = tree_cons (NULL_TREE, init, TREE_VALUE (l)); - + return NULL_TREE; } @@ -6665,7 +6703,7 @@ build_ctor_vtbl_group (binfo, t) /* Build a version of VTBL (with the wrong type) for use in constructing the addresses of secondary vtables in the construction vtable group. */ - vtbl = build_vtable (BINFO_TYPE (binfo), id, vtable_entry_type); + vtbl = build_vtable (BINFO_TYPE (binfo), id, ptr_type_node); list = build_tree_list (vtbl, NULL_TREE); accumulate_vtbl_inits (binfo, TYPE_BINFO (TREE_TYPE (binfo)), binfo, t, list); @@ -6762,7 +6800,7 @@ dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l) if (BINFO_NEW_VTABLE_MARKED (binfo, t) /* We need a new vtable, even for a primary base, when we're building a construction vtable. */ - || (ctor_vtbl_p && orig_binfo == rtti_binfo)) + || (ctor_vtbl_p && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo)))) { tree vtbl; tree index; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6080abd..d935c35 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -530,6 +530,7 @@ enum cp_tree_index CPTI_DELTA_TYPE, CPTI_VTABLE_INDEX_TYPE, CPTI_CLEANUP_TYPE, + CPTI_VTT_PARM_TYPE, CPTI_TI_DESC_TYPE, CPTI_BLTN_DESC_TYPE, @@ -578,6 +579,7 @@ enum cp_tree_index CPTI_DELTA2_IDENTIFIER, CPTI_DELTA_IDENTIFIER, CPTI_IN_CHARGE_IDENTIFIER, + CPTI_VTT_PARM_IDENTIFIER, CPTI_INDEX_IDENTIFIER, CPTI_NELTS_IDENTIFIER, CPTI_THIS_IDENTIFIER, @@ -690,6 +692,11 @@ extern tree cp_global_trees[CPTI_MAX]; #define delta2_identifier cp_global_trees[CPTI_DELTA2_IDENTIFIER] #define delta_identifier cp_global_trees[CPTI_DELTA_IDENTIFIER] #define in_charge_identifier cp_global_trees[CPTI_IN_CHARGE_IDENTIFIER] + +/* The name of the parameter that contains a pointer to the VTT to use + for this subobject constructor or destructor. */ +#define vtt_parm_identifier cp_global_trees[CPTI_VTT_PARM_IDENTIFIER] + #define index_identifier cp_global_trees[CPTI_INDEX_IDENTIFIER] #define nelts_identifier cp_global_trees[CPTI_NELTS_IDENTIFIER] #define this_identifier cp_global_trees[CPTI_THIS_IDENTIFIER] @@ -731,6 +738,10 @@ extern tree cp_global_trees[CPTI_MAX]; /* The type of a destructor. */ #define cleanup_type cp_global_trees[CPTI_CLEANUP_TYPE] +/* The type of the vtt parameter passed to subobject constructors and + destructors. */ +#define vtt_parm_type cp_global_trees[CPTI_VTT_PARM_TYPE] + /* Global state. */ struct stmt_tree { @@ -1755,6 +1766,14 @@ struct lang_type is primary *somewhere* in the hierarchy. */ #define BINFO_VBASE_PRIMARY_P(NODE) TREE_LANG_FLAG_6 (NODE) +/* The index in the VTT where this subobject's sub-VTT can be found. + NULL_TREE if there is no sub-VTT. */ +#define BINFO_SUBVTT_INDEX(NODE) TREE_VEC_ELT ((NODE), 8) + +/* The index in the VTT where the vptr for this subobject can be + found. NULL_TREE if there is no secondary vptr in the VTT. */ +#define BINFO_VPTR_INDEX(NODE) TREE_VEC_ELT ((NODE), 9) + /* Used by various search routines. */ #define IDENTIFIER_MARKED(NODE) TREE_LANG_FLAG_0 (NODE) @@ -1884,6 +1903,9 @@ struct lang_decl /* In a FUNCTION_DECL, this is DECL_CLONED_FUNCTION. */ tree cloned_function; + /* In a FUNCTION_DECL, this is VTT_PARM. */ + tree vtt_parm; + union { tree sorted_fields; @@ -1972,6 +1994,25 @@ struct lang_decl #define DECL_CLONED_FUNCTION(NODE) \ (DECL_LANG_SPECIFIC (NODE)->cloned_function) +/* In a maybe-in-charge constructor or destructor, this is the VTT + parameter. It's not actually on the DECL_ARGUMENTS list. */ +#define DECL_VTT_PARM(NODE) \ + (DECL_LANG_SPECIFIC (NODE)->vtt_parm) + +/* If there's a DECL_VTT_PARM, this is a magic variable that indicates + whether or not the VTT parm should be used. In a subobject + constructor, `true' is substituted for this value; in a complete + object constructor, `false' is substituted instead. */ +#define DECL_USE_VTT_PARM(NODE) \ + (TREE_CHAIN (DECL_VTT_PARM (NODE))) + +/* Non-zero if NODE is a FUNCTION_DECL for which a VTT parameter is + required. */ +#define DECL_NEEDS_VTT_PARM_P(NODE) \ + (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (NODE)) \ + && (DECL_BASE_CONSTRUCTOR_P (NODE) \ + || DECL_BASE_DESTRUCTOR_P (NODE))) + /* Non-zero if NODE is a user-defined conversion operator. */ #define DECL_CONV_FN_P(NODE) \ (IDENTIFIER_TYPENAME_P (DECL_NAME (NODE))) @@ -3820,6 +3861,7 @@ extern void maybe_note_name_used_in_class PARAMS ((tree, tree)); extern void note_name_declared_in_class PARAMS ((tree, tree)); extern tree get_vtbl_decl_for_binfo PARAMS ((tree)); extern tree in_charge_arg_for_name PARAMS ((tree)); +extern tree get_vtt_name PARAMS ((tree)); /* in cvt.c */ extern tree convert_to_reference PARAMS ((tree, tree, int, int, tree)); @@ -4054,6 +4096,7 @@ extern void mark_used PARAMS ((tree)); extern tree handle_class_head PARAMS ((tree, tree, tree)); extern tree lookup_arg_dependent PARAMS ((tree, tree, tree)); extern void finish_static_data_member_decl PARAMS ((tree, tree, tree, int)); +extern tree build_artificial_parm PARAMS ((tree, tree)); /* in parse.y */ extern void cp_parse_init PARAMS ((void)); @@ -4303,7 +4346,6 @@ extern tree lookup_nested_tag PARAMS ((tree, tree)); extern tree get_matching_virtual PARAMS ((tree, tree, int)); extern void get_pure_virtuals PARAMS ((tree)); extern tree init_vbase_pointers PARAMS ((tree, tree)); -extern void expand_indirect_vtbls_init PARAMS ((tree)); extern void get_vbase_types PARAMS ((tree)); extern void maybe_suppress_debug_info PARAMS ((tree)); extern void note_debug_info_needed PARAMS ((tree)); @@ -4340,6 +4382,7 @@ extern tree unmarked_vtable_pathp PARAMS ((tree, void *)); extern tree convert_pointer_to_vbase PARAMS ((tree, tree)); extern tree find_vbase_instance PARAMS ((tree, tree)); extern tree binfo_for_vbase PARAMS ((tree, tree)); +extern void fixup_all_virtual_upcast_offsets PARAMS ((tree)); /* in semantics.c */ extern void finish_expr_stmt PARAMS ((tree)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 05c17f6..5704a17 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3369,6 +3369,7 @@ duplicate_decls (newdecl, olddecl) DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl); DECL_NEEDS_FINAL_OVERRIDER_P (newdecl) |= DECL_NEEDS_FINAL_OVERRIDER_P (olddecl); DECL_THIS_STATIC (newdecl) |= DECL_THIS_STATIC (olddecl); + DECL_VTT_PARM (newdecl) = DECL_VTT_PARM (olddecl); new_defines_function = DECL_INITIAL (newdecl) != NULL_TREE; /* Optionally warn about more than one declaration for the same @@ -6074,6 +6075,7 @@ initialize_predefined_identifiers () { "__pfn_or_delta2", &pfn_or_delta2_identifier, 0 }, { "_vptr", &vptr_identifier, 0 }, { "__cp_push_exception", &cp_push_exception_identifier, 0 }, + { "__vtt_parm", &vtt_parm_identifier, 0 }, { NULL, NULL, 0 } }; @@ -6325,6 +6327,7 @@ init_decl_processing () const_ptr_type_node = build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_CONST)); + vtt_parm_type = build_pointer_type (const_ptr_type_node); c_common_nodes_and_builtins (1, flag_no_builtin, flag_no_nonansi_builtin); lang_type_promotes_to = convert_type_from_ellipsis; @@ -8740,7 +8743,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals, quals = NULL_TREE; } - if (IDENTIFIER_OPNAME_P (DECL_NAME (decl))) + if (DECL_OVERLOADED_OPERATOR_P (decl)) grok_op_properties (decl, virtualp, check < 0); if (ctype && decl_function_context (decl)) @@ -14744,6 +14747,7 @@ lang_mark_tree (t) ggc_mark_tree (ld->befriending_classes); ggc_mark_tree (ld->saved_tree); ggc_mark_tree (ld->cloned_function); + ggc_mark_tree (ld->vtt_parm); if (TREE_CODE (t) == TYPE_DECL) ggc_mark_tree (ld->u.sorted_fields); else if (TREE_CODE (t) == FUNCTION_DECL diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 5b72098..315e3c8 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -924,6 +924,22 @@ grok_x_components (specs) break; } +/* Returns a PARM_DECL for a parameter of the indicated TYPE, with the + indicated NAME. */ + +tree +build_artificial_parm (name, type) + tree name; + tree type; +{ + tree parm; + + parm = build_decl (PARM_DECL, name, type); + SET_DECL_ARTIFICIAL (parm); + DECL_ARG_TYPE (parm) = type; + return parm; +} + /* Constructors for types with virtual baseclasses need an "in-charge" flag saying whether this constructor is responsible for initialization of virtual baseclasses or not. All destructors also need this "in-charge" @@ -956,10 +972,7 @@ maybe_retrofit_in_chrg (fn) return; /* First add it to DECL_ARGUMENTS... */ - parm = build_decl (PARM_DECL, in_charge_identifier, integer_type_node); - /* Mark the artificial `__in_chrg' parameter as "artificial". */ - SET_DECL_ARTIFICIAL (parm); - DECL_ARG_TYPE (parm) = integer_type_node; + parm = build_artificial_parm (in_charge_identifier, integer_type_node); TREE_READONLY (parm) = 1; parms = DECL_ARGUMENTS (fn); TREE_CHAIN (parm) = TREE_CHAIN (parms); @@ -978,6 +991,18 @@ maybe_retrofit_in_chrg (fn) /* Now we've got the in-charge parameter. */ DECL_HAS_IN_CHARGE_PARM_P (fn) = 1; + + /* If this is a subobject constructor or destructor, our caller will + pass us a pointer to our VTT. */ + if (flag_new_abi && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn))) + { + DECL_VTT_PARM (fn) = build_artificial_parm (vtt_parm_identifier, + vtt_parm_type); + DECL_CONTEXT (DECL_VTT_PARM (fn)) = fn; + DECL_USE_VTT_PARM (fn) = build_artificial_parm (NULL_TREE, + boolean_type_node); + DECL_CONTEXT (DECL_USE_VTT_PARM (fn)) = fn; + } } /* Classes overload their constituent function names automatically. @@ -1032,12 +1057,9 @@ grokclassfn (ctype, function, flags, quals) assigned to. */ this_quals |= TYPE_QUAL_CONST; qual_type = cp_build_qualified_type (type, this_quals); - parm = build_decl (PARM_DECL, this_identifier, qual_type); + parm = build_artificial_parm (this_identifier, qual_type); c_apply_type_quals_to_decl (this_quals, parm); - /* Mark the artificial `this' parameter as "artificial". */ - SET_DECL_ARTIFICIAL (parm); - DECL_ARG_TYPE (parm) = type; /* We can make this a register, so long as we don't accidentally complain if someone tries to take its address. */ DECL_REGISTER (parm) = 1; diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 7d6892e..cc5be91 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -53,6 +53,7 @@ static tree build_new_1 PARAMS ((tree)); static tree get_cookie_size PARAMS ((tree)); static tree build_dtor_call PARAMS ((tree, special_function_kind, int)); static tree build_field_list PARAMS ((tree, tree, int *)); +static tree build_vtbl_address PARAMS ((tree)); /* Set up local variable for this file. MUST BE CALLED AFTER INIT_DECL_PROCESSING. */ @@ -172,7 +173,14 @@ initialize_vtbl_ptrs (addr) NULL, dfs_unmarked_real_bases_queue_p, list); dfs_walk (TYPE_BINFO (type), dfs_unmark, dfs_marked_real_bases_queue_p, type); - expand_indirect_vtbls_init (addr); + + /* If we're not using thunks, we may need to adjust the deltas in + the vtable to handle virtual base classes correctly. When we are + using thunks, we either use construction vtables (which are + preloaded with the right answers) or nothing (in which case + vitual function calls sometimes don't work right.) */ + if (TYPE_USES_VIRTUAL_BASECLASSES (type) && !flag_vtable_thunks) + fixup_all_virtual_upcast_offsets (addr); } /* Subroutine of emit_base_init. */ @@ -276,7 +284,7 @@ perform_member_init (member, init, explicit) expr = build_component_ref (current_class_ref, member, NULL_TREE, explicit); - expr = build_delete (type, expr, sfk_base_destructor, + expr = build_delete (type, expr, sfk_complete_destructor, LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); if (expr != error_mark_node) @@ -726,6 +734,32 @@ emit_base_init () } } +/* Returns the address of the vtable (i.e., the value that should be + assigned to the vptr) for BINFO. */ + +static tree +build_vtbl_address (binfo) + tree binfo; +{ + tree vtbl; + + /* Figure out what vtable BINFO's vtable is based on, and mark it as + used. */ + vtbl = get_vtbl_decl_for_binfo (binfo); + assemble_external (vtbl); + TREE_USED (vtbl) = 1; + + /* Now compute the address to use when initializing the vptr. */ + vtbl = BINFO_VTABLE (binfo); + if (TREE_CODE (vtbl) == VAR_DECL) + { + vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl); + TREE_CONSTANT (vtbl) = 1; + } + + return vtbl; +} + /* This code sets up the virtual function tables appropriate for the pointer DECL. It is a one-ply initialization. @@ -739,23 +773,40 @@ expand_virtual_init (binfo, decl) tree type = BINFO_TYPE (binfo); tree vtbl, vtbl_ptr; tree vtype, vtype_binfo; - tree b; + tree vtt_index; /* Compute the location of the vtable. */ vtype = DECL_CONTEXT (TYPE_VFIELD (type)); vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0); - 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) - vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl); + + /* Compute the initializer for vptr. */ + vtbl = build_vtbl_address (binfo); + + /* Under the new ABI, we may get this vptr from a VTT, if this is a + subobject constructor or subobject destructor. */ + vtt_index = BINFO_VPTR_INDEX (binfo); + if (vtt_index) + { + tree vtbl2; + tree vtt_parm; + + /* Compute the value to use, when there's a VTT. */ + vtt_parm = DECL_VTT_PARM (current_function_decl); + vtbl2 = build (PLUS_EXPR, + TREE_TYPE (vtt_parm), + vtt_parm, + vtt_index); + vtbl2 = build1 (INDIRECT_REF, TREE_TYPE (vtbl), vtbl2); + + /* The actual initializer is the VTT value only in the subobject + constructor. In maybe_clone_body we'll substitute NULL for + the vtt_parm in the case of the non-subobject constructor. */ + vtbl = build (COND_EXPR, + TREE_TYPE (vtbl), + DECL_USE_VTT_PARM (current_function_decl), + vtbl2, + vtbl); + } /* Compute the location of the vtpr. */ decl = convert_pointer_to_real (vtype_binfo, decl); diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index b7711d6..52292ff 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -902,6 +902,10 @@ maybe_clone_body (fn) DECL_SOURCE_LINE (clone) = DECL_SOURCE_LINE (fn); DECL_INLINE (clone) = DECL_INLINE (fn); DECL_THIS_INLINE (clone) = DECL_THIS_INLINE (fn); + DECL_COMDAT (clone) = DECL_COMDAT (fn); + DECL_WEAK (clone) = DECL_WEAK (fn); + DECL_ONE_ONLY (clone) = DECL_ONE_ONLY (fn); + DECL_SECTION_NAME (clone) = DECL_SECTION_NAME (fn); /* Start processing the function. */ push_to_top_level (); @@ -934,7 +938,31 @@ maybe_clone_body (fn) in_charge = in_charge_arg_for_name (DECL_NAME (clone)); splay_tree_insert (id.decl_map, (splay_tree_key) parm, - (splay_tree_key) in_charge); + (splay_tree_value) in_charge); + + /* For a subobject constructor or destructor, the next + argument is the VTT parameter. Remap the VTT_PARM + from the CLONE to this parameter. */ + if (DECL_NEEDS_VTT_PARM_P (clone)) + { + splay_tree_insert (id.decl_map, + (splay_tree_key) DECL_VTT_PARM (fn), + (splay_tree_value) clone_parm); + splay_tree_insert (id.decl_map, + (splay_tree_key) DECL_USE_VTT_PARM (fn), + (splay_tree_value) boolean_true_node); + clone_parm = TREE_CHAIN (clone_parm); + } + /* Otherwise, map the VTT parameter to `NULL'. */ + else if (DECL_VTT_PARM (fn)) + { + splay_tree_insert (id.decl_map, + (splay_tree_key) DECL_VTT_PARM (fn), + (splay_tree_value) null_pointer_node); + splay_tree_insert (id.decl_map, + (splay_tree_key) DECL_USE_VTT_PARM (fn), + (splay_tree_value) boolean_false_node); + } } /* Map other parameters to their equivalents in the cloned function. */ diff --git a/gcc/cp/search.c b/gcc/cp/search.c index bebca05..1160cd4 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -144,7 +144,6 @@ static int protected_accessible_p PARAMS ((tree, tree, tree)); 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 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 *)); @@ -2770,14 +2769,14 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori /* Fixup all the virtual upcast offsets for TYPE. DECL_PTR is the address of the sub-object being initialized. */ -static void -fixup_all_virtual_upcast_offsets (type, decl_ptr) - tree type; +void +fixup_all_virtual_upcast_offsets (decl_ptr) tree decl_ptr; { tree if_stmt; tree in_charge_node; tree vbases; + tree type; /* Only tweak the vtables if we're in charge. */ in_charge_node = current_in_charge_parm; @@ -2791,6 +2790,7 @@ fixup_all_virtual_upcast_offsets (type, decl_ptr) /* Iterate through the virtual bases, fixing up the upcast offset for each one. */ + type = TREE_TYPE (TREE_TYPE (decl_ptr)); for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; vbases = TREE_CHAIN (vbases)) @@ -2820,22 +2820,6 @@ fixup_all_virtual_upcast_offsets (type, decl_ptr) finish_if_stmt (); } -/* Generate the code needed to initialize all the virtual function - table slots of all the virtual baseclasses. ADDR points to the - address of the complete object we are initializing. */ - -void -expand_indirect_vtbls_init (addr) - tree addr; -{ - tree type; - - type = TREE_TYPE (TREE_TYPE (addr)); - - if (TYPE_USES_VIRTUAL_BASECLASSES (type)) - fixup_all_virtual_upcast_offsets (type, addr); -} - /* get virtual base class types. This adds type to the vbase_types list in reverse dfs order. Ordering is very important, so don't change it. */ diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index dbeb7f1..77728ba 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -1257,15 +1257,15 @@ setup_vtbl_ptr () tree compound_stmt; int saved_cfnd; - /* If the dtor is empty, and we know there is not possible way we - could use any vtable entries, before they are possibly set by - a base class dtor, we don't have to setup the vtables, as we - know that any base class dtoring will set up any vtables it - needs. We avoid MI, because one base class dtor can do a + /* If the dtor is empty, and we know there is not any possible + way we could use any vtable entries, before they are possibly + set by a base class dtor, we don't have to setup the vtables, + as we know that any base class dtor will set up any vtables + it needs. We avoid MI, because one base class dtor can do a virtual dispatch to an overridden function that would need to have a non-related vtable set up, we cannot avoid setting up - vtables in that case. We could change this to see if there is - just one vtable. */ + vtables in that case. We could change this to see if there + is just one vtable. */ if_stmt = begin_if_stmt (); /* If it is not safe to avoid setting up the vtables, then diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 078558e..646a892 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -847,7 +847,7 @@ make_binfo (offset, binfo, vtable, virtuals) tree offset, binfo; tree vtable, virtuals; { - tree new_binfo = make_tree_vec (8); + tree new_binfo = make_tree_vec (10); tree type; if (TREE_CODE (binfo) == TREE_VEC) diff --git a/gcc/testsuite/g++.old-deja/g++.other/vbase1.C b/gcc/testsuite/g++.old-deja/g++.other/vbase1.C new file mode 100644 index 0000000..99a3867 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/vbase1.C @@ -0,0 +1,51 @@ +// Origin: Mark Mitchell <mark@codesourcery.com> +// Special g++ Options: -w + +int result; + +struct A { + A (); + + int i; +}; + +A* ap; + +A::A () +{ + ap = this; +} + +struct B : virtual public A +{ + B (); + ~B (); + + int j; +}; + +B::B () { + if ((A*) this != ap) + result = 1; +} + +B::~B () { + if ((A*) this != ap) + result = 1; +} + +struct C : public B { +}; + +struct D : public C, public B +{ +}; + +int main () +{ + { + D d; + } + + return result; +} diff --git a/gcc/testsuite/g++.old-deja/g++.other/vbase2.C b/gcc/testsuite/g++.old-deja/g++.other/vbase2.C new file mode 100644 index 0000000..2f15249 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/vbase2.C @@ -0,0 +1,36 @@ +// Origin: Mark Mitchell <mark@codesourcery.com> + +int i; + +struct A +{ + ~A (); +}; + +A::~A () { + i = 1; +} + +struct B : virtual public A { +}; + +struct C { + C (); + + B b; +}; + +C::C () { + throw 3; +} + +int main () +{ + try { + C c; + } catch (...) { + } + + if (i != 1) + return 1; +} |