Patchwork [C++] PR 53567

login
register
mail settings
Submitter Paolo Carlini
Date June 4, 2012, 10:55 p.m.
Message ID <4FCD3CE8.2040307@oracle.com>
Download mbox | patch
Permalink /patch/162884/
State New
Headers show

Comments

Paolo Carlini - June 4, 2012, 10:55 p.m.
Hi,

On 06/04/2012 08:12 PM, Jason Merrill wrote:
> On 06/04/2012 10:15 AM, Paolo Carlini wrote:
>> @@ -5413,7 +5413,7 @@ build_op_delete_call (enum tree_code code, tree ad
>>       fns = lookup_name_nonclass (fnname);
>>
>>     /* Strip const and volatile from addr.  */
>> -  addr = cp_convert (ptr_type_node, addr);
>> +  addr = cp_convert (ptr_type_node, addr, tf_warning_or_error);
>
> build_op_delete_call is called from build_new_1, so it should be 
> complainified.
Ok.
>> +          if (complain & tf_error)
>> +        {
>> +          if (flags & LOOKUP_COMPLAIN)
>> +            permerror (loc, "conversion from %q#T to %q#T",
>> +                   intype, type);
>> +          if (!flag_permissive)
>> +            return error_mark_node;
>> +        }
>> +          else
>>          return error_mark_node;
>
> I don't think we want to check both tf_error and LOOKUP_COMPLAIN 
> everywhere.  We could use one to set the other, but at this point I 
> think we want to do away with LOOKUP_COMPLAIN entirely as its function 
> has been taken over.
Well, if you mean not using it in the functions we are touching, 
something like the below passes the testsuite, for example.

If, more generally, you mean we should remove it completely, I'm afraid 
some cases are rather nasty. For example, I think that whenever we go 
through implicit_conversion, thus its flags &=, the following function 
calls can easily have at the same time complain & tf_error true and 
flags & LOOKUP_COMPLAIN false. Thus, just as an example, the lines in 
build_user_type_conversion_1

       if ((flags & LOOKUP_COMPLAIN)
&& (complain & tf_error))
     {
       error ("conversion from %qT to %qT is ambiguous",
          fromtype, totype);
       print_z_candidates (location_of (expr), candidates);
     }

cannot simply discard the information in flags, that would not work for 
g++.dg/overload/ref-conv2.C. More generally, it looks like there are a 
few such cases in call.c, where we are checking both. Is there a 
conceptually simple recipe to simplify such tests? Or handle such 
cleanup separately from this bug... ;)

Thanks,
Paolo.

/////////////////////
/cp
2012-06-04  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/53567
	* typeck.c (cp_perform_integral_promotions): New, like
	perform_integral_promotions but also takes a tsubst_flags_t parameter.
	(pointer_diff): Add tsubst_flags_t parameter.
	(decay_conversion, cp_default_conversion, cp_build_array_ref,
	cp_build_binary_op, cp_build_unary_op, build_static_cast_1,
	build_reinterpret_cast_1, cp_build_modify_expr,
	convert_for_assignment): Adjust.
	* optimize.c (build_delete_destructor_body): Adjust.
	* init.c (expand_virtual_init, expand_default_init,
	build_new, build_vec_delete_1, build_vec_init, build_delete): Adjust.
	* class.c (build_base_path): Likewise.
	* decl.c (compute_array_index_type, finish_destructor_body): Likewise.
	* rtti.c (ifnonnull): Add tsubst_flags_t parameter.
	(build_typeid, build_dynamic_cast_1): Adjust.
	* except.c (initialize_handler_parm): Likewise.
	* typeck2.c (process_init_constructor_record): Likewise.
	* semantics.c (finish_goto_stmt, handle_omp_for_class_iterator,
	finish_static_assert): Likewise.
	* call.c (build_op_delete_call): Add tsubst_flags_t parameter.
	(convert_like_real, convert_arg_to_ellipsis, convert_for_arg_passing):
	Adjust.
	* cvt.c (cp_convert_to_pointer, convert_to_pointer_force,
	build_up_reference, convert_to_reference, cp_convert,
	cp_convert_and_check, ocp_convert, convert_force): Add tsubst_flags_t
	parameter.
	* cp-tree.h: Adjust prototypes.

/testsuite
2012-06-04  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/53567
	* g++.dg/cpp0x/alias-decl-19.C: New.
Jason Merrill - June 4, 2012, 11:23 p.m.
On 06/04/2012 06:55 PM, Paolo Carlini wrote:
> If, more generally, you mean we should remove it completely, I'm afraid
> some cases are rather nasty. For example, I think that whenever we go
> through implicit_conversion, thus its flags &=, the following function
> calls can easily have at the same time complain & tf_error true and
> flags & LOOKUP_COMPLAIN false.

In cases where we currently don't set LOOKUP_COMPLAIN in flags, we can 
instead set complain to tf_none.

Jason
Paolo Carlini - June 4, 2012, 11:45 p.m.
On 06/05/2012 01:23 AM, Jason Merrill wrote:
> On 06/04/2012 06:55 PM, Paolo Carlini wrote:
>> If, more generally, you mean we should remove it completely, I'm afraid
>> some cases are rather nasty. For example, I think that whenever we go
>> through implicit_conversion, thus its flags &=, the following function
>> calls can easily have at the same time complain & tf_error true and
>> flags & LOOKUP_COMPLAIN false.
>
> In cases where we currently don't set LOOKUP_COMPLAIN in flags, we can 
> instead set complain to tf_none.
Ok, I'll see what happens in the various specific circumstances. Indeed, 
earlier today I wondered myself if in principle not setting 
LOOKUP_COMPLAIN was just tf_none, but looking at the code things seemed 
more complex, when eg we are currently warning without checking 
LOOKUP_COMPLAIN and with complain available normally we would protect 
the warning with complain & tf_warning. But I don't want to speak too 
early ;) Let me see.

Thanks!
Paolo.
Paolo Carlini - June 5, 2012, 12:22 a.m.
On 06/05/2012 01:45 AM, Paolo Carlini wrote:
> On 06/05/2012 01:23 AM, Jason Merrill wrote:
>> On 06/04/2012 06:55 PM, Paolo Carlini wrote:
>>> If, more generally, you mean we should remove it completely, I'm afraid
>>> some cases are rather nasty. For example, I think that whenever we go
>>> through implicit_conversion, thus its flags &=, the following function
>>> calls can easily have at the same time complain & tf_error true and
>>> flags & LOOKUP_COMPLAIN false.
>>
>> In cases where we currently don't set LOOKUP_COMPLAIN in flags, we 
>> can instead set complain to tf_none.
> Ok, I'll see what happens in the various specific circumstances. 
> Indeed, earlier today I wondered myself if in principle not setting 
> LOOKUP_COMPLAIN was just tf_none, but looking at the code things 
> seemed more complex, when eg we are currently warning without checking 
> LOOKUP_COMPLAIN and with complain available normally we would protect 
> the warning with complain & tf_warning. But I don't want to speak too 
> early ;) Let me see.
In fact, I think setting complain to tf_warning may work better.

Paolo.
Jason Merrill - June 5, 2012, 2:10 a.m.
On 06/04/2012 08:22 PM, Paolo Carlini wrote:
> In fact, I think setting complain to tf_warning may work better.

Sounds plausible.

Jason

Patch

