aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2000-04-11 20:16:36 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2000-04-11 20:16:36 +0000
commitdb9b217498015006694d428ada8d8aed292a432f (patch)
tree00bde8ebf754ce1bd6c1c550c95312c0647e115f /gcc
parentc23c855f38f4287ce82018ca40892379bcdbf715 (diff)
downloadgcc-db9b217498015006694d428ada8d8aed292a432f.zip
gcc-db9b217498015006694d428ada8d8aed292a432f.tar.gz
gcc-db9b217498015006694d428ada8d8aed292a432f.tar.bz2
cp-tree.h (cp_tree_index): Add CPTI_DTOR_IDENTIFIER.
* 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. From-SVN: r33084
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog51
-rw-r--r--gcc/cp/call.c35
-rw-r--r--gcc/cp/class.c162
-rw-r--r--gcc/cp/cp-tree.h78
-rw-r--r--gcc/cp/decl.c8
-rw-r--r--gcc/cp/decl2.c7
-rw-r--r--gcc/cp/dump.c1
-rw-r--r--gcc/cp/method.c11
-rw-r--r--gcc/cp/optimize.c127
-rw-r--r--gcc/cp/pt.c56
-rw-r--r--gcc/cp/search.c15
-rw-r--r--gcc/cp/semantics.c10
12 files changed, 515 insertions, 46 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index c3b2d479..18f252d 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,56 @@
2000-04-11 Mark Mitchell <mark@codesourcery.com>
+ * 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 040801b..c003248 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 5262faa..d954ac0 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 b9fa50e..db6a41c 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 a07cb3a..6b490a6 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 3e0a9df..83279a1 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 7f81094..dd6673c 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 c5e4805..ecc7dc0 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 b12a2ff..9f2fe35 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 0e3277e..caf84c8 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 fda652d..7ca43b3 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 e7fcb63..8b9bfac 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)