diff mbox

C++ PATCH to deal with trivial but non-callable [cd]tors

Message ID 52680FD9.7040302@redhat.com
State New
Headers show

Commit Message

Jason Merrill Oct. 23, 2013, 6:05 p.m. UTC
Late in the C++11 process it was decided that a constructor or 
destructor can be trivial but not callable; as a result, everywhere that 
assumed that a call to a trivial function didn't need any processing 
needed to be updated.  This patch does that.

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

Comments

Paolo Carlini Oct. 23, 2013, 6:12 p.m. UTC | #1
On 10/23/2013 08:05 PM, Jason Merrill wrote:
> @@ -4674,15 +4674,8 @@ deduce_noexcept_on_destructors (tree t)
>     if (!CLASSTYPE_METHOD_VEC (t))
>       return;
>   
> -  bool saved_nontrivial_dtor = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t);
> -
> -  /* Avoid early exit from synthesized_method_walk (c++/57645).  */
> -  TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = true;
> -
>     for (tree fns = CLASSTYPE_DESTRUCTORS (t); fns; fns = OVL_NEXT (fns))
>       deduce_noexcept_on_destructor (OVL_CURRENT (fns));
> -
> -  TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = saved_nontrivial_dtor;
>   }
>   
>   /* Subroutine of set_one_vmethod_tm_attributes.  Search base classes
Cool.

Paolo.
Eric Botcazou Oct. 25, 2013, 5:53 p.m. UTC | #2
> Late in the C++11 process it was decided that a constructor or
> destructor can be trivial but not callable; as a result, everywhere that
> assumed that a call to a trivial function didn't need any processing
> needed to be updated.  This patch does that.

This has introduced a problem for the -fdump-ada-spec machinery, which boils 
down to the TYPE_METHODS field of the following structure:

 struct _outer {
   struct _inner {
     int x;
   } inner;
 } outer;

Previously it was empty, now it contains the following destructor:

 <function_decl 0x7ffff6c6e300 _outer
    type <method_type 0x7ffff6c6d2a0
        type <void_type 0x7ffff6b0ebd0 void VOID
            align 8 symtab 0 alias set -1 canonical type 0x7ffff6b0ebd0
            pointer_to_this <pointer_type 0x7ffff6b0ec78>>
        QI
        size <integer_cst 0x7ffff6b04280 constant 8>
        unit size <integer_cst 0x7ffff6b042a0 constant 1>
        align 8 symtab 0 alias set -1 canonical type 0x7ffff6c6d1f8 method 
basetype <record_type 0x7ffff6c5c930 _outer>
        arg-types <tree_list 0x7ffff6c52fa0 value <pointer_type 
0x7ffff6c5cc78>
            chain <tree_list 0x7ffff6c52f78 value <integer_type 0x7ffff6b0e5e8 
int>
                chain <tree_list 0x7ffff6b00b18 value <void_type 
0x7ffff6b0ebd0 void>>>>
        throws <tree_list 0x7ffff6c527a8>>
    public abstract external autoinline decl_3 QI file t5.h line 1 col 9 align 
16 context <record_type 0x7ffff6c5c930 _outer>
    arguments <parm_decl 0x7ffff6c6c480 this
[...]
   full-name "_outer::~_outer() throw ()"
    not-really-extern chain <function_decl 0x7ffff6c6e500 __base_dtor >>


The destructor is created as a side effect of the call to type_build_dtor_call 
added to cxx_maybe_build_cleanup by the patch:

@@ -14296,7 +14300,7 @@ cxx_maybe_build_cleanup (tree decl, tsub
     }
   /* Handle ordinary C++ destructors.  */
   type = TREE_TYPE (decl);
-  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+  if (type_build_dtor_call (type))
     {
       int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
       bool has_vbases = (TREE_CODE (type) == RECORD_TYPE

#0  implicitly_declare_fn (kind=sfk_destructor, type=0x7ffff6c5c930, 
    const_p=false, inherited_ctor=0x0, inherited_parms=0x0)
    at /home/eric/gnat/gnat-head/src/gcc/cp/method.c:1551
#1  0x0000000000758ef5 in lazily_declare_fn (sfk=sfk_destructor, 
    type=0x7ffff6c5c930) at /home/eric/gnat/gnat-head/src/gcc/cp/method.c:1950
#2  0x000000000075ee64 in lookup_fnfields_1 (type=0x7ffff6c5c930, 
    name=0x7ffff6b0aec8) at /home/eric/gnat/gnat-head/src/gcc/cp/search.c:1471
#3  0x000000000075eea5 in lookup_fnfields_slot (type=0x7ffff6c5c930, 
    name=0x7ffff6b0aec8) at /home/eric/gnat/gnat-head/src/gcc/cp/search.c:1483
#4  0x0000000000687dc7 in type_build_dtor_call (t=0x7ffff6c5c930)
    at /home/eric/gnat/gnat-head/src/gcc/cp/class.c:5193
#5  0x00000000005ef967 in cxx_maybe_build_cleanup (decl=0x7ffff6c64390, 
    complain=3) at /home/eric/gnat/gnat-head/src/gcc/cp/decl.c:14303
#6  0x00000000005c99aa in expand_static_init (decl=0x7ffff6c64390, init=0x0)
    at /home/eric/gnat/gnat-head/src/gcc/cp/decl.c:6902
#7  0x00000000005c8d6c in cp_finish_decl (decl=0x7ffff6c64390, init=0x0, 
    init_const_expr_p=false, asmspec_tree=0x0, flags=1)
    at /home/eric/gnat/gnat-head/src/gcc/cp/decl.c:6504
#8  0x00000000006e22b5 in cp_parser_init_declarator (parser=0x7ffff6c5b068, 
    decl_specifiers=0x7fffffffda00, checks=0x0, 
    function_definition_allowed_p=true, member_p=false, 
    declares_class_or_enum=2, function_definition_p=0x7fffffffda8b, 
    maybe_range_for_decl=0x0)
    at /home/eric/gnat/gnat-head/src/gcc/cp/parser.c:16640


Is that expected and, consequently, should we adjust the machinery?
Jason Merrill Oct. 25, 2013, 7:04 p.m. UTC | #3
On 10/25/2013 01:53 PM, Eric Botcazou wrote:
> This has introduced a problem for the -fdump-ada-spec machinery, which boils
> down to the TYPE_METHODS field of the following structure:
>
>   struct _outer {
>     struct _inner {
>       int x;
>     } inner;
>   } outer;
>
> Previously it was empty, now it contains the following destructor:
>[snip]
> Is that expected and, consequently, should we adjust the machinery?