Index: testsuite/g++.dg/cpp0x/alias-decl-19.C
===================================================================
--- testsuite/g++.dg/cpp0x/alias-decl-19.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/alias-decl-19.C	(revision 0)
@@ -0,0 +1,31 @@ 
+// PR c++/53567
+// { dg-do compile { target c++11 } }
+
+template <unsigned int, bool> struct IntegerType { typedef unsigned type; };
+
+template <class EnumT>
+using UnderlyingEnumType = typename IntegerType<sizeof(EnumT), (EnumT(-1) > EnumT(0))>::type;
+
+template <class EnumT, class UnderlyingT = UnderlyingEnumType<EnumT>>
+struct EnumMask
+{
+  constexpr EnumMask(EnumT val) : m_val(val) {}
+  operator EnumT() { return m_val; }
+
+  EnumT m_val;
+};
+
+enum class A : unsigned { x };
+
+template <class EnumT>
+EnumMask<EnumT> operator ~(EnumT lhs)
+{
+  return EnumT(~unsigned(lhs) & unsigned(EnumT::maskAll)); // { dg-error "not a member" }
+
+}
+
+int main()
+{
+  ~A::x;
+  return 0;
+}
Index: cp/typeck.c
===================================================================
--- cp/typeck.c	(revision 188203)
+++ cp/typeck.c	(working copy)
@@ -52,7 +52,7 @@  static tree rationalize_conditional_expr (enum tre
 static int comp_ptr_ttypes_real (tree, tree, int);
 static bool comp_except_types (tree, tree, bool);
 static bool comp_array_types (const_tree, const_tree, bool);
-static tree pointer_diff (tree, tree, tree);
+static tree pointer_diff (tree, tree, tree, tsubst_flags_t);
 static tree get_delta_difference (tree, tree, bool, bool, tsubst_flags_t);
 static void casts_away_constness_r (tree *, tree *, tsubst_flags_t);
 static bool casts_away_constness (tree, tree, tsubst_flags_t);
@@ -1906,7 +1906,7 @@  decay_conversion (tree exp, tsubst_flags_t complai
       /* This way is better for a COMPONENT_REF since it can
 	 simplify the offset for a component.  */
       adr = cp_build_addr_expr (exp, complain);
-      return cp_convert (ptrtype, adr);
+      return cp_convert (ptrtype, adr, complain);
     }
 
   /* If a bitfield is used in a context where integral promotion
@@ -1950,12 +1950,12 @@  cp_default_conversion (tree exp, tsubst_flags_t co
   /* Check for target-specific promotions.  */
   tree promoted_type = targetm.promoted_type (TREE_TYPE (exp));
   if (promoted_type)
-    exp = cp_convert (promoted_type, exp);
+    exp = cp_convert (promoted_type, exp, complain);
   /* Perform the integral promotions first so that bitfield
      expressions (which may promote to "int", even if the bitfield is
      declared "unsigned") are promoted correctly.  */
   else if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (TREE_TYPE (exp)))
-    exp = perform_integral_promotions (exp);
+    exp = cp_perform_integral_promotions (exp, complain);
   /* Perform the other conversions.  */
   exp = decay_conversion (exp, complain);
 
@@ -1975,7 +1975,7 @@  default_conversion (tree exp)
    converted value.  */
 
 tree
-perform_integral_promotions (tree expr)
+cp_perform_integral_promotions (tree expr, tsubst_flags_t complain)
 {
   tree type;
   tree promoted_type;
@@ -1995,10 +1995,18 @@  tree
     return expr;
   promoted_type = type_promotes_to (type);
   if (type != promoted_type)
-    expr = cp_convert (promoted_type, expr);
+    expr = cp_convert (promoted_type, expr, complain);
   return expr;
 }
 
+/* C version.  */
+
+tree
+perform_integral_promotions (tree expr)
+{
+  return cp_perform_integral_promotions (expr, tf_warning_or_error);
+}
+
 /* Returns nonzero iff exp is a STRING_CST or the result of applying
    decay_conversion to one.  */
 
@@ -2945,7 +2953,7 @@  cp_build_array_ref (location_t loc, tree array, tr
 	 does not say that we should.  In fact, the natural thing would
 	 seem to be to convert IDX to ptrdiff_t; we're performing
 	 pointer arithmetic.)  */
-      idx = perform_integral_promotions (idx);
+      idx = cp_perform_integral_promotions (idx, complain);
 
       /* An array that is indexed by a non-constant
 	 cannot be stored in a register; we must be able to do
@@ -3867,7 +3875,8 @@  cp_build_binary_op (location_t location,
       if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
 	  && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (type0),
 							TREE_TYPE (type1)))
-	return pointer_diff (op0, op1, common_pointer_type (type0, type1));
+	return pointer_diff (op0, op1, common_pointer_type (type0, type1),
+			     complain);
       /* In all other cases except pointer - int, the usual arithmetic
 	 rules apply.  */
       else if (!(code0 == POINTER_TYPE && code1 == INTEGER_TYPE))
@@ -4003,7 +4012,7 @@  cp_build_binary_op (location_t location,
 	  /* Convert the shift-count to an integer, regardless of
 	     size of value being shifted.  */
 	  if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
-	    op1 = cp_convert (integer_type_node, op1);
+	    op1 = cp_convert (integer_type_node, op1, complain);
 	  /* Avoid converting op1 to result_type later.  */
 	  converted = 1;
 	}
@@ -4031,7 +4040,7 @@  cp_build_binary_op (location_t location,
 	  /* Convert the shift-count to an integer, regardless of
 	     size of value being shifted.  */
 	  if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
-	    op1 = cp_convert (integer_type_node, op1);
+	    op1 = cp_convert (integer_type_node, op1, complain);
 	  /* Avoid converting op1 to result_type later.  */
 	  converted = 1;
 	}
@@ -4062,7 +4071,7 @@  cp_build_binary_op (location_t location,
 	  /* Convert the shift-count to an integer, regardless of
 	     size of value being shifted.  */
 	  if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
-	    op1 = cp_convert (integer_type_node, op1);
+	    op1 = cp_convert (integer_type_node, op1, complain);
 	}
       break;
 
@@ -4162,12 +4171,12 @@  cp_build_binary_op (location_t location,
 	      op0 = cp_build_binary_op (location,
 					TRUTH_ANDIF_EXPR, e1, e2,
 					complain);
-	      op1 = cp_convert (TREE_TYPE (op0), integer_one_node); 
+	      op1 = cp_convert (TREE_TYPE (op0), integer_one_node, complain); 
 	    }
      	  else 
 	    {
 	      op0 = build_ptrmemfunc_access_expr (op0, pfn_identifier);
-	      op1 = cp_convert (TREE_TYPE (op0), op1);
+	      op1 = cp_convert (TREE_TYPE (op0), op1, complain);
 	    }
 	  result_type = TREE_TYPE (op0);
 	}
@@ -4190,9 +4199,9 @@  cp_build_binary_op (location_t location,
 					 CPO_COMPARISON, complain);
 
 	  if (!same_type_p (TREE_TYPE (op0), type))
-	    op0 = cp_convert_and_check (type, op0);
+	    op0 = cp_convert_and_check (type, op0, complain);
 	  if (!same_type_p (TREE_TYPE (op1), type))
-	    op1 = cp_convert_and_check (type, op1);
+	    op1 = cp_convert_and_check (type, op1, complain);
 
 	  if (op0 == error_mark_node || op1 == error_mark_node)
 	    return error_mark_node;
