Patchwork C++ PATCH for c++/48530 (hard errors with deleted destructors)

login
register
mail settings
Submitter Jason Merrill
Date April 26, 2011, 6:59 p.m.
Message ID <4DB71606.6040500@redhat.com>
Download mbox | patch
Permalink /patch/92950/
State New
Headers show

Comments

Jason Merrill - April 26, 2011, 6:59 p.m.
Daniel Krugler has been doing well at ferreting out parts of the 
compiler that haven't been properly SFINAE'd yet...

Tested x86_64-pc-linux-gnu, applied to trunk.
commit 93016efbbb141f1bd917c4032b4a94b2b4c85516
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Apr 25 20:07:15 2011 -0400

    	PR c++/48530
    	* decl.c (cxx_maybe_build_cleanup): Add complain parm.
    	* tree.c (force_target_expr): Add complain parm.
    	(build_target_expr_with_type): Likewise.
    	(get_target_expr_sfinae): Split out.
    	(build_vec_init_expr, bot_manip): Adjust.
    	* init.c (build_vec_delete, build_vec_delete_1): Add complain parm.
    	(build_delete, build_dtor_call): Likewise.
    	(perform_direct_initialization_if_possible): Adjust.
    	(build_vec_init): Handle error return.
    	* cvt.c (force_rvalue): Add complain parm.
    	Call build_special_member_call directly.
    	* decl2.c (delete_sanity): Add complain parm.
    	(build_cleanup): Adjust.
    	* pt.c (tsubst_copy_and_build, tsubst_expr): Adjust.
    	* semantics.c (finish_stmt_expr_expr): Adjust.
    	(finish_compound_literal): Adjust.
    	* parser.c (cp_parser_delete_expression): Adjust.
    	* typeck2.c (build_functional_cast): Adjust.
    	* cp-tree.h: Adjust.

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index cf8e1a5..10efd1c 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4144,7 +4144,11 @@  build_conditional_expr (tree arg1, tree arg2, tree arg3,
 	  && TREE_CODE (arg3) != THROW_EXPR)
 	{
 	  if (!VOID_TYPE_P (arg3_type))
-	    arg3 = force_rvalue (arg3);
+	    {
+	      arg3 = force_rvalue (arg3, complain);
+	      if (arg3 == error_mark_node)
+		return error_mark_node;
+	    }
 	  arg3_type = TREE_TYPE (arg3);
 	  result_type = arg3_type;
 	}
@@ -4152,7 +4156,11 @@  build_conditional_expr (tree arg1, tree arg2, tree arg3,
 	       && TREE_CODE (arg3) == THROW_EXPR)
 	{
 	  if (!VOID_TYPE_P (arg2_type))
-	    arg2 = force_rvalue (arg2);
+	    {
+	      arg2 = force_rvalue (arg2, complain);
+	      if (arg2 == error_mark_node)
+		return error_mark_node;
+	    }
 	  arg2_type = TREE_TYPE (arg2);
 	  result_type = arg2_type;
 	}
@@ -4359,11 +4367,11 @@  build_conditional_expr (tree arg1, tree arg2, tree arg3,
      that isn't wrapped with a TARGET_EXPR plays havoc with exception
      regions.  */
 
-  arg2 = force_rvalue (arg2);
+  arg2 = force_rvalue (arg2, complain);
   if (!CLASS_TYPE_P (arg2_type))
     arg2_type = TREE_TYPE (arg2);
 
-  arg3 = force_rvalue (arg3);
+  arg3 = force_rvalue (arg3, complain);
   if (!CLASS_TYPE_P (arg3_type))
     arg3_type = TREE_TYPE (arg3);
 
@@ -5642,7 +5650,7 @@  convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 		expr = convert_bitfield_to_declared_type (expr);
 		expr = fold_convert (type, expr);
 	      }
-	    expr = build_target_expr_with_type (expr, type);
+	    expr = build_target_expr_with_type (expr, type, complain);
 	  }
 
 	/* Take the address of the thing to which we will bind the
@@ -6341,7 +6349,7 @@  build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
 	  if (TREE_CODE (arg) == TARGET_EXPR)
 	    return arg;
 	  else if (trivial)
-	    return force_target_expr (DECL_CONTEXT (fn), arg);
+	    return force_target_expr (DECL_CONTEXT (fn), arg, complain);
 	}
       else if (TREE_CODE (arg) == TARGET_EXPR || trivial)
 	{
@@ -8246,7 +8254,7 @@  set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
       if (TREE_STATIC (var))
 	init = add_stmt_to_compound (init, register_dtor_fn (var));
       else
-	*cleanup = cxx_maybe_build_cleanup (var);
+	*cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error);
 
       /* We must be careful to destroy the temporary only
 	 after its initialization has taken place.  If the
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 66ac4e8..228e33c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4740,7 +4740,7 @@  extern void adjust_clone_args			(tree);
 /* in cvt.c */
 extern tree convert_to_reference		(tree, tree, int, int, tree);
 extern tree convert_from_reference		(tree);
