summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>2000-04-12 07:48:13 +0000
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>2000-04-12 07:48:13 +0000
commitf04596da7acdf62fd10b7cc69bedc50e1e28fbf7 (patch)
tree1607e4b03e19e5a1a352f78d3cd7ac33ece46c16
parent9e9aeda163538477eb6c509185dda1078615cf64 (diff)
downloadppe42-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/ChangeLog37
-rw-r--r--gcc/cp/call.c55
-rw-r--r--gcc/cp/class.c41
-rw-r--r--gcc/cp/cp-tree.h32
-rw-r--r--gcc/cp/decl.c104
-rw-r--r--gcc/cp/except.c27
-rw-r--r--gcc/cp/exception.cc23
-rw-r--r--gcc/cp/init.c117
-rw-r--r--gcc/cp/optimize.c11
-rw-r--r--gcc/cp/search.c2
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
OpenPOWER on IntegriCloud