@@ -4456,16 +4465,16 @@  cp_build_binary_op (location_t location,
 	  if (first_complex)
 	    {
 	      if (TREE_TYPE (op0) != result_type)
-		op0 = cp_convert_and_check (result_type, op0);
+		op0 = cp_convert_and_check (result_type, op0, complain);
 	      if (TREE_TYPE (op1) != real_type)
-		op1 = cp_convert_and_check (real_type, op1);
+		op1 = cp_convert_and_check (real_type, op1, complain);
 	    }
 	  else
 	    {
 	      if (TREE_TYPE (op0) != real_type)
-		op0 = cp_convert_and_check (real_type, op0);
+		op0 = cp_convert_and_check (real_type, op0, complain);
 	      if (TREE_TYPE (op1) != result_type)
-		op1 = cp_convert_and_check (result_type, op1);
+		op1 = cp_convert_and_check (result_type, op1, complain);
 	    }
 	  if (TREE_CODE (op0) == ERROR_MARK || TREE_CODE (op1) == ERROR_MARK)
 	    return error_mark_node;
@@ -4550,7 +4559,7 @@  cp_build_binary_op (location_t location,
 	  tree val
 	    = shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
 	  if (val != 0)
-	    return cp_convert (boolean_type_node, val);
+	    return cp_convert (boolean_type_node, val, complain);
 	  op0 = xop0, op1 = xop1;
 	  converted = 1;
 	  resultcode = xresultcode;
@@ -4580,9 +4589,9 @@  cp_build_binary_op (location_t location,
   if (! converted)
     {
       if (TREE_TYPE (op0) != result_type)
-	op0 = cp_convert_and_check (result_type, op0);
+	op0 = cp_convert_and_check (result_type, op0, complain);
       if (TREE_TYPE (op1) != result_type)
-	op1 = cp_convert_and_check (result_type, op1);
+	op1 = cp_convert_and_check (result_type, op1, complain);
 
       if (op0 == error_mark_node || op1 == error_mark_node)
 	return error_mark_node;
@@ -4594,7 +4603,7 @@  cp_build_binary_op (location_t location,
   result = build2 (resultcode, build_type, op0, op1);
   result = fold_if_not_in_template (result);
   if (final_type != 0)
-    result = cp_convert (final_type, result);
+    result = cp_convert (final_type, result, complain);
 
   if (TREE_OVERFLOW_P (result) 
       && !TREE_OVERFLOW_P (op0) 
@@ -4627,7 +4636,7 @@  cp_pointer_int_sum (enum tree_code resultcode, tre
    The resulting tree has type int.  */
 
 static tree
-pointer_diff (tree op0, tree op1, tree ptrtype)
+pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
 {
   tree result;
   tree restype = ptrdiff_type_node;
@@ -4637,24 +4646,48 @@  static tree
     return error_mark_node;
 
   if (TREE_CODE (target_type) == VOID_TYPE)
-    permerror (input_location, "ISO C++ forbids using pointer of type %<void *%> in subtraction");
+    {
+      if (complain & tf_error)
+	permerror (input_location, "ISO C++ forbids using pointer of "
+		   "type %<void *%> in subtraction");
+      else
+	return error_mark_node;
+    }
   if (TREE_CODE (target_type) == FUNCTION_TYPE)
-    permerror (input_location, "ISO C++ forbids using pointer to a function in subtraction");
+    {
+      if (complain & tf_error)
+	permerror (input_location, "ISO C++ forbids using pointer to "
+		   "a function in subtraction");
+      else
+	return error_mark_node;
+    }
   if (TREE_CODE (target_type) == METHOD_TYPE)
-    permerror (input_location, "ISO C++ forbids using pointer to a method in subtraction");
+    {
+      if (complain & tf_error)
+	permerror (input_location, "ISO C++ forbids using pointer to "
+		   "a method in subtraction");
+      else
+	return error_mark_node;
+    }
 
   /* First do the subtraction as integers;
      then drop through to build the divide operator.  */
 
   op0 = cp_build_binary_op (input_location,
 			    MINUS_EXPR,
-			    cp_convert (restype, op0),
-			    cp_convert (restype, op1),
-			    tf_warning_or_error);
+			    cp_convert (restype, op0, complain),
+			    cp_convert (restype, op1, complain),
+			    complain);
 
   /* This generates an error if op1 is a pointer to an incomplete type.  */
   if (!COMPLETE_TYPE_P (TREE_TYPE (TREE_TYPE (op1))))
-    error ("invalid use of a pointer to an incomplete type in pointer arithmetic");
+    {
+      if (complain & tf_error)
+	error ("invalid use of a pointer to an incomplete type in "
+	       "pointer arithmetic");
+      else
+	return error_mark_node;
+    }
 
   op1 = (TYPE_PTROB_P (ptrtype)
 	 ? size_in_bytes (target_type)
@@ -4662,7 +4695,8 @@  static tree
 
   /* Do the division.  */
 
-  result = build2 (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1));
+  result = build2 (EXACT_DIV_EXPR, restype, op0,
+		   cp_convert (restype, op1, complain));
   return fold_if_not_in_template (result);
 }
 
@@ -5175,7 +5209,7 @@  cp_build_unary_op (enum tree_code code, tree xarg,
 	else
 	  {
 	    if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg)))
-	      arg = perform_integral_promotions (arg);
+	      arg = cp_perform_integral_promotions (arg, complain);
 
 	    /* Make sure the result is not an lvalue: a unary plus or minus
 	       expression is always a rvalue.  */
@@ -5200,7 +5234,7 @@  cp_build_unary_op (enum tree_code code, tree xarg,
 						   arg, true)))
 	errstring = _("wrong type argument to bit-complement");
       else if (!noconvert && CP_INTEGRAL_TYPE_P (TREE_TYPE (arg)))
-	arg = perform_integral_promotions (arg);
+	arg = cp_perform_integral_promotions (arg, complain);
       break;
 
     case ABS_EXPR:
@@ -5358,7 +5392,7 @@  cp_build_unary_op (enum tree_code code, tree xarg,
 	else
 	  inc = integer_one_node;
 
-	inc = cp_convert (argtype, inc);
+	inc = cp_convert (argtype, inc, complain);
 
 	/* If 'arg' is an Objective-C PROPERTY_REF expression, then we
 	   need to ask Objective-C to build the increment or decrement
@@ -6074,7 +6108,7 @@  build_static_cast_1 (tree type, tree expr, bool c_
        || SCALAR_FLOAT_TYPE_P (type))
       && (INTEGRAL_OR_ENUMERATION_TYPE_P (intype)
 	  || SCALAR_FLOAT_TYPE_P (intype)))
-    return ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL);
+    return ocp_convert (type, expr, CONV_C_CAST, LOOKUP_NORMAL, complain);
 
   if (TYPE_PTR_P (type) && TYPE_PTR_P (intype)
       && CLASS_TYPE_P (TREE_TYPE (type))
@@ -6417,7 +6451,7 @@  build_reinterpret_cast_1 (tree type, tree expr, bo
       return error_mark_node;
     }
 
-  return cp_convert (type, expr);
+  return cp_convert (type, expr, complain);
 }
 
 tree
@@ -7078,7 +7112,7 @@  cp_build_modify_expr (tree lhs, enum tree_code mod
 				     NULL_TREE, 0, complain, LOOKUP_IMPLICIT);
 
   if (!same_type_p (lhstype, olhstype))
-    newrhs = cp_convert_and_check (lhstype, newrhs);
+    newrhs = cp_convert_and_check (lhstype, newrhs, complain);
 
   if (modifycode != INIT_EXPR)
     {
@@ -7599,7 +7633,7 @@  convert_for_assignment (tree type, tree rhs,
       if (!warn_pmf2ptr
 	  && TYPE_PTR_P (type)
 	  && TYPE_PTRMEMFUNC_P (rhstype))
-	rhs = cp_convert (strip_top_quals (type), rhs);
+	rhs = cp_convert (strip_top_quals (type), rhs, complain);
       else
 	{
 	  if (complain & tf_error)
Index: cp/optimize.c
===================================================================
--- cp/optimize.c	(revision 188203)
+++ cp/optimize.c	(working copy)
@@ -138,7 +138,8 @@  build_delete_destructor_body (tree delete_dtor, tr
                                       virtual_size,
                                       /*global_p=*/false,
                                       /*placement=*/NULL_TREE,
-                                      /*alloc_fn=*/NULL_TREE);
+                                      /*alloc_fn=*/NULL_TREE,
+				      tf_warning_or_error);
   add_stmt (call_delete);
 
   /* Return the address of the object.  */
Index: cp/init.c
===================================================================
--- cp/init.c	(revision 188203)
+++ cp/init.c	(working copy)
@@ -1180,7 +1180,7 @@  expand_virtual_init (tree binfo, tree decl)
   gcc_assert (vtbl_ptr != error_mark_node);
 
   /* Assign the vtable to the vptr.  */
-  vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0);
+  vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0, tf_warning_or_error);
   finish_expr_stmt (cp_build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl,
 					  tf_warning_or_error));
 }
@@ -1598,7 +1598,8 @@  expand_default_init (tree binfo, tree true_exp, tr
 	   have already built up the constructor call so we could wrap it
 	   in an exception region.  */;
       else
-	init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
+	init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP,
+			    flags, complain);
 
       if (TREE_CODE (init) == MUST_NOT_THROW_EXPR)
 	/* We need to protect the initialization of a catch parm with a
@@ -2656,7 +2657,8 @@  build_new_1 (VEC(tree,gc) **placement, tree type,
 		      size,
 		      globally_qualified_p,
 		      placement_allocation_fn_p ? alloc_call : NULL_TREE,
-		      alloc_fn));
+		      alloc_fn,
+		      complain));
 
 	  if (!cleanup)
 	    /* We're done.  */;
@@ -2815,7 +2817,7 @@  build_new (VEC(tree,gc) **placement, tree type, tr
             return error_mark_node;
         }
       nelts = mark_rvalue_use (nelts);