-extern tree force_rvalue			(tree);
+extern tree force_rvalue			(tree, tsubst_flags_t);
 extern tree ocp_convert				(tree, tree, int, int);
 extern tree cp_convert				(tree, tree);
 extern tree cp_convert_and_check                (tree, tree);
@@ -4854,7 +4854,7 @@  extern tree next_initializable_field (tree);
 extern bool defer_mark_used_calls;
 extern GTY(()) VEC(tree, gc) *deferred_mark_used_calls;
 extern tree finish_case_label			(location_t, tree, tree);
-extern tree cxx_maybe_build_cleanup		(tree);
+extern tree cxx_maybe_build_cleanup		(tree, tsubst_flags_t);
 
 /* in decl2.c */
 extern bool check_java_method			(tree);
@@ -4866,7 +4866,7 @@  extern bool vague_linkage_p			(tree);
 extern void grokclassfn				(tree, tree,
 						 enum overload_flags);
 extern tree grok_array_decl			(tree, tree);
-extern tree delete_sanity			(tree, tree, bool, int);
+extern tree delete_sanity			(tree, tree, bool, int, tsubst_flags_t);
 extern tree check_classfn			(tree, tree, tree);
 extern void check_member_template		(tree);
 extern tree grokfield (const cp_declarator *, cp_decl_specifier_seq *,
@@ -4973,10 +4973,11 @@  extern tree build_vec_init			(tree, tree, tree, bool, int,
                                                  tsubst_flags_t);
 extern tree build_delete			(tree, tree,
 						 special_function_kind,
-						 int, int);
+						 int, int, tsubst_flags_t);
 extern void push_base_cleanups			(void);
 extern tree build_vec_delete			(tree, tree,
-						 special_function_kind, int);
+						 special_function_kind, int,
+						 tsubst_flags_t);
 extern tree create_temporary_var		(tree);
 extern void initialize_vtbl_ptrs		(tree);
 extern tree build_java_class_ref		(tree);
@@ -5374,8 +5375,8 @@  extern void maybe_add_lambda_conv_op            (tree);
 
 /* in tree.c */
 void cp_free_lang_data 				(tree t);
-extern tree force_target_expr			(tree, tree);
-extern tree build_target_expr_with_type		(tree, tree);
+extern tree force_target_expr			(tree, tree, tsubst_flags_t);
+extern tree build_target_expr_with_type		(tree, tree, tsubst_flags_t);
 extern void lang_check_failed			(const char *, int,
 						 const char *) ATTRIBUTE_NORETURN;
 extern tree stabilize_expr			(tree, tree *);
@@ -5408,6 +5409,7 @@  extern tree build_min_non_dep_call_vec		(tree, tree, VEC(tree,gc) *);
 extern tree build_cplus_new			(tree, tree, tsubst_flags_t);
 extern tree build_aggr_init_expr		(tree, tree, tsubst_flags_t);
 extern tree get_target_expr			(tree);
+extern tree get_target_expr_sfinae		(tree, tsubst_flags_t);
 extern tree build_cplus_array_type		(tree, tree);
 extern tree build_array_of_n_type		(tree, int);
 extern tree build_array_copy			(tree);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index de981bc..64fe871 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -531,11 +531,17 @@  convert_from_reference (tree val)
    argument of class type into a temporary.  */
 
 tree
