diff mbox

[C++] PR 53567

Message ID 4FCCC301.7040505@oracle.com
State New
Headers show

Commit Message

Paolo Carlini June 4, 2012, 2:15 p.m. UTC
Hi,

in this "error reporting routines re-entered" ICE we try to emit a 
warning from ocp_convert while we are already producing an error message 
(we get to ocp_convert via the usual tsubst (tf_none) called by 
dump_template_bindings). I considered whether we could avoid the 
specific problem by passing different FLAGS to ocp_convert when 
build_static_cast_1 is called with tf_none, but I think it would be 
tricky and error-prone, because ocp_convert has a mix of errors, 
warnings, errors not protected by flags & LOOKUP_COMPLAIN. Anyway, when 
I tried the usual tsubst_flags_t route, I saw a large patch but also 
quite a few loose ends solved (which I noticed other times), 
convert_to_reference isn't special anymore in having to "synthesize" a 
complain, all in all very few explicit tf_warning_or_error remain, and 
in safe places, as far as I can see.

Bootstrapped and tested x86_64-linux.

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.
	* 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): 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, convert_like_real,
	convert_arg_to_ellipsis, convert_for_arg_passing): Likewise.
	* 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.

Comments

Jason Merrill June 4, 2012, 6:12 p.m. UTC | #1
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.

> +	      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.

Jason
diff mbox

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 188167)
+++ cp/typeck.c	(working copy)
@@ -53,7 +53,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);
@@ -1907,7 +1907,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
@@ -1951,12 +1951,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);
 
@@ -1976,7 +1976,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;
@@ -1996,10 +1996,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.  */
 
@@ -2946,7 +2954,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
@@ -3868,7 +3876,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))
@@ -4004,7 +4013,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;
 	}
@@ -4032,7 +4041,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;
 	}
@@ -4063,7 +4072,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;
 
@@ -4163,12 +4172,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);
 	}
@@ -4191,9 +4200,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;
@@ -4457,16 +4466,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;
@@ -4551,7 +4560,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;
@@ -4581,9 +4590,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;
@@ -4595,7 +4604,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) 
@@ -4628,7 +4637,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;
@@ -4638,24 +4647,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)
@@ -4663,7 +4696,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);
 }
 
@@ -5176,7 +5210,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.  */
@@ -5201,7 +5235,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:
@@ -5359,7 +5393,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
@@ -6075,7 +6109,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))
@@ -6418,7 +6452,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
@@ -7079,7 +7113,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)
     {
@@ -7600,7 +7634,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/init.c
===================================================================
--- cp/init.c	(revision 188167)
+++ 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
@@ -2815,7 +2816,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 +3013,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);
 	}
@@ -3189,14 +3190,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 +3666,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 +3692,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));
Index: cp/class.c
===================================================================
--- cp/class.c	(revision 188167)
+++ 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 188167)
+++ 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;
 
Index: cp/rtti.c
===================================================================
--- cp/rtti.c	(revision 188167)
+++ 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 188167)
+++ 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 188167)
+++ cp/typeck2.c	(working copy)
@@ -1265,7 +1265,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 188167)
+++ cp/semantics.c	(working copy)
@@ -565,7 +565,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;
 	}
@@ -4527,7 +4528,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);
@@ -4582,7 +4584,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)
@@ -5131,7 +5133,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 188167)
+++ cp/call.c	(working copy)
@@ -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);
 
   if (placement)
     {
@@ -5685,9 +5685,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 +5713,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 +5852,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 +6018,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 +6100,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 +6337,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 188167)
+++ 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,15 @@  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)
+		{
+		  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;
 	    }
 
@@ -727,7 +743,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 +757,8 @@  tree
 	  rval = build_type_conversion (type, e);
 	  if (rval)
 	    return rval;
-	  if (flags & LOOKUP_COMPLAIN)
+	  if ((complain & tf_error)
+	      && (flags & LOOKUP_COMPLAIN))
 	    error_at (loc, "%q#T used where a %qT was expected", intype, type);
 	  return error_mark_node;
 	}
@@ -748,8 +766,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 +788,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 +798,10 @@  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)
+	      && (flags & LOOKUP_COMPLAIN))
+	    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));
@@ -793,8 +815,10 @@  tree
 	  if (rval)
 	    return rval;
 	  else
-	    if (flags & LOOKUP_COMPLAIN)
-	      error_at (loc, "%q#T used where a floating point value was expected",
+	    if ((complain & tf_error)
+		&& (flags & LOOKUP_COMPLAIN))
+	      error_at (loc,
+			"%q#T used where a floating point value was expected",
 			TREE_TYPE (e));
 	}
       if (code == REAL_TYPE)
@@ -826,35 +850,33 @@  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 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
+      else if (complain & tf_error)
 	error_at (loc, "conversion from %qT to non-scalar type %qT requested",
 		  TREE_TYPE (expr), type);
     }
@@ -1416,7 +1438,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 +1447,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 +1455,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 +1470,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 188167)
+++ cp/cp-tree.h	(working copy)
@@ -5001,16 +5001,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);
@@ -5899,6 +5902,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);