-      nelts = cp_save_expr (cp_convert (sizetype, nelts));
+      nelts = cp_save_expr (cp_convert (sizetype, nelts, complain));
     }
 
   /* ``A reference cannot be created by the new operator.  A reference
@@ -3012,12 +3014,12 @@  build_vec_delete_1 (tree base, tree maxindex, tree
 	  base_tbd = cp_build_binary_op (input_location,
 					 MINUS_EXPR,
 					 cp_convert (string_type_node,
-						     base),
+						     base, complain),
 					 cookie_size,
 					 complain);
 	  if (base_tbd == error_mark_node)
 	    return error_mark_node;
-	  base_tbd = cp_convert (ptype, base_tbd);
+	  base_tbd = cp_convert (ptype, base_tbd, complain);
 	  /* True size with header.  */
 	  virtual_size = size_binop (PLUS_EXPR, virtual_size, cookie_size);
 	}
@@ -3026,7 +3028,8 @@  build_vec_delete_1 (tree base, tree maxindex, tree
 					      base_tbd, virtual_size,
 					      use_global_delete & 1,
 					      /*placement=*/NULL_TREE,
-					      /*alloc_fn=*/NULL_TREE);
+					      /*alloc_fn=*/NULL_TREE,
+					      complain);
     }
 
   body = loop;
@@ -3189,14 +3192,14 @@  build_vec_init (tree base, tree maxindex, tree ini
       return stmt_expr;
     }
 
-  maxindex = cp_convert (ptrdiff_type_node, maxindex);
+  maxindex = cp_convert (ptrdiff_type_node, maxindex, complain);
   if (TREE_CODE (atype) == ARRAY_TYPE)
     {
       ptype = build_pointer_type (type);
       base = decay_conversion (base, complain);
       if (base == error_mark_node)
 	return error_mark_node;
-      base = cp_convert (ptype, base);
+      base = cp_convert (ptype, base, complain);
     }
   else
     ptype = atype;
@@ -3665,7 +3668,7 @@  build_delete (tree type, tree addr, special_functi
 	addr = save_expr (addr);
 
       /* Throw away const and volatile on target type of addr.  */
-      addr = convert_force (build_pointer_type (type), addr, 0);
+      addr = convert_force (build_pointer_type (type), addr, 0, complain);
     }
   else if (TREE_CODE (type) == ARRAY_TYPE)
     {
@@ -3691,7 +3694,7 @@  build_delete (tree type, tree addr, special_functi
       if (TREE_SIDE_EFFECTS (addr))
 	addr = save_expr (addr);
 
-      addr = convert_force (build_pointer_type (type), addr, 0);
+      addr = convert_force (build_pointer_type (type), addr, 0, complain);
     }
 
   gcc_assert (MAYBE_CLASS_TYPE_P (type));
@@ -3705,7 +3708,8 @@  build_delete (tree type, tree addr, special_functi
 				   cxx_sizeof_nowarn (type),
 				   use_global_delete,
 				   /*placement=*/NULL_TREE,
-				   /*alloc_fn=*/NULL_TREE);
+				   /*alloc_fn=*/NULL_TREE,
+				   complain);
     }
   else
     {
@@ -3744,7 +3748,8 @@  build_delete (tree type, tree addr, special_functi
 					    cxx_sizeof_nowarn (type),
 					    /*global_p=*/false,
 					    /*placement=*/NULL_TREE,
-					    /*alloc_fn=*/NULL_TREE);
+					    /*alloc_fn=*/NULL_TREE,
+					    complain);
 	  /* Call the complete object destructor.  */
 	  auto_delete = sfk_complete_destructor;
 	}
@@ -3756,7 +3761,8 @@  build_delete (tree type, tree addr, special_functi
 	  build_op_delete_call (DELETE_EXPR, addr, cxx_sizeof_nowarn (type),
 				/*global_p=*/false,
 				/*placement=*/NULL_TREE,
-				/*alloc_fn=*/NULL_TREE);
+				/*alloc_fn=*/NULL_TREE,
+				complain);
 	}
 
       expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL, complain),
Index: cp/class.c
===================================================================
--- cp/class.c	(revision 188203)
+++ cp/class.c	(working copy)
@@ -366,7 +366,7 @@  build_base_path (enum tree_code code,
   /* Now that we've saved expr, build the real null test.  */
   if (null_test)
     {
-      tree zero = cp_convert (TREE_TYPE (expr), nullptr_node);
+      tree zero = cp_convert (TREE_TYPE (expr), nullptr_node, complain);
       null_test = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
 			       expr, zero);
     }
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 188203)
+++ cp/decl.c	(working copy)
@@ -8104,9 +8104,10 @@  compute_array_index_type (tree name, tree size, ts
       processing_template_decl = 0;
       itype = cp_build_binary_op (input_location,
 				  MINUS_EXPR,
-				  cp_convert (ssizetype, size),
-				  cp_convert (ssizetype, integer_one_node),
-				  tf_warning_or_error);
+				  cp_convert (ssizetype, size, complain),
+				  cp_convert (ssizetype, integer_one_node,
+					      complain),
+				  complain);
       itype = fold (itype);
       processing_template_decl = saved_processing_template_decl;
 
@@ -13290,11 +13291,12 @@  finish_destructor_body (void)
       an implicit definition), non-placement operator delete shall
       be looked up in the scope of the destructor's class and if
       found shall be accessible and unambiguous.  */
-      exprstmt = build_op_delete_call(DELETE_EXPR, current_class_ptr,
-				      virtual_size,
-				      /*global_p=*/false,
-				      /*placement=*/NULL_TREE,
-				      /*alloc_fn=*/NULL_TREE);
+      exprstmt = build_op_delete_call (DELETE_EXPR, current_class_ptr,
+				       virtual_size,
+				       /*global_p=*/false,
+				       /*placement=*/NULL_TREE,
+				       /*alloc_fn=*/NULL_TREE,
+				       tf_warning_or_error);
 
       if_stmt = begin_if_stmt ();
       finish_if_stmt_cond (build2 (BIT_AND_EXPR, integer_type_node,
Index: cp/rtti.c
===================================================================
--- cp/rtti.c	(revision 188203)
+++ cp/rtti.c	(working copy)
@@ -99,7 +99,7 @@  VEC(tree,gc) *unemitted_tinfo_decls;
    and are generated as needed. */
 static GTY (()) VEC(tinfo_s,gc) *tinfo_descs;
 
-static tree ifnonnull (tree, tree);
+static tree ifnonnull (tree, tree, tsubst_flags_t);
 static tree tinfo_name (tree, bool);
 static tree build_dynamic_cast_1 (tree, tree, tsubst_flags_t);
 static tree throw_bad_cast (void);
@@ -336,7 +336,8 @@  build_typeid (tree exp)
          This is an lvalue use of expr then.  */
       exp = mark_lvalue_use (exp);
       exp = stabilize_reference (exp);
-      cond = cp_convert (boolean_type_node, TREE_OPERAND (exp, 0));
+      cond = cp_convert (boolean_type_node, TREE_OPERAND (exp, 0),
+			 tf_warning_or_error);
     }
 
   exp = get_tinfo_decl_dynamic (exp);
@@ -498,12 +499,13 @@  get_typeid (tree type)
    RESULT, it must have previously had a save_expr applied to it.  */
 
 static tree
-ifnonnull (tree test, tree result)
+ifnonnull (tree test, tree result, tsubst_flags_t complain)
 {
   return build3 (COND_EXPR, TREE_TYPE (result),
 		 build2 (EQ_EXPR, boolean_type_node, test,
-			 cp_convert (TREE_TYPE (test), nullptr_node)),
-		 cp_convert (TREE_TYPE (result), nullptr_node),
+			 cp_convert (TREE_TYPE (test), nullptr_node,
+				     complain)),
+		 cp_convert (TREE_TYPE (result), nullptr_node, complain),
 		 result);
 }
 
@@ -596,7 +598,7 @@  build_dynamic_cast_1 (tree type, tree expr, tsubst
 
       /* Apply trivial conversion T -> T& for dereferenced ptrs.  */
       expr = convert_to_reference (exprtype, expr, CONV_IMPLICIT,
-				   LOOKUP_NORMAL, NULL_TREE);
+				   LOOKUP_NORMAL, NULL_TREE, complain);
     }
 
   /* The dynamic_cast operator shall not cast away constness.  */
