From b429d3ee1b1dc11f93cbcac2625e2054afd3be43 Mon Sep 17 00:00:00 2001 From: mmitchel Date: Wed, 14 Feb 2001 06:32:15 +0000 Subject: [PATCH] * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@39659 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 12 +++++ gcc/cp/call.c | 64 +++++++++++++------------- gcc/cp/class.c | 14 ++++-- gcc/cp/cp-tree.h | 2 +- gcc/cp/decl.c | 46 +++++++++--------- gcc/cp/init.c | 18 ++++++++ gcc/testsuite/g++.old-deja/g++.oliva/delete1.C | 4 +- 7 files changed, 96 insertions(+), 64 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 64deaaf338a..4dad89821ba 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2001-02-13 Mark Mitchell + + * 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 * lang-specs.h: Add more __EXCEPTIONS. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 7cb34bd1724..11cb6404054 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -3547,6 +3547,7 @@ build_op_delete_call (code, addr, size, flags, placement) int flags; { tree fn, fns, fnname, fntype, argtypes, args, type; + int pass; if (addr == error_mark_node) return error_mark_node; @@ -3595,48 +3596,45 @@ build_op_delete_call (code, addr, size, flags, placement) 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); diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 3f50da33108..2d8ab83dee2 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4319,10 +4319,16 @@ clone_function_decl (fn, update_method_vec_p) 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); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index eb7afc04ff5..7881429dadf 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1456,7 +1456,7 @@ struct lang_type #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)) diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index ead15dbdd76..3e3f37be89d 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -13730,9 +13730,7 @@ static void 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); @@ -13814,31 +13812,31 @@ finish_destructor_body () } } - 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); diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 4e68b645b73..becb347bc96 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -3235,6 +3235,9 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) 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. */ @@ -3243,6 +3246,21 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) 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) diff --git a/gcc/testsuite/g++.old-deja/g++.oliva/delete1.C b/gcc/testsuite/g++.old-deja/g++.oliva/delete1.C index dee7f219f2e..d8ddefec32e 100644 --- a/gcc/testsuite/g++.old-deja/g++.oliva/delete1.C +++ b/gcc/testsuite/g++.old-deja/g++.oliva/delete1.C @@ -1,6 +1,6 @@ // Build don't link: -// Copyright (C) 1999 Free Software Foundation +// Copyright (C) 1999, 2001 Free Software Foundation // by Alexandre Oliva // simplified from bug report by K. Haley @@ -21,7 +21,7 @@ struct bar : foo { 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 { -- 2.11.4.GIT