summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>2016-04-20 19:59:56 +0000
committernathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>2016-04-20 19:59:56 +0000
commit2b073aa68143d9c2ce52cde0243eca27cae888d3 (patch)
treecc271a4402029d6096a19aed56d717400e6ea923
parent8a574c111102d77e90033c3d2a94e071cd69c5fb (diff)
downloadgcc-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/ChangeLog8
-rw-r--r--gcc/cp/init.c12
-rw-r--r--gcc/cp/optimize.c24
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/g++.dg/eh/delete1.C79
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;
+}