-force_rvalue (tree expr)
+force_rvalue (tree expr, tsubst_flags_t complain)
 {
-  if (MAYBE_CLASS_TYPE_P (TREE_TYPE (expr)) && TREE_CODE (expr) != TARGET_EXPR)
-    expr = ocp_convert (TREE_TYPE (expr), expr,
-			CONV_IMPLICIT|CONV_FORCE_TEMP, LOOKUP_NORMAL);
+  tree type = TREE_TYPE (expr);
+  if (MAYBE_CLASS_TYPE_P (type) && TREE_CODE (expr) != TARGET_EXPR)
+    {
+      VEC(tree,gc) *args = make_tree_vector_single (expr);
+      expr = build_special_member_call (NULL_TREE, complete_ctor_identifier,
+					&args, type, LOOKUP_NORMAL, complain);
+      release_tree_vector (args);
+      expr = build_cplus_new (type, expr, complain);
+    }
   else
     expr = decay_conversion (expr);
 
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index dcd18ab..ccc5fd0 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5640,7 +5640,7 @@  initialize_local_var (tree decl, tree init)
     DECL_READ_P (decl) = 1;
 
   /* Generate a cleanup, if necessary.  */
-  cleanup = cxx_maybe_build_cleanup (decl);
+  cleanup = cxx_maybe_build_cleanup (decl, tf_warning_or_error);
 
   /* Perform the initialization.  */
   if (init)
@@ -13309,7 +13309,7 @@  complete_vars (tree type)
    cleanup need be done.  */
 
 tree
-cxx_maybe_build_cleanup (tree decl)
+cxx_maybe_build_cleanup (tree decl, tsubst_flags_t complain)
 {
   tree type;
   tree attr;
@@ -13344,8 +13344,9 @@  cxx_maybe_build_cleanup (tree decl)
       fn = lookup_name (id);
       arg = build_address (decl);
       mark_used (decl);
-      cleanup = cp_build_function_call_nary (fn, tf_warning_or_error,
-					     arg, NULL_TREE);
+      cleanup = cp_build_function_call_nary (fn, complain, arg, NULL_TREE);
+      if (cleanup == error_mark_node)
+	return error_mark_node;
     }
   /* Handle ordinary C++ destructors.  */
   type = TREE_TYPE (decl);
@@ -13367,9 +13368,11 @@  cxx_maybe_build_cleanup (tree decl)
 	flags |= LOOKUP_NONVIRTUAL;
 
       call = build_delete (TREE_TYPE (addr), addr,
-			   sfk_complete_destructor, flags, 0);
-      if (cleanup)
-	cleanup = build_compound_expr (input_location, cleanup, call);
+			   sfk_complete_destructor, flags, 0, complain);
+      if (call == error_mark_node)
+	cleanup = error_mark_node;
+      else if (cleanup)
+	cleanup = cp_build_compound_expr (cleanup, call, complain);
       else
 	cleanup = call;
     }
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a9c2455..d1b252d 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -419,7 +419,8 @@  grok_array_decl (tree array_expr, tree index_exp)
    Implements ARM $5.3.4.  This is called from the parser.  */
 
 tree
-delete_sanity (tree exp, tree size, bool doing_vec, int use_global_delete)
+delete_sanity (tree exp, tree size, bool doing_vec, int use_global_delete,
+	       tsubst_flags_t complain)
 {
   tree t, type;
 
@@ -475,10 +476,11 @@  delete_sanity (tree exp, tree size, bool doing_vec, int use_global_delete)
   if (doing_vec)
     return build_vec_delete (t, /*maxindex=*/NULL_TREE,
 			     sfk_deleting_destructor,
-			     use_global_delete);
+			     use_global_delete, complain);
   else
     return build_delete (type, t, sfk_deleting_destructor,
-			 LOOKUP_NORMAL, use_global_delete);
+			 LOOKUP_NORMAL, use_global_delete,
+			 complain);
 }
 
 /* Report an error if the indicated template declaration is not the
@@ -2594,7 +2596,8 @@  build_cleanup (tree decl)
     temp = build_address (decl);
   temp = build_delete (TREE_TYPE (temp), temp,
 		       sfk_complete_destructor,
-		       LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
+		       LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0,
+		       tf_warning_or_error);
   return temp;
 }
 
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 04d2bb2..25beba8 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -37,7 +37,6 @@  static tree finish_init_stmts (bool, tree, tree);
 static void construct_virtual_base (tree, tree);
 static void expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t);
 static void expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t);
-static tree build_vec_delete_1 (tree, tree, tree, special_function_kind, int);
 static void perform_member_init (tree, tree);
 static tree build_builtin_delete_call (tree);
 static int member_init_ok_or_else (tree, tree, tree);
@@ -46,7 +45,6 @@  static tree sort_mem_initializers (tree, tree);
 static tree initializing_context (tree);
 static void expand_cleanup_for_base (tree, tree);
 static tree dfs_initialize_vtbl_ptrs (tree, void *);
-static tree build_dtor_call (tree, special_function_kind, int);
 static tree build_field_list (tree, tree, int *);
 static tree build_vtbl_address (tree);
 static int diagnose_uninitialized_cst_or_ref_member_1 (tree, tree, bool, bool);
@@ -620,7 +618,8 @@  perform_member_init (tree member, tree init)
 					     /*preserve_reference=*/false,
 					     tf_warning_or_error);
       expr = build_delete (type, expr, sfk_complete_destructor,
-			   LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
+			   LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0,
+			   tf_warning_or_error);
 
       if (expr != error_mark_node)
 	finish_eh_cleanup (expr);
