diff options
author | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-04-12 07:48:13 +0000 |
---|---|---|
committer | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-04-12 07:48:13 +0000 |
commit | f04596da7acdf62fd10b7cc69bedc50e1e28fbf7 (patch) | |
tree | 1607e4b03e19e5a1a352f78d3cd7ac33ece46c16 | |
parent | 9e9aeda163538477eb6c509185dda1078615cf64 (diff) | |
download | ppe42-gcc-f04596da7acdf62fd10b7cc69bedc50e1e28fbf7.tar.gz ppe42-gcc-f04596da7acdf62fd10b7cc69bedc50e1e28fbf7.zip |
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@33096 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/cp/ChangeLog | 37 | ||||
-rw-r--r-- | gcc/cp/call.c | 55 | ||||
-rw-r--r-- | gcc/cp/class.c | 41 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 32 | ||||
-rw-r--r-- | gcc/cp/decl.c | 104 | ||||
-rw-r--r-- | gcc/cp/except.c | 27 | ||||
-rw-r--r-- | gcc/cp/exception.cc | 23 | ||||
-rw-r--r-- | gcc/cp/init.c | 117 | ||||
-rw-r--r-- | gcc/cp/optimize.c | 11 | ||||
-rw-r--r-- | gcc/cp/search.c | 2 |
10 files changed, 295 insertions, 154 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 18f252d2bf9..8ebc5ae217f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,40 @@ +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. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index c0032488e9b..1ffbf60290e 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index d954ac0b736..f0a84f83221 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index db6a41c7c3a..a0e6d8a49bc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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) \ @@ -3761,7 +3789,8 @@ extern void unreverse_member_declarations PARAMS ((tree)); 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 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)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 6b490a65131..cfb4618dc6e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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); + { + *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,24 +13897,18 @@ 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); - - 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 (); - } + 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); @@ -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 diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 8e32659a302..dba1466eea0 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -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 diff --git a/gcc/cp/exception.cc b/gcc/cp/exception.cc index b7d6a64b2ae..3f61b3ed66a 100644 --- a/gcc/cp/exception.cc +++ b/gcc/cp/exception.cc @@ -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. diff --git a/gcc/cp/init.c b/gcc/cp/init.c index d94c69c635b..11549c24a7a 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -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); } diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index 9f2fe35ac66..5c78950af35 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -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); diff --git a/gcc/cp/search.c b/gcc/cp/search.c index 7ca43b3e67d..197a6adaf8e 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -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 |