Commit 298d6f60 by Mark Mitchell Committed by Mark Mitchell

cp-tree.h (IDENTIFIER_CTOR_OR_DTOR_P): New macro.

	* cp-tree.h (IDENTIFIER_CTOR_OR_DTOR_P): New macro.
	(cp_tree_index): Add CPTI_PUSH_EXCEPTION_IDENTIFIER.
	(cp_push_exception_identifier): New macro.
	(DECL_COMPLETE_DESTRUCTOR_P): New macro.
	(DECL_BASE_DESTRUCTOR_P): Likewise.
	(DECL_DELETING_DESTRUCTOR_P): Likewise.
	(get_vtbl_decl_for_binfo): Fix formatting.
	(in_charge_arg_for_name): New macro.
	(maybe_build_cleanup_and_delete): Remove declaration.
	* call.c (build_field_call): Use IDENTIFIER_CTOR_OR_DTOR_P.
	(in_charge_arg_for_name): New function.
	(build_new_method_call): Use it.  Handle cloned destructors.
	(build_clone): Don't make the base constructor virtual.
	Automatically defer generated functions.
	(clone_function_decl): Handle destructors, too.
	(clone_constructors_and_destructors): Likewise.
	(create_vtable_ptr): Don't create a vtable entry for a cloned
	function.
	* decl.c (predefined_identifier): Add ctor_or_dtor_p.
	(initialize_predefined_identifiers): Update appropriately.
	(finish_destructor_body): Simplify.
	(maybe_build_cleanup_and_delete): Remove.
	* except.c (expand_throw): Handle new-ABI destructors.
	* init.c (expand_cleanup_for_base): Use base_dtor_identifier.
	(build_dtor_call): New function.
	(build_delete): Use it.  Simplify.
	* optimize.c (maybe_clone_body): Handle destructors.
	* search.c (lookup_field_queue_p): Use IDENTIFIER_CTOR_OR_DTOR_P.