@@ -2720,7 +2719,8 @@  build_java_class_ref (tree type)
 
 static tree
 build_vec_delete_1 (tree base, tree maxindex, tree type,
-    special_function_kind auto_delete_vec, int use_global_delete)
+		    special_function_kind auto_delete_vec,
+		    int use_global_delete, tsubst_flags_t complain)
 {
   tree virtual_size;
   tree ptype = build_pointer_type (type = complete_type (type));
@@ -2749,6 +2749,9 @@  build_vec_delete_1 (tree base, tree maxindex, tree type,
   /* We should only have 1-D arrays here.  */
   gcc_assert (TREE_CODE (type) != ARRAY_TYPE);
 
+  if (base == error_mark_node || maxindex == error_mark_node)
+    return error_mark_node;
+
   if (! MAYBE_CLASS_TYPE_P (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
     goto no_destructor;
 
@@ -2762,7 +2765,9 @@  build_vec_delete_1 (tree base, tree maxindex, tree type,
 						  POINTER_PLUS_EXPR, ptype,
 						  fold_convert (ptype, base),
 						  virtual_size),
-				     tf_warning_or_error);
+				     complain);
+  if (tbase_init == error_mark_node)
+    return error_mark_node;
   controller = build3 (BIND_EXPR, void_type_node, tbase,
 		       NULL_TREE, NULL_TREE);
   TREE_SIDE_EFFECTS (controller) = 1;
@@ -2771,15 +2776,17 @@  build_vec_delete_1 (tree base, tree maxindex, tree type,
 		 build2 (EQ_EXPR, boolean_type_node, tbase,
 			 fold_convert (ptype, base)));
   tmp = fold_build1_loc (input_location, NEGATE_EXPR, sizetype, size_exp);
-  body = build_compound_expr
-    (input_location, 
-     body, cp_build_modify_expr (tbase, NOP_EXPR,
-				 build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp),
-				 tf_warning_or_error));
-  body = build_compound_expr
-    (input_location,
-     body, build_delete (ptype, tbase, sfk_complete_destructor,
-			 LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1));
+  tmp = build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp);
+  tmp = cp_build_modify_expr (tbase, NOP_EXPR, tmp, complain);
+  if (tmp == error_mark_node)
+    return error_mark_node;
+  body = build_compound_expr (input_location, body, tmp);
+  tmp = build_delete (ptype, tbase, sfk_complete_destructor,
+		      LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1,
+		      complain);
+  if (tmp == error_mark_node)
+    return error_mark_node;
+  body = build_compound_expr (input_location, body, tmp);
 
   loop = build1 (LOOP_EXPR, void_type_node, body);
   loop = build_compound_expr (input_location, tbase_init, loop);
@@ -2803,14 +2810,15 @@  build_vec_delete_1 (tree base, tree maxindex, tree type,
 	  tree cookie_size;
 
 	  cookie_size = targetm.cxx.get_cookie_size (type);
-	  base_tbd
-	    = cp_convert (ptype,
-			  cp_build_binary_op (input_location,
-					      MINUS_EXPR,
-					      cp_convert (string_type_node,
-							  base),
-					      cookie_size,
-					      tf_warning_or_error));
+	  base_tbd = cp_build_binary_op (input_location,
+					 MINUS_EXPR,
+					 cp_convert (string_type_node,
+						     base),
+					 cookie_size,
+					 complain);
+	  if (base_tbd == error_mark_node)
+	    return error_mark_node;
+	  base_tbd = cp_convert (ptype, base_tbd);
 	  /* True size with header.  */
 	  virtual_size = size_binop (PLUS_EXPR, virtual_size, cookie_size);
 	}
@@ -2853,7 +2861,7 @@  build_vec_delete_1 (tree base, tree maxindex, tree type,
     /* Pre-evaluate the SAVE_EXPR outside of the BIND_EXPR.  */
     body = build2 (COMPOUND_EXPR, void_type_node, base, body);
 
-  return convert_to_void (body, ICV_CAST, tf_warning_or_error);
+  return convert_to_void (body, ICV_CAST, complain);
 }
 
 /* Create an unnamed variable of the indicated TYPE.  */
@@ -2942,6 +2950,7 @@  build_vec_init (tree base, tree maxindex, tree init,
   tree const_init = NULL_TREE;
   tree obase = base;
   bool xvalue = false;
+  bool errors = false;
 
   if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype))
     maxindex = array_type_nelts (atype);