In C++ all classes have destructors, but we try to defer building the 
implicit declaration.  My patch causes us to build those implicit 
declarations more often, which is probably a bit of a memory regression, 
but it would be good for your code to handle the dtor being declared.

Jason
diff mbox

Patch

commit cbc14ce6b840e6311b8c580564f8c836f8dc18ae
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Oct 22 16:38:01 2013 -0400

    	In C++11 a trivial [cd]tor might not be callable.
    	* class.c (user_provided_p): A function deleted on its declation
    	in the class is not user-provided.
    	(type_build_ctor_call): Also force a ctor call if we
    	might have a deleted or private trivial ctor.
    	(type_build_dtor_call): New.
    	(deduce_noexcept_on_destructors): Remove obsolete code.
    	* cp-tree.h: Declare type_build_dtor_call.
    	* decl.c (expand_static_init): Make sure trivial dtors are callable.
    	(cxx_maybe_build_cleanup): Likewise.
    	* except.c (build_throw): Likewise.
    	* init.c (build_value_init): Handle trivial but not callable ctors.
    	(perform_target_ctor): Make sure trivial dtor is callable.
    	(perform_member_init): Likewise.
    	(expand_cleanup_for_base): Likewise.
    	(build_vec_delete_1): Likewise.
    	(build_delete): Likewise.
    	(push_base_cleanups): Likewise.
    	(build_new_1): Avoid redundant error.
    	* method.c (synthesized_method_walk): Can't ever exit early in C++11.
    	Always process the subobject destructor.
    	* semantics.c (finish_compound_literal): Make sure trivial dtor is
    	callable.
    	* typeck2.c (split_nonconstant_init): Likewise.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 3ed73b8..cd90140 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -9273,6 +9273,9 @@  set_up_extended_ref_temp (tree decl, tree expr, vec<tree, va_gc> **cleanups,
 	    static_aggregates = tree_cons (NULL_TREE, var,
 					   static_aggregates);
 	}
+      else
+	/* Check whether the dtor is callable.  */
+	cxx_maybe_build_cleanup (var, tf_warning_or_error);
     }
 
   *initp = init;
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index c587e55..43f90d7 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4674,15 +4674,8 @@  deduce_noexcept_on_destructors (tree t)
   if (!CLASSTYPE_METHOD_VEC (t))
     return;
 
-  bool saved_nontrivial_dtor = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t);
-
-  /* Avoid early exit from synthesized_method_walk (c++/57645).  */
-  TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = true;
-
   for (tree fns = CLASSTYPE_DESTRUCTORS (t); fns; fns = OVL_NEXT (fns))
     deduce_noexcept_on_destructor (OVL_CURRENT (fns));
-
-  TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = saved_nontrivial_dtor;
 }
 
 /* Subroutine of set_one_vmethod_tm_attributes.  Search base classes
@@ -4884,7 +4877,8 @@  user_provided_p (tree fn)
     return true;
   else
     return (!DECL_ARTIFICIAL (fn)
-	    && !DECL_DEFAULTED_IN_CLASS_P (fn));
+	    && !(DECL_INITIALIZED_IN_CLASS_P (fn)
+		 && (DECL_DEFAULTED_FN (fn) || DECL_DELETED_FN (fn))));
 }
 
 /* Returns true iff class T has a user-provided constructor.  */
@@ -5149,7 +5143,7 @@  type_has_user_declared_move_assign (tree t)
 }
 
 /* Nonzero if we need to build up a constructor call when initializing an
-   object of this class, either because it has a user-provided constructor
+   object of this class, either because it has a user-declared constructor
    or because it doesn't have a default constructor (so we need to give an
    error if no initializer is provided).  Use TYPE_NEEDS_CONSTRUCTING when
    what you care about is whether or not an object can be produced by a
@@ -5165,8 +5159,46 @@  type_build_ctor_call (tree t)
   if (TYPE_NEEDS_CONSTRUCTING (t))
     return true;
   inner = strip_array_types (t);
-  return (CLASS_TYPE_P (inner) && !TYPE_HAS_DEFAULT_CONSTRUCTOR (inner)
-	  && !ANON_AGGR_TYPE_P (inner));
+  if (!CLASS_TYPE_P (inner) || ANON_AGGR_TYPE_P (inner))
+    return false;
+  if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (inner))
+    return true;
+  /* A user-declared constructor might be private, and a constructor might
+     be trivial but deleted.  */
+  for (tree fns = lookup_fnfields_slot (inner, complete_ctor_identifier);
+       fns; fns = OVL_NEXT (fns))
+    {
+      tree fn = OVL_CURRENT (fns);
+      if (!DECL_ARTIFICIAL (fn)
+	  || DECL_DELETED_FN (fn))
+	return true;
+    }
+  return false;
+}
+
+/* Like type_build_ctor_call, but for destructors.  */
+
+bool
+type_build_dtor_call (tree t)
+{
+  tree inner;
+  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
+    return true;
+  inner = strip_array_types (t);
+  if (!CLASS_TYPE_P (inner) || ANON_AGGR_TYPE_P (inner)
+      || !COMPLETE_TYPE_P (inner))
+    return false;
+  /* A user-declared destructor might be private, and a destructor might
+     be trivial but deleted.  */
+  for (tree fns = lookup_fnfields_slot (inner, complete_dtor_identifier);
+       fns; fns = OVL_NEXT (fns))
+    {
+      tree fn = OVL_CURRENT (fns);
+      if (!DECL_ARTIFICIAL (fn)
+	  || DECL_DELETED_FN (fn))
+	return true;
+    }
+  return false;
 }
 
 /* Remove all zero-width bit-fields from T.  */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b1347e2..507b389 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5115,6 +5115,7 @@  extern bool type_has_move_assign		(tree);
 extern bool type_has_user_declared_move_constructor (tree);
 extern bool type_has_user_declared_move_assign(tree);
 extern bool type_build_ctor_call		(tree);