From-SVN: r33096
parent 1ba82fb2
2000-04-12 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (IDENTIFIER_CTOR_OR_DTOR_P): New macro.
(cp_tree_index): Add CPTI_PUSH_EXCEPTION_IDENTIFIER.
(cp_push_exception_identifier): New macro.
(DECL_COMPLETE_DESTRUCTOR_P): New macro.
(DECL_BASE_DESTRUCTOR_P): Likewise.
(DECL_DELETING_DESTRUCTOR_P): Likewise.
(get_vtbl_decl_for_binfo): Fix formatting.
(in_charge_arg_for_name): New macro.
(maybe_build_cleanup_and_delete): Remove declaration.
* call.c (build_field_call): Use IDENTIFIER_CTOR_OR_DTOR_P.
(in_charge_arg_for_name): New function.
(build_new_method_call): Use it. Handle cloned destructors.
(build_clone): Don't make the base constructor virtual.
Automatically defer generated functions.
(clone_function_decl): Handle destructors, too.
(clone_constructors_and_destructors): Likewise.
(create_vtable_ptr): Don't create a vtable entry for a cloned
function.
* decl.c (predefined_identifier): Add ctor_or_dtor_p.
(initialize_predefined_identifiers): Update appropriately.
(finish_destructor_body): Simplify.
(maybe_build_cleanup_and_delete): Remove.
* except.c (expand_throw): Handle new-ABI destructors.
* init.c (expand_cleanup_for_base): Use base_dtor_identifier.
(build_dtor_call): New function.
(build_delete): Use it. Simplify.
* optimize.c (maybe_clone_body): Handle destructors.
* search.c (lookup_field_queue_p): Use IDENTIFIER_CTOR_OR_DTOR_P.
* exception.cc (cleanup_fn): New typedef.
(CALL_CLEANUP): New macro.
(cp_eh_info): Use them.
(__cp_push_exception): Likewise.
(__cp_pop_exception): Likewise.
2000-04-11 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (cp_tree_index): Add CPTI_DTOR_IDENTIFIER.
......
......@@ -130,7 +130,7 @@ build_field_call (basetype_path, instance_ptr, name, parms)
{
tree field, instance;
if (name == ctor_identifier || name == dtor_identifier)
if (IDENTIFIER_CTOR_OR_DTOR_P (name))
return NULL_TREE;
/* Speed up the common case. */
......@@ -4172,6 +4172,29 @@ build_over_call (cand, args, flags)
return convert_from_reference (fn);
}
/* Returns the value to use for the in-charge parameter when making a
call to a function with the indicated NAME. */
tree
in_charge_arg_for_name (name)
tree name;
{
if (name == base_ctor_identifier
|| name == base_dtor_identifier)
return integer_zero_node;
else if (name == complete_ctor_identifier)
return integer_one_node;
else if (name == complete_dtor_identifier)
return integer_two_node;
else if (name == deleting_dtor_identifier)
return integer_three_node;
/* This function should only be called with one of the names listed
above. */
my_friendly_abort (20000411);
return NULL_TREE;
}
static tree
build_new_method_call (instance, name, args, basetype_path, flags)
tree instance, name, args, basetype_path;
......@@ -4253,30 +4276,30 @@ build_new_method_call (instance, name, args, basetype_path, flags)
/* Callers should explicitly indicate whether they want to construct
the complete object or just the part without virtual bases. */
my_friendly_assert (name != ctor_identifier, 20000408);
/* Similarly for destructors. */
my_friendly_assert (name != dtor_identifier, 20000408);
if (name == complete_ctor_identifier
|| name == base_ctor_identifier)
if (IDENTIFIER_CTOR_OR_DTOR_P (name))
{
pretty_name = constructor_name (basetype);
int constructor_p;
constructor_p = (name == complete_ctor_identifier
|| name == base_ctor_identifier);
pretty_name = (constructor_p
? constructor_name (basetype) : dtor_identifier);
if (!flag_new_abi)
{
/* 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;
args = tree_cons (NULL_TREE, in_charge, args);
}
if (!constructor_p
|| TYPE_USES_VIRTUAL_BASECLASSES (basetype))
args = tree_cons (NULL_TREE,
in_charge_arg_for_name (name),
args);
/* We want to call the normal constructor function under the
old ABI. */
name = ctor_identifier;
name = constructor_p ? ctor_identifier : dtor_identifier;
}
}
else
......
......@@ -3883,6 +3883,14 @@ build_clone (fn, name)
/* And it hasn't yet been deferred. */
DECL_DEFERRED_FN (clone) = 0;
/* The base-class destructor is not virtual. */
if (name == base_dtor_identifier)
{
DECL_VIRTUAL_P (clone) = 0;
if (TREE_CODE (clone) != TEMPLATE_DECL)
DECL_VINDEX (clone) = NULL_TREE;
}
/* If there was an in-charge paramter, drop it from the function
type. */
if (DECL_HAS_IN_CHARGE_PARM_P (clone))
......@@ -3948,6 +3956,8 @@ build_clone (fn, name)
DECL_TEMPLATE_INFO (result) = copy_node (DECL_TEMPLATE_INFO (result));
DECL_TI_TEMPLATE (result) = clone;
}
else if (DECL_DEFERRED_FN (fn))
defer_fn (clone);
return clone;
}
......@@ -3963,8 +3973,10 @@ clone_function_decl (fn, update_method_vec_p)
{
tree clone;
if (DECL_CONSTRUCTOR_P (fn))
if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn))
{
/* For each constructor, we need two variants: an in-charge version
and a not-in-charge version. */
clone = build_clone (fn, complete_ctor_identifier);
if (update_method_vec_p)
add_method (DECL_CONTEXT (clone), NULL, clone);
......@@ -3973,8 +3985,22 @@ clone_function_decl (fn, update_method_vec_p)
add_method (DECL_CONTEXT (clone), NULL, clone);
}
else
/* We don't do destructors yet. */
my_friendly_abort (20000411);
{
my_friendly_assert (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn), 20000411);
/* For each destructor, we need two variants: an in-charge
version, a not-in-charge version, and an in-charge deleting
version. */
clone = build_clone (fn, complete_dtor_identifier);
if (update_method_vec_p)
add_method (DECL_CONTEXT (clone), NULL, clone);
clone = build_clone (fn, deleting_dtor_identifier);
if (update_method_vec_p)
add_method (DECL_CONTEXT (clone), NULL, clone);
clone = build_clone (fn, base_dtor_identifier);
if (update_method_vec_p)
add_method (DECL_CONTEXT (clone), NULL, clone);
}
}
/* For each of the constructors and destructors in T, create an
......@@ -3995,12 +4021,10 @@ clone_constructors_and_destructors (t)
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. */
for (fns = CLASSTYPE_DESTRUCTORS (t); fns; fns = OVL_NEXT (fns))
clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
}
/* Remove all zero-width bit-fields from T. */
......@@ -4130,7 +4154,8 @@ create_vtable_ptr (t, empty_p, vfuns_p,
/* Loop over the virtual functions, adding them to our various
vtables. */
for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn))
if (DECL_VINDEX (fn))
if (DECL_VINDEX (fn)
&& !(flag_new_abi && DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)))
add_virtual_function (new_virtuals_p, overridden_virtuals_p,
vfuns_p, fn, t);
......
......@@ -66,6 +66,7 @@ Boston, MA 02111-1307, USA. */
ICS_BAD_FLAG (in _CONV)
FN_TRY_BLOCK_P (in TRY_BLOCK)
SCOPE_NO_CLEANUPS_P (in SCOPE_STMT)
IDENTIFIER_CTOR_OR_DTOR_P (in IDENTIFIER_NODE)
4: BINFO_NEW_VTABLE_MARKED.
TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
or FIELD_DECL).
......@@ -482,6 +483,11 @@ struct tree_srcloc
OPERATOR_TYPENAME_FORMAT, \
strlen (OPERATOR_TYPENAME_FORMAT)))
/* Nonzero if this identifier is the name of a constructor or
destructor. */
#define IDENTIFIER_CTOR_OR_DTOR_P(NODE) \
TREE_LANG_FLAG_3 (NODE)
/* Nonzero means reject anything that ISO standard C++ forbids. */
extern int pedantic;
......@@ -571,6 +577,7 @@ enum cp_tree_index
CPTI_PFN_IDENTIFIER,
CPTI_PFN_OR_DELTA2_IDENTIFIER,
CPTI_VPTR_IDENTIFIER,
CPTI_PUSH_EXCEPTION_IDENTIFIER,
CPTI_LANG_NAME_C,
CPTI_LANG_NAME_CPLUSPLUS,
......@@ -682,6 +689,9 @@ extern tree cp_global_trees[CPTI_MAX];
#define pfn_identifier cp_global_trees[CPTI_PFN_IDENTIFIER]
#define pfn_or_delta2_identifier cp_global_trees[CPTI_PFN_OR_DELTA2_IDENTIFIER]
#define vptr_identifier cp_global_trees[CPTI_VPTR_IDENTIFIER]
/* The name of the function to call to push an exception onto the
exception stack. */
#define cp_push_exception_identifier cp_global_trees[CPTI_PUSH_EXCEPTION_IDENTIFIER]
#define lang_name_c cp_global_trees[CPTI_LANG_NAME_C]
#define lang_name_cplusplus cp_global_trees[CPTI_LANG_NAME_CPLUSPLUS]
......@@ -1963,6 +1973,24 @@ struct lang_decl
#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 destructor for a complete
object. */
#define DECL_COMPLETE_DESTRUCTOR_P(NODE) \
(DECL_DESTRUCTOR_P (NODE) \
&& DECL_NAME (NODE) == complete_dtor_identifier)
/* Nonzero if NODE (a FUNCTION_DECL) is a destructor for a base
object. */
#define DECL_BASE_DESTRUCTOR_P(NODE) \
(DECL_DESTRUCTOR_P (NODE) \
&& DECL_NAME (NODE) == base_dtor_identifier)
/* Nonzero if NODE (a FUNCTION_DECL) is a destructor for a complete
object. */
#define DECL_DELETING_DESTRUCTOR_P(NODE) \
(DECL_DESTRUCTOR_P (NODE) \
&& DECL_NAME (NODE) == deleting_dtor_identifier)
/* Nonzero if NODE (a FUNCTION_DECL) is a cloned constructor or
destructor. */
#define DECL_CLONED_FUNCTION_P(NODE) \
......@@ -3762,6 +3790,7 @@ extern void invalidate_class_lookup_cache PARAMS ((void));
extern void maybe_note_name_used_in_class PARAMS ((tree, tree));
extern void note_name_declared_in_class PARAMS ((tree, tree));
extern tree get_vtbl_decl_for_binfo PARAMS ((tree));
extern tree in_charge_arg_for_name PARAMS ((tree));
/* in cvt.c */
extern tree convert_to_reference PARAMS ((tree, tree, int, int, tree));
......@@ -3898,7 +3927,6 @@ extern tree finish_function PARAMS ((int));
extern tree start_method PARAMS ((tree, tree, tree));
extern tree finish_method PARAMS ((tree));
extern void hack_incomplete_structures PARAMS ((tree));
extern tree maybe_build_cleanup_and_delete PARAMS ((tree));
extern tree maybe_build_cleanup PARAMS ((tree));
extern void cplus_expand_expr_stmt PARAMS ((tree));
extern void finish_stmt PARAMS ((void));
......
......@@ -6045,6 +6045,8 @@ typedef struct predefined_identifier
const char *name;
/* The place where the IDENTIFIER_NODE should be stored. */
tree *node;
/* Non-zero if this is the name of a constructor or destructor. */
int ctor_or_dtor_p;
} predefined_identifier;
/* Create all the predefined identifiers. */
......@@ -6056,30 +6058,35 @@ initialize_predefined_identifiers ()
/* A table of identifiers to create at startup. */
static predefined_identifier predefined_identifiers[] = {
{ "C++", &lang_name_cplusplus },
{ "C", &lang_name_c },
{ "Java", &lang_name_java },
{ CTOR_NAME, &ctor_identifier },
{ "__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 },
{ VTABLE_DELTA_NAME, &delta_identifier },
{ IN_CHARGE_NAME, &in_charge_identifier },
{ VTABLE_INDEX_NAME, &index_identifier },
{ "nelts", &nelts_identifier },
{ THIS_NAME, &this_identifier },
{ VTABLE_PFN_NAME, &pfn_identifier },
{ "__pfn_or_delta2", &pfn_or_delta2_identifier },
{ "_vptr", &vptr_identifier },
{ NULL, NULL }
{ "C++", &lang_name_cplusplus, 0 },
{ "C", &lang_name_c, 0 },
{ "Java", &lang_name_java, 0 },
{ CTOR_NAME, &ctor_identifier, 1 },
{ "__base_ctor", &base_ctor_identifier, 1 },
{ "__comp_ctor", &complete_ctor_identifier, 1 },
{ DTOR_NAME, &dtor_identifier, 1 },
{ "__comp_dtor", &complete_dtor_identifier, 1 },
{ "__base_dtor", &base_dtor_identifier, 1 },
{ "__deleting_dtor", &deleting_dtor_identifier, 1 },
{ VTABLE_DELTA2_NAME, &delta2_identifier, 0 },
{ VTABLE_DELTA_NAME, &delta_identifier, 0 },
{ IN_CHARGE_NAME, &in_charge_identifier, 0 },
{ VTABLE_INDEX_NAME, &index_identifier, 0 },
{ "nelts", &nelts_identifier, 0 },
{ THIS_NAME, &this_identifier, 0 },
{ VTABLE_PFN_NAME, &pfn_identifier, 0 },
{ "__pfn_or_delta2", &pfn_or_delta2_identifier, 0 },
{ "_vptr", &vptr_identifier, 0 },
{ "__cp_push_exception", &cp_push_exception_identifier, 0 },
{ NULL, NULL, 0 }
};
for (pid = predefined_identifiers; pid->name; ++pid)
{
*pid->node = get_identifier (pid->name);
if (pid->ctor_or_dtor_p)
IDENTIFIER_CTOR_OR_DTOR_P (*pid->node) = 1;
}
}
/* Create the predefined scalar types of C,
......@@ -13811,9 +13818,9 @@ static void
finish_destructor_body ()
{
tree compound_stmt;
tree in_charge;
tree virtual_size;
tree exprstmt;
tree if_stmt;
/* Create a block to contain all the extra code. */
compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
......@@ -13831,16 +13838,9 @@ finish_destructor_body ()
will set the flag again. */
TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
/* These are two cases where we cannot delegate deletion. */
if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
|| TYPE_GETS_REG_DELETE (current_class_type))
in_charge = integer_zero_node;
else
in_charge = current_in_charge_parm;
exprstmt = build_delete (current_class_type,
current_class_ref,
in_charge,
integer_zero_node,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
0);
......@@ -13873,8 +13873,8 @@ finish_destructor_body ()
TYPE_BINFO (current_class_type));
finish_expr_stmt
(build_scoped_method_call
(current_class_ref, vb, dtor_identifier,
build_tree_list (NULL_TREE, integer_zero_node)));
(current_class_ref, vb, complete_dtor_identifier,
NULL_TREE));
}
vbases = TREE_CHAIN (vbases);
}
......@@ -13897,11 +13897,6 @@ finish_destructor_body ()
only defines placement deletes we don't do anything here. So we
pass LOOKUP_SPECULATIVELY; delete_sanity will complain for us if
they ever try to delete one of these. */
if (TYPE_GETS_REG_DELETE (current_class_type)
|| TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
{
tree if_stmt;
exprstmt = build_op_delete_call
(DELETE_EXPR, current_class_ptr, virtual_size,
LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
......@@ -13914,7 +13909,6 @@ finish_destructor_body ()
finish_expr_stmt (exprstmt);
finish_then_clause (if_stmt);
finish_if_stmt ();
}
/* Close the block we started above. */
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
......@@ -14560,16 +14554,6 @@ maybe_build_cleanup_1 (decl, auto_delete)
}
/* If DECL is of a type which needs a cleanup, build that cleanup
here. The cleanup does free the storage with a call to delete. */
tree
maybe_build_cleanup_and_delete (decl)
tree decl;
{
return maybe_build_cleanup_1 (decl, integer_three_node);
}
/* If DECL is of a type which needs a cleanup, build that cleanup
here. The cleanup does not free the storage with a call a delete. */
tree
......
......@@ -888,14 +888,20 @@ expand_throw (exp)
/* First, decay it. */
exp = decay_conversion (exp);
/* cleanup_type is void (*)(void *, int),
the internal type of a destructor. */
/* The CLEANUP_TYPE is the internal type of a destructor. Under
the old ABI, destructors are two-argument functions; under
the new ABI they take only one argument. */
if (cleanup_type == NULL_TREE)
cleanup_type = build_pointer_type
(build_function_type
(void_type_node, tree_cons
(NULL_TREE, ptr_type_node, tree_cons
(NULL_TREE, integer_type_node, void_list_node))));
{
tree arg_types;
arg_types = void_list_node;
if (!flag_new_abi)
arg_types = tree_cons (NULL_TREE, integer_type_node, arg_types);
arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
cleanup_type = (build_pointer_type
(build_function_type (void_type_node, arg_types)));
}
if (TYPE_PTR_P (TREE_TYPE (exp)))
throw_type = build_eh_type_type (TREE_TYPE (exp));
......@@ -949,7 +955,10 @@ expand_throw (exp)
if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
{
cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
dtor_identifier, 0);
(flag_new_abi
? complete_dtor_identifier
: dtor_identifier),
0);
cleanup = TREE_VALUE (cleanup);
mark_used (cleanup);
mark_addressable (cleanup);
......@@ -970,7 +979,7 @@ expand_throw (exp)
TREE_TYPE (cleanup) = cleanup_type;
}
fn = get_identifier ("__cp_push_exception");
fn = cp_push_exception_identifier;
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
......
......@@ -78,6 +78,21 @@ std::unexpected ()
__unexpected_func ();
}
/* The type of a function called to clean up an exception object.
(These will be destructors.) Under the old ABI, these take a
second argument (the `in-charge' argument), that indicates whether
or not do delete the object, and whether or not to destroy virtual
bases. Under the new ABI, there is no second argument. */
#if !defined (__GXX_ABI_VERSION) || __GXX_ABI_VERSION < 100
typedef void (*cleanup_fn)(void *, int);
/* The `2' is the value for the in-charge parameter that indicates
that virtual bases should be destroyed. */
#define CALL_CLEANUP(FN, THIS) FN (THIS, 2)
#else
typedef void (*cleanup_fn)(void *);
#define CALL_CLEANUP(FN, THIS) FN (THIS)
#endif
/* C++-specific state about the current exception.
This must match init_exception_processing().
......@@ -90,7 +105,7 @@ struct cp_eh_info
__eh_info eh_info;
void *value;
void *type;
void (*cleanup)(void *, int);
cleanup_fn cleanup;
bool caught;
cp_eh_info *next;
long handlers;
......@@ -202,7 +217,7 @@ __cplus_type_matcher (__eh_info *info_, void *match_info,
Used by expand_throw(). */
extern "C" void
__cp_push_exception (void *value, void *type, void (*cleanup)(void *, int))
__cp_push_exception (void *value, void *type, cleanup_fn cleanup)
{
cp_eh_info *p = (cp_eh_info *) __eh_alloc (sizeof (cp_eh_info));
......@@ -251,8 +266,8 @@ __cp_pop_exception (cp_eh_info *p)
*q = p->next;
if (p->cleanup)
/* 2 is a magic value for destructors; see build_delete(). */
p->cleanup (p->original_value, 2); // value may have been adjusted.
// value may have been adjusted.
CALL_CLEANUP (p->cleanup, p->original_value);
if (! __is_pointer (p->type))
__eh_free (p->original_value); // value may have been adjusted.
......
......@@ -51,6 +51,7 @@ static tree get_temp_regvar PARAMS ((tree, tree));
static tree dfs_initialize_vtbl_ptrs PARAMS ((tree, void *));
static tree build_new_1 PARAMS ((tree));
static tree get_cookie_size PARAMS ((tree));
static tree build_dtor_call PARAMS ((tree, tree, int));
/* Set up local variable for this file. MUST BE CALLED AFTER
INIT_DECL_PROCESSING. */
......@@ -713,8 +714,7 @@ expand_cleanup_for_base (binfo, flag)
/* Call the destructor. */
expr = (build_scoped_method_call
(current_class_ref, binfo, dtor_identifier,
build_tree_list (NULL_TREE, integer_zero_node)));
(current_class_ref, binfo, base_dtor_identifier, NULL_TREE));
if (flag)
expr = fold (build (COND_EXPR, void_type_node,
truthvalue_conversion (flag),
......@@ -2963,6 +2963,71 @@ build_x_delete (addr, which_delete, virtual_size)
return build_op_delete_call (code, addr, virtual_size, flags, NULL_TREE);
}
/* Call the destructor for EXP using the IN_CHARGE parameter. FLAGS
are as for build_delete. */
static tree
build_dtor_call (exp, in_charge, flags)
tree exp;
tree in_charge;
int flags;
{
tree name = NULL_TREE;
tree call1;
tree call2;
tree call3;
tree result;
/* First, try to figure out statically which function to call. */
in_charge = fold (in_charge);
if (tree_int_cst_equal (in_charge, integer_zero_node))
name = base_dtor_identifier;
else if (tree_int_cst_equal (in_charge, integer_one_node))
name = deleting_dtor_identifier;
else if (tree_int_cst_equal (in_charge, integer_two_node))
name = complete_dtor_identifier;
if (name)
{
if (!binfo)
return build_method_call (exp, name, NULL_TREE, NULL_TREE, flags);
else
return build_scoped_method_call (exp, binfo, name, NULL_TREE);
}
/* If that didn't work, build the various alternatives. */
if (!binfo)
{
call1 = build_method_call (exp, complete_dtor_identifier,
NULL_TREE, NULL_TREE, flags);
call2 = build_method_call (exp, deleting_dtor_identifier,
NULL_TREE, NULL_TREE, flags);
call3 = build_method_call (exp, base_dtor_identifier,
NULL_TREE, NULL_TREE, flags);
}
else
{
call1 = build_scoped_method_call (exp, binfo,
complete_dtor_identifier, NULL_TREE);
call2 = build_scoped_method_call (exp, binfo,
deleting_dtor_identifier, NULL_TREE);
call3 = build_scoped_method_call (exp, binfo,
base_dtor_identifier, NULL_TREE);
}
/* Build the conditionals. */
result = build (COND_EXPR, void_type_node,
fold (build (BIT_AND_EXPR, integer_type_node,
in_charge, integer_two_node)),
call1,
call3);
result = build (COND_EXPR, void_type_node,
fold (build (BIT_AND_EXPR, integer_type_node,
in_charge, integer_one_node)),
call2,
result);
return result;
}
/* Generate a call to a destructor. TYPE is the type to cast ADDR to.
ADDR is an expression which yields the store to be destroyed.
AUTO_DELETE is nonzero if a call to DELETE should be made or not.
......@@ -3084,10 +3149,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
else
passed_auto_delete = auto_delete;
expr = build_method_call
(ref, dtor_identifier, build_tree_list (NULL_TREE, passed_auto_delete),
NULL_TREE, flags);
expr = build_dtor_call (ref, passed_auto_delete, NULL_TREE, flags);
if (do_delete)
expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
......@@ -3111,8 +3173,6 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (type);
tree base_binfo = n_baseclasses > 0 ? TREE_VEC_ELT (binfos, 0) : NULL_TREE;
tree exprstmt = NULL_TREE;
tree parent_auto_delete = auto_delete;
tree cond;
/* Set this again before we call anything, as we might get called
recursively. */
......@@ -3120,50 +3180,19 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
/* If we have member delete or vbases, we call delete in
finish_function. */
if (auto_delete == integer_zero_node)
cond = NULL_TREE;
else if (base_binfo == NULL_TREE
|| TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo)))
{
cond = build (COND_EXPR, void_type_node,
build (BIT_AND_EXPR, integer_type_node, auto_delete, integer_one_node),
build_builtin_delete_call (addr),
void_zero_node);
}
else
cond = NULL_TREE;
if (cond)
exprstmt = build_tree_list (NULL_TREE, cond);
if (base_binfo
&& ! TREE_VIA_VIRTUAL (base_binfo)
&& TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo)))
{
tree this_auto_delete;
if (BINFO_OFFSET_ZEROP (base_binfo))
this_auto_delete = parent_auto_delete;
else
this_auto_delete = integer_zero_node;
expr = build_scoped_method_call
(ref, base_binfo, dtor_identifier,
build_tree_list (NULL_TREE, this_auto_delete));
exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}
my_friendly_assert (auto_delete == integer_zero_node, 20000411);
/* Take care of the remaining baseclasses. */
for (i = 1; i < n_baseclasses; i++)
for (i = 0; i < n_baseclasses; i++)
{
base_binfo = TREE_VEC_ELT (binfos, i);
if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))
|| TREE_VIA_VIRTUAL (base_binfo))
continue;
expr = build_scoped_method_call
(ref, base_binfo, dtor_identifier,
build_tree_list (NULL_TREE, integer_zero_node));
expr = build_scoped_method_call (ref, base_binfo,
base_dtor_identifier,
NULL_TREE);
exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}
......
......@@ -804,10 +804,6 @@ maybe_clone_body (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);
......@@ -850,12 +846,7 @@ maybe_clone_body (fn)
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;
in_charge = in_charge_arg_for_name (DECL_NAME (clone));
splay_tree_insert (id.decl_map,
(splay_tree_key) parm,
(splay_tree_key) in_charge);
......
......@@ -1337,7 +1337,7 @@ lookup_field_queue_p (binfo, data)
struct lookup_field_info *lfi = (struct lookup_field_info *) data;
/* Don't look for constructors or destructors in base classes. */
if (lfi->name == ctor_identifier || lfi->name == dtor_identifier)
if (IDENTIFIER_CTOR_OR_DTOR_P (lfi->name))
return NULL_TREE;
/* If this base class is hidden by the best-known value so far, we
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment