]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/55635 (Deallocation function ("operator delete") not called when destructor...
authorNathan Sidwell <nathan@acm.org>
Wed, 20 Apr 2016 19:59:56 +0000 (19:59 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Wed, 20 Apr 2016 19:59:56 +0000 (19:59 +0000)
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.

From-SVN: r235297

gcc/cp/ChangeLog
gcc/cp/init.c
gcc/cp/optimize.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/eh/delete1.C [new file with mode: 0644]

index 7cccddb3e4461ca016c733c9dc7c2f1dafdbca3f..50f3cc3bfd93f1fff5d99410eec21e2a9df49bb5 100644 (file)
@@ -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
index 5997d53ddb5503dd727c09f52026289f4b7f3772..4d19e46842ee4495aaea11199537c0ce55b049c0 100644 (file)
@@ -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)
index 6f80b3d6d842c8616477391bf8c0d3775ef101b8..e2032c1d90ef633111e5c81da7aab0fab0fae912 100644 (file)
@@ -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 ())
index 1bb941147ce855159683bf56c5a3d8822b1a3bc4..c767cd59ae7221f20128bb87863621108a1d3463 100644 (file)
@@ -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 (file)
index 0000000..43d7bc0
--- /dev/null
@@ -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;
+}