The standard says that whether an implicitly defined constructor is deleted depends on whether "any potentially constructed subobject has a type with a destructor that is deleted or inaccessible from the defaulted default constructor", but it does not say the same about triviality, nor that it is considered in deciding whether a union constructor is deleted. So when we're walking subobjects we need to limit the effect of a destructor considered from a constructor.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 5a920efa41b717560b8f7ac45ebcd3c474cfac00
Author: Jason Merrill <ja...@redhat.com>
Date:   Fri Jan 8 17:54:23 2016 -0500

    	PR c++/69131
    	* method.c (walk_field_subobs): Add dtor_from_ctor parm.
    	(process_subob_fn): Likewise.  Don't consider triviality if true.
    	(synthesize_method_walk): Pass it.

diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index bcf0a6c..2af1ed2 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1097,7 +1097,7 @@ is_trivially_xible (enum tree_code code, tree to, tree from)
 static void
 process_subob_fn (tree fn, tree *spec_p, bool *trivial_p,
 		  bool *deleted_p, bool *constexpr_p,
-		  bool diag, tree arg)
+		  bool diag, tree arg, bool dtor_from_ctor = false)
 {
   if (!fn || fn == error_mark_node)
     goto bad;
@@ -1109,7 +1109,7 @@ process_subob_fn (tree fn, tree *spec_p, bool *trivial_p,
       *spec_p = merge_exception_specifiers (*spec_p, raises);
     }
 
-  if (!trivial_fn_p (fn))
+  if (!trivial_fn_p (fn) && !dtor_from_ctor)
     {
       if (trivial_p)
 	*trivial_p = false;
@@ -1142,14 +1142,17 @@ process_subob_fn (tree fn, tree *spec_p, bool *trivial_p,
 }
 
 /* Subroutine of synthesized_method_walk to allow recursion into anonymous
-   aggregates.  */
+   aggregates.  If DTOR_FROM_CTOR is true, we're walking subobject destructors
+   called from a synthesized constructor, in which case we don't consider
+   the triviality of the subobject destructor.  */
 
 static void
 walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
 		   int quals, bool copy_arg_p, bool move_p,
 		   bool assign_p, tree *spec_p, bool *trivial_p,
 		   bool *deleted_p, bool *constexpr_p,
-		   bool diag, int flags, tsubst_flags_t complain)
+		   bool diag, int flags, tsubst_flags_t complain,
+		   bool dtor_from_ctor = false)
 {
   tree field;
   for (field = fields; field; field = DECL_CHAIN (field))
@@ -1285,7 +1288,7 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
       rval = locate_fn_flags (mem_type, fnname, argtype, flags, complain);
 
       process_subob_fn (rval, spec_p, trivial_p, deleted_p,
-			constexpr_p, diag, field);
+			constexpr_p, diag, field, dtor_from_ctor);
     }
 }
 
@@ -1515,7 +1518,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 				      NULL_TREE, flags, complain);
 	      process_subob_fn (rval, NULL, NULL,
 				deleted_p, NULL, false,
-				basetype);
+				basetype, /*dtor_from_ctor*/true);
 	    }
 	}
     }
@@ -1530,7 +1533,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 		       sfk_destructor, TYPE_UNQUALIFIED, false,
 		       false, false, NULL, NULL,
 		       deleted_p, NULL,
-		       false, flags, complain);
+		       false, flags, complain, /*dtor_from_ctor*/true);
 
   pop_scope (scope);
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/union7.C b/gcc/testsuite/g++.dg/cpp0x/union7.C
new file mode 100644
index 0000000..c42d217
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/union7.C
@@ -0,0 +1,15 @@
+// PR c++/69131
+// { dg-do compile { target c++11 } }
+
+struct X
+{
+  ~X() {}
+};
+
+union U
+{
+  X x;
+  ~U() {}
+};
+
+U u;

Reply via email to