@@ -644,7 +646,7 @@  build_dynamic_cast_1 (tree type, tree expr, tsubst
 	  expr1 = build_headof (expr);
 	  if (TREE_TYPE (expr1) != type)
 	    expr1 = build1 (NOP_EXPR, type, expr1);
-	  return ifnonnull (expr, expr1);
+	  return ifnonnull (expr, expr1, complain);
 	}
       else
 	{
@@ -752,12 +754,12 @@  build_dynamic_cast_1 (tree type, tree expr, tsubst
 	      neq = cp_truthvalue_conversion (result);
 	      return cp_convert (type,
 				 build3 (COND_EXPR, TREE_TYPE (result),
-					 neq, result, bad));
+					 neq, result, bad), complain);
 	    }
 
 	  /* Now back to the type we want from a void*.  */
-	  result = cp_convert (type, result);
-	  return ifnonnull (expr, result);
+	  result = cp_convert (type, result, complain);
+	  return ifnonnull (expr, result, complain);
 	}
     }
   else
Index: cp/except.c
===================================================================
--- cp/except.c	(revision 188203)
+++ cp/except.c	(working copy)
@@ -424,7 +424,8 @@  initialize_handler_parm (tree decl, tree exp)
       && TYPE_PTR_P (TREE_TYPE (init_type)))
     exp = cp_build_addr_expr (exp, tf_warning_or_error);
 
-  exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
+  exp = ocp_convert (init_type, exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0,
+		     tf_warning_or_error);
 
   init = convert_from_reference (exp);
 
@@ -435,7 +436,8 @@  initialize_handler_parm (tree decl, tree exp)
       /* Generate the copy constructor call directly so we can wrap it.
 	 See also expand_default_init.  */
       init = ocp_convert (TREE_TYPE (decl), init,
-			  CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
+			  CONV_IMPLICIT|CONV_FORCE_TEMP, 0,
+			  tf_warning_or_error);
       /* Force cleanups now to avoid nesting problems with the
 	 MUST_NOT_THROW_EXPR.  */
       init = fold_build_cleanup_point_expr (TREE_TYPE (init), init);
Index: cp/typeck2.c
===================================================================
--- cp/typeck2.c	(revision 188203)
+++ cp/typeck2.c	(working copy)
@@ -1264,7 +1264,7 @@  process_init_constructor_record (tree type, tree i
 
       /* If this is a bitfield, now convert to the lowered type.  */
       if (type != TREE_TYPE (field))
-	next = cp_convert_and_check (TREE_TYPE (field), next);
+	next = cp_convert_and_check (TREE_TYPE (field), next, complain);
       flags |= picflag_from_initializer (next);
       CONSTRUCTOR_APPEND_ELT (v, field, next);
     }
Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 188203)
+++ cp/semantics.c	(working copy)
@@ -564,7 +564,8 @@  finish_goto_stmt (tree destination)
       destination = mark_rvalue_use (destination);
       if (!processing_template_decl)
 	{
-	  destination = cp_convert (ptr_type_node, destination);
+	  destination = cp_convert (ptr_type_node, destination,
+				    tf_warning_or_error);
 	  if (error_operand_p (destination))
 	    return NULL_TREE;
 	}
@@ -4526,7 +4527,8 @@  handle_omp_for_class_iterator (int i, location_t l
 		  if (error_operand_p (iter_incr))
 		    return true;
 		  incr = TREE_OPERAND (rhs, 1);
-		  incr = cp_convert (TREE_TYPE (diff), incr);
+		  incr = cp_convert (TREE_TYPE (diff), incr,
+				     tf_warning_or_error);
 		  if (TREE_CODE (rhs) == MINUS_EXPR)
 		    {
 		      incr = build1 (NEGATE_EXPR, TREE_TYPE (diff), incr);
@@ -4581,7 +4583,7 @@  handle_omp_for_class_iterator (int i, location_t l
       return true;
     }
 
-  incr = cp_convert (TREE_TYPE (diff), incr);
+  incr = cp_convert (TREE_TYPE (diff), incr, tf_warning_or_error);
   for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
     if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
 	&& OMP_CLAUSE_DECL (c) == iter)
@@ -5130,7 +5132,7 @@  finish_static_assert (tree condition, tree message
 
   /* Fold the expression and convert it to a boolean value. */
   condition = fold_non_dependent_expr (condition);
-  condition = cp_convert (boolean_type_node, condition);
+  condition = cp_convert (boolean_type_node, condition, tf_warning_or_error);
   condition = maybe_constant_value (condition);
 
   if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition))
Index: cp/call.c
===================================================================
--- cp/call.c	(revision 188204)
+++ cp/call.c	(working copy)
@@ -5379,7 +5379,7 @@  non_placement_deallocation_fn_p (tree t)
 tree
 build_op_delete_call (enum tree_code code, tree addr, tree size,
 		      bool global_p, tree placement,
-		      tree alloc_fn)
+		      tree alloc_fn, tsubst_flags_t complain)
 {
   tree fn = NULL_TREE;
   tree fns, fnname, type, t;
@@ -5413,7 +5413,7 @@  build_op_delete_call (enum tree_code code, tree ad
     fns = lookup_name_nonclass (fnname);
 
   /* Strip const and volatile from addr.  */
-  addr = cp_convert (ptr_type_node, addr);
+  addr = cp_convert (ptr_type_node, addr, complain);
 
   if (placement)
     {
@@ -5452,8 +5452,13 @@  build_op_delete_call (enum tree_code code, tree ad
 		  && FUNCTION_ARG_CHAIN (elt) == void_list_node)
 		goto ok;
 	    }
-	  permerror (0, "non-placement deallocation function %q+D", fn);
-	  permerror (input_location, "selected for placement delete");
+	  if (complain & tf_error)
+	    {
+	      permerror (0, "non-placement deallocation function %q+D", fn);
+	      permerror (input_location, "selected for placement delete");
+	    }
+	  else
+	    return error_mark_node;
 	ok:;
 	}
     }
@@ -5518,7 +5523,7 @@  build_op_delete_call (enum tree_code code, tree ad
 	  VEC_quick_push (tree, args, addr);
 	  if (FUNCTION_ARG_CHAIN (fn) != void_list_node)
 	    VEC_quick_push (tree, args, size);
-	  ret = cp_build_function_call_vec (fn, &args, tf_warning_or_error);
+	  ret = cp_build_function_call_vec (fn, &args, complain);
 	  VEC_free (tree, gc, args);
 	  return ret;
 	}
@@ -5531,14 +5536,16 @@  build_op_delete_call (enum tree_code code, tree ad
      be freed.  */
   if (alloc_fn)
     {
-      if (!placement)
+      if ((complain & tf_warning)
+	  && !placement)
 	warning (0, "no corresponding deallocation function for %qD",
 		 alloc_fn);
       return NULL_TREE;
     }
 
-  error ("no suitable %<operator %s%> for %qT",
-	 operator_name_info[(int)code].name, type);
+  if (complain & tf_error)
+    error ("no suitable %<operator %s%> for %qT",
+	   operator_name_info[(int)code].name, type);
   return error_mark_node;
 }
 
@@ -5685,9 +5692,10 @@  convert_like_real (conversion *convs, tree expr, t
 					complain);
 	      if (convs->kind == ck_ref_bind)
 		return convert_to_reference (totype, expr, CONV_IMPLICIT,
-					     LOOKUP_NORMAL, NULL_TREE);
+					     LOOKUP_NORMAL, NULL_TREE,
+					     complain);
 	      else
