diff options
author | nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-04-20 19:59:56 +0000 |
---|---|---|
committer | nathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-04-20 19:59:56 +0000 |
commit | 2b073aa68143d9c2ce52cde0243eca27cae888d3 (patch) | |
tree | cc271a4402029d6096a19aed56d717400e6ea923 | |
parent | 8a574c111102d77e90033c3d2a94e071cd69c5fb (diff) | |
download | gcc-2b073aa68143d9c2ce52cde0243eca27cae888d3.tar.gz |
cp/
PR c++/55635
* init.c (build_vec_delete_1): Protect operator delete call in try
finally.
(build_delete): Likewise.
* optimize.c (build_delete_destructor_body): Likewise.
testsuite/
PR c++/55635
* g++.dg/eh/delete1.C: New.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@235297 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/cp/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/cp/init.c | 12 | ||||
-rw-r--r-- | gcc/cp/optimize.c | 24 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/eh/delete1.C | 79 |
5 files changed, 113 insertions, 15 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7cccddb3e44..50f3cc3bfd9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2016-04-20 Nathan Sidwell <nathan@acm.org> + + PR c++/55635 + * init.c (build_vec_delete_1): Protect operator delete call in try + finally. + (build_delete): Likewise. + * optimize.c (build_delete_destructor_body): Likewise. + 2016-04-20 Ilya Verbin <ilya.verbin@intel.com> PR c++/69363 diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 5997d53ddb5..4d19e46842e 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -3673,7 +3673,9 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, else if (!body) body = deallocate_expr; else - body = build_compound_expr (input_location, body, deallocate_expr); + /* The delete operator mist be called, even if a destructor + throws. */ + body = build2 (TRY_FINALLY_EXPR, void_type_node, body, deallocate_expr); if (!body) body = integer_zero_node; @@ -4510,7 +4512,13 @@ build_delete (tree otype, tree addr, special_function_kind auto_delete, if (expr == error_mark_node) return error_mark_node; if (do_delete) - expr = build2 (COMPOUND_EXPR, void_type_node, expr, do_delete); + /* The delete operator must be called, regardless of whether + the destructor throws. + + [expr.delete]/7 The deallocation function is called + regardless of whether the destructor for the object or some + element of the array throws an exception. */ + expr = build2 (TRY_FINALLY_EXPR, void_type_node, expr, do_delete); /* We need to calculate this before the dtor changes the vptr. */ if (head) diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index 6f80b3d6d84..e2032c1d90e 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -112,26 +112,24 @@ clone_body (tree clone, tree fn, void *arg_map) static void build_delete_destructor_body (tree delete_dtor, tree complete_dtor) { - tree call_dtor, call_delete; tree parm = DECL_ARGUMENTS (delete_dtor); tree virtual_size = cxx_sizeof (current_class_type); /* Call the corresponding complete destructor. */ gcc_assert (complete_dtor); - call_dtor = build_cxx_call (complete_dtor, 1, &parm, - tf_warning_or_error); - add_stmt (call_dtor); - - add_stmt (build_stmt (0, LABEL_EXPR, cdtor_label)); + tree call_dtor = build_cxx_call (complete_dtor, 1, &parm, + tf_warning_or_error); /* Call the delete function. */ - call_delete = build_op_delete_call (DELETE_EXPR, current_class_ptr, - virtual_size, - /*global_p=*/false, - /*placement=*/NULL_TREE, - /*alloc_fn=*/NULL_TREE, - tf_warning_or_error); - add_stmt (call_delete); + tree call_delete = build_op_delete_call (DELETE_EXPR, current_class_ptr, + virtual_size, + /*global_p=*/false, + /*placement=*/NULL_TREE, + /*alloc_fn=*/NULL_TREE, + tf_warning_or_error); + + /* Operator delete must be called, whether or not the dtor throws. */ + add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, call_dtor, call_delete)); /* Return the address of the object. */ if (targetm.cxx.cdtor_returns_this ()) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1bb941147ce..c767cd59ae7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-04-20 Nathan Sidwell <nathan@acm.org> + + PR c++/55635 + * g++.dg/eh/delete1.C: New. + 2016-04-20 H.J. Lu <hongjiu.lu@intel.com> * gcc.target/i386/avx256-unaligned-store-2.c: Add diff --git a/gcc/testsuite/g++.dg/eh/delete1.C b/gcc/testsuite/g++.dg/eh/delete1.C new file mode 100644 index 00000000000..43d7bc077f0 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/delete1.C @@ -0,0 +1,79 @@ +// { dg-do run } +// pr 55635, the delete operator must be called, regardless of whether +// the dtor throws + +static int deleted; + +void operator delete (void *) throw () +{ + deleted = 1; +} + +struct Foo { + ~Foo() throw(int) {throw 1;} +}; + +struct Baz { + void operator delete (void *) throw () + { + deleted = 2; + } + virtual ~Baz() throw(int) {throw 1;} +}; + +int non_virt () +{ + deleted = 0; + + Foo *p = new Foo; + try { delete p; } + catch (...) { return deleted != 1;} + return 1; +} + +int virt_glob () +{ + deleted = 0; + + Baz *p = ::new Baz; + try { ::delete p; } + catch (...) { return deleted != 1;} + return 1; +} + +int virt_del () +{ + deleted = 0; + + Baz *p = new Baz; + try { delete p; } + catch (...) { return deleted != 2;} + return 1; +} + +int ary () +{ + deleted = 0; + + Baz *p = new Baz[5]; + try { delete[] p; } + catch (...) { return deleted != 1;} + return 1; +} + +int main () +{ + if (non_virt ()) + return 1; + + if (virt_glob ()) + return 2; + + if (virt_del ()) + return 3; + + if (ary ()) + return 4; + + return 0; +} |