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
This commit is contained in:
parent
c23c855f38
commit
db9b217498
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
162
gcc/cp/class.c
162
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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
56
gcc/cp/pt.c
56
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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue