Patchwork C++ PATCH to synthesized_method_walk

login
register
mail settings
Submitter Jason Merrill
Date Sept. 6, 2010, 4:39 a.m.
Message ID <4C84707A.2050201@redhat.com>
Download mbox | patch
Permalink /patch/63871/
State New
Headers show

Comments

Jason Merrill - Sept. 6, 2010, 4:39 a.m.
My earlier overhaul of implicit declarations to actually do overload 
resolution forgot to consider that constructors need to call destructors 
to cleanup the partially constructed object in case something throws an 
exception.  This patch does that unless the constructor is trivial.

Tested x86_64-pc-linux-gnu, applied to trunk.

Patch

commit bb23019874834c4872a0f36bd2c8ee5256d7e86a
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Sep 6 00:15:56 2010 -0400

    	* method.c (synthesized_method_walk): In constructors, also check
    	subobject destructors.

diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 359e71d..0ec3826 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1052,10 +1052,15 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
   int i, quals, flags;
   tsubst_flags_t complain;
   const char *msg;
+  bool ctor_p;
+  tree cleanup_spec;
+  bool cleanup_trivial = true;
+  bool cleanup_deleted = false;
 
+  cleanup_spec
+    = (cxx_dialect >= cxx0x ? noexcept_true_spec : empty_except_spec);
   if (spec_p)
-    *spec_p = (cxx_dialect >= cxx0x
-	       ? noexcept_true_spec : empty_except_spec);
+    *spec_p = cleanup_spec;
 
   if (deleted_p)
     {
@@ -1109,6 +1114,7 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
     return;
 #endif
 
+  ctor_p = false;
   assign_p = false;
   check_vdtor = false;
   switch (sfk)
@@ -1129,6 +1135,7 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
     case sfk_constructor:
     case sfk_move_constructor:
     case sfk_copy_constructor:
+      ctor_p = true;
       fnname = complete_ctor_identifier;
       break;
 
@@ -1176,7 +1183,16 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
       rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
 
       process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
-			msg, BINFO_TYPE (base_binfo));
+			msg, basetype);
+      if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype))
+	{
+	  /* In a constructor we also need to check the subobject
+	     destructors for cleanup of partially constructed objects.  */
+	  rval = locate_fn_flags (base_binfo, complete_dtor_identifier,
+				  NULL_TREE, flags, complain);
+	  process_subob_fn (rval, false, &cleanup_spec, &cleanup_trivial,
+			    &cleanup_deleted, NULL, basetype);
+	}
 
       if (check_vdtor && type_has_virtual_destructor (basetype))
 	{
@@ -1186,6 +1202,7 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 	     to have a null rval (no class-specific op delete).  */
 	  if (rval && rval == error_mark_node && deleted_p)
 	    *deleted_p = true;
+	  check_vdtor = false;
 	}
     }
 
@@ -1206,12 +1223,20 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 	       "or trivial copy constructor");
       FOR_EACH_VEC_ELT (tree, vbases, i, base_binfo)
 	{
+	  tree basetype = BINFO_TYPE (base_binfo);
 	  if (copy_arg_p)
-	    argtype = build_stub_type (BINFO_TYPE (base_binfo), quals, move_p);
+	    argtype = build_stub_type (basetype, quals, move_p);
 	  rval = locate_fn_flags (base_binfo, fnname, argtype, flags, complain);
 
 	  process_subob_fn (rval, move_p, spec_p, trivial_p, deleted_p,
-			    msg, BINFO_TYPE (base_binfo));
+			    msg, basetype);
+	  if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype))
+	    {
+	      rval = locate_fn_flags (base_binfo, complete_dtor_identifier,
+				      NULL_TREE, flags, complain);
+	      process_subob_fn (rval, false, &cleanup_spec, &cleanup_trivial,
+				&cleanup_deleted, NULL, basetype);
+	    }
 	}
     }
   if (!diag)
@@ -1225,12 +1250,26 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
   walk_field_subobs (TYPE_FIELDS (ctype), fnname, sfk, quals,
 		     copy_arg_p, move_p, assign_p, spec_p, trivial_p,
 		     deleted_p, msg, flags, complain);
+  if (ctor_p)
+    walk_field_subobs (TYPE_FIELDS (ctype), complete_dtor_identifier,
+		       sfk_destructor, TYPE_UNQUALIFIED, false,
+		       false, false, &cleanup_spec, &cleanup_trivial,
+		       &cleanup_deleted, NULL, flags, complain);
 
   pop_scope (scope);
 
   --cp_unevaluated_operand;
   --c_inhibit_evaluation_warnings;
 
+  /* If the constructor isn't trivial, consider the subobject cleanups.  */
+  if (ctor_p && trivial_p && !*trivial_p)
+    {
+      if (deleted_p && cleanup_deleted)
+	*deleted_p = true;
+      if (spec_p)
+	*spec_p = merge_exception_specifiers (*spec_p, cleanup_spec);
+    }
+
 #ifdef ENABLE_CHECKING
   /* If we expected this to be trivial but it isn't, then either we're in
      C++0x mode and this is a copy/move ctor/op= or there's an error.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/implicit9.C b/gcc/testsuite/g++.dg/cpp0x/implicit9.C
new file mode 100644
index 0000000..3a6dbc5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/implicit9.C
@@ -0,0 +1,12 @@ 
+// Test that private base dtor makes derived ctor deleted
+// { dg-options -std=c++0x }
+
+struct A
+{
+  A();
+private:
+  ~A();				// { dg-error "private" }
+};
+
+struct B: A { };		// { dg-error "implicitly deleted|context" }
+B * b = new B;			// { dg-error "deleted" }