+extern bool type_build_dtor_call		(tree);
 extern void explain_non_literal_class		(tree);
 extern void defaulted_late_check		(tree);
 extern bool defaultable_fn_check		(tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index fe8fe4e..1e92f2a 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6897,7 +6897,11 @@  expand_static_init (tree decl, tree init)
   /* Some variables require no dynamic initialization.  */
   if (!init
       && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
-    return;
+    {
+      /* Make sure the destructor is callable.  */
+      cxx_maybe_build_cleanup (decl, tf_warning_or_error);
+      return;
+    }
 
   if (DECL_THREAD_LOCAL_P (decl) && DECL_GNU_TLS_P (decl)
       && !DECL_FUNCTION_SCOPE_P (decl))
@@ -14296,7 +14300,7 @@  cxx_maybe_build_cleanup (tree decl, tsubst_flags_t complain)
     }
   /* Handle ordinary C++ destructors.  */
   type = TREE_TYPE (decl);
-  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+  if (type_build_dtor_call (type))
     {
       int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
       bool has_vbases = (TREE_CODE (type) == RECORD_TYPE
@@ -14317,6 +14321,8 @@  cxx_maybe_build_cleanup (tree decl, tsubst_flags_t complain)
 			   sfk_complete_destructor, flags, 0, complain);
       if (call == error_mark_node)
 	cleanup = error_mark_node;
+      else if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
+	/* Discard the call.  */;
       else if (cleanup)
 	cleanup = cp_build_compound_expr (cleanup, call, complain);
       else
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index c76d944..daac0fd 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -868,17 +868,21 @@  build_throw (tree exp)
 
       throw_type = build_eh_type_type (prepare_eh_type (TREE_TYPE (object)));
 
-      if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object)))
+      cleanup = NULL_TREE;
+      if (type_build_dtor_call (TREE_TYPE (object)))
 	{
-	  cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
+	  tree fn = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
 				     complete_dtor_identifier, 0);
-	  cleanup = BASELINK_FUNCTIONS (cleanup);
-	  mark_used (cleanup);
-	  cxx_mark_addressable (cleanup);
-	  /* Pretend it's a normal function.  */
-	  cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
+	  fn = BASELINK_FUNCTIONS (fn);
+	  mark_used (fn);
+	  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (object)))
+	    {
+	      cxx_mark_addressable (fn);
+	      /* Pretend it's a normal function.  */
+	      cleanup = build1 (ADDR_EXPR, cleanup_type, fn);
+	    }
 	}
-      else
+      if (cleanup == NULL_TREE)
 	cleanup = build_int_cst (cleanup_type, 0);
 
       /* ??? Indicate that this function call throws throw_type.  */
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index d18dc5e..78ea986 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -312,60 +312,55 @@  build_value_init (tree type, tsubst_flags_t complain)
 
      To value-initialize an object of type T means:
 
-     - if T is a class type (clause 9) with a user-provided constructor
-       (12.1), then the default constructor for T is called (and the
-       initialization is ill-formed if T has no accessible default
-       constructor);
+     - if T is a class type (clause 9) with either no default constructor
+       (12.1) or a default constructor that is user-provided or deleted,
+       then then the object is default-initialized;
 
-     - if T is a non-union class type without a user-provided constructor,
-       then every non-static data member and base-class component of T is
-       value-initialized;92)
+     - if T is a (possibly cv-qualified) class type without a user-provided
+       or deleted default constructor, then the object is zero-initialized
+       and the semantic constraints for default-initialization are checked,
+       and if T has a non-trivial default constructor, the object is
+       default-initialized;
 
      - if T is an array type, then each element is value-initialized;
 
      - otherwise, the object is zero-initialized.
 
      A program that calls for default-initialization or
-     value-initialization of an entity of reference type is ill-formed.
-
-     92) Value-initialization for such a class object may be implemented by
-     zero-initializing the object and then calling the default
-     constructor.  */
+     value-initialization of an entity of reference type is ill-formed.  */
 
   /* The AGGR_INIT_EXPR tweaking below breaks in templates.  */
   gcc_assert (!processing_template_decl
 	      || (SCALAR_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE));
 
-  if (CLASS_TYPE_P (type))
+  if (type_build_ctor_call (type))
     {
-      /* Instead of the above, only consider the user-providedness of the
-	 default constructor itself so value-initializing a class with an
-	 explicitly defaulted default constructor and another user-provided
-	 constructor works properly (c++std-core-19883).  */
-      if (type_has_user_provided_default_constructor (type)
-	  || (!TYPE_HAS_DEFAULT_CONSTRUCTOR (type)
-	      && type_has_user_provided_constructor (type)))
-	return build_aggr_init_expr
-	  (type,
-	   build_special_member_call (NULL_TREE, complete_ctor_identifier,
-				      NULL, type, LOOKUP_NORMAL,
-				      complain));
+      tree ctor = build_aggr_init_expr
+	(type,
+	 build_special_member_call (NULL_TREE, complete_ctor_identifier,
+				    NULL, type, LOOKUP_NORMAL,
+				    complain));
+      if (ctor == error_mark_node
+	  || type_has_user_provided_default_constructor (type))
+	return ctor;
       else if (TYPE_HAS_COMPLEX_DFLT (type))
 	{
 	  /* This is a class that needs constructing, but doesn't have
 	     a user-provided constructor.  So we need to zero-initialize
 	     the object and then call the implicitly defined ctor.
 	     This will be handled in simplify_aggr_init_expr.  */
-	  tree ctor = build_special_member_call
-	    (NULL_TREE, complete_ctor_identifier,
-	     NULL, type, LOOKUP_NORMAL, complain);
-	  ctor = build_aggr_init_expr (type, ctor);
-	  if (ctor != error_mark_node)
-	    AGGR_INIT_ZERO_FIRST (ctor) = 1;
+	  AGGR_INIT_ZERO_FIRST (ctor) = 1;
 	  return ctor;
 	}
     }
-  return build_value_init_noctor (type, complain);
+
+  /* Discard any access checking during subobject initialization;
+     the checks are implied by the call to the ctor which we have
+     verified is OK (cpp0x/defaulted46.C).  */
+  push_deferring_access_checks (dk_deferred);
+  tree r = build_value_init_noctor (type, complain);
+  pop_deferring_access_checks ();
+  return r;
 }
 
 /* Like build_value_init, but don't call the constructor for TYPE.  Used
@@ -503,14 +498,15 @@  perform_target_ctor (tree init)
   finish_expr_stmt (build_aggr_init (decl, init,
 				     LOOKUP_NORMAL|LOOKUP_DELEGATING_CONS,
 				     tf_warning_or_error));
-  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+  if (type_build_dtor_call (type))
     {
       tree expr = build_delete (type, decl, sfk_complete_destructor,
 				LOOKUP_NORMAL
 				|LOOKUP_NONVIRTUAL
 				|LOOKUP_DESTRUCTOR,
 				0, tf_warning_or_error);
-      if (expr != error_mark_node)
+      if (expr != error_mark_node
+	  && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
 	finish_eh_cleanup (expr);
     }
 }
@@ -732,7 +728,7 @@  perform_member_init (tree member, tree init)
 						tf_warning_or_error));
     }
 
-  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+  if (type_build_dtor_call (type))
     {
       tree expr;
 
@@ -744,7 +740,8 @@  perform_member_init (tree member, tree init)
 			   LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0,
 			   tf_warning_or_error);
 
-      if (expr != error_mark_node)
+      if (expr != error_mark_node
+	  && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
 	finish_eh_cleanup (expr);
     }
 }
@@ -1192,7 +1189,7 @@  expand_cleanup_for_base (tree binfo, tree flag)
 {
   tree expr;
 
-  if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (binfo)))
+  if (!type_build_dtor_call (BINFO_TYPE (binfo)))
     return;
 
   /* Call the destructor.  */