@@ -3087,7 +3096,8 @@  build_vec_init (tree base, tree maxindex, tree init,
 	  else
 	    one_init = cp_build_modify_expr (baseref, NOP_EXPR,
 					     elt, complain);
-
+	  if (one_init == error_mark_node)
+	    errors = true;
 	  if (try_const)
 	    {
 	      tree e = one_init;
@@ -3120,10 +3130,18 @@  build_vec_init (tree base, tree maxindex, tree init,
 	    finish_expr_stmt (one_init);
 	  current_stmt_tree ()->stmts_are_full_exprs_p = 0;
 
-	  finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, 0,
-                                               complain));
-	  finish_expr_stmt (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
-                                               complain));
+	  one_init = cp_build_unary_op (PREINCREMENT_EXPR, base, 0, complain);
+	  if (one_init == error_mark_node)
+	    errors = true;
+	  else
+	    finish_expr_stmt (one_init);
+
+	  one_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
+					complain);
+	  if (one_init == error_mark_node)
+	    errors = true;
+	  else
+	    finish_expr_stmt (one_init);
 	}
 
       if (try_const)
@@ -3149,7 +3167,7 @@  build_vec_init (tree base, tree maxindex, tree init,
 	{
           if (complain & tf_error)
             error ("initializer ends prematurely");
-	  return error_mark_node;
+	  errors = true;
 	}
     }
 
@@ -3176,9 +3194,11 @@  build_vec_init (tree base, tree maxindex, tree init,
       finish_for_cond (build2 (NE_EXPR, boolean_type_node, iterator,
 			       build_int_cst (TREE_TYPE (iterator), -1)),
 		       for_stmt);
-      finish_for_expr (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
-                                          complain),
-		       for_stmt);
+      elt_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
+				    complain);
+      if (elt_init == error_mark_node)
+	errors = true;
+      finish_for_expr (elt_init, for_stmt);
 
       to = build1 (INDIRECT_REF, type, base);
 
@@ -3219,9 +3239,7 @@  build_vec_init (tree base, tree maxindex, tree init,
       else if (explicit_value_init_p)
 	{
 	  elt_init = build_value_init (type, complain);
-	  if (elt_init == error_mark_node)
-	    return error_mark_node;
-	  else
+	  if (elt_init != error_mark_node)
 	    elt_init = build2 (INIT_EXPR, type, to, elt_init);
 	}
       else
@@ -3230,6 +3248,9 @@  build_vec_init (tree base, tree maxindex, tree init,
 	  elt_init = build_aggr_init (to, init, 0, complain);
 	}
 
+      if (elt_init == error_mark_node)
+	errors = true;
+
       current_stmt_tree ()->stmts_are_full_exprs_p = 1;
       finish_expr_stmt (elt_init);
       current_stmt_tree ()->stmts_are_full_exprs_p = 0;
@@ -3263,7 +3284,9 @@  build_vec_init (tree base, tree maxindex, tree init,
       finish_cleanup_try_block (try_block);
       e = build_vec_delete_1 (rval, m,
 			      inner_elt_type, sfk_base_destructor,
-			      /*use_global_delete=*/0);
+			      /*use_global_delete=*/0, complain);
+      if (e == error_mark_node)
+	errors = true;
       finish_cleanup (e, try_block);
     }
 
@@ -3286,6 +3309,8 @@  build_vec_init (tree base, tree maxindex, tree init,
 
   if (const_init)
     return build2 (INIT_EXPR, atype, obase, const_init);
+  if (errors)
+    return error_mark_node;
   return stmt_expr;
 }
 
@@ -3293,7 +3318,8 @@  build_vec_init (tree base, tree maxindex, tree init,
    build_delete.  */
 
 static tree
-build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
+build_dtor_call (tree exp, special_function_kind dtor_kind, int flags,
+		 tsubst_flags_t complain)
 {
   tree name;
   tree fn;
@@ -3320,7 +3346,7 @@  build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
 				/*conversion_path=*/NULL_TREE,
 				flags,
 				/*fn_p=*/NULL,
-				tf_warning_or_error);
+				complain);
 }
 
 /* Generate a call to a destructor. TYPE is the type to cast ADDR to.
@@ -3334,7 +3360,7 @@  build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
 
 tree
 build_delete (tree type, tree addr, special_function_kind auto_delete,
-    int flags, int use_global_delete)
+	      int flags, int use_global_delete, tsubst_flags_t complain)
 {
   tree expr;
 
@@ -3369,8 +3395,9 @@  build_delete (tree type, tree addr, special_function_kind auto_delete,
 	  complete_type (type);
 	  if (!COMPLETE_TYPE_P (type))
 	    {
-	      if (warning (0, "possible problem detected in invocation of "
-			   "delete operator:"))
+	      if ((complain & tf_warning)
+		  && warning (0, "possible problem detected in invocation of "
+			      "delete operator:"))
 		{
 		  cxx_incomplete_type_diagnostic (addr, type, DK_WARNING);
 		  inform (input_location, "neither the destructor nor the class-specific "
@@ -3395,18 +3422,21 @@  build_delete (tree type, tree addr, special_function_kind auto_delete,
 
       if (TYPE_DOMAIN (type) == NULL_TREE)
 	{
-	  error ("unknown array size in delete");
+	  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);
+			       auto_delete, use_global_delete, complain);
     }
   else
     {
       /* Don't check PROTECT here; leave that decision to the
 	 destructor.  If the destructor is accessible, call it,
 	 else report error.  */