-		return cp_convert (totype, expr);
+		return cp_convert (totype, expr, complain);
 	    }
 	  else if (t->kind == ck_user || !t->bad_p)
 	    {
@@ -5712,7 +5720,7 @@  convert_like_real (conversion *convs, tree expr, t
 	permerror (DECL_SOURCE_LOCATION (fn),
 		   "  initializing argument %P of %qD", argnum, fn);
 
-      return cp_convert (totype, expr);
+      return cp_convert (totype, expr, complain);
     }
 
   if (issue_conversion_warnings && (complain & tf_warning))
@@ -5851,7 +5859,7 @@  convert_like_real (conversion *convs, tree expr, t
 	/* Take the address explicitly rather than via decay_conversion
 	   to avoid the error about taking the address of a temporary.  */
 	array = cp_build_addr_expr (array, complain);
-	array = cp_convert (build_pointer_type (elttype), array);
+	array = cp_convert (build_pointer_type (elttype), array, complain);
 
 	/* Build up the initializer_list object.  */
 	totype = complete_type (totype);
@@ -6017,7 +6025,7 @@  convert_like_real (conversion *convs, tree expr, t
 	   reference.  This will adjust the pointer if a derived to
 	   base conversion is being performed.  */
 	expr = cp_convert (build_pointer_type (TREE_TYPE (ref_type)),
-			   expr);
+			   expr, complain);
 	/* Convert the pointer to the desired reference type.  */
 	return build_nop (ref_type, expr);
       }
@@ -6099,9 +6107,9 @@  convert_arg_to_ellipsis (tree arg, tsubst_flags_t
 	  if (complain & tf_warning)
 	    warning_at (loc, OPT_Wabi, "scoped enum %qT will not promote to an "
 			"integral type in a future version of GCC", arg_type);
-	  arg = cp_convert (ENUM_UNDERLYING_TYPE (arg_type), arg);
+	  arg = cp_convert (ENUM_UNDERLYING_TYPE (arg_type), arg, complain);
 	}
-      arg = perform_integral_promotions (arg);
+      arg = cp_perform_integral_promotions (arg, complain);
     }
 
   arg = require_complete_type (arg);
@@ -6336,7 +6344,7 @@  convert_for_arg_passing (tree type, tree val, tsub
 	   && COMPLETE_TYPE_P (type)
 	   && INT_CST_LT_UNSIGNED (TYPE_SIZE (type),
 				   TYPE_SIZE (integer_type_node)))
-    val = perform_integral_promotions (val);
+    val = cp_perform_integral_promotions (val, complain);
   if ((complain & tf_warning)
       && warn_suggest_attribute_format)
     {
Index: cp/cvt.c
===================================================================
--- cp/cvt.c	(revision 188203)
+++ cp/cvt.c	(working copy)
@@ -38,10 +38,10 @@  along with GCC; see the file COPYING3.  If not see
 #include "decl.h"
 #include "target.h"
 
-static tree cp_convert_to_pointer (tree, tree);
-static tree convert_to_pointer_force (tree, tree);
+static tree cp_convert_to_pointer (tree, tree, tsubst_flags_t);
+static tree convert_to_pointer_force (tree, tree, tsubst_flags_t);
 static tree build_type_conversion (tree, tree);
-static tree build_up_reference (tree, tree, int, tree);
+static tree build_up_reference (tree, tree, int, tree, tsubst_flags_t);
 static void warn_ref_binding (location_t, tree, tree, tree);
 
 /* Change of width--truncation and extension of integers or reals--
@@ -74,7 +74,7 @@  static void warn_ref_binding (location_t, tree, tr
    else try C-style pointer conversion.  */
 
 static tree
-cp_convert_to_pointer (tree type, tree expr)
+cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
 {
   tree intype = TREE_TYPE (expr);
   enum tree_code form;
@@ -89,15 +89,17 @@  static tree
       intype = complete_type (intype);
       if (!COMPLETE_TYPE_P (intype))
 	{
-	  error_at (loc, "can%'t convert from incomplete type %qT to %qT",
-		    intype, type);
+	  if (complain & tf_error)
+	    error_at (loc, "can%'t convert from incomplete type %qT to %qT",
+		      intype, type);
 	  return error_mark_node;
 	}
 
       rval = build_type_conversion (type, expr);
       if (rval)
 	{
-	  if (rval == error_mark_node)
+	  if ((complain & tf_error)
+	      && rval == error_mark_node)
 	    error_at (loc, "conversion of %qE from %qT to %qT is ambiguous",
 		      expr, intype, type);
 	  return rval;
@@ -111,7 +113,7 @@  static tree
     {
       if (TYPE_PTRMEMFUNC_P (intype)
 	  || TREE_CODE (intype) == METHOD_TYPE)
-	return convert_member_func_to_ptr (type, expr, tf_warning_or_error);
+	return convert_member_func_to_ptr (type, expr, complain);
       if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
 	return build_nop (type, expr);
       intype = TREE_TYPE (expr);
@@ -159,8 +161,7 @@  static tree
 	  if (binfo || same_p)
 	    {
 	      if (binfo)
-		expr = build_base_path (code, expr, binfo, 0,
-					tf_warning_or_error);
+		expr = build_base_path (code, expr, binfo, 0, complain);
 	      /* Add any qualifier conversions.  */
 	      return build_nop (type, expr);
 	    }
@@ -168,8 +169,9 @@  static tree
 
       if (TYPE_PTRMEMFUNC_P (type))
 	{
-	  error_at (loc, "cannot convert %qE from type %qT to type %qT",
-		    expr, intype, type);
+	  if (complain & tf_error)
+	    error_at (loc, "cannot convert %qE from type %qT to type %qT",
+		      expr, intype, type);
 	  return error_mark_node;
 	}
 
@@ -178,20 +180,20 @@  static tree
   else if ((TYPE_PTRDATAMEM_P (type) && TYPE_PTRDATAMEM_P (intype))
 	   || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
     return convert_ptrmem (type, expr, /*allow_inverse_p=*/false,
-			   /*c_cast_p=*/false, tf_warning_or_error);
+			   /*c_cast_p=*/false, complain);
   else if (TYPE_PTRMEMFUNC_P (intype))
     {
       if (!warn_pmf2ptr)
 	{
 	  if (TREE_CODE (expr) == PTRMEM_CST)
-	    return cp_convert_to_pointer (type,
-					  PTRMEM_CST_MEMBER (expr));
+	    return cp_convert_to_pointer (type, PTRMEM_CST_MEMBER (expr),
+					  complain);
 	  else if (TREE_CODE (expr) == OFFSET_REF)
 	    {
 	      tree object = TREE_OPERAND (expr, 0);
 	      return get_member_function_from_ptrfunc (&object,
 						       TREE_OPERAND (expr, 1),
-						       tf_warning_or_error);
+						       complain);
 	    }
 	}
       error_at (loc, "cannot convert %qE from type %qT to type %qT",
@@ -201,14 +203,15 @@  static tree
 
   if (null_ptr_cst_p (expr))
     {
-      if (c_inhibit_evaluation_warnings == 0
+      if ((complain & tf_warning)
+	  && c_inhibit_evaluation_warnings == 0
 	  && !NULLPTR_TYPE_P (TREE_TYPE (expr)))
 	warning_at (loc, OPT_Wzero_as_null_pointer_constant,
 		    "zero as null pointer constant");
 
       if (TYPE_PTRMEMFUNC_P (type))
 	return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), expr, 0,
-				 /*c_cast_p=*/false, tf_warning_or_error);
+				 /*c_cast_p=*/false, complain);
 
       if (TYPE_PTRDATAMEM_P (type))
 	{
@@ -223,7 +226,8 @@  static tree
     }
   else if (TYPE_PTRMEM_P (type) && INTEGRAL_CODE_P (form))
     {
-      error_at (loc, "invalid conversion from %qT to %qT", intype, type);
+      if (complain & tf_error)
+	error_at (loc, "invalid conversion from %qT to %qT", intype, type);
       return error_mark_node;
     }
 
@@ -231,7 +235,8 @@  static tree
     {
       if (TYPE_PRECISION (intype) == POINTER_SIZE)
 	return build1 (CONVERT_EXPR, type, expr);
-      expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 0), expr);
+      expr = cp_convert (c_common_type_for_size (POINTER_SIZE, 0), expr,
+			 complain);
       /* Modes may be different but sizes should be the same.  There
 	 is supposed to be some integral type that is the same width
 	 as a pointer.  */
@@ -242,10 +247,11 @@  static tree
     }
 
   if (type_unknown_p (expr))
-    return instantiate_type (type, expr, tf_warning_or_error);
+    return instantiate_type (type, expr, complain);
 
-  error_at (loc, "cannot convert %qE from type %qT to type %qT",
-	    expr, intype, type);
+  if (complain & tf_error)
+    error_at (loc, "cannot convert %qE from type %qT to type %qT",
+	      expr, intype, type);
   return error_mark_node;
 }
 
@@ -254,7 +260,7 @@  static tree
    (such as conversion from sub-type to private super-type).  */
 
 static tree
-convert_to_pointer_force (tree type, tree expr)
+convert_to_pointer_force (tree type, tree expr, tsubst_flags_t complain)
 {
   tree intype = TREE_TYPE (expr);
   enum tree_code form = TREE_CODE (intype);
@@ -284,8 +290,7 @@  static tree
 	    return error_mark_node;
 	  if (binfo)
 	    {
-	      expr = build_base_path (code, expr, binfo, 0,
-				      tf_warning_or_error);
+	      expr = build_base_path (code, expr, binfo, 0, complain);
 	      if (expr == error_mark_node)
 		 return error_mark_node;
 	      /* Add any qualifier conversions.  */
@@ -297,7 +302,7 @@  static tree
 	}
     }
 
-  return cp_convert_to_pointer (type, expr);
+  return cp_convert_to_pointer (type, expr, complain);
 }
 
 /* We are passing something to a function which requires a reference.
@@ -309,7 +314,8 @@  static tree
      If DIRECT_BIND is set, DECL is the reference we're binding to.  */
 
 static tree