@@ -1202,6 +1199,10 @@  expand_cleanup_for_base (tree binfo, tree flag)
 				    binfo,
 				    LOOKUP_NORMAL | LOOKUP_NONVIRTUAL,
                                     tf_warning_or_error);
+
+  if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (binfo)))
+    return;
+
   if (flag)
     expr = fold_build3_loc (input_location,
 			COND_EXPR, void_type_node,
@@ -2360,7 +2361,7 @@  build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
 
   is_initialized = (type_build_ctor_call (elt_type) || *init != NULL);
 
-  if (*init == NULL)
+  if (*init == NULL && cxx_dialect < cxx11)
     {
       bool maybe_uninitialized_error = false;
       /* A program that calls for default-initialization [...] of an
@@ -3152,8 +3153,21 @@  build_vec_delete_1 (tree base, tree maxindex, tree type,
 
   size_exp = size_in_bytes (type);
 
-  if (! MAYBE_CLASS_TYPE_P (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
+  if (! MAYBE_CLASS_TYPE_P (type))
     goto no_destructor;
+  else if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
+    {
+      /* Make sure the destructor is callable.  */
+      if (type_build_dtor_call (type))
+	{
+	  tmp = build_delete (ptype, base, sfk_complete_destructor,
+			      LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1,
+			      complain);
+	  if (tmp == error_mark_node)
+	    return error_mark_node;
+	}
+      goto no_destructor;
+    }
 
   /* The below is short by the cookie size.  */
   virtual_size = size_binop (MULT_EXPR, size_exp,
@@ -3829,7 +3843,7 @@  build_dtor_call (tree exp, special_function_kind dtor_kind, int flags,
    flags.  See cp-tree.h for more info.  */
 
 tree
-build_delete (tree type, tree addr, special_function_kind auto_delete,
+build_delete (tree otype, tree addr, special_function_kind auto_delete,
 	      int flags, int use_global_delete, tsubst_flags_t complain)
 {
   tree expr;
@@ -3837,22 +3851,33 @@  build_delete (tree type, tree addr, special_function_kind auto_delete,
   if (addr == error_mark_node)
     return error_mark_node;
 
+  tree type = TYPE_MAIN_VARIANT (otype);
+
   /* Can happen when CURRENT_EXCEPTION_OBJECT gets its type
      set to `error_mark_node' before it gets properly cleaned up.  */
   if (type == error_mark_node)
     return error_mark_node;
 
-  type = TYPE_MAIN_VARIANT (type);
+  if (TREE_CODE (type) == POINTER_TYPE)
+    type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
 
-  addr = mark_rvalue_use (addr);
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      if (TYPE_DOMAIN (type) == NULL_TREE)
+	{
+	  if (complain & tf_error)
+	    error ("unknown array size in delete");
+	  return error_mark_node;
+	}
+      return build_vec_delete (addr, array_type_nelts (type),
+			       auto_delete, use_global_delete, complain);
+    }
 
-  if (TYPE_PTR_P (type))
+  if (TYPE_PTR_P (otype))
     {
       bool complete_p = true;
 
-      type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
-      if (TREE_CODE (type) == ARRAY_TYPE)
-	goto handle_array;
+      addr = mark_rvalue_use (addr);
 
       /* We don't want to warn about delete of void*, only other
 	  incomplete types.  Deleting other incomplete types
@@ -3908,19 +3933,6 @@  build_delete (tree type, tree addr, special_function_kind auto_delete,
       /* Throw away const and volatile on target type of addr.  */
       addr = convert_force (build_pointer_type (type), addr, 0, complain);
     }
-  else if (TREE_CODE (type) == ARRAY_TYPE)
-    {
-    handle_array:
-
-      if (TYPE_DOMAIN (type) == NULL_TREE)
-	{
-	  if (complain & tf_error)
-	    error ("unknown array size in delete");
-	  return error_mark_node;
-	}
-      return build_vec_delete (addr, array_type_nelts (type),
-			       auto_delete, use_global_delete, complain);
-    }
   else
     {
       /* Don't check PROTECT here; leave that decision to the
@@ -3935,10 +3947,18 @@  build_delete (tree type, tree addr, special_function_kind auto_delete,
       addr = convert_force (build_pointer_type (type), addr, 0, complain);
     }
 
-  gcc_assert (MAYBE_CLASS_TYPE_P (type));
-
   if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
     {
+      /* Make sure the destructor is callable.  */
+      if (type_build_dtor_call (type))
+	{
+	  expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL,
+							 complain),
+				  sfk_complete_destructor, flags, complain);
+	  if (expr == error_mark_node)
+	    return error_mark_node;
+	}
+
       if (auto_delete != sfk_deleting_destructor)
 	return void_zero_node;
 
@@ -4062,7 +4082,7 @@  push_base_cleanups (void)
       for (vbases = CLASSTYPE_VBASECLASSES (current_class_type), i = 0;
 	   vec_safe_iterate (vbases, i, &base_binfo); i++)
 	{
-	  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo)))
+	  if (type_build_dtor_call (BINFO_TYPE (base_binfo)))
 	    {
 	      expr = build_special_member_call (current_class_ref,
 						base_dtor_identifier,
@@ -4070,10 +4090,13 @@  push_base_cleanups (void)
 						base_binfo,
 						(LOOKUP_NORMAL
 						 | LOOKUP_NONVIRTUAL),
-                                                tf_warning_or_error);
-	      expr = build3 (COND_EXPR, void_type_node, cond,
-			     expr, void_zero_node);
-	      finish_decl_cleanup (NULL_TREE, expr);
+						tf_warning_or_error);
+	      if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo)))
+		{
+		  expr = build3 (COND_EXPR, void_type_node, cond,
+				 expr, void_zero_node);
+		  finish_decl_cleanup (NULL_TREE, expr);
+		}
 	    }
 	}
     }