-      addr = cp_build_addr_expr (addr, tf_warning_or_error);
+      addr = cp_build_addr_expr (addr, complain);
+      if (addr == error_mark_node)
+	return error_mark_node;
       if (TREE_SIDE_EFFECTS (addr))
 	addr = save_expr (addr);
 
@@ -3478,9 +3508,10 @@  build_delete (tree type, tree addr, special_function_kind auto_delete,
 				/*alloc_fn=*/NULL_TREE);
 	}
 
-      expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL, 
-                                                     tf_warning_or_error),
-			      auto_delete, flags);
+      expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL, complain),
+			      auto_delete, flags, complain);
+      if (expr == error_mark_node)
+	return error_mark_node;
       if (do_delete)
 	expr = build2 (COMPOUND_EXPR, void_type_node, expr, do_delete);
 
@@ -3492,10 +3523,14 @@  build_delete (tree type, tree addr, special_function_kind auto_delete,
 	/* Explicit destructor call; don't check for null pointer.  */
 	ifexp = integer_one_node;
       else
-	/* Handle deleting a null pointer.  */
-	ifexp = fold (cp_build_binary_op (input_location,
-					  NE_EXPR, addr, integer_zero_node,
-					  tf_warning_or_error));
+	{
+	  /* Handle deleting a null pointer.  */
+	  ifexp = fold (cp_build_binary_op (input_location,
+					    NE_EXPR, addr, integer_zero_node,
+					    complain));
+	  if (ifexp == error_mark_node)
+	    return error_mark_node;
+	}
 
       if (ifexp != integer_one_node)
 	expr = build3 (COND_EXPR, void_type_node,
@@ -3588,7 +3623,7 @@  push_base_cleanups (void)
 	  expr = build_delete (this_type, this_member,
 			       sfk_complete_destructor,
 			       LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
-			       0);
+			       0, tf_warning_or_error);
 	  finish_decl_cleanup (NULL_TREE, expr);
 	}
     }
@@ -3612,7 +3647,8 @@  push_base_cleanups (void)
 
 tree
 build_vec_delete (tree base, tree maxindex,
-    special_function_kind auto_delete_vec, int use_global_delete)
+		  special_function_kind auto_delete_vec,
+		  int use_global_delete, tsubst_flags_t complain)
 {
   tree type;
   tree rval;
@@ -3638,7 +3674,7 @@  build_vec_delete (tree base, tree maxindex,
 			    size_ptr_type,
 			    fold_convert (size_ptr_type, base),
 			    cookie_addr);
-      maxindex = cp_build_indirect_ref (cookie_addr, RO_NULL, tf_warning_or_error);
+      maxindex = cp_build_indirect_ref (cookie_addr, RO_NULL, complain);
     }
   else if (TREE_CODE (type) == ARRAY_TYPE)
     {
@@ -3646,7 +3682,9 @@  build_vec_delete (tree base, tree maxindex,
 	 bad name.  */
       maxindex = array_type_nelts_total (type);
       type = strip_array_types (type);
-      base = cp_build_addr_expr (base, tf_warning_or_error);
+      base = cp_build_addr_expr (base, complain);
+      if (base == error_mark_node)
+	return error_mark_node;
       if (TREE_SIDE_EFFECTS (base))
 	{
 	  base_init = get_target_expr (base);
@@ -3655,14 +3693,14 @@  build_vec_delete (tree base, tree maxindex,
     }
   else
     {
-      if (base != error_mark_node)
+      if (base != error_mark_node && !(complain & tf_error))
 	error ("type to vector delete is neither pointer or array type");
       return error_mark_node;
     }
 
   rval = build_vec_delete_1 (base, maxindex, type, auto_delete_vec,
-			     use_global_delete);
-  if (base_init)
+			     use_global_delete, complain);
+  if (base_init && rval != error_mark_node)
     rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), base_init, rval);
 
   return rval;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 7d3121c..85d5ab5 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -6294,7 +6294,8 @@  cp_parser_delete_expression (cp_parser* parser)
   if (cp_parser_non_integral_constant_expression (parser, NIC_DEL))
     return error_mark_node;
 