-build_up_reference (tree type, tree arg, int flags, tree decl)
+build_up_reference (tree type, tree arg, int flags, tree decl,
+		    tsubst_flags_t complain)
 {
   tree rval;
   tree argtype = TREE_TYPE (arg);
@@ -351,12 +357,12 @@  static tree
 	return error_mark_node;
       if (binfo == NULL_TREE)
 	return error_not_base_type (target_type, argtype);
-      rval = build_base_path (PLUS_EXPR, rval, binfo, 1,
-			      tf_warning_or_error);
+      rval = build_base_path (PLUS_EXPR, rval, binfo, 1, complain);
     }
   else
     rval
-      = convert_to_pointer_force (build_pointer_type (target_type), rval);
+      = convert_to_pointer_force (build_pointer_type (target_type),
+				  rval, complain);
   return build_nop (type, rval);
 }
 
@@ -403,15 +409,13 @@  warn_ref_binding (location_t loc, tree reftype, tr
 
 tree
 convert_to_reference (tree reftype, tree expr, int convtype,
-		      int flags, tree decl)
+		      int flags, tree decl, tsubst_flags_t complain)
 {
   tree type = TYPE_MAIN_VARIANT (TREE_TYPE (reftype));
   tree intype;
   tree rval = NULL_TREE;
   tree rval_as_conversion = NULL_TREE;
   bool can_convert_intype_to_type;
-  tsubst_flags_t complain = ((flags & LOOKUP_COMPLAIN)
-			     ? tf_warning_or_error : tf_none);
   location_t loc = EXPR_LOC_OR_HERE (expr);
 
   if (TREE_CODE (type) == FUNCTION_TYPE
@@ -457,7 +461,8 @@  convert_to_reference (tree reftype, tree expr, int
 	  tree ttl = TREE_TYPE (reftype);
 	  tree ttr = lvalue_type (expr);
 
-	  if (! real_lvalue_p (expr))
+	  if ((complain & tf_warning)
+	      && ! real_lvalue_p (expr))
 	    warn_ref_binding (loc, reftype, intype, decl);
 
 	  if (! (convtype & CONV_CONST)
@@ -466,7 +471,7 @@  convert_to_reference (tree reftype, tree expr, int
 		       ttr, reftype);
 	}
 
-      return build_up_reference (reftype, expr, flags, decl);
+      return build_up_reference (reftype, expr, flags, decl, complain);
     }
   else if ((convtype & CONV_REINTERPRET) && lvalue_p (expr))
     {
@@ -477,16 +482,17 @@  convert_to_reference (tree reftype, tree expr, int
 
       /* B* bp; A& ar = (A&)bp; is valid, but it's probably not what they
 	 meant.  */
-      if (TREE_CODE (intype) == POINTER_TYPE
+      if ((complain & tf_warning)
+	  && TREE_CODE (intype) == POINTER_TYPE
 	  && (comptypes (TREE_TYPE (intype), type,
 			 COMPARE_BASE | COMPARE_DERIVED)))
 	warning_at (loc, 0, "casting %qT to %qT does not dereference pointer",
 		    intype, reftype);
 
-      rval = cp_build_addr_expr (expr, tf_warning_or_error);
+      rval = cp_build_addr_expr (expr, complain);
       if (rval != error_mark_node)
 	rval = convert_force (build_pointer_type (TREE_TYPE (reftype)),
-			      rval, 0);
+			      rval, 0, complain);
       if (rval != error_mark_node)
 	rval = build1 (NOP_EXPR, reftype, rval);
     }
@@ -494,11 +500,12 @@  convert_to_reference (tree reftype, tree expr, int
     {
       rval = convert_for_initialization (NULL_TREE, type, expr, flags,
 					 ICR_CONVERTING, 0, 0,
-                                         tf_warning_or_error);
+                                         complain);
       if (rval == NULL_TREE || rval == error_mark_node)
 	return rval;
-      warn_ref_binding (loc, reftype, intype, decl);
-      rval = build_up_reference (reftype, rval, flags, decl);
+      if (complain & tf_warning)
+	warn_ref_binding (loc, reftype, intype, decl);
+      rval = build_up_reference (reftype, rval, flags, decl, complain);
     }
 
   if (rval)
@@ -595,9 +602,9 @@  cp_fold_convert (tree type, tree expr)
 /* C++ conversions, preference to static cast conversions.  */
 
 tree
-cp_convert (tree type, tree expr)
+cp_convert (tree type, tree expr, tsubst_flags_t complain)
 {
-  return ocp_convert (type, expr, CONV_OLD_CONVERT, LOOKUP_NORMAL);
+  return ocp_convert (type, expr, CONV_OLD_CONVERT, LOOKUP_NORMAL, complain);
 }
 
 /* C++ equivalent of convert_and_check but using cp_convert as the
@@ -608,16 +615,17 @@  tree
    i.e. because of language rules and not because of an explicit cast.  */
 
 tree
-cp_convert_and_check (tree type, tree expr)
+cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
 {
   tree result;
 
   if (TREE_TYPE (expr) == type)
     return expr;
   
-  result = cp_convert (type, expr);
+  result = cp_convert (type, expr, complain);
 
-  if (c_inhibit_evaluation_warnings == 0
+  if ((complain & tf_warning)
+      && c_inhibit_evaluation_warnings == 0
       && !TREE_OVERFLOW_P (expr)
       && result != error_mark_node)
     warnings_for_convert_and_check (type, expr, result);
@@ -630,7 +638,8 @@  tree
    FLAGS indicates how we should behave.  */
 
 tree
-ocp_convert (tree type, tree expr, int convtype, int flags)
+ocp_convert (tree type, tree expr, int convtype, int flags,
+	     tsubst_flags_t complain)
 {
   tree e = expr;
   enum tree_code code = TREE_CODE (type);
@@ -647,7 +656,8 @@  tree
   if ((invalid_conv_diag
        = targetm.invalid_conversion (TREE_TYPE (expr), type)))
     {
-      error (invalid_conv_diag);
+      if (complain & tf_error)
+	error (invalid_conv_diag);
       return error_mark_node;
     }
 
@@ -696,7 +706,7 @@  tree
 
   if (code == VOID_TYPE && (convtype & CONV_STATIC))
     {
-      e = convert_to_void (e, ICV_CAST, tf_warning_or_error);
+      e = convert_to_void (e, ICV_CAST, complain);
       return e;
     }
 
@@ -714,9 +724,14 @@  tree
 	       && ! (convtype & CONV_STATIC))
 	      || TREE_CODE (intype) == POINTER_TYPE)
 	    {
-	      if (flags & LOOKUP_COMPLAIN)
-		permerror (loc, "conversion from %q#T to %q#T", intype, type);
-	      if (!flag_permissive)
+	      if (complain & tf_error)
+		{
+		  permerror (loc, "conversion from %q#T to %q#T",
+			     intype, type);
+		  if (!flag_permissive)
+		    return error_mark_node;
+		}
+	      else
 		return error_mark_node;
 	    }
 
@@ -727,7 +742,8 @@  tree
 	     the original value is within the range of the enumeration
 	     values. Otherwise, the resulting enumeration value is
 	     unspecified.  */
-	  if (TREE_CODE (expr) == INTEGER_CST
+	  if ((complain & tf_warning)
+	      && TREE_CODE (expr) == INTEGER_CST
 	      && !int_fits_type_p (expr, ENUM_UNDERLYING_TYPE (type)))
 	    warning_at (loc, OPT_Wconversion, 
 			"the result of the conversion is unspecified because "
@@ -740,7 +756,7 @@  tree
 	  rval = build_type_conversion (type, e);
 	  if (rval)
 	    return rval;
-	  if (flags & LOOKUP_COMPLAIN)
+	  if (complain & tf_error)
 	    error_at (loc, "%q#T used where a %qT was expected", intype, type);
 	  return error_mark_node;
 	}
@@ -748,8 +764,10 @@  tree
 	{
 	  if (TREE_CODE (intype) == VOID_TYPE)
 	    {
-	      error_at (loc, "could not convert %qE from %<void%> to %<bool%>",
-			expr);
+	      if (complain & tf_error)
+		error_at (loc,
+			  "could not convert %qE from %<void%> to %<bool%>",
+			  expr);
 	      return error_mark_node;
 	    }
 
@@ -768,7 +786,7 @@  tree
   if (NULLPTR_TYPE_P (type) && e && null_ptr_cst_p (e))
     return nullptr_node;
   if (POINTER_TYPE_P (type) || TYPE_PTRMEM_P (type))
-    return fold_if_not_in_template (cp_convert_to_pointer (type, e));
+    return fold_if_not_in_template (cp_convert_to_pointer (type, e, complain));
   if (code == VECTOR_TYPE)
     {
       tree in_vtype = TREE_TYPE (e);
@@ -778,8 +796,9 @@  tree
 	  ret_val = build_type_conversion (type, e);
 	  if (ret_val)
 	    return ret_val;
-	  if (flags & LOOKUP_COMPLAIN)
-	    error_at (loc, "%q#T used where a %qT was expected", in_vtype, type);
+	  if (complain & tf_error)
+	    error_at (loc, "%q#T used where a %qT was expected",
+		      in_vtype, type);
 	  return error_mark_node;
 	}
       return fold_if_not_in_template (convert_to_vector (type, e));
@@ -792,10 +811,10 @@  tree
 	  rval = build_type_conversion (type, e);
 	  if (rval)
 	    return rval;
-	  else
-	    if (flags & LOOKUP_COMPLAIN)
-	      error_at (loc, "%q#T used where a floating point value was expected",
-			TREE_TYPE (e));
+	  else if (complain & tf_error)
+	    error_at (loc,
+		      "%q#T used where a floating point value was expected",
+		      TREE_TYPE (e));
 	}
       if (code == REAL_TYPE)
 	return fold_if_not_in_template (convert_to_real (type, e));
@@ -826,33 +845,31 @@  tree
 	return error_mark_node;
 
       if (BRACE_ENCLOSED_INITIALIZER_P (ctor))
-	ctor = perform_implicit_conversion (type, ctor, tf_warning_or_error);
+	ctor = perform_implicit_conversion (type, ctor, complain);
       else if ((flags & LOOKUP_ONLYCONVERTING)
 	       && ! (CLASS_TYPE_P (dtype) && DERIVED_FROM_P (type, dtype)))
 	/* For copy-initialization, first we create a temp of the proper type
 	   with a user-defined conversion sequence, then we direct-initialize
 	   the target with the temp (see [dcl.init]).  */
-	ctor = build_user_type_conversion (type, ctor, flags,
-					   tf_warning_or_error);
+	ctor = build_user_type_conversion (type, ctor, flags, complain);
       else
 	{
 	  VEC(tree,gc) *ctor_vec = make_tree_vector_single (ctor);
 	  ctor = build_special_member_call (NULL_TREE,
 					    complete_ctor_identifier,
 					    &ctor_vec,
-					    type, flags,
-					    tf_warning_or_error);
+					    type, flags, complain);
 	  release_tree_vector (ctor_vec);
 	}
       if (ctor)
-	return build_cplus_new (type, ctor, tf_warning_or_error);
+	return build_cplus_new (type, ctor, complain);
     }
 
-  if (flags & LOOKUP_COMPLAIN)
+  if (complain & tf_error)
     {
       /* If the conversion failed and expr was an invalid use of pointer to
 	 member function, try to report a meaningful error.  */
-      if (invalid_nonstatic_memfn_p (expr, tf_warning_or_error))
+      if (invalid_nonstatic_memfn_p (expr, complain))
 	/* We displayed the error message.  */;
       else
 	error_at (loc, "conversion from %qT to non-scalar type %qT requested",
@@ -1416,7 +1433,8 @@  convert (tree type, tree expr)
     return fold_if_not_in_template (build_nop (type, expr));
 
   return ocp_convert (type, expr, CONV_OLD_CONVERT,
-		      LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
+		      LOOKUP_NORMAL|LOOKUP_NO_CONVERSION,
+		      tf_warning_or_error);
 }
 
 /* Like cp_convert, except permit conversions to take place which
@@ -1424,7 +1442,7 @@  convert (tree type, tree expr)
    (such as conversion from sub-type to private super-type).  */
 
 tree
-convert_force (tree type, tree expr, int convtype)
+convert_force (tree type, tree expr, int convtype, tsubst_flags_t complain)
 {
   tree e = expr;
   enum tree_code code = TREE_CODE (type);
@@ -1432,10 +1450,11 @@  tree
   if (code == REFERENCE_TYPE)
     return (fold_if_not_in_template
 	    (convert_to_reference (type, e, CONV_C_CAST, LOOKUP_COMPLAIN,
-				   NULL_TREE)));
+				   NULL_TREE, complain)));
 
   if (code == POINTER_TYPE)
-    return fold_if_not_in_template (convert_to_pointer_force (type, e));
+    return fold_if_not_in_template (convert_to_pointer_force (type, e,
+							      complain));
 
   /* From typeck.c convert_for_assignment */
   if (((TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE && TREE_CODE (e) == ADDR_EXPR
@@ -1446,9 +1465,9 @@  tree
       && TYPE_PTRMEMFUNC_P (type))
     /* compatible pointer to member functions.  */
     return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), e, 1,
-			     /*c_cast_p=*/1, tf_warning_or_error);
+			     /*c_cast_p=*/1, complain);
 
-  return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL);
+  return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL, complain);
 }
 
 /* Convert an aggregate EXPR to type XTYPE.  If a conversion
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 188203)
+++ cp/cp-tree.h	(working copy)
@@ -4894,7 +4894,9 @@  extern tree build_new_op			(location_t, enum tree_
 						 tsubst_flags_t);
 extern tree build_op_call			(tree, VEC(tree,gc) **,
 						 tsubst_flags_t);
-extern tree build_op_delete_call		(enum tree_code, tree, tree, bool, tree, tree);
+extern tree build_op_delete_call		(enum tree_code, tree, tree,
+						 bool, tree, tree,
+						 tsubst_flags_t);
 extern bool can_convert				(tree, tree, tsubst_flags_t);
 extern bool can_convert_arg			(tree, tree, tree, int,
 						 tsubst_flags_t);
@@ -5001,16 +5003,19 @@  extern void adjust_clone_args			(tree);
 extern void deduce_noexcept_on_destructor       (tree);
 
 /* in cvt.c */