@@ -4082,8 +4105,8 @@  push_base_cleanups (void)
   for (binfo = TYPE_BINFO (current_class_type), i = 0;
        BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
     {
-      if (TYPE_HAS_TRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo))
-	  || BINFO_VIRTUAL_P (base_binfo))
+      if (BINFO_VIRTUAL_P (base_binfo)
+	  || !type_build_dtor_call (BINFO_TYPE (base_binfo)))
 	continue;
 
       expr = build_special_member_call (current_class_ref,
@@ -4091,7 +4114,8 @@  push_base_cleanups (void)
 					NULL, base_binfo,
 					LOOKUP_NORMAL | LOOKUP_NONVIRTUAL,
                                         tf_warning_or_error);
-      finish_decl_cleanup (NULL_TREE, expr);
+      if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (BINFO_TYPE (base_binfo)))
+	finish_decl_cleanup (NULL_TREE, expr);
     }
 
   /* Don't automatically destroy union members.  */
@@ -4108,7 +4132,7 @@  push_base_cleanups (void)
 	continue;
       if (ANON_UNION_TYPE_P (this_type))
 	continue;
-      if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (this_type))
+      if (type_build_dtor_call (this_type))
 	{
 	  tree this_member = (build_class_member_access_expr
 			      (current_class_ref, member,
@@ -4119,7 +4143,8 @@  push_base_cleanups (void)
 			       sfk_complete_destructor,
 			       LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
 			       0, tf_warning_or_error);
-	  finish_decl_cleanup (NULL_TREE, expr);
+	  if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (this_type))
+	    finish_decl_cleanup (NULL_TREE, expr);
 	}
     }
 }
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 4ac533e..593a4a6 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1265,8 +1265,9 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
      class versions and other properties of the type.  But a subobject
      class can be trivially copyable and yet have overload resolution
      choose a template constructor for initialization, depending on
-     rvalueness and cv-quals.  So we can't exit early for copy/move
-     methods in C++0x.  The same considerations apply in C++98/03, but
+     rvalueness and cv-quals.  And furthermore, a member in a base might
+     be trivial but deleted or otherwise not callable.  So we can't exit
+     early in C++0x.  The same considerations apply in C++98/03, but
      there the definition of triviality does not consider overload
      resolution, so a constructor can be trivial even if it would otherwise
      call a non-trivial constructor.  */
@@ -1282,7 +1283,7 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 	    inform (input_location, "defaulted default constructor does "
 		    "not initialize any non-static data member");
 	}
-      if (!diag)
+      if (!diag && cxx_dialect < cxx11)
 	return;
     }
 
@@ -1323,7 +1324,7 @@  synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p,
 
       process_subob_fn (rval, spec_p, trivial_p, deleted_p,
 			constexpr_p, diag, basetype);
-      if (ctor_p && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (basetype))
+      if (ctor_p)
 	{
 	  /* In a constructor we also need to check the subobject
 	     destructors for cleanup of partially constructed objects.  */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index e56052d..052746c 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2521,6 +2521,10 @@  finish_compound_literal (tree type, tree compound_literal,
       decl = pushdecl_top_level (decl);
       DECL_NAME (decl) = make_anon_name ();
       SET_DECL_ASSEMBLER_NAME (decl, DECL_NAME (decl));
+      /* Make sure the destructor is callable.  */
+      tree clean = cxx_maybe_build_cleanup (decl, complain);
+      if (clean == error_mark_node)
+	return error_mark_node;
       return decl;
     }
   else
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 011406c..4b71a76 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -640,12 +640,13 @@  split_nonconstant_init_1 (tree dest, tree init)
 	      code = build_stmt (input_location, EXPR_STMT, code);
 	      code = maybe_cleanup_point_expr_void (code);
 	      add_stmt (code);
-	      if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (inner_type))
+	      if (type_build_dtor_call (inner_type))
 		{
 		  code = (build_special_member_call
 			  (sub, complete_dtor_identifier, NULL, inner_type,
 			   LOOKUP_NORMAL, tf_warning_or_error));
-		  finish_eh_cleanup (code);
+		  if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (inner_type))
+		    finish_eh_cleanup (code);
 		}
 
 	      num_split_elts++;
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted19.C b/gcc/testsuite/g++.dg/cpp0x/defaulted19.C
index 5603632..f7de073 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted19.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted19.C
@@ -1,5 +1,6 @@ 
-// We allocate a cookie to help us run the destructor even if it's deleted.
-// { dg-options -std=c++11 }
+// We don't allocate a cookie to help us run the destructor if it's trivial,
+// even if it's deleted.
+// { dg-options "-std=c++11" }
 // { dg-do run }
 
 struct A