-  return delete_sanity (expression, NULL_TREE, array_p, global_scope_p);
+  return delete_sanity (expression, NULL_TREE, array_p, global_scope_p,
+			tf_warning_or_error);
 }
 
 /* Returns true if TOKEN may start a cast-expression and false
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 70fcbba..db71cd5 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12094,7 +12094,7 @@  tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
 			    init = build_value_init (TREE_TYPE (decl),
 						     complain);
 			    if (TREE_CODE (init) == AGGR_INIT_EXPR)
-			      init = get_target_expr (init);
+			      init = get_target_expr_sfinae (init, complain);
 			  }
 			else
 			  init = t;
@@ -12838,7 +12838,8 @@  tsubst_copy_and_build (tree t,
        (RECUR (TREE_OPERAND (t, 0)),
 	RECUR (TREE_OPERAND (t, 1)),
 	DELETE_EXPR_USE_VEC (t),
-	DELETE_EXPR_USE_GLOBAL (t));
+	DELETE_EXPR_USE_GLOBAL (t),
+	complain);
 
     case COMPOUND_EXPR:
       return build_x_compound_expr (RECUR (TREE_OPERAND (t, 0)),
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 7763ae0..7dd489d 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1835,7 +1835,7 @@  finish_stmt_expr_expr (tree expr, tree stmt_expr)
 	  /* It actually has a value we need to deal with.  First, force it
 	     to be an rvalue so that we won't need to build up a copy
 	     constructor call later when we try to assign it to something.  */
-	  expr = force_rvalue (expr);
+	  expr = force_rvalue (expr, tf_warning_or_error);
 	  if (error_operand_p (expr))
 	    return error_mark_node;
 
@@ -1892,7 +1892,7 @@  finish_stmt_expr (tree stmt_expr, bool has_no_scope)
 	 temporary object created by the final expression is destroyed at
 	 the end of the full-expression containing the
 	 statement-expression.  */
-      result = force_target_expr (type, result);
+      result = force_target_expr (type, result, tf_warning_or_error);
     }
 
   return result;
@@ -2407,7 +2407,7 @@  finish_compound_literal (tree type, tree compound_literal,
       return decl;
     }
   else
-    return get_target_expr (compound_literal);
+    return get_target_expr_sfinae (compound_literal, complain);
 }
 
 /* Return the declaration for the function-name variable indicated by
@@ -7957,7 +7957,7 @@  build_lambda_object (tree lambda_expr)
 	     There's normally no way to express direct-initialization
 	     from an element of a CONSTRUCTOR, so we build up a special
 	     TARGET_EXPR to bypass the usual copy-initialization.  */
-	  val = force_rvalue (val);
+	  val = force_rvalue (val, tf_warning_or_error);
 	  if (TREE_CODE (val) == TARGET_EXPR)
 	    TARGET_EXPR_DIRECT_INIT_P (val) = true;
 	}
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 23daa6c..151e084 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -39,7 +39,7 @@  static tree bot_replace (tree *, int *, void *);
 static int list_hash_eq (const void *, const void *);
 static hashval_t list_hash_pieces (tree, tree, tree);
 static hashval_t list_hash (const void *);
-static tree build_target_expr (tree, tree);
+static tree build_target_expr (tree, tree, tsubst_flags_t);
 static tree count_trees_r (tree *, int *, void *);
 static tree verify_stmt_tree_r (tree *, int *, void *);
 static tree build_local_temp (tree);
@@ -281,7 +281,7 @@  builtin_valid_in_constant_expr_p (const_tree decl)
 /* Build a TARGET_EXPR, initializing the DECL with the VALUE.  */
 
 static tree
-build_target_expr (tree decl, tree value)
+build_target_expr (tree decl, tree value, tsubst_flags_t complain)
 {
   tree t;
 
@@ -292,8 +292,10 @@  build_target_expr (tree decl, tree value)
 					    TREE_TYPE (value)));
 #endif
 
-  t = build4 (TARGET_EXPR, TREE_TYPE (decl), decl, value,
-	      cxx_maybe_build_cleanup (decl), NULL_TREE);
+  t = cxx_maybe_build_cleanup (decl, complain);
+  if (t == error_mark_node)
+    return error_mark_node;
+  t = build4 (TARGET_EXPR, TREE_TYPE (decl), decl, value, t, NULL_TREE);
   /* We always set TREE_SIDE_EFFECTS so that expand_expr does not
      ignore the TARGET_EXPR.  If there really turn out to be no
      side-effects, then the optimizer should be able to get rid of
@@ -453,7 +455,7 @@  build_cplus_new (tree type, tree init, tsubst_flags_t complain)
   else
     return rval;
 
-  rval = build_target_expr (slot, rval);
+  rval = build_target_expr (slot, rval, complain);
   TARGET_EXPR_IMPLICIT_P (rval) = 1;
 
   return rval;
@@ -526,7 +528,7 @@  build_vec_init_expr (tree type, tree init)
     VEC_INIT_EXPR_IS_CONSTEXPR (init) = true;
   VEC_INIT_EXPR_VALUE_INIT (init) = value_init;
 
-  init = build_target_expr (slot, init);
+  init = build_target_expr (slot, init, tf_warning_or_error);
   TARGET_EXPR_IMPLICIT_P (init) = 1;
 
   return init;
@@ -559,7 +561,7 @@  build_array_copy (tree init)
    indicated TYPE.  */
 
 tree
