* cp-tree.h (CLASSTYPE_DESTRUCTORS): Fix typo in comment.
* call.c (build_op_delete_call): Simplify to remove duplicate
code.
* class.c (clone_function_decl): Don't build the deleting variant
of a non-virtual destructor.
* decl.c (finish_destructor_body): Don't call delete if this is a
non-virtual destructor.
* init.c (build_delete): Explicitly call `operator delete' when
deleting an object with a non-virtual destructor.
From-SVN: r39659
+2001-02-13 Mark Mitchell <mark@codesourcery.com>
+
+ * cp-tree.h (CLASSTYPE_DESTRUCTORS): Fix typo in comment.
+ * call.c (build_op_delete_call): Simplify to remove duplicate
+ code.
+ * class.c (clone_function_decl): Don't build the deleting variant
+ of a non-virtual destructor.
+ * decl.c (finish_destructor_body): Don't call delete if this is a
+ non-virtual destructor.
+ * init.c (build_delete): Explicitly call `operator delete' when
+ deleting an object with a non-virtual destructor.
+
2001-02-13 Jason Merrill <jason@redhat.com>
* lang-specs.h: Add more __EXCEPTIONS.
int flags;
{
tree fn, fns, fnname, fntype, argtypes, args, type;
+ int pass;
if (addr == error_mark_node)
return error_mark_node;
args = NULL_TREE;
}
- argtypes = tree_cons (NULL_TREE, ptr_type_node, argtypes);
- fntype = build_function_type (void_type_node, argtypes);
-
/* Strip const and volatile from addr. */
addr = cp_convert (ptr_type_node, addr);
- fn = instantiate_type (fntype, fns, itf_no_attributes);
-
- if (fn != error_mark_node)
+ /* We make two tries at finding a matching `operator delete'. On
+ the first pass, we look for an one-operator (or placement)
+ operator delete. If we're not doing placement delete, then on
+ the second pass we look for a two-argument delete. */
+ for (pass = 0; pass < (placement ? 1 : 2); ++pass)
{
- if (TREE_CODE (fns) == TREE_LIST)
- /* Member functions. */
- enforce_access (type, fn);
- return build_function_call (fn, tree_cons (NULL_TREE, addr, args));
- }
-
- /* If we are doing placement delete we do nothing if we don't find a
- matching op delete. */
- if (placement)
- return NULL_TREE;
+ if (pass == 0)
+ argtypes = tree_cons (NULL_TREE, ptr_type_node, argtypes);
+ else
+ /* Normal delete; now try to find a match including the size
+ argument. */
+ argtypes = tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, sizetype,
+ void_list_node));
- /* Normal delete; now try to find a match including the size argument. */
- argtypes = tree_cons (NULL_TREE, ptr_type_node,
- tree_cons (NULL_TREE, sizetype, void_list_node));
- fntype = build_function_type (void_type_node, argtypes);
+ fntype = build_function_type (void_type_node, argtypes);
+ fn = instantiate_type (fntype, fns, itf_no_attributes);
- fn = instantiate_type (fntype, fns, itf_no_attributes);
+ if (fn != error_mark_node)
+ {
+ /* Member functions. */
+ if (BASELINK_P (fns))
+ enforce_access (type, fn);
- if (fn != error_mark_node)
- {
- if (BASELINK_P (fns))
- /* Member functions. */
- enforce_access (type, fn);
- return build_function_call
- (fn, tree_cons (NULL_TREE, addr,
- build_tree_list (NULL_TREE, size)));
+ if (pass == 0)
+ args = tree_cons (NULL_TREE, addr, args);
+ else
+ args = tree_cons (NULL_TREE, addr,
+ build_tree_list (NULL_TREE, size));
+ return build_function_call (fn, args);
+ }
}
- /* finish_function passes LOOKUP_SPECULATIVELY if we're in a
- destructor, in which case the error should be deferred
- until someone actually tries to delete one of these. */
- if (flags & LOOKUP_SPECULATIVELY)
+ /* If we are doing placement delete we do nothing if we don't find a
+ matching op delete. */
+ if (placement)
return NULL_TREE;
cp_error ("no suitable `operator delete' for `%T'", type);
version. We clone the deleting version first because that
means it will go second on the TYPE_METHODS list -- and that
corresponds to the correct layout order in the virtual
- function table. */
- clone = build_clone (fn, deleting_dtor_identifier);
- if (update_method_vec_p)
- add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+ function table.
+
+ For a non-virtual destructor, we do not build a deleting
+ destructor. */
+ if (DECL_VIRTUAL_P (fn))
+ {
+ clone = build_clone (fn, deleting_dtor_identifier);
+ if (update_method_vec_p)
+ add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
+ }
clone = build_clone (fn, complete_dtor_identifier);
if (update_method_vec_p)
add_method (DECL_CONTEXT (clone), clone, /*error_p=*/0);
#define CLASSTYPE_CONSTRUCTORS(NODE) \
(TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (NODE), CLASSTYPE_CONSTRUCTOR_SLOT))
-/* A FUNCTION_DECL for the destructor for NODE. These are te
+/* A FUNCTION_DECL for the destructor for NODE. These are the
destructors that take an in-charge parameter. */
#define CLASSTYPE_DESTRUCTORS(NODE) \
(TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (NODE), CLASSTYPE_DESTRUCTOR_SLOT))
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);
}
}
- virtual_size = c_sizeof (current_class_type);
-
- /* At the end, call delete if that's what's requested. */
+ /* In a virtual destructor, we must call delete. */
+ if (DECL_VIRTUAL_P (current_function_decl))
+ {
+ tree if_stmt;
+ tree virtual_size = c_sizeof (current_class_type);
- /* FDIS sez: At the point of definition of a virtual destructor
- (including an implicit definition), non-placement operator delete
- shall be looked up in the scope of the destructor's class and if
- found shall be accessible and unambiguous.
+ /* [class.dtor]
- This is somewhat unclear, but I take it to mean that if the class
- 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);
+ At the point of definition of a virtual destructor (including
+ an implicit definition), non-placement operator delete shall
+ be looked up in the scope of the destructor's class and if
+ found shall be accessible and unambiguous. */
+ 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 ();
+ 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);
tree do_delete = NULL_TREE;
tree ifexp;
+ /* For `::delete x', we must not use the deleting destructor
+ since then we would not be sure to get the global `operator
+ delete'. */
if (use_global_delete && auto_delete == sfk_deleting_destructor)
{
/* Delete the object. */
call. */
auto_delete = sfk_complete_destructor;
}
+ /* If the destructor is non-virtual, there is no deleting
+ variant. Instead, we must explicitly call the appropriate
+ `operator delete' here. */
+ else if (!DECL_VIRTUAL_P (CLASSTYPE_DESTRUCTORS (type))
+ && auto_delete == sfk_deleting_destructor)
+ {
+ /* Buidl the call. */
+ do_delete = build_op_delete_call (DELETE_EXPR,
+ addr,
+ c_sizeof_nowarn (type),
+ LOOKUP_NORMAL,
+ NULL_TREE);
+ /* Call the complete object destructor. */
+ auto_delete = sfk_complete_destructor;
+ }
expr = build_dtor_call (ref, auto_delete, flags);
if (do_delete)
// Build don't link:
-// Copyright (C) 1999 Free Software Foundation
+// Copyright (C) 1999, 2001 Free Software Foundation
// by Alexandre Oliva <oliva@dcc.unicamp.br>
// simplified from bug report by K. Haley <khaley@bigfoot.com>
delete this; // ERROR - delete is private
// An implicit invocation of delete is emitted in destructors, but
// it should only be checked in virtual destructors
- } // gets bogus error - not virtual - XFAIL *-*-*
+ } // gets bogus error - not virtual
} bar_;
struct baz : foo {