@@ -17,5 +18,5 @@  void *operator new[](__SIZE_TYPE__ t)
 int main()
 {
   A* ap = new A[5];
-  return ap == p;
+  return ap != p;
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted19a.C b/gcc/testsuite/g++.dg/cpp0x/defaulted19a.C
new file mode 100644
index 0000000..6d2a26a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted19a.C
@@ -0,0 +1,24 @@ 
+// We allocate a cookie to help us run the destructor if it's non-trivial,
+// even if it's deleted.
+// { dg-options "-std=c++0x" }
+// { dg-do run }
+
+struct B { ~B() {} };
+struct A
+{
+  B b;
+  ~A() = delete;
+};
+
+void *p = 0;
+void *operator new[](__SIZE_TYPE__ t)
+{
+  p = ::operator new (t);
+  return p;
+}
+
+int main()
+{
+  A* ap = new A[5];
+  return ap == p;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted2.C b/gcc/testsuite/g++.dg/cpp0x/defaulted2.C
index 8a8c874..3cef600 100644
--- a/gcc/testsuite/g++.dg/cpp0x/defaulted2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted2.C
@@ -62,7 +62,7 @@  int main()
 {
   F f;
   F f2(f);			// { dg-error "use" }
-  B* b = new const B;		// { dg-error "uninitialized const" }
+  const B* b = new const B;		// { dg-error "uninitialized const" }
   U u;				// { dg-error "deleted" }
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/defaulted46.C b/gcc/testsuite/g++.dg/cpp0x/defaulted46.C
new file mode 100644
index 0000000..d4562c9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/defaulted46.C
@@ -0,0 +1,17 @@ 
+// { dg-require-effective-target c++11 }
+
+struct A
+{
+protected:
+  A() = default;
+  int i;
+};
+
+struct B: A {
+  B() = default;
+};
+
+int main()
+{
+  B();
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/implicit11.C b/gcc/testsuite/g++.dg/cpp0x/implicit11.C
index 3b536e7..9f5841d 100644
--- a/gcc/testsuite/g++.dg/cpp0x/implicit11.C
+++ b/gcc/testsuite/g++.dg/cpp0x/implicit11.C
@@ -12,6 +12,6 @@  struct B: A { };		// { dg-error "deleted" }
 extern B eb;
 int main()
 {
-  B* b1 = new B;		// { dg-error "use of deleted function" "" { xfail *-*-* } }
+  B* b1 = new B;		// { dg-error "use of deleted function" }
   B* b2 = new B(eb);		// { dg-error "use of deleted function" }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae21.C b/gcc/testsuite/g++.dg/cpp0x/sfinae21.C
index 3eab43c..62c003a 100644
--- a/gcc/testsuite/g++.dg/cpp0x/sfinae21.C
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae21.C
@@ -9,6 +9,10 @@  char f(int);
 template<class>
 char (&f(...))[2];
 
-struct ND { ND() = delete; };
+struct ND {
+  // Make ND() non-aggregate.
+  virtual void f();
+  ND() = delete;
+};
 
 static_assert(sizeof(f<ND[1]>(0)) != 1, "Error");
diff --git a/gcc/testsuite/g++.dg/ext/anon-struct4.C b/gcc/testsuite/g++.dg/ext/anon-struct4.C
index 5d0bf71..9c8e887 100644
--- a/gcc/testsuite/g++.dg/ext/anon-struct4.C
+++ b/gcc/testsuite/g++.dg/ext/anon-struct4.C
@@ -1,5 +1,5 @@ 
 // PR c++/14401
 
-struct { struct { int& i ; } bar ; } foo ; // { dg-error "uninitialized" "uninit" }
+struct { struct { int& i ; } bar ; } foo ; // { dg-error "deleted|uninitialized" "uninit" }
 // { dg-warning "anonymous" "anon" { target c++98 } 3 }
-// { dg-message "should be initialized" "ref-uninit" { target *-*-* } 3 }
+// { dg-message "should be initialized" "ref-uninit" { target c++98 } 3 }
diff --git a/gcc/testsuite/g++.dg/init/ctor8.C b/gcc/testsuite/g++.dg/init/ctor8.C
index 3491f6a..7eb72eb 100644
--- a/gcc/testsuite/g++.dg/init/ctor8.C
+++ b/gcc/testsuite/g++.dg/init/ctor8.C
@@ -1,9 +1,10 @@ 
 // PR c++/29039
 
-typedef struct S {
+typedef struct S {	    // { dg-error "reference" "" { target c++11 } }
   int &r; 
 }; // { dg-warning "'typedef' was ignored" }
 
+
 S f () {
-  return S (); // { dg-error "reference" }
+  return S (); // { dg-error "reference|deleted" }
 }
diff --git a/gcc/testsuite/g++.dg/init/pr25811.C b/gcc/testsuite/g++.dg/init/pr25811.C
index c906a9b..e8945da 100644
--- a/gcc/testsuite/g++.dg/init/pr25811.C
+++ b/gcc/testsuite/g++.dg/init/pr25811.C
@@ -1,51 +1,51 @@ 
 // PR c++/25811
 // { dg-do compile }
 
-struct A1
+struct A1		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const j; // { dg-message "should be initialized" }
+  int const j; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct A2
+struct A2		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const volatile i; // { dg-message "should be initialized" }
+  int const volatile i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct A3
+struct A3		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int& ref; // { dg-message "should be initialized" }
+  int& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct A4
+struct A4		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const& ref; // { dg-message "should be initialized" }
+  int const& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct A5
+struct A5		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int& ref; // { dg-message "should be initialized" }
-  int const i; // { dg-message "should be initialized" }
+  int& ref; // { dg-message "should be initialized" "" { target c++98 } }
+  int const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-template <class T> struct S1
+template <class T> struct S1 // { dg-error "uninitialized" "" { target c++11 } }
 {
-  T const i; // { dg-message "should be initialized" }
+  T const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-template <class T> struct S2
+template <class T> struct S2 // { dg-error "uninitialized" "" { target c++11 } }
 {
-  T const volatile i; // { dg-message "should be initialized" }
+  T const volatile i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-template <class T> struct S3
+template <class T> struct S3 // { dg-error "uninitialized" "" { target c++11 } }
 {
-  T& ref; // { dg-message "should be initialized" }
+  T& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-template <class T> struct S4
+template <class T> struct S4 // { dg-error "uninitialized" "" { target c++11 } }
 {
-  T const i; // { dg-message "should be initialized" }
-  T& ref; // { dg-message "should be initialized" }
+  T const i; // { dg-message "should be initialized" "" { target c++98 } }
+  T& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
 struct X
@@ -55,44 +55,44 @@  struct X
   int const& r;
 };
 
-struct Y11
+struct Y11		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const i; // { dg-message "should be initialized" }
+  int const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct Y1
+struct Y1		// { dg-error "deleted" "" { target c++11 } }
 {
   Y11 a[1];
 };
 
-struct Y22
+struct Y22		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int& ref; // { dg-message "should be initialized" }
+  int& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct Y2
+struct Y2		// { dg-error "deleted" "" { target c++11 } }
 {
   Y22 a[1];
 };
 
-struct Z1
+struct Z1		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const i; // { dg-message "should be initialized" }
+  int const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct Z2
+struct Z2 // { dg-error "uninitialized" "" { target c++11 } }
 {
-  int& ref; // { dg-message "should be initialized" }
+  int& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct Z3
+struct Z3 // { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const i; // { dg-message "should be initialized" }
+  int const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct Z4
+struct Z4 // { dg-error "uninitialized" "" { target c++11 } }
 {
-  int& ref; // { dg-message "should be initialized" }
+  int& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
 struct Z5
@@ -100,7 +100,7 @@  struct Z5
   int i;
 };
 
-struct Z
+struct Z		// { dg-error "deleted" "" { target c++11 } }
 {
   Z1 z1;
   Z2 z2;
@@ -109,54 +109,54 @@  struct Z
   Z5 z5;
 };
 
-union U
+union U // { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const i; // { dg-message "should be initialized" }
+  int const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
 void f1 ()
 {
-  new A1; // { dg-error "uninitialized const member" }
+  new A1; // { dg-error "deleted|uninitialized const member" }
 }
 
 void f2 ()
 {
-  new A2; // { dg-error "uninitialized const member" }
+  new A2; // { dg-error "deleted|uninitialized const member" }
 }
 
 void f3 ()
 {
-  new A3; // { dg-error "uninitialized reference member" }
+  new A3; // { dg-error "deleted|uninitialized reference member" }
 }
 
 void f4 ()
 {
-  new A4; // { dg-error "uninitialized reference member" }
+  new A4; // { dg-error "deleted|uninitialized reference member" }
 }
 
 void f5 ()
 {
-  new A5; // { dg-error "uninitialized reference member|uninitialized const member" }
+  new A5; // { dg-error "deleted|uninitialized reference member|uninitialized const member" }
 }
 
 void f6 ()
 {
-  new S1<int>; // { dg-error "uninitialized const member" }
+  new S1<int>; // { dg-error "deleted|uninitialized const member" }
 }
 
 void f7 ()
 {
-  new S2<int>; // { dg-error "uninitialized const member" }
+  new S2<int>; // { dg-error "deleted|uninitialized const member" }
 }
 
 void f8 ()
 {
-  new S3<int>; // { dg-error "uninitialized reference member" }
+  new S3<int>; // { dg-error "deleted|uninitialized reference member" }
 }
 
 void f9 ()
 {
-  new S4<int>; // { dg-error "uninitialized reference member|uninitialized const member" }
+  new S4<int>; // { dg-error "deleted|uninitialized reference member|uninitialized const member" }
 }
 
 void f10 ()
@@ -166,30 +166,30 @@  void f10 ()
 
 void f11 ()
 {
-  new A1[1]; // { dg-error "uninitialized const member" }
+  new A1[1]; // { dg-error "deleted|uninitialized const member" }
 }
 
 void f12 ()
 {
-  new A3[1]; // { dg-error "uninitialized reference member" }
+  new A3[1]; // { dg-error "deleted|uninitialized reference member" }
 }
 
 void f13 ()
 {
-  new Y1; // { dg-error "uninitialized const member" }
+  new Y1; // { dg-error "deleted|uninitialized const member" }
 }
 
 void f14 ()
 {
-  new Y2; // { dg-error "uninitialized reference member" }
+  new Y2; // { dg-error "deleted|uninitialized reference member" }
 }
 
 void f15 ()
 {
-  new Z; // { dg-error "uninitialized reference member|uninitialized const member" }
+  new Z; // { dg-error "deleted|uninitialized reference member|uninitialized const member" }
 }
 
 void f16 ()
 {
-  new U; // { dg-error "uninitialized const member" }
+  new U; // { dg-error "deleted|uninitialized const member" }
 }
diff --git a/gcc/testsuite/g++.dg/init/pr29043.C b/gcc/testsuite/g++.dg/init/pr29043.C
index 6ed31b5..f868dfb 100644
--- a/gcc/testsuite/g++.dg/init/pr29043.C
+++ b/gcc/testsuite/g++.dg/init/pr29043.C
@@ -1,27 +1,27 @@ 
 // PR c++/29043
 // { dg-do compile }
 
-struct S 
+struct S		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const i; // { dg-message "should be initialized" }
+  int const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
 class C
 {
 public:
-  C() {} // { dg-error "uninitialized const member" }   
+  C() {} // { dg-error "uninitialized const member|deleted" }
   S s;
 };
 
-struct S2
+struct S2		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int& ref; // { dg-message "should be initialized" }
+  int& ref;   // { dg-message "should be initialized" "" { target c++98 } }
 };
 
 class C2
 {
 public:
-  C2() {} // { dg-error "uninitialized reference member" }   
+  C2() {} // { dg-error "uninitialized reference member|deleted" }
   S2 s;
 };
 
@@ -33,14 +33,14 @@  class C3
   };
 };
 
-struct S4
+struct S4		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const i; // { dg-message "should be initialized" }
+  int const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
 struct C4
 {
-  C4() {} // { dg-error "uninitialized const member" }
+  C4() {} // { dg-error "uninitialized const member|deleted" }
   S4 s4[ 1 ];
 };
 
diff --git a/gcc/testsuite/g++.dg/init/pr43719.C b/gcc/testsuite/g++.dg/init/pr43719.C
index d3487c9..13a8221 100644
--- a/gcc/testsuite/g++.dg/init/pr43719.C
+++ b/gcc/testsuite/g++.dg/init/pr43719.C
@@ -1,51 +1,51 @@ 
 // PR c++/43719
 // { dg-do compile }
 
-struct A1
+struct A1		  // { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const j; // { dg-message "should be initialized" }
+  int const j; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct A2
+struct A2		  // { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const volatile i; // { dg-message "should be initialized" }
+  int const volatile i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct A3
+struct A3		  // { dg-error "uninitialized" "" { target c++11 } }
 {
-  int& ref; // { dg-message "should be initialized" }
+  int& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct A4
+struct A4		  // { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const& ref; // { dg-message "should be initialized" }
+  int const& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct A5
+struct A5		  // { dg-error "uninitialized" "" { target c++11 } }
 {
-  int& ref; // { dg-message "should be initialized" }
-  int const i; // { dg-message "should be initialized" }
+  int& ref; // { dg-message "should be initialized" "" { target c++98 } }
+  int const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-template <class T> struct S1
+template <class T> struct S1 // { dg-error "uninitialized" "" { target c++11 } }
 {
-  T const i; // { dg-message "should be initialized" }
+  T const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-template <class T> struct S2
+template <class T> struct S2 // { dg-error "uninitialized" "" { target c++11 } }
 {
-  T const volatile i; // { dg-message "should be initialized" }
+  T const volatile i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-template <class T> struct S3
+template <class T> struct S3 // { dg-error "uninitialized" "" { target c++11 } }
 {
-  T& ref; // { dg-message "should be initialized" }
+  T& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-template <class T> struct S4
+template <class T> struct S4 // { dg-error "uninitialized" "" { target c++11 } }
 {
-  T const i; // { dg-message "should be initialized" }
-  T& ref; // { dg-message "should be initialized" }
+  T const i; // { dg-message "should be initialized" "" { target c++98 } }
+  T& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
 struct X
@@ -55,44 +55,44 @@  struct X
   int const& r;
 };
 
-struct Y11
+struct Y11		  // { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const i; // { dg-message "should be initialized" }
+  int const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct Y1
+struct Y1		  // { dg-error "deleted" "" { target c++11 } }
 {
   Y11 a[1];
 };
 
-struct Y22
+struct Y22	       // { dg-error "uninitialized" "" { target c++11 } }
 {
-  int& ref; // { dg-message "should be initialized" }
+  int& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct Y2
+struct Y2		      // { dg-error "deleted" "" { target c++11 } }
 {
   Y22 a[1];
 };
 
-struct Z1
+struct Z1		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const i; // { dg-message "should be initialized" }
+  int const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct Z2
+struct Z2		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int& ref; // { dg-message "should be initialized" }
+  int& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct Z3
+struct Z3		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const i; // { dg-message "should be initialized" }
+  int const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
-struct Z4
+struct Z4		// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int& ref; // { dg-message "should be initialized" }
+  int& ref; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
 struct Z5
@@ -100,7 +100,7 @@  struct Z5
   int i;
 };
 
-struct Z
+struct Z		// { dg-error "deleted" "" { target c++11 } }
 {
   Z1 z1;
   Z2 z2;
@@ -109,55 +109,55 @@  struct Z
   Z5 z5;
 };
 
-union U
+union U			// { dg-error "uninitialized" "" { target c++11 } }
 {
-  int const i; // { dg-message "should be initialized" }
+  int const i; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
 
 void f1 ()
 {
-  A1 a1; // { dg-error "uninitialized const member" }
+  A1 a1; // { dg-error "uninitialized const member|deleted" }
 }
 
 void f2 ()
 {
-  A2 a2; // { dg-error "uninitialized const member" }
+  A2 a2; // { dg-error "uninitialized const member|deleted" }
 }
 
 void f3 ()
 {
-  A3 a3; // { dg-error "uninitialized reference member" }
+  A3 a3; // { dg-error "uninitialized reference member|deleted" }
 }
 
 void f4 ()
 {
-  A4 a4; // { dg-error "uninitialized reference member" }
+  A4 a4; // { dg-error "uninitialized reference member|deleted" }
 }
 
 void f5 ()
 {
-  A5 a5; // { dg-error "uninitialized reference member|uninitialized const member" }
+  A5 a5; // { dg-error "uninitialized reference member|uninitialized const member|deleted" }
 }
 
 void f6 ()
 {
-  S1<int> s; // { dg-error "uninitialized const member" }
+  S1<int> s; // { dg-error "uninitialized const member|deleted" }
 }
 
 void f7 ()
 {
-  S2<int> s; // { dg-error "uninitialized const member" }
+  S2<int> s; // { dg-error "uninitialized const member|deleted" }
 }
 
 void f8 ()
 {
-  S3<int> s; // { dg-error "uninitialized reference member" }
+  S3<int> s; // { dg-error "uninitialized reference member|deleted" }
 }
 
 void f9 ()
 {
-  S4<int> s; // { dg-error "uninitialized reference member|uninitialized const member" }
+  S4<int> s; // { dg-error "uninitialized reference member|uninitialized const member|deleted" }
 }
 
 void f10 ()
@@ -167,31 +167,31 @@  void f10 ()
 
 void f11 ()
 {
-  A1 a[ 1 ]; // { dg-error "uninitialized const member" }
+  A1 a[ 1 ]; // { dg-error "uninitialized const member|deleted" }
 }
 
 void f12 ()
 {
-  A3 a[ 1 ]; // { dg-error "uninitialized reference member" }
+  A3 a[ 1 ]; // { dg-error "uninitialized reference member|deleted" }
 }
 
 void f13 ()
 {
-  Y1 y1; // { dg-error "uninitialized const member" }
+  Y1 y1; // { dg-error "uninitialized const member|deleted" }
 }
 
 void f14 ()
 {
-  Y2 y2; // { dg-error "uninitialized reference member" }
+  Y2 y2; // { dg-error "uninitialized reference member|deleted" }
 }
 
 void f15 ()
 {
-  Z z; // { dg-error "uninitialized reference member|uninitialized const member" }
+  Z z; // { dg-error "uninitialized reference member|uninitialized const member|deleted" }
 }
 
 void f16 ()
 {
-  U u; // { dg-error "uninitialized const member" }
+  U u; // { dg-error "uninitialized const member|deleted" }
 }
 
diff --git a/gcc/testsuite/g++.dg/init/pr44086.C b/gcc/testsuite/g++.dg/init/pr44086.C
index e3304f4..b4b0833 100644
--- a/gcc/testsuite/g++.dg/init/pr44086.C
+++ b/gcc/testsuite/g++.dg/init/pr44086.C
@@ -1,15 +1,15 @@ 
 // PR c++/44086
 // { dg-do compile }
 
-struct A
+struct A		// { dg-error "uninitialized" "" { target c++11 } }
 {
-    int const i : 2; // { dg-message "should be initialized" }
+    int const i : 2; // { dg-message "should be initialized" "" { target c++98 } }
 };
 
 void f()
 {
-    A a;    // { dg-error "uninitialized const" }
-    new A;  // { dg-error "uninitialized const" }
-    A();
-    new A();
+    A a;		      // { dg-error "deleted|uninitialized const" }
+    new A;		      // { dg-error "deleted|uninitialized const" }
+    A();		      // { dg-error "deleted" "" { target c++11 } }
+    new A();		      // { dg-error "deleted" "" { target c++11 } }
 }
diff --git a/gcc/testsuite/g++.dg/init/ref14.C b/gcc/testsuite/g++.dg/init/ref14.C
index 212e6e9..6ac4241 100644
--- a/gcc/testsuite/g++.dg/init/ref14.C
+++ b/gcc/testsuite/g++.dg/init/ref14.C
@@ -1,4 +1,6 @@ 
 // PR c++/33459
+// { dg-prune-output "uninitialized" }
+// { dg-prune-output "deleted" }
 
 union A
 {
diff --git a/gcc/testsuite/g++.dg/init/uninitialized1.C b/gcc/testsuite/g++.dg/init/uninitialized1.C
index 200c424..1e4f7ae 100644
--- a/gcc/testsuite/g++.dg/init/uninitialized1.C
+++ b/gcc/testsuite/g++.dg/init/uninitialized1.C
@@ -1,12 +1,12 @@ 
 // PR c++/58126
 
-struct A {
+struct A {		// { dg-error "uninitialized" "" { target c++11 } }
   const int value1;
   int& value2;
 };
 
-struct B : A { };
+struct B : A { };	// { dg-error "deleted" "" { target c++11 } }
 
-A a;  // { dg-error "uninitialized const member in 'struct A'|uninitialized reference member in 'struct A'" }
+A a;  // { dg-error "deleted|uninitialized const member in 'struct A'|uninitialized reference member in 'struct A'" }
 
-B b;  // { dg-error "uninitialized const member in base 'struct A' of 'struct B'|uninitialized reference member in base 'struct A' of 'struct B'" }
+B b;  // { dg-error "deleted|uninitialized const member in base 'struct A' of 'struct B'|uninitialized reference member in base 'struct A' of 'struct B'" }