This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: Clone destructors
- To: gcc-patches at gcc dot gnu dot org
- Subject: C++ PATCH: Clone destructors
- From: Mark Mitchell <mark at codesourcery dot com>
- Date: Wed, 12 Apr 2000 00:56:55 -0700
- Organization: CodeSourcery, LLC
This patch clones destructors, just like constructors. I temporarily
removed one minor space optimization: delegation of deletion to base
classes. The way it had been done was incorrect for the new ABI, and
I wanted to think about it a bit. I'll add the optimization back in
tomorrow, if possible.
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com
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.
Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.441
diff -c -p -r1.441 cp-tree.h
*** cp-tree.h 2000/04/11 20:16:35 1.441
--- cp-tree.h 2000/04/12 07:37:52
*************** Boston, MA 02111-1307, USA. */
*** 66,71 ****
--- 66,72 ----
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).
*************** struct tree_srcloc
*** 482,487 ****
--- 483,493 ----
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;
*************** enum cp_tree_index
*** 571,576 ****
--- 577,583 ----
CPTI_PFN_IDENTIFIER,
CPTI_PFN_OR_DELTA2_IDENTIFIER,
CPTI_VPTR_IDENTIFIER,
+ CPTI_PUSH_EXCEPTION_IDENTIFIER,
CPTI_LANG_NAME_C,
CPTI_LANG_NAME_CPLUSPLUS,
*************** extern tree cp_global_trees[CPTI_MAX];
*** 682,687 ****
--- 689,697 ----
#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]
*************** struct lang_decl
*** 1963,1968 ****
--- 1973,1996 ----
#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) \
*************** extern void unreverse_member_declaration
*** 3761,3767 ****
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));
/* in cvt.c */
extern tree convert_to_reference PARAMS ((tree, tree, int, int, tree));
--- 3789,3796 ----
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));
*************** extern tree finish_function PARAMS ((i
*** 3898,3904 ****
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));
--- 3927,3932 ----
Index: call.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/call.c,v
retrieving revision 1.209
diff -c -p -r1.209 call.c
*** call.c 2000/04/11 20:16:34 1.209
--- call.c 2000/04/12 07:37:45
*************** build_field_call (basetype_path, instanc
*** 130,136 ****
{
tree field, instance;
! if (name == ctor_identifier || name == dtor_identifier)
return NULL_TREE;
/* Speed up the common case. */
--- 130,136 ----
{
tree field, instance;
! if (IDENTIFIER_CTOR_OR_DTOR_P (name))
return NULL_TREE;
/* Speed up the common case. */
*************** build_over_call (cand, args, flags)
*** 4172,4177 ****
--- 4172,4200 ----
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;
*************** build_new_method_call (instance, name, a
*** 4253,4282 ****
/* 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);
! if (name == complete_ctor_identifier
! || name == base_ctor_identifier)
{
! pretty_name = constructor_name (basetype);
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);
! }
/* We want to call the normal constructor function under the
old ABI. */
! name = ctor_identifier;
}
}
else
--- 4276,4305 ----
/* 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 (IDENTIFIER_CTOR_OR_DTOR_P (name))
{
! 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 (!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 = constructor_p ? ctor_identifier : dtor_identifier;
}
}
else
Index: class.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/class.c,v
retrieving revision 1.290
diff -c -p -r1.290 class.c
*** class.c 2000/04/11 20:16:35 1.290
--- class.c 2000/04/12 07:37:49
*************** build_clone (fn, name)
*** 3883,3888 ****
--- 3883,3896 ----
/* 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))
*************** build_clone (fn, name)
*** 3948,3953 ****
--- 3956,3963 ----
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;
}
*************** clone_function_decl (fn, update_method_v
*** 3963,3970 ****
{
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);
--- 3973,3982 ----
{
tree clone;
! 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);
*************** clone_function_decl (fn, update_method_v
*** 3973,3980 ****
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
--- 3985,4006 ----
add_method (DECL_CONTEXT (clone), NULL, clone);
}
else
! {
! 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
*************** clone_constructors_and_destructors (t)
*** 3995,4006 ****
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. */
--- 4021,4030 ----
if (!CLASSTYPE_METHOD_VEC (t))
return;
for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
clone_function_decl (OVL_CURRENT (fns), /*update_method_vec_p=*/1);
! 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. */
*************** create_vtable_ptr (t, empty_p, vfuns_p,
*** 4130,4136 ****
/* 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))
add_virtual_function (new_virtuals_p, overridden_virtuals_p,
vfuns_p, fn, t);
--- 4154,4161 ----
/* 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)
! && !(flag_new_abi && DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)))
add_virtual_function (new_virtuals_p, overridden_virtuals_p,
vfuns_p, fn, t);
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.589
diff -c -p -r1.589 decl.c
*** decl.c 2000/04/11 20:16:35 1.589
--- decl.c 2000/04/12 07:38:01
*************** typedef struct predefined_identifier
*** 6045,6050 ****
--- 6045,6052 ----
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. */
*************** initialize_predefined_identifiers ()
*** 6056,6085 ****
/* 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 }
};
for (pid = predefined_identifiers; pid->name; ++pid)
! *pid->node = get_identifier (pid->name);
}
/* Create the predefined scalar types of C,
--- 6058,6092 ----
/* A table of identifiers to create at startup. */
static predefined_identifier predefined_identifiers[] = {
! { "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,
*************** static void
*** 13811,13819 ****
finish_destructor_body ()
{
tree compound_stmt;
- tree in_charge;
tree virtual_size;
tree exprstmt;
/* Create a block to contain all the extra code. */
compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
--- 13818,13826 ----
finish_destructor_body ()
{
tree compound_stmt;
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);
*************** finish_destructor_body ()
*** 13831,13846 ****
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,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
0);
--- 13838,13846 ----
will set the flag again. */
TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
exprstmt = build_delete (current_class_type,
current_class_ref,
! integer_zero_node,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
0);
*************** finish_destructor_body ()
*** 13873,13880 ****
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)));
}
vbases = TREE_CHAIN (vbases);
}
--- 13873,13880 ----
TYPE_BINFO (current_class_type));
finish_expr_stmt
(build_scoped_method_call
! (current_class_ref, vb, complete_dtor_identifier,
! NULL_TREE));
}
vbases = TREE_CHAIN (vbases);
}
*************** finish_destructor_body ()
*** 13897,13921 ****
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);
- if_stmt = begin_if_stmt ();
- finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
- current_in_charge_parm,
- integer_one_node),
- if_stmt);
- 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);
}
--- 13897,13915 ----
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. */
! exprstmt = build_op_delete_call
! (DELETE_EXPR, current_class_ptr, virtual_size,
! LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
!
! if_stmt = begin_if_stmt ();
! finish_if_stmt_cond (build (BIT_AND_EXPR, integer_type_node,
! current_in_charge_parm,
! integer_one_node),
! if_stmt);
! 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);
}
*************** maybe_build_cleanup_1 (decl, auto_delete
*** 14557,14572 ****
return rval;
}
return 0;
- }
-
- /* 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
--- 14551,14556 ----
Index: except.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/except.c,v
retrieving revision 1.106
diff -c -p -r1.106 except.c
*** except.c 2000/03/19 18:25:26 1.106
--- except.c 2000/04/12 07:38:02
*************** expand_throw (exp)
*** 888,901 ****
/* First, decay it. */
exp = decay_conversion (exp);
! /* cleanup_type is void (*)(void *, int),
! the internal type of a destructor. */
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))));
if (TYPE_PTR_P (TREE_TYPE (exp)))
throw_type = build_eh_type_type (TREE_TYPE (exp));
--- 888,907 ----
/* First, decay it. */
exp = decay_conversion (exp);
! /* 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)
! {
! 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));
*************** expand_throw (exp)
*** 949,955 ****
if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
{
cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
! dtor_identifier, 0);
cleanup = TREE_VALUE (cleanup);
mark_used (cleanup);
mark_addressable (cleanup);
--- 955,964 ----
if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
{
cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
! (flag_new_abi
! ? complete_dtor_identifier
! : dtor_identifier),
! 0);
cleanup = TREE_VALUE (cleanup);
mark_used (cleanup);
mark_addressable (cleanup);
*************** expand_throw (exp)
*** 970,976 ****
TREE_TYPE (cleanup) = cleanup_type;
}
! fn = get_identifier ("__cp_push_exception");
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
--- 979,985 ----
TREE_TYPE (cleanup) = cleanup_type;
}
! fn = cp_push_exception_identifier;
if (IDENTIFIER_GLOBAL_VALUE (fn))
fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
Index: exception.cc
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/exception.cc,v
retrieving revision 1.31
diff -c -p -r1.31 exception.cc
*** exception.cc 2000/03/11 09:00:13 1.31
--- exception.cc 2000/04/12 07:38:02
*************** std::unexpected ()
*** 78,83 ****
--- 78,98 ----
__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().
*************** struct cp_eh_info
*** 90,96 ****
__eh_info eh_info;
void *value;
void *type;
! void (*cleanup)(void *, int);
bool caught;
cp_eh_info *next;
long handlers;
--- 105,111 ----
__eh_info eh_info;
void *value;
void *type;
! cleanup_fn cleanup;
bool caught;
cp_eh_info *next;
long handlers;
*************** __cplus_type_matcher (__eh_info *info_,
*** 202,208 ****
Used by expand_throw(). */
extern "C" void
! __cp_push_exception (void *value, void *type, void (*cleanup)(void *, int))
{
cp_eh_info *p = (cp_eh_info *) __eh_alloc (sizeof (cp_eh_info));
--- 217,223 ----
Used by expand_throw(). */
extern "C" void
! __cp_push_exception (void *value, void *type, cleanup_fn cleanup)
{
cp_eh_info *p = (cp_eh_info *) __eh_alloc (sizeof (cp_eh_info));
*************** __cp_pop_exception (cp_eh_info *p)
*** 251,258 ****
*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.
if (! __is_pointer (p->type))
__eh_free (p->original_value); // value may have been adjusted.
--- 266,273 ----
*q = p->next;
if (p->cleanup)
! // 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.
Index: init.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/init.c,v
retrieving revision 1.183
diff -c -p -r1.183 init.c
*** init.c 2000/04/11 16:56:13 1.183
--- init.c 2000/04/12 07:38:04
*************** expand_cleanup_for_base (binfo, flag)
*** 713,720 ****
/* Call the destructor. */
expr = (build_scoped_method_call
! (current_class_ref, binfo, dtor_identifier,
! build_tree_list (NULL_TREE, integer_zero_node)));
if (flag)
expr = fold (build (COND_EXPR, void_type_node,
truthvalue_conversion (flag),
--- 713,719 ----
/* Call the destructor. */
expr = (build_scoped_method_call
! (current_class_ref, binfo, base_dtor_identifier, NULL_TREE));
if (flag)
expr = fold (build (COND_EXPR, void_type_node,
truthvalue_conversion (flag),
*************** build_x_delete (addr, which_delete, virt
*** 2963,2968 ****
--- 2962,3030 ----
return build_op_delete_call (code, addr, virtual_size, flags, NULL_TREE);
}
+ tree
+ build_dtor_call (exp, in_charge, binfo, flags)
+ tree exp;
+ tree in_charge;
+ tree binfo;
+ 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.
*************** build_delete (type, addr, auto_delete, f
*** 3084,3093 ****
else
passed_auto_delete = auto_delete;
! expr = build_method_call
! (ref, dtor_identifier, build_tree_list (NULL_TREE, passed_auto_delete),
! NULL_TREE, flags);
!
if (do_delete)
expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
--- 3146,3152 ----
else
passed_auto_delete = auto_delete;
! expr = build_dtor_call (ref, passed_auto_delete, NULL_TREE, flags);
if (do_delete)
expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
*************** build_delete (type, addr, auto_delete, f
*** 3111,3118 ****
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. */
--- 3170,3175 ----
*************** build_delete (type, addr, auto_delete, f
*** 3120,3169 ****
/* 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);
! }
/* Take care of the remaining baseclasses. */
! for (i = 1; 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));
exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}
--- 3177,3195 ----
/* If we have member delete or vbases, we call delete in
finish_function. */
! my_friendly_assert (auto_delete == integer_zero_node, 20000411);
/* Take care of the remaining baseclasses. */
! 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,
! base_dtor_identifier,
! NULL_TREE);
exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
}
Index: optimize.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/optimize.c,v
retrieving revision 1.23
diff -c -p -r1.23 optimize.c
*** optimize.c 2000/04/11 20:16:35 1.23
--- optimize.c 2000/04/12 07:38:05
*************** maybe_clone_body (fn)
*** 804,813 ****
&& !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);
--- 804,809 ----
*************** maybe_clone_body (fn)
*** 850,861 ****
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);
--- 846,852 ----
if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1)
{
tree in_charge;
! 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);
Index: search.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/search.c,v
retrieving revision 1.172
diff -c -p -r1.172 search.c
*** search.c 2000/04/11 20:16:35 1.172
--- search.c 2000/04/12 07:38:07
*************** lookup_field_queue_p (binfo, data)
*** 1337,1343 ****
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)
return NULL_TREE;
/* If this base class is hidden by the best-known value so far, we
--- 1337,1343 ----
struct lookup_field_info *lfi = (struct lookup_field_info *) data;
/* Don't look for constructors or destructors in base classes. */
! 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