-extern tree convert_to_reference		(tree, tree, int, int, tree);
+extern tree convert_to_reference		(tree, tree, int, int, tree,
+						 tsubst_flags_t);
 extern tree convert_from_reference		(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);
+extern tree ocp_convert				(tree, tree, int, int,
+						 tsubst_flags_t);
+extern tree cp_convert				(tree, tree, tsubst_flags_t);
+extern tree cp_convert_and_check                (tree, tree, tsubst_flags_t);
 extern tree cp_fold_convert			(tree, tree);
 extern tree convert_to_void			(tree, impl_conv_void,
                                  		 tsubst_flags_t);
-extern tree convert_force			(tree, tree, int);
+extern tree convert_force			(tree, tree, int,
+						 tsubst_flags_t);
 extern tree build_expr_type_conversion		(int, tree, bool);
 extern tree type_promotes_to			(tree);
 extern tree perform_qualification_conversions	(tree, tree);
@@ -5901,6 +5906,7 @@  extern void check_template_keyword		(tree);
 extern bool check_raw_literal_operator		(const_tree decl);
 extern bool check_literal_operator_args		(const_tree, bool *, bool *);
 extern void maybe_warn_about_useless_cast       (tree, tree, tsubst_flags_t);
+extern tree cp_perform_integral_promotions      (tree, tsubst_flags_t);
 
 /* in typeck2.c */
 extern void require_complete_eh_spec_types	(tree, tree);