diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c3b2d4795f2..18f252d2bf9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,56 @@ 2000-04-11 Mark Mitchell + * cp-tree.h (cp_tree_index): Add CPTI_DTOR_IDENTIFIER. + (complete_dtor_identifier): New macro. + (CLASSTYPE_FIRST_CONVERSION): Remove. + (CLASSTYPE_CONSTRUCTOR_SLOT): New macro. + (CLASSTYPE_DESTRUCTOR_SLOT): Likewise. + (CLASSTYPE_FIRST_CONVERSION_SLOT): Likewise. + (CLASSTYPE_CONSTRUCTORS): Likewise. + (CLASSTYPE_DESTRUCTORS): Likewise. + (lang_decl): Add cloned_function. + (DECL_COMPLETE_CONSTRUCTOR_P): New macro. + (DECL_BASE_CONSTRUCTOR_P): Likewise. + (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P): Likewise. + (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P): Likewise. + (DECL_CLONED_FUNCTION_P): Likewise. + (DECL_CLONED_FUNCTION): Likewise. + (clone_function_decl): Declare. + (maybe_clone_body): Likewise. + * call.c (build_user_type_conversion_1): Call complete object + constructors in the new ABI. + (build_new_method_call): Don't add in-charge parameters under the + new ABI. + * class.c (add_method): Use DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P, + DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P, CLASSTYPE_CONSTRUCTOR_SLOT, and + CLASSTYPE_DESTRUCTOR_SLOT. + (build_clone): New function. + (clone_function_decl): Likewise. + (clone_constructors_and_destructors): Likewise. + (check_bases_and_members): Use it. + * decl.c (iniitialize_predefined_identifiers): Initialize + complete_dtor_identifier. + (finish_function): Don't add extra code to a clone. + (lang_mark_tree): Mark cloned_function. + * decl2.c (mark_used): Don't bother trying to instantiate things + we synthesized. + * dump.c (dequeue_and_dump): Don't dump CP_DECL_CONTEXT twice. + * method.c (set_mangled_name_for_decl): Don't treat clones as + constructors. + (synthesize_method): Sythesize cloned functions, not the clones. + * optimize.c (inline_data): Update comment on ret_label. + (remap_block): Don't assume DECL_INITIAL exists. + (copy_body_r): Allow ret_label to be NULL. + (maybe_clone_body): Define. + * pt.c (tsubst_decl): Handle clones. + (instantiate_clone): New function. + (instantiate_template): Use it. + (set_mangled_name_for_template_decl): Don't treat clones as + constructors. + * search.c (lookup_fnfields_1): Use CLASSTYPE_CONSTRUCTOR_SLOT, + CLASSTYPE_DESTRUCTOR_SLOT, and CLASSTYPE_FIRST_CONVERSION_SLOT. + * semantics.c (expand_body): Clone function bodies as necessary. + * optimize.c (remap_decl): Avoid sharing structure for arrays whose size is only known at run-time. * tree.c (copy_tree_r): Don't copy PARM_DECLs. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 040801b76ec..c0032488e9b 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -2277,7 +2277,12 @@ build_user_type_conversion_1 (totype, expr, flags) tree templates = NULL_TREE; if (IS_AGGR_TYPE (totype)) - ctors = lookup_fnfields (TYPE_BINFO (totype), ctor_identifier, 0); + ctors = lookup_fnfields (TYPE_BINFO (totype), + (flag_new_abi + ? complete_ctor_identifier + : ctor_identifier), + 0); + if (IS_AGGR_TYPE (fromtype) && (! IS_AGGR_TYPE (totype) || ! DERIVED_FROM_P (totype, fromtype))) convs = lookup_conversions (fromtype); @@ -4253,22 +4258,26 @@ build_new_method_call (instance, name, args, basetype_path, flags) || name == base_ctor_identifier) { pretty_name = constructor_name (basetype); - /* Add the in-charge parameter as an implicit first argument. */ - if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)) + + if (!flag_new_abi) { - tree in_charge; + /* Add the in-charge parameter as an implicit first argument. */ + if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)) + { + tree in_charge; - if (name == complete_ctor_identifier) - in_charge = integer_one_node; - else - in_charge = integer_zero_node; + if (name == complete_ctor_identifier) + in_charge = integer_one_node; + else + in_charge = integer_zero_node; - args = tree_cons (NULL_TREE, in_charge, args); + args = tree_cons (NULL_TREE, in_charge, args); + } + + /* We want to call the normal constructor function under the + old ABI. */ + name = ctor_identifier; } - - /* We want to call the normal constructor function under the old - ABI. */ - name = ctor_identifier; } else pretty_name = name; diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 5262faa6a9b..d954ac0b736 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -174,6 +174,8 @@ 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)); +static void clone_constructors_and_destructors PARAMS ((tree)); +static tree build_clone PARAMS ((tree, tree)); /* Variables shared between class.c and call.c. */ @@ -1150,14 +1152,15 @@ add_method (type, fields, method) method_vec = CLASSTYPE_METHOD_VEC (type); len = TREE_VEC_LENGTH (method_vec); - if (DECL_NAME (method) == constructor_name (type)) - /* A new constructor or destructor. Constructors go in - slot 0; destructors go in slot 1. */ - slot = DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method)) ? 1 : 0; + /* Constructors and destructors go in special slots. */ + if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (method)) + slot = CLASSTYPE_CONSTRUCTOR_SLOT; + else if (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (method)) + slot = CLASSTYPE_DESTRUCTOR_SLOT; else { /* See if we already have an entry with this name. */ - for (slot = 2; slot < len; ++slot) + for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; slot < len; ++slot) if (!TREE_VEC_ELT (method_vec, slot) || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, slot))) @@ -3855,6 +3858,151 @@ check_methods (t) } } +/* FN is a constructor or destructor. Clone the declaration to create + a specialized in-charge or not-in-charge version, as indicated by + NAME. */ + +static tree +build_clone (fn, name) + tree fn; + tree name; +{ + tree parms; + tree clone; + + /* Copy the function. */ + clone = copy_decl (fn); + /* Remember where this function came from. */ + DECL_CLONED_FUNCTION (clone) = fn; + /* Reset the function name. */ + DECL_NAME (clone) = name; + DECL_ASSEMBLER_NAME (clone) = DECL_NAME (clone); + /* There's no pending inline data for this function. */ + DECL_PENDING_INLINE_INFO (clone) = NULL; + DECL_PENDING_INLINE_P (clone) = 0; + /* And it hasn't yet been deferred. */ + DECL_DEFERRED_FN (clone) = 0; + + /* If there was an in-charge paramter, drop it from the function + type. */ + if (DECL_HAS_IN_CHARGE_PARM_P (clone)) + { + tree basetype; + tree parmtypes; + tree exceptions; + + exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (clone)); + basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (clone)); + parmtypes = TYPE_ARG_TYPES (TREE_TYPE (clone)); + /* Skip the `this' parameter. */ + parmtypes = TREE_CHAIN (parmtypes); + /* Skip the in-charge parameter. */ + parmtypes = TREE_CHAIN (parmtypes); + TREE_TYPE (clone) + = build_cplus_method_type (basetype, + TREE_TYPE (TREE_TYPE (clone)), + parmtypes); + if (exceptions) + TREE_TYPE (clone) = build_exception_variant (TREE_TYPE (clone), + exceptions); + } + + /* Copy the function parameters. But, DECL_ARGUMENTS aren't + function parameters; instead, those are the template parameters. */ + if (TREE_CODE (clone) != TEMPLATE_DECL) + { + DECL_ARGUMENTS (clone) = copy_list (DECL_ARGUMENTS (clone)); + /* Remove the in-charge parameter. */ + if (DECL_HAS_IN_CHARGE_PARM_P (clone)) + { + TREE_CHAIN (DECL_ARGUMENTS (clone)) + = TREE_CHAIN (TREE_CHAIN (DECL_ARGUMENTS (clone))); + DECL_HAS_IN_CHARGE_PARM_P (clone) = 0; + } + for (parms = DECL_ARGUMENTS (clone); parms; parms = TREE_CHAIN (parms)) + { + DECL_CONTEXT (parms) = clone; + copy_lang_decl (parms); + } + } + + /* Mangle the function name. */ + set_mangled_name_for_decl (clone); + + /* Create the RTL for this function. */ + DECL_RTL (clone) = NULL_RTX; + rest_of_decl_compilation (clone, NULL, /*top_level=*/1, at_eof); + + /* Make it easy to find the CLONE given the FN. */ + TREE_CHAIN (clone) = TREE_CHAIN (fn); + TREE_CHAIN (fn) = clone; + + /* If this is a template, handle the DECL_TEMPLATE_RESULT as well. */ + if (TREE_CODE (clone) == TEMPLATE_DECL) + { + tree result; + + DECL_TEMPLATE_RESULT (clone) + = build_clone (DECL_TEMPLATE_RESULT (clone), name); + result = DECL_TEMPLATE_RESULT (clone); + DECL_TEMPLATE_INFO (result) = copy_node (DECL_TEMPLATE_INFO (result)); + DECL_TI_TEMPLATE (result) = clone; + } + + return clone; +} + +/* Produce declarations for all appropriate clones of FN. If + UPDATE_METHOD_VEC_P is non-zero, the clones are added to the + CLASTYPE_METHOD_VEC as well. */ + +void +clone_function_decl (fn, update_method_vec_p) + tree fn; + int update_method_vec_p; +{ + tree clone; + + if (DECL_CONSTRUCTOR_P (fn)) + { + clone = build_clone (fn, complete_ctor_identifier); + if (update_method_vec_p) + add_method (DECL_CONTEXT (clone), NULL, clone); + clone = build_clone (fn, base_ctor_identifier); + if (update_method_vec_p) + add_method (DECL_CONTEXT (clone), NULL, clone); + } + else + /* We don't do destructors yet. */ + my_friendly_abort (20000411); +} + +/* For each of the constructors and destructors in T, create an + in-charge and not-in-charge variant. */ + +static void +clone_constructors_and_destructors (t) + tree t; +{ + tree fns; + + /* We only clone constructors and destructors under the new ABI. */ + if (!flag_new_abi) + return; + + /* If for some reason we don't have a CLASSTYPE_METHOD_VEC, we bail + out now. */ + if (!CLASSTYPE_METHOD_VEC (t)) + return; + + /* For each constructor, we need two variants: an in-charge version + and a not-in-charge version. */ + for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns)) + clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1); + + /* For now, we don't do the destructors. */ +} + /* Remove all zero-width bit-fields from T. */ static void @@ -3950,6 +4098,10 @@ check_bases_and_members (t, empty_p) cant_have_const_ctor, no_const_asn_ref); + /* Create the in-charge and not-in-charge variants of constructors + and destructors. */ + clone_constructors_and_destructors (t); + /* Process the using-declarations. */ for (; access_decls; access_decls = TREE_CHAIN (access_decls)) handle_using_decl (TREE_VALUE (access_decls), t); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b9fa50e7424..db6a41c7c3a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -559,6 +559,7 @@ enum cp_tree_index CPTI_COMPLETE_CTOR_IDENTIFIER, CPTI_BASE_CTOR_IDENTIFIER, CPTI_DTOR_IDENTIFIER, + CPTI_COMPLETE_DTOR_IDENTIFIER, CPTI_BASE_DTOR_IDENTIFIER, CPTI_DELETING_DTOR_IDENTIFIER, CPTI_DELTA2_IDENTIFIER, @@ -653,14 +654,18 @@ extern tree cp_global_trees[CPTI_MAX]; frequently. */ /* The name of a constructor that takes an in-charge parameter to - decide whether or not to call virtual base classes. */ + decide whether or not to construct virtual base classes. */ #define ctor_identifier cp_global_trees[CPTI_CTOR_IDENTIFIER] /* The name of a constructor that constructs virtual base classes. */ #define complete_ctor_identifier cp_global_trees[CPTI_COMPLETE_CTOR_IDENTIFIER] /* The name of a constructor that does not construct virtual base classes. */ #define base_ctor_identifier cp_global_trees[CPTI_BASE_CTOR_IDENTIFIER] -/* The name of a destructor that destroys virtual base classes. */ +/* The name of a destructor that takes an in-charge parameter to + decide whether or not to destroy virtual base classes and whether + or not to delete the object. */ #define dtor_identifier cp_global_trees[CPTI_DTOR_IDENTIFIER] +/* The name of a destructor that destroys virtual base classes. */ +#define complete_dtor_identifier cp_global_trees[CPTI_COMPLETE_DTOR_IDENTIFIER] /* The name of a destructor that does not destroy virtual base classes. */ #define base_dtor_identifier cp_global_trees[CPTI_BASE_DTOR_IDENTIFIER] @@ -1475,17 +1480,29 @@ struct lang_type either a FUNCTION_DECL, a TEMPLATE_DECL, or an OVERLOAD. All functions with the same name end up in the same slot. The first two elements are for constructors, and destructors, respectively. - These are followed by ordinary member functions. There may be - empty entries at the end of the vector. */ + Any conversion operators are next, followed by ordinary member + functions. There may be empty entries at the end of the vector. */ #define CLASSTYPE_METHOD_VEC(NODE) (TYPE_LANG_SPECIFIC(NODE)->methods) -/* The first type conversion operator in the class (the others can be - searched with TREE_CHAIN), or the first non-constructor function if - there are no type conversion operators. */ -#define CLASSTYPE_FIRST_CONVERSION(NODE) \ - TREE_VEC_LENGTH (CLASSTYPE_METHOD_VEC (NODE)) > 2 \ - ? TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (NODE), 2) \ - : NULL_TREE; +/* The slot in the CLASSTYPE_METHOD_VEC where constructors go. */ +#define CLASSTYPE_CONSTRUCTOR_SLOT 0 + +/* The slot in the CLASSTYPE_METHOD_VEC where destructors go. */ +#define CLASSTYPE_DESTRUCTOR_SLOT 1 + +/* The first slot in the CLASSTYPE_METHOD_VEC where conversion + operators can appear. */ +#define CLASSTYPE_FIRST_CONVERSION_SLOT 2 + +/* A FUNCTION_DECL or OVERLOAD for the constructors for NODE. These + are the constructors that take an in-charge parameter. */ +#define CLASSTYPE_CONSTRUCTORS(NODE) \ + (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (NODE), CLASSTYPE_CONSTRUCTOR_SLOT)) + +/* A FUNCTION_DECL for the destructor for NODE. These are te + destructors that take an in-charge parameter. */ +#define CLASSTYPE_DESTRUCTORS(NODE) \ + (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (NODE), CLASSTYPE_DESTRUCTOR_SLOT)) /* Mark bits for depth-first and breath-first searches. */ @@ -1882,6 +1899,9 @@ struct lang_decl /* In a FUNCTION_DECL, this is DECL_SAVED_TREE. */ tree saved_tree; + /* In a FUNCTION_DECL, this is DECL_CLONED_FUNCTION. */ + tree cloned_function; + union { tree sorted_fields; @@ -1909,6 +1929,24 @@ struct lang_decl /* For FUNCTION_DECLs: nonzero means that this function is a constructor. */ #define DECL_CONSTRUCTOR_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.constructor_attr) +/* Nonzero if NODE (a FUNCTION_DECL) is a constructor for a complete + object. */ +#define DECL_COMPLETE_CONSTRUCTOR_P(NODE) \ + (DECL_CONSTRUCTOR_P (NODE) \ + && DECL_NAME (NODE) == complete_ctor_identifier) + +/* Nonzero if NODE (a FUNCTION_DECL) is a constructor for a base + object. */ +#define DECL_BASE_CONSTRUCTOR_P(NODE) \ + (DECL_CONSTRUCTOR_P (NODE) \ + && DECL_NAME (NODE) == base_ctor_identifier) + +/* Nonzero if NODE (a FUNCTION_DECL) is a constructor, but not either the + specialized in-charge constructor or the specialized not-in-charge + constructor. */ +#define DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P(NODE) \ + (DECL_CONSTRUCTOR_P (NODE) && !DECL_CLONED_FUNCTION_P (NODE)) + /* Nonzero if NODE (a FUNCTION_DECL) is a copy constructor. */ #define DECL_COPY_CONSTRUCTOR_P(NODE) \ (DECL_CONSTRUCTOR_P (NODE) && copy_args_p (NODE)) @@ -1919,6 +1957,22 @@ struct lang_decl (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (NODE)) \ && DECL_LANGUAGE (NODE) == lang_cplusplus) +/* Nonzero if NODE (a FUNCTION_DECL) is a destructor, but not the + specialized in-charge constructor, in-charge deleting constructor, + or the the base destructor. */ +#define DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P(NODE) \ + (DECL_DESTRUCTOR_P (NODE) && !DECL_CLONED_FUNCTION_P (NODE)) + +/* Nonzero if NODE (a FUNCTION_DECL) is a cloned constructor or + destructor. */ +#define DECL_CLONED_FUNCTION_P(NODE) \ + (DECL_CLONED_FUNCTION (NODE) != NULL_TREE) + +/* If DECL_CLONED_FUNCTION_P holds, this is the function that was + cloned. */ +#define DECL_CLONED_FUNCTION(NODE) \ + (DECL_LANG_SPECIFIC (NODE)->cloned_function) + /* Non-zero if NODE is a user-defined conversion operator. */ #define DECL_CONV_FN_P(NODE) \ (IDENTIFIER_TYPENAME_P (DECL_NAME (NODE)) && TREE_TYPE (DECL_NAME (NODE))) @@ -3723,6 +3777,7 @@ extern tree build_type_conversion PARAMS ((tree, tree, int)); extern tree build_expr_type_conversion PARAMS ((int, tree, int)); extern tree type_promotes_to PARAMS ((tree)); extern tree perform_qualification_conversions PARAMS ((tree, tree)); +extern void clone_function_decl PARAMS ((tree, int)); /* decl.c */ /* resume_binding_level */ @@ -4093,6 +4148,7 @@ extern tree implicitly_declare_fn PARAMS ((special_function_kind, /* In optimize.c */ extern void optimize_function PARAMS ((tree)); extern int calls_setjmp_p PARAMS ((tree)); +extern int maybe_clone_body PARAMS ((tree)); /* in pt.c */ extern void init_pt PARAMS ((void)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index a07cb3acad4..6b490a65131 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -6063,6 +6063,7 @@ initialize_predefined_identifiers () { "__base_ctor", &base_ctor_identifier }, { "__comp_ctor", &complete_ctor_identifier }, { DTOR_NAME, &dtor_identifier }, + { "__comp_dtor", &complete_dtor_identifier }, { "__base_dtor", &base_dtor_identifier }, { "__deleting_dtor", &deleting_dtor_identifier }, { VTABLE_DELTA2_NAME, &delta2_identifier }, @@ -13966,7 +13967,11 @@ finish_function (flags) store_parm_decls (); } - if (building_stmt_tree ()) + /* For a cloned function, we've already got all the code we need; + there's no need to add any extra bits. */ + if (building_stmt_tree () && DECL_CLONED_FUNCTION_P (fndecl)) + ; + else if (building_stmt_tree ()) { if (DECL_CONSTRUCTOR_P (fndecl)) { @@ -14763,6 +14768,7 @@ lang_mark_tree (t) { ggc_mark_tree (ld->befriending_classes); ggc_mark_tree (ld->saved_tree); + ggc_mark_tree (ld->cloned_function); 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 3e0a9df8c39..83279a12efc 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -5228,7 +5228,12 @@ mark_used (decl) && ! DECL_INITIAL (decl) /* Kludge: don't synthesize for default args. */ && current_function_decl) - synthesize_method (decl); + { + synthesize_method (decl); + /* If we've already synthesized the method we don't need to + instantiate it, so we can return right away. */ + return; + } /* If this is a function or variable that is an instance of some template, we now know that we will need to actually do the diff --git a/gcc/cp/dump.c b/gcc/cp/dump.c index 7f81094d4b0..dd6673c4e54 100644 --- a/gcc/cp/dump.c +++ b/gcc/cp/dump.c @@ -557,7 +557,6 @@ dequeue_and_dump (di) case FUNCTION_DECL: case THUNK_DECL: - dump_child ("scpe", CP_DECL_CONTEXT (t)); dump_child ("mngl", DECL_ASSEMBLER_NAME (t)); dump_child ("args", DECL_ARGUMENTS (t)); if (DECL_EXTERNAL (t)) diff --git a/gcc/cp/method.c b/gcc/cp/method.c index c5e4805d7d9..ecc7dc03fc5 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1748,7 +1748,7 @@ set_mangled_name_for_decl (decl) DECL_ASSEMBLER_NAME (decl) = build_decl_overload (DECL_NAME (decl), parm_types, DECL_FUNCTION_MEMBER_P (decl) - + DECL_CONSTRUCTOR_P (decl)); + + DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)); } /* Build an overload name for the type expression TYPE. */ @@ -2359,6 +2359,15 @@ synthesize_method (fndecl) if (at_eof) import_export_decl (fndecl); + /* If we've been asked to synthesize a clone, just synthesize the + cloned function instead. Doing so will automatically fill in the + body for the clone. */ + if (DECL_CLONED_FUNCTION_P (fndecl)) + { + synthesize_method (DECL_CLONED_FUNCTION (fndecl)); + return; + } + if (! context) push_to_top_level (); else if (nested) diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index b12a2ff6362..9f2fe35ac66 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -50,7 +50,9 @@ typedef struct inline_data inlining the body of `h', the stack will contain, `h', followed by `g', followed by `f'. */ varray_type fns; - /* The label to jump to when a return statement is encountered. */ + /* The label to jump to when a return statement is encountered. If + this value is NULL, then return statements will simply be + remapped as return statements, rather than as jumps. */ tree ret_label; /* The map from local declarations in the inlined function to equivalents in the function into which it is being inlined. */ @@ -157,6 +159,7 @@ remap_block (scope_stmt, decls, id) tree old_block; tree new_block; tree old_var; + tree *first_block; tree fn; /* Make the new block. */ @@ -175,9 +178,12 @@ remap_block (scope_stmt, decls, id) /* Remap the variable. */ new_var = remap_decl (old_var, id); - if (!new_var) - /* We didn't remap this variable, so we can't mess with - its TREE_CHAIN. */ + /* If we didn't remap this variable, so we can't mess with + its TREE_CHAIN. If we remapped this variable to + something other than a declaration (say, if we mapped it + to a constant), then we must similarly omit any mention + of it here. */ + if (!new_var || !DECL_P (new_var)) ; else { @@ -191,8 +197,12 @@ remap_block (scope_stmt, decls, id) function into which this block is being inlined. In rest_of_compilation we will straighten out the BLOCK tree. */ fn = VARRAY_TREE (id->fns, 0); - BLOCK_CHAIN (new_block) = BLOCK_CHAIN (DECL_INITIAL (fn)); - BLOCK_CHAIN (DECL_INITIAL (fn)) = new_block; + if (DECL_INITIAL (fn)) + first_block = &BLOCK_CHAIN (DECL_INITIAL (fn)); + else + first_block = &DECL_INITIAL (fn); + BLOCK_CHAIN (new_block) = *first_block; + *first_block = new_block; /* Remember the remapped block. */ splay_tree_insert (id->decl_map, (splay_tree_key) old_block, @@ -261,7 +271,7 @@ copy_body_r (tp, walk_subtrees, data) /* If this is a RETURN_STMT, change it into an EXPR_STMT and a GOTO_STMT with the RET_LABEL as its target. */ - if (TREE_CODE (*tp) == RETURN_STMT) + if (TREE_CODE (*tp) == RETURN_STMT && id->ret_label) { tree return_stmt = *tp; tree goto_stmt; @@ -774,3 +784,106 @@ calls_setjmp_p (fn) != NULL_TREE); } +/* FN is a function that has a complete body. Clone the body as + necessary. Returns non-zero if there's no longer any need to + process the main body. */ + +int +maybe_clone_body (fn) + tree fn; +{ + inline_data id; + tree clone; + + /* We don't clone constructors and destructors under the old ABI. */ + if (!flag_new_abi) + return 0; + + /* We only clone constructors and destructors. */ + if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn) + && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)) + return 0; + + /* We don't yet handle destructors. */ + if (DECL_DESTRUCTOR_P (fn)) + return 0; + + /* We know that any clones immediately follow FN in the TYPE_METHODS + list. */ + for (clone = TREE_CHAIN (fn); + clone && DECL_CLONED_FUNCTION_P (clone); + clone = TREE_CHAIN (clone)) + { + tree parm; + tree clone_parm; + int parmno; + + /* Update CLONE's source position information to match FN's. */ + DECL_SOURCE_FILE (clone) = DECL_SOURCE_FILE (fn); + DECL_SOURCE_LINE (clone) = DECL_SOURCE_LINE (fn); + + /* Start processing the function. */ + push_to_top_level (); + start_function (NULL_TREE, clone, NULL_TREE, SF_PRE_PARSED); + store_parm_decls (); + + /* Just clone the body, as if we were making an inline call. + But, remap the parameters in the callee to the parameters of + caller. If there's an in-charge parameter, map it to an + appropriate constant. */ + memset (&id, 0, sizeof (id)); + VARRAY_TREE_INIT (id.fns, 2, "fns"); + VARRAY_PUSH_TREE (id.fns, clone); + VARRAY_PUSH_TREE (id.fns, fn); + + /* Remap the parameters. */ + id.decl_map = splay_tree_new (splay_tree_compare_pointers, + NULL, NULL); + for (parmno = 0, + parm = DECL_ARGUMENTS (fn), + clone_parm = DECL_ARGUMENTS (clone); + parm; + ++parmno, + parm = TREE_CHAIN (parm)) + { + /* Map the in-charge parameter to an appropriate constant. */ + if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1) + { + tree in_charge; + + if (DECL_COMPLETE_CONSTRUCTOR_P (clone)) + in_charge = integer_one_node; + else + in_charge = integer_zero_node; + + splay_tree_insert (id.decl_map, + (splay_tree_key) parm, + (splay_tree_key) in_charge); + } + /* Map other parameters to their equivalents in the cloned + function. */ + else + { + splay_tree_insert (id.decl_map, + (splay_tree_key) parm, + (splay_tree_value) clone_parm); + clone_parm = TREE_CHAIN (clone_parm); + } + } + + /* Actually copy the body. */ + TREE_CHAIN (DECL_SAVED_TREE (clone)) = copy_body (&id); + + /* Clean up. */ + splay_tree_delete (id.decl_map); + VARRAY_FREE (id.fns); + + /* Now, expand this function into RTL, if appropriate. */ + current_function_name_declared = 1; + expand_body (finish_function (0)); + pop_from_top_level (); + } + + /* We don't need to process the original function any further. */ + return 1; +} diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 0e3277e6d94..caf84c8d516 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -159,6 +159,7 @@ static int template_args_equal PARAMS ((tree, tree)); static void print_template_context PARAMS ((int)); static void tsubst_default_arguments PARAMS ((tree)); static tree for_each_template_parm_r PARAMS ((tree *, int *, void *)); +static tree instantiate_clone PARAMS ((tree, tree)); /* Called once to initialize pt.c. */ @@ -5708,6 +5709,13 @@ tsubst_decl (t, args, type, in_decl) DECL_PENDING_INLINE_INFO (r) = 0; DECL_PENDING_INLINE_P (r) = 0; TREE_USED (r) = 0; + if (DECL_CLONED_FUNCTION (r)) + { + DECL_CLONED_FUNCTION (r) = tsubst (DECL_CLONED_FUNCTION (t), + args, /*complain=*/1, t); + TREE_CHAIN (r) = TREE_CHAIN (DECL_CLONED_FUNCTION (r)); + TREE_CHAIN (DECL_CLONED_FUNCTION (r)) = r; + } /* Set up the DECL_TEMPLATE_INFO for R and compute its mangled name. There's no need to do this in the special friend @@ -7367,6 +7375,43 @@ tsubst_expr (t, args, complain, in_decl) return NULL_TREE; } +/* TMPL is a TEMPLATE_DECL for a cloned constructor or destructor. + Instantiate it with the ARGS. */ + +static tree +instantiate_clone (tmpl, args) + tree tmpl; + tree args; +{ + tree spec; + tree clone; + + /* Instantiated the cloned function, rather than the clone. */ + spec = instantiate_template (DECL_CLONED_FUNCTION (tmpl), args); + + /* Then, see if we've already cloned the instantiation. */ + for (clone = TREE_CHAIN (spec); + clone && DECL_CLONED_FUNCTION_P (clone); + clone = TREE_CHAIN (clone)) + if (DECL_NAME (clone) == DECL_NAME (tmpl)) + return clone; + + /* If we haven't, do so know. */ + if (!clone) + clone_function_decl (spec, /*update_method_vec_p=*/0); + + /* Look again. */ + for (clone = TREE_CHAIN (spec); + clone && DECL_CLONED_FUNCTION_P (clone); + clone = TREE_CHAIN (clone)) + if (DECL_NAME (clone) == DECL_NAME (tmpl)) + return clone; + + /* We should always have found the clone by now. */ + my_friendly_abort (20000411); + return NULL_TREE; +} + /* Instantiate the indicated variable or function template TMPL with the template arguments in TARG_PTR. */ @@ -7385,6 +7430,10 @@ instantiate_template (tmpl, targ_ptr) my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 283); + /* If this function is a clone, handle it specially. */ + if (DECL_CLONED_FUNCTION_P (tmpl)) + return instantiate_clone (tmpl, targ_ptr); + /* Check to see if we already have this specialization. */ spec = retrieve_specialization (tmpl, targ_ptr); if (spec != NULL_TREE) @@ -9389,6 +9438,11 @@ instantiate_decl (d, defer_ok) my_friendly_assert (TREE_CODE (d) == FUNCTION_DECL || TREE_CODE (d) == VAR_DECL, 0); + /* Don't instantiate cloned functions. Instead, instantiate the + functions they cloned. */ + if (TREE_CODE (d) == FUNCTION_DECL && DECL_CLONED_FUNCTION_P (d)) + d = DECL_CLONED_FUNCTION (d); + if (DECL_TEMPLATE_INSTANTIATED (d)) /* D has already been instantiated. It might seem reasonable to check whether or not D is an explict instantiation, and, if so, @@ -9935,7 +9989,7 @@ set_mangled_name_for_template_decl (decl) = build_decl_overload_real (DECL_NAME (decl), parm_types, ret_type, tparms, targs, DECL_FUNCTION_MEMBER_P (decl) - + DECL_CONSTRUCTOR_P (decl)); + + DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)); /* Restore the previously active namespace. */ current_namespace = saved_namespace; diff --git a/gcc/cp/search.c b/gcc/cp/search.c index fda652d5ca2..7ca43b3e67d 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -1688,13 +1688,16 @@ lookup_fnfields_1 (type, name) /* Constructors are first... */ if (name == ctor_identifier) - return methods[0] ? 0 : -1; - + return (methods[CLASSTYPE_CONSTRUCTOR_SLOT] + ? CLASSTYPE_CONSTRUCTOR_SLOT : -1); /* and destructors are second. */ if (name == dtor_identifier) - return methods[1] ? 1 : -1; + return (methods[CLASSTYPE_DESTRUCTOR_SLOT] + ? CLASSTYPE_DESTRUCTOR_SLOT : -1); - for (i = 2; i < len && methods[i]; ++i) + for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; + i < len && methods[i]; + ++i) { #ifdef GATHER_STATISTICS n_outer_fields_searched++; @@ -1737,7 +1740,9 @@ lookup_fnfields_1 (type, name) above so that we will always find specializations first.) */ if (IDENTIFIER_TYPENAME_P (name)) { - for (i = 2; i < len && methods[i]; ++i) + for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; + i < len && methods[i]; + ++i) { tmp = OVL_CURRENT (methods[i]); if (! DECL_CONV_FN_P (tmp)) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index e7fcb63e988..8b9bfac7acd 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2717,6 +2717,16 @@ expand_body (fn) /* Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs. */ walk_tree (&DECL_SAVED_TREE (fn), simplify_aggr_init_exprs_r, NULL); + /* If this is a constructor or destructor body, we have to clone it + under the new ABI. */ + if (maybe_clone_body (fn)) + { + /* We don't want to process FN again, so pretend we've written + it out, even though we haven't. */ + TREE_ASM_WRITTEN (fn) = 1; + return; + } + /* There's no reason to do any of the work here if we're only doing semantic analysis; this code just generates RTL. */ if (flag_syntax_only)