-build_target_expr_with_type (tree init, tree type)
+build_target_expr_with_type (tree init, tree type, tsubst_flags_t complain)
 {
   gcc_assert (!VOID_TYPE_P (type));
 
@@ -577,9 +579,9 @@  build_target_expr_with_type (tree init, tree type)
        another one here.  A CONSTRUCTOR is aggregate initialization, which
        is handled separately.  A VA_ARG_EXPR is magic creation of an
        aggregate; there's no additional work to be done.  */
-    return force_rvalue (init);
+    return force_rvalue (init, complain);
 
-  return force_target_expr (type, init);
+  return force_target_expr (type, init, complain);
 }
 
 /* Like the above function, but without the checking.  This function should
@@ -588,27 +590,33 @@  build_target_expr_with_type (tree init, tree type)
    infinite recursion.  */
 
 tree
-force_target_expr (tree type, tree init)
+force_target_expr (tree type, tree init, tsubst_flags_t complain)
 {
   tree slot;
 
   gcc_assert (!VOID_TYPE_P (type));
 
   slot = build_local_temp (type);
-  return build_target_expr (slot, init);
+  return build_target_expr (slot, init, complain);
 }
 
 /* Like build_target_expr_with_type, but use the type of INIT.  */
 
 tree
-get_target_expr (tree init)
+get_target_expr_sfinae (tree init, tsubst_flags_t complain)
 {
   if (TREE_CODE (init) == AGGR_INIT_EXPR)
-    return build_target_expr (AGGR_INIT_EXPR_SLOT (init), init);
+    return build_target_expr (AGGR_INIT_EXPR_SLOT (init), init, complain);
   else if (TREE_CODE (init) == VEC_INIT_EXPR)
-    return build_target_expr (VEC_INIT_EXPR_SLOT (init), init);
+    return build_target_expr (VEC_INIT_EXPR_SLOT (init), init, complain);
   else
-    return build_target_expr_with_type (init, TREE_TYPE (init));
+    return build_target_expr_with_type (init, TREE_TYPE (init), complain);
+}
+
+tree
+get_target_expr (tree init)
+{
+  return get_target_expr_sfinae (init, tf_warning_or_error);
 }
 
 /* If EXPR is a bitfield reference, convert it to the declared type of
@@ -1810,7 +1818,8 @@  bot_manip (tree* tp, int* walk_subtrees, void* data)
 	u = build_cplus_new (TREE_TYPE (t), TREE_OPERAND (t, 1),
 			     tf_warning_or_error);
       else
-	u = build_target_expr_with_type (TREE_OPERAND (t, 1), TREE_TYPE (t));
+	u = build_target_expr_with_type (TREE_OPERAND (t, 1), TREE_TYPE (t),
+					 tf_warning_or_error);
 
       /* Map the old variable to the new one.  */
       splay_tree_insert (target_remap,
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 49f4e7e..5522868 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1610,7 +1610,7 @@  build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
       && !TYPE_HAS_USER_CONSTRUCTOR (type))
     {
       exp = build_value_init (type, complain);
-      exp = get_target_expr (exp);
+      exp = get_target_expr_sfinae (exp, complain);
       /* FIXME this is wrong */
       if (literal_type_p (type))
 	TREE_CONSTANT (exp) = true;
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae17.C b/gcc/testsuite/g++.dg/cpp0x/sfinae17.C
new file mode 100644
index 0000000..dbbd9ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae17.C
@@ -0,0 +1,31 @@ 
+// PR c++/48530
+// { dg-options -std=c++0x }
+
+template<class T,
+	 class = decltype(T{})
+>
+char f(int);
+
+template<class>
+char (&f(...))[2];
+
+struct DelDtor {
+  ~DelDtor() = delete;
+};
+
+static_assert(sizeof(f<DelDtor[2]>(0)) != 1, "Error");
+
+struct A
+{
+  static DelDtor *p;
+};
+
+template<class T,
+	 class = decltype(delete T::p, (T*)0)
+>
+char g(int);
+
+template<class>
+char (&g(...))[2];
+
+static_assert(sizeof(g<DelDtor>(0)) != 1, "Error");