public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ Patch] PR 53567
@ 2012-06-04 14:17 Paolo Carlini
  2012-06-04 18:12 ` Jason Merrill
  0 siblings, 1 reply; 19+ messages in thread
From: Paolo Carlini @ 2012-06-04 14:17 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill

[-- Attachment #1: Type: text/plain, Size: 942 bytes --]

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.

/////////////////////

[-- Attachment #2: CL_53567 --]
[-- Type: text/plain, Size: 1437 bytes --]

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


[-- Attachment #3: patch_53567_5 --]
[-- Type: text/plain, Size: 46830 bytes --]

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);
 }
 \f
@@ -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);

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-04 14:17 [C++ Patch] PR 53567 Paolo Carlini
@ 2012-06-04 18:12 ` Jason Merrill
  2012-06-04 22:57   ` Paolo Carlini
  0 siblings, 1 reply; 19+ messages in thread
From: Jason Merrill @ 2012-06-04 18:12 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches

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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-04 18:12 ` Jason Merrill
@ 2012-06-04 22:57   ` Paolo Carlini
  2012-06-04 23:23     ` Jason Merrill
  0 siblings, 1 reply; 19+ messages in thread
From: Paolo Carlini @ 2012-06-04 22:57 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2152 bytes --]

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.

/////////////////////

[-- Attachment #2: CL_53567_6 --]
[-- Type: text/plain, Size: 1546 bytes --]

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


[-- Attachment #3: patch_53567_6 --]
[-- Type: text/plain, Size: 52050 bytes --]

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);
 }
 \f
@@ -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);

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-04 22:57   ` Paolo Carlini
@ 2012-06-04 23:23     ` Jason Merrill
  2012-06-04 23:47       ` Paolo Carlini
  0 siblings, 1 reply; 19+ messages in thread
From: Jason Merrill @ 2012-06-04 23:23 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches

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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-04 23:23     ` Jason Merrill
@ 2012-06-04 23:47       ` Paolo Carlini
  2012-06-05  0:24         ` Paolo Carlini
  0 siblings, 1 reply; 19+ messages in thread
From: Paolo Carlini @ 2012-06-04 23:47 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

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.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-04 23:47       ` Paolo Carlini
@ 2012-06-05  0:24         ` Paolo Carlini
  2012-06-05  2:11           ` Jason Merrill
  0 siblings, 1 reply; 19+ messages in thread
From: Paolo Carlini @ 2012-06-05  0:24 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

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.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-05  0:24         ` Paolo Carlini
@ 2012-06-05  2:11           ` Jason Merrill
  2012-06-05 11:02             ` Paolo Carlini
  0 siblings, 1 reply; 19+ messages in thread
From: Jason Merrill @ 2012-06-05  2:11 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches

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

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-05  2:11           ` Jason Merrill
@ 2012-06-05 11:02             ` Paolo Carlini
  2012-06-05 14:17               ` Jason Merrill
  0 siblings, 1 reply; 19+ messages in thread
From: Paolo Carlini @ 2012-06-05 11:02 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 608 bytes --]

Hi,

On 06/05/2012 04:10 AM, Jason Merrill wrote:
> On 06/04/2012 08:22 PM, Paolo Carlini wrote:
>> In fact, I think setting complain to tf_warning may work better.
> Sounds plausible.
Having quickly tried hackish implementations of the idea of allowing 
warnings, the way I actually propose to implement it in 
implicit_conversion is by masking out tf_error in the same place where 
we adjust the flags: exactly were we used to mask out LOOKUP_COMPLAIN we 
now mask out tf_error.

The patch passes bootstrap and testing on x86_64-linux, LOOKUP_COMPLAIN 
is gone ;)

Thanks,
Paolo.

///////////////////////


[-- Attachment #2: CL_53567_12 --]
[-- Type: text/plain, Size: 2509 bytes --]

/cp
2012-06-05  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_1,
	build_new, build_vec_delete_1, build_vec_init, build_delete): Adjust.
	(construct_virtual_base): Adjust LOOKUP_COMPLAIN -> LOOKUP_NORMAL.
	* class.c (build_base_path): Adjust.
	* decl.c (compute_array_index_type, finish_destructor_body): Likewise.
	* method.c (synthesized_method_walk): Adjust LOOKUP_PROTECT -> 
	LOOKUP_NORMAL.
	* 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.
	* pt.c (tsubst_friend_class): Adjust LOOKUP_COMPLAIN -> LOOKUP_NORMAL.
	* semantics.c (finish_goto_stmt, handle_omp_for_class_iterator,
	finish_static_assert): Likewise.
	* parser.c (cp_parser_lookup_name): Adjust LOOKUP_COMPLAIN -> 
	LOOKUP_NORMAL.
	* call.c (build_op_delete_call): Add tsubst_flags_t parameter.
	(convert_like_real, convert_arg_to_ellipsis, convert_for_arg_passing):
	Adjust.
	(standard_conversion): Adjust LOOKUP_COMPLAIN -> LOOKUP_NORMAL.
	(implicit_conversion): Adjust LOOKUP_PROTECT -> LOOKUP_NORMAL; mask
	out tf_error.
	(build_user_type_conversion_1, build_new_op_1, build_over_call): Use
	complain & tf_error instead of flags & LOOKUP_COMPLAIN.
	* 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.
	(convert_to_reference, ocp_convert): Use complain & tf_error instead
	of flags & LOOKUP_COMPLAIN.
	(convert_force): Adjust LOOKUP_COMPLAIN -> LOOKUP_NORMAL.
	* name-lookup.c (identifier_type_value_1, lookup_qualified_name,
	lookup_name_real, lookup_function_nonclass, lookup_name,
	lookup_name_prefer_type): Adjust LOOKUP_COMPLAIN -> LOOKUP_NORMAL.
	* cp-tree.h: Adjust prototypes; remove LOOKUP_COMPLAIN.

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

	PR c++/53567
	* g++.dg/cpp0x/alias-decl-19.C: New.



[-- Attachment #3: patch_53567_12 --]
[-- Type: text/plain, Size: 63006 bytes --]

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);
 }
 \f
@@ -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)
@@ -7723,10 +7757,8 @@ convert_for_assignment (tree type, tree rhs,
    latter (X(X&)).
 
    If using constructor make sure no conversion operator exists, if one does
-   exist, an ambiguity exists.
+   exist, an ambiguity exists.  */
 
-   If flags doesn't include LOOKUP_COMPLAIN, don't complain about anything.  */
-
 tree
 convert_for_initialization (tree exp, tree type, tree rhs, int flags,
 			    impl_conv_rhs errtype, tree fndecl, int parmnum,
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));
 }
@@ -1250,7 +1250,7 @@ construct_virtual_base (tree vbase, tree arguments
   exp = convert_to_base_statically (current_class_ref, vbase);
 
   expand_aggr_init_1 (vbase, current_class_ref, exp, arguments,
-		      LOOKUP_COMPLAIN, tf_warning_or_error);
+		      LOOKUP_NORMAL, tf_warning_or_error);
   finish_then_clause (inner_if_stmt);
   finish_if_stmt (inner_if_stmt);
 
@@ -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/method.c
===================================================================
--- cp/method.c	(revision 188203)
+++ cp/method.c	(working copy)
@@ -1228,17 +1228,10 @@ synthesized_method_walk (tree ctype, special_funct
 
   scope = push_scope (ctype);
 
-  if (diag)
-    {
-      flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
-      complain = tf_warning_or_error;
-    }
-  else
-    {
-      flags = LOOKUP_PROTECT|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
-      complain = tf_none;
-    }
+  flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
 
+  complain = diag ? tf_warning_or_error : tf_none;
+
   if (const_p)
     quals = TYPE_QUAL_CONST;
   else
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/pt.c
===================================================================
--- cp/pt.c	(revision 188203)
+++ cp/pt.c	(working copy)
@@ -8475,7 +8475,7 @@ tsubst_friend_class (tree friend_tmpl, tree args)
      both F templates are the same.  */
   tmpl = lookup_name_real (DECL_NAME (friend_tmpl), 0, 0,
 			   /*block_p=*/true, 0, 
-			   LOOKUP_COMPLAIN | LOOKUP_HIDDEN);
+			   LOOKUP_NORMAL | LOOKUP_HIDDEN);
 
   /* But, if we don't find one, it might be because we're in a
      situation like this:
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/parser.c
===================================================================
--- cp/parser.c	(revision 188203)
+++ cp/parser.c	(working copy)
@@ -20322,7 +20322,7 @@ cp_parser_lookup_name (cp_parser *parser, tree nam
   tree object_type = parser->context->object_type;
 
   if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
-    flags |= LOOKUP_COMPLAIN;
+    flags |= LOOKUP_NORMAL;
 
   /* Assume that the lookup will be unambiguous.  */
   if (ambiguous_decls)
Index: cp/call.c
===================================================================
--- cp/call.c	(revision 188204)
+++ cp/call.c	(working copy)
@@ -1095,7 +1095,7 @@ standard_conversion (tree to, tree from, tree expr
       && expr && type_unknown_p (expr))
     {
       tsubst_flags_t tflags = tf_conv;
-      if (!(flags & LOOKUP_PROTECT))
+      if (!(flags & LOOKUP_NORMAL))
 	tflags |= tf_no_access_control;
       expr = instantiate_type (to, expr, tflags);
       if (expr == error_mark_node)
@@ -1693,8 +1693,10 @@ implicit_conversion (tree to, tree from, tree expr
      resolution, or after we've chosen one.  */
   flags &= (LOOKUP_ONLYCONVERTING|LOOKUP_NO_CONVERSION|LOOKUP_COPY_PARM
 	    |LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND|LOOKUP_PREFER_RVALUE
-	    |LOOKUP_NO_NARROWING|LOOKUP_PROTECT);
+	    |LOOKUP_NO_NARROWING|LOOKUP_NORMAL);
 
+  complain &= ~tf_error;
+
   if (TREE_CODE (to) == REFERENCE_TYPE)
     conv = reference_binding (to, from, expr, c_cast_p, flags, complain);
   else
@@ -3607,8 +3609,7 @@ build_user_type_conversion_1 (tree totype, tree ex
   cand = tourney (candidates, complain);
   if (cand == 0)
     {
-      if ((flags & LOOKUP_COMPLAIN)
-	  && (complain & tf_error))
+      if (complain & tf_error)
 	{
 	  error ("conversion from %qT to %qT is ambiguous",
 		 fromtype, totype);
@@ -5098,7 +5099,7 @@ build_new_op_1 (location_t loc, enum tree_code cod
 	     distinguish between prefix and postfix ++ and
 	     operator++() was used for both, so we allow this with
 	     -fpermissive.  */
-	  if (flags & LOOKUP_COMPLAIN)
+	  else
 	    {
 	      const char *msg = (flag_permissive) 
 		? G_("no %<%D(int)%> declared for postfix %qs,"
@@ -5127,7 +5128,7 @@ build_new_op_1 (location_t loc, enum tree_code cod
 	  break;
 
 	default:
-	  if ((flags & LOOKUP_COMPLAIN) && (complain & tf_error))
+	  if (complain & tf_error)
 	    {
 		/* If one of the arguments of the operator represents
 		   an invalid use of member function pointer, try to report
@@ -5153,7 +5154,7 @@ build_new_op_1 (location_t loc, enum tree_code cod
       cand = tourney (candidates, complain);
       if (cand == 0)
 	{
-	  if ((flags & LOOKUP_COMPLAIN) && (complain & tf_error))
+	  if (complain & tf_error)
 	    {
 	      op_error (loc, code, code2, arg1, arg2, arg3, TRUE);
 	      print_z_candidates (loc, candidates);
@@ -5379,7 +5380,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 +5414,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 +5453,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 +5524,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 +5537,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 +5693,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 +5721,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 +5860,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 +6026,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 +6108,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 +6345,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)
     {
@@ -6487,7 +6496,7 @@ build_over_call (struct z_candidate *cand, int fla
       if (flags & LOOKUP_SPECULATIVE)
 	{
 	  if (!speculative_access_check (cand->access_path, access_fn, fn,
-					 !!(flags & LOOKUP_COMPLAIN)))
+					 complain & tf_error))
 	    return error_mark_node;
 	}
       else
@@ -6500,13 +6509,13 @@ build_over_call (struct z_candidate *cand, int fla
     {
       if (DECL_DELETED_FN (fn))
 	{
-	  if (flags & LOOKUP_COMPLAIN)
+	  if (complain & tf_error)
 	    mark_used (fn);
 	  return error_mark_node;
 	}
       if (cand->viable == 1)
 	return fn;
-      else if (!(flags & LOOKUP_COMPLAIN))
+      else if (!(complain & tf_error))
 	/* Reject bad conversions now.  */
 	return error_mark_node;
       /* else continue to get conversion error.  */
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);
@@ -340,7 +346,7 @@ static tree
   if (rval == error_mark_node)
     return error_mark_node;
 
-  if ((flags & LOOKUP_PROTECT)
+  if ((flags & LOOKUP_NORMAL)
       && TYPE_MAIN_VARIANT (argtype) != TYPE_MAIN_VARIANT (target_type)
       && MAYBE_CLASS_TYPE_P (argtype)
       && MAYBE_CLASS_TYPE_P (target_type))
@@ -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
@@ -452,21 +456,26 @@ convert_to_reference (tree reftype, tree expr, int
   if (((convtype & CONV_STATIC) && can_convert (intype, type, complain))
       || ((convtype & CONV_IMPLICIT) && can_convert_intype_to_type))
     {
-      if (flags & LOOKUP_COMPLAIN)
-	{
-	  tree ttl = TREE_TYPE (reftype);
-	  tree ttr = lvalue_type (expr);
+      {
+	tree ttl = TREE_TYPE (reftype);
+	tree ttr = lvalue_type (expr);
 
-	  if (! real_lvalue_p (expr))
-	    warn_ref_binding (loc, reftype, intype, decl);
+	if ((complain & tf_warning)
+	    && ! real_lvalue_p (expr))
+	  warn_ref_binding (loc, reftype, intype, decl);
 
-	  if (! (convtype & CONV_CONST)
-		   && !at_least_as_qualified_p (ttl, ttr))
-	    permerror (loc, "conversion from %qT to %qT discards qualifiers",
-		       ttr, reftype);
-	}
+	if (! (convtype & CONV_CONST)
+	    && !at_least_as_qualified_p (ttl, ttr))
+	  {
+	    if (complain & tf_error)
+	      permerror (loc, "conversion from %qT to %qT discards qualifiers",
+			 ttr, reftype);
+	    else
+	      return error_mark_node;
+	  }
+      }
 
-      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,28 +486,29 @@ 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);
     }
   else
     {
       rval = convert_for_initialization (NULL_TREE, type, expr, flags,
-					 ICR_CONVERTING, 0, 0,
-                                         tf_warning_or_error);
+					 ICR_CONVERTING, 0, 0, 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)
@@ -507,7 +517,7 @@ convert_to_reference (tree reftype, tree expr, int
       return rval;
     }
 
-  if (flags & LOOKUP_COMPLAIN)
+  if (complain & tf_error)
     error_at (loc, "cannot convert type %qT to type %qT", intype, reftype);
 
   return error_mark_node;
@@ -595,9 +605,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 +618,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 +641,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 +659,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 +709,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 +727,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 +745,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 +759,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 +767,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 +789,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 +799,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 +814,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 +848,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 +1436,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,18 +1445,19 @@ 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);
 
   if (code == REFERENCE_TYPE)
     return (fold_if_not_in_template
-	    (convert_to_reference (type, e, CONV_C_CAST, LOOKUP_COMPLAIN,
-				   NULL_TREE)));
+	    (convert_to_reference (type, e, CONV_C_CAST, LOOKUP_NORMAL,
+				   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 +1468,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)
@@ -4370,17 +4370,13 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, T
    probably be modified to accept explicit boolean flags for the
    behaviors relevant to them.  */
 /* Check for access violations.  */
-#define LOOKUP_PROTECT (1 << 0)
-/* Complain if no suitable member function matching the arguments is
-   found.  */
-#define LOOKUP_COMPLAIN (1 << 1)
-#define LOOKUP_NORMAL (LOOKUP_PROTECT | LOOKUP_COMPLAIN)
+#define LOOKUP_NORMAL (1 << 0)
 /* Even if the function found by lookup is a virtual function, it
    should be called directly.  */
-#define LOOKUP_NONVIRTUAL (1 << 2)
+#define LOOKUP_NONVIRTUAL (1 << 1)
 /* Non-converting (i.e., "explicit") constructors are not tried.  This flag
    indicates that we are not performing direct-initialization.  */
-#define LOOKUP_ONLYCONVERTING (1 << 3)
+#define LOOKUP_ONLYCONVERTING (1 << 2)
 #define LOOKUP_IMPLICIT (LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING)
 /* If a temporary is created, it should be created so that it lives
    as long as the current variable bindings; otherwise it only lives
@@ -4388,20 +4384,20 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, T
    direct-initialization in cases where other parts of the compiler
    have already generated a temporary, such as reference
    initialization and the catch parameter.  */
-#define DIRECT_BIND (1 << 4)
+#define DIRECT_BIND (1 << 3)
 /* We're performing a user-defined conversion, so more user-defined
    conversions are not permitted (only built-in conversions).  */
-#define LOOKUP_NO_CONVERSION (1 << 5)
+#define LOOKUP_NO_CONVERSION (1 << 4)
 /* The user has explicitly called a destructor.  (Therefore, we do
    not need to check that the object is non-NULL before calling the
    destructor.)  */
-#define LOOKUP_DESTRUCTOR (1 << 6)
+#define LOOKUP_DESTRUCTOR (1 << 5)
 /* Do not permit references to bind to temporaries.  */
-#define LOOKUP_NO_TEMP_BIND (1 << 7)
+#define LOOKUP_NO_TEMP_BIND (1 << 6)
 /* Do not accept objects, and possibly namespaces.  */
-#define LOOKUP_PREFER_TYPES (1 << 8)
+#define LOOKUP_PREFER_TYPES (1 << 7)
 /* Do not accept objects, and possibly types.   */
-#define LOOKUP_PREFER_NAMESPACES (1 << 9)
+#define LOOKUP_PREFER_NAMESPACES (1 << 8)
 /* Accept types or namespaces.  */
 #define LOOKUP_PREFER_BOTH (LOOKUP_PREFER_TYPES | LOOKUP_PREFER_NAMESPACES)
 /* Return friend declarations and un-declared builtin functions.
@@ -4894,7 +4890,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 +4999,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 +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);
Index: cp/name-lookup.c
===================================================================
--- cp/name-lookup.c	(revision 188203)
+++ cp/name-lookup.c	(working copy)
@@ -1854,7 +1854,7 @@ identifier_type_value_1 (tree id)
     return REAL_IDENTIFIER_TYPE_VALUE (id);
   /* Have to search for it. It must be on the global level, now.
      Ask lookup_name not to return non-types.  */
-  id = lookup_name_real (id, 2, 1, /*block_p=*/true, 0, LOOKUP_COMPLAIN);
+  id = lookup_name_real (id, 2, 1, /*block_p=*/true, 0, LOOKUP_NORMAL);
   if (id)
     return TREE_TYPE (id);
   return NULL_TREE;
@@ -4345,7 +4345,7 @@ lookup_qualified_name (tree scope, tree name, bool
     {
       struct scope_binding binding = EMPTY_SCOPE_BINDING;
 
-      flags |= LOOKUP_COMPLAIN;
+      flags |= LOOKUP_NORMAL;
       if (is_type_p)
 	flags |= LOOKUP_PREFER_TYPES;
       if (qualified_lookup_using_namespace (name, scope, &binding, flags))
@@ -4772,7 +4772,7 @@ lookup_name_real (tree name, int prefer_type, int
 tree
 lookup_name_nonclass (tree name)
 {
-  return lookup_name_real (name, 0, 1, /*block_p=*/true, 0, LOOKUP_COMPLAIN);
+  return lookup_name_real (name, 0, 1, /*block_p=*/true, 0, LOOKUP_NORMAL);
 }
 
 tree
@@ -4781,21 +4781,21 @@ lookup_function_nonclass (tree name, VEC(tree,gc)
   return
     lookup_arg_dependent (name,
 			  lookup_name_real (name, 0, 1, block_p, 0,
-					    LOOKUP_COMPLAIN),
+					    LOOKUP_NORMAL),
 			  args, false);
 }
 
 tree
 lookup_name (tree name)
 {
-  return lookup_name_real (name, 0, 0, /*block_p=*/true, 0, LOOKUP_COMPLAIN);
+  return lookup_name_real (name, 0, 0, /*block_p=*/true, 0, LOOKUP_NORMAL);
 }
 
 tree
 lookup_name_prefer_type (tree name, int prefer_type)
 {
   return lookup_name_real (name, prefer_type, 0, /*block_p=*/true,
-			   0, LOOKUP_COMPLAIN);
+			   0, LOOKUP_NORMAL);
 }
 
 /* Look up NAME for type used in elaborated name specifier in


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-05 11:02             ` Paolo Carlini
@ 2012-06-05 14:17               ` Jason Merrill
  2012-06-05 16:18                 ` Paolo Carlini
  2012-06-06  1:00                 ` Paolo Carlini
  0 siblings, 2 replies; 19+ messages in thread
From: Jason Merrill @ 2012-06-05 14:17 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches

On 06/05/2012 07:00 AM, Paolo Carlini wrote:
> 	(construct_virtual_base): Adjust LOOKUP_COMPLAIN ->  LOOKUP_NORMAL.

This and the similar changes elsewhere seem dangerous; they're adding 
adding LOOKUP_PROTECT that wasn't there before.  Instead, let's replace 
LOOKUP_COMPLAIN with 0 or some macro defined to 0.

I would also keep the LOOKUP_PROTECT macro rather than replace its uses 
with LOOKUP_NORMAL.

Jason

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-05 14:17               ` Jason Merrill
@ 2012-06-05 16:18                 ` Paolo Carlini
  2012-06-05 16:34                   ` Jason Merrill
  2012-06-06  1:00                 ` Paolo Carlini
  1 sibling, 1 reply; 19+ messages in thread
From: Paolo Carlini @ 2012-06-05 16:18 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

Hi,

Il giorno 05/giu/2012, alle ore 16:16, Jason Merrill <jason@redhat.com> ha scritto:

> On 06/05/2012 07:00 AM, Paolo Carlini wrote:
>>    (construct_virtual_base): Adjust LOOKUP_COMPLAIN ->  LOOKUP_NORMAL.
> 
> This and the similar changes elsewhere seem dangerous; they're adding adding LOOKUP_PROTECT that wasn't there before.  Instead, let's replace LOOKUP_COMPLAIN with 0 or some macro defined to 0.

Indeed, sorry about that, somehow I got confused.

> I would also keep the LOOKUP_PROTECT macro rather than replace its uses with LOOKUP_NORMAL.

To be sure: NORMAL used to be just PROTECT | COMPLAIN, thus it's just about names, right? You mean, we do away with the NORMAL name, you mean? (indeed I had a moment of esitation about this, when I noticed that the comment preceding now NORMAL is the one which used to preceed PROTECT)
> 


I'll send an updated patch later today.

Thanks!
Paolo

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-05 16:18                 ` Paolo Carlini
@ 2012-06-05 16:34                   ` Jason Merrill
  2012-06-05 16:50                     ` Paolo Carlini
  0 siblings, 1 reply; 19+ messages in thread
From: Jason Merrill @ 2012-06-05 16:34 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches

On 06/05/2012 11:29 AM, Paolo Carlini wrote:
> To be sure: NORMAL used to be just PROTECT | COMPLAIN, thus it's just about names, right?

Yes.

> You mean, we do away with the NORMAL name, you mean?

We could, but I think it's fine to have it as an alias for 
LOOKUP_PROTECT; the LOOKUP_NORMAL name implies that we're doing a normal 
name lookup, whereas LOOKUP_PROTECT is what that implies.

Jason

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-05 16:34                   ` Jason Merrill
@ 2012-06-05 16:50                     ` Paolo Carlini
  0 siblings, 0 replies; 19+ messages in thread
From: Paolo Carlini @ 2012-06-05 16:50 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

Hi,

> We could, but I think it's fine to have it as an alias for LOOKUP_PROTECT; the LOOKUP_NORMAL name implies that we're doing a normal name lookup, whereas LOOKUP_PROTECT is what that implies.

Believe it or not, yesterday for a few minutes I had it exactly as an alias. Ok, I'll do that.

Paolo

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-05 14:17               ` Jason Merrill
  2012-06-05 16:18                 ` Paolo Carlini
@ 2012-06-06  1:00                 ` Paolo Carlini
  2012-06-06  2:29                   ` Jason Merrill
  1 sibling, 1 reply; 19+ messages in thread
From: Paolo Carlini @ 2012-06-06  1:00 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 740 bytes --]

Hi,

On 06/05/2012 04:16 PM, Jason Merrill wrote:
> On 06/05/2012 07:00 AM, Paolo Carlini wrote:
>>     (construct_virtual_base): Adjust LOOKUP_COMPLAIN ->  LOOKUP_NORMAL.
>
> This and the similar changes elsewhere seem dangerous; they're adding 
> adding LOOKUP_PROTECT that wasn't there before.  Instead, let's 
> replace LOOKUP_COMPLAIN with 0 or some macro defined to 0.
>
> I would also keep the LOOKUP_PROTECT macro rather than replace its 
> uses with LOOKUP_NORMAL.
Thus, as agreed, the below implements both the above (assuming I'm not 
doing something stupid, I'm again at the end of a pretty long day, like 
last time ;)

Patch passes bootstrap and testing on the usual x86_64-linux.

Thanks!
Paolo.

//////////////////////////


[-- Attachment #2: CL_53567_13 --]
[-- Type: text/plain, Size: 2381 bytes --]

/cp
2012-06-06  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_1,
	build_new, build_vec_delete_1, build_vec_init, build_delete): Adjust.
	(construct_virtual_base): Adjust LOOKUP_COMPLAIN -> 0.
	* class.c (build_base_path): Adjust.
	* decl.c (compute_array_index_type, finish_destructor_body): Likewise.
	* method.c (synthesized_method_walk): Adjust flag and complain.
	* 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.
	* pt.c (tsubst_friend_class): Don't change flags.
	* semantics.c (finish_goto_stmt, handle_omp_for_class_iterator,
	finish_static_assert): Likewise.
	* parser.c (cp_parser_lookup_name): Just pass 0 as flags to
	lookup_name_real.
	* call.c (build_op_delete_call): Add tsubst_flags_t parameter.
	(convert_like_real, convert_arg_to_ellipsis, convert_for_arg_passing):
	Adjust.
	(standard_conversion): Adjust LOOKUP_COMPLAIN -> 0.
	(implicit_conversion): Mask out tf_error.
	(build_user_type_conversion_1, build_new_op_1, build_over_call): Use
	complain & tf_error instead of flags & LOOKUP_COMPLAIN.
	* 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.
	(convert_to_reference, ocp_convert): Use complain & tf_error instead
	of flags & LOOKUP_COMPLAIN.
	(convert_force): Adjust LOOKUP_COMPLAIN -> 0.
	* name-lookup.c (identifier_type_value_1, lookup_qualified_name,
	lookup_name_real, lookup_function_nonclass, lookup_name,
	lookup_name_prefer_type): Adjust LOOKUP_COMPLAIN -> 0.
	* cp-tree.h: Adjust prototypes; remove LOOKUP_COMPLAIN.

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

	PR c++/53567
	* g++.dg/cpp0x/alias-decl-19.C: New.

[-- Attachment #3: patch_53567_13 --]
[-- Type: text/plain, Size: 63005 bytes --]

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 188251)
+++ 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);
 }
 \f
@@ -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)
@@ -7723,10 +7757,8 @@ convert_for_assignment (tree type, tree rhs,
    latter (X(X&)).
 
    If using constructor make sure no conversion operator exists, if one does
-   exist, an ambiguity exists.
+   exist, an ambiguity exists.  */
 
-   If flags doesn't include LOOKUP_COMPLAIN, don't complain about anything.  */
-
 tree
 convert_for_initialization (tree exp, tree type, tree rhs, int flags,
 			    impl_conv_rhs errtype, tree fndecl, int parmnum,
Index: cp/optimize.c
===================================================================
--- cp/optimize.c	(revision 188251)
+++ 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 188251)
+++ 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));
 }
@@ -1250,7 +1250,7 @@ construct_virtual_base (tree vbase, tree arguments
   exp = convert_to_base_statically (current_class_ref, vbase);
 
   expand_aggr_init_1 (vbase, current_class_ref, exp, arguments,
-		      LOOKUP_COMPLAIN, tf_warning_or_error);
+		      0, tf_warning_or_error);
   finish_then_clause (inner_if_stmt);
   finish_if_stmt (inner_if_stmt);
 
@@ -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 188251)
+++ 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 188251)
+++ 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/method.c
===================================================================
--- cp/method.c	(revision 188251)
+++ cp/method.c	(working copy)
@@ -1228,17 +1228,10 @@ synthesized_method_walk (tree ctype, special_funct
 
   scope = push_scope (ctype);
 
-  if (diag)
-    {
-      flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
-      complain = tf_warning_or_error;
-    }
-  else
-    {
-      flags = LOOKUP_PROTECT|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
-      complain = tf_none;
-    }
+  flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
 
+  complain = diag ? tf_warning_or_error : tf_none;
+
   if (const_p)
     quals = TYPE_QUAL_CONST;
   else
Index: cp/rtti.c
===================================================================
--- cp/rtti.c	(revision 188251)
+++ 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 188251)
+++ 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 188251)
+++ 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/pt.c
===================================================================
--- cp/pt.c	(revision 188251)
+++ cp/pt.c	(working copy)
@@ -8474,8 +8474,7 @@ tsubst_friend_class (tree friend_tmpl, tree args)
 
      both F templates are the same.  */
   tmpl = lookup_name_real (DECL_NAME (friend_tmpl), 0, 0,
-			   /*block_p=*/true, 0, 
-			   LOOKUP_COMPLAIN | LOOKUP_HIDDEN);
+			   /*block_p=*/true, 0, LOOKUP_HIDDEN);
 
   /* But, if we don't find one, it might be because we're in a
      situation like this:
Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 188251)
+++ 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/parser.c
===================================================================
--- cp/parser.c	(revision 188251)
+++ cp/parser.c	(working copy)
@@ -20317,13 +20317,9 @@ cp_parser_lookup_name (cp_parser *parser, tree nam
 		       tree *ambiguous_decls,
 		       location_t name_location)
 {
-  int flags = 0;
   tree decl;
   tree object_type = parser->context->object_type;
 
-  if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
-    flags |= LOOKUP_COMPLAIN;
-
   /* Assume that the lookup will be unambiguous.  */
   if (ambiguous_decls)
     *ambiguous_decls = NULL_TREE;
@@ -20495,7 +20491,7 @@ cp_parser_lookup_name (cp_parser *parser, tree nam
       /* Look it up in the enclosing context, too.  */
       decl = lookup_name_real (name, tag_type != none_type,
 			       /*nonclass=*/0,
-			       /*block_p=*/true, is_namespace, flags);
+			       /*block_p=*/true, is_namespace, 0);
       parser->object_scope = object_type;
       parser->qualifying_scope = NULL_TREE;
       if (object_decl)
@@ -20505,7 +20501,7 @@ cp_parser_lookup_name (cp_parser *parser, tree nam
     {
       decl = lookup_name_real (name, tag_type != none_type,
 			       /*nonclass=*/0,
-			       /*block_p=*/true, is_namespace, flags);
+			       /*block_p=*/true, is_namespace, 0);
       parser->qualifying_scope = NULL_TREE;
       parser->object_scope = NULL_TREE;
     }
Index: cp/call.c
===================================================================
--- cp/call.c	(revision 188251)
+++ cp/call.c	(working copy)
@@ -1695,6 +1695,8 @@ implicit_conversion (tree to, tree from, tree expr
 	    |LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND|LOOKUP_PREFER_RVALUE
 	    |LOOKUP_NO_NARROWING|LOOKUP_PROTECT);
 
+  complain &= ~tf_error;
+
   if (TREE_CODE (to) == REFERENCE_TYPE)
     conv = reference_binding (to, from, expr, c_cast_p, flags, complain);
   else
@@ -3607,8 +3609,7 @@ build_user_type_conversion_1 (tree totype, tree ex
   cand = tourney (candidates, complain);
   if (cand == 0)
     {
-      if ((flags & LOOKUP_COMPLAIN)
-	  && (complain & tf_error))
+      if (complain & tf_error)
 	{
 	  error ("conversion from %qT to %qT is ambiguous",
 		 fromtype, totype);
@@ -5098,7 +5099,7 @@ build_new_op_1 (location_t loc, enum tree_code cod
 	     distinguish between prefix and postfix ++ and
 	     operator++() was used for both, so we allow this with
 	     -fpermissive.  */
-	  if (flags & LOOKUP_COMPLAIN)
+	  else
 	    {
 	      const char *msg = (flag_permissive) 
 		? G_("no %<%D(int)%> declared for postfix %qs,"
@@ -5127,7 +5128,7 @@ build_new_op_1 (location_t loc, enum tree_code cod
 	  break;
 
 	default:
-	  if ((flags & LOOKUP_COMPLAIN) && (complain & tf_error))
+	  if (complain & tf_error)
 	    {
 		/* If one of the arguments of the operator represents
 		   an invalid use of member function pointer, try to report
@@ -5153,7 +5154,7 @@ build_new_op_1 (location_t loc, enum tree_code cod
       cand = tourney (candidates, complain);
       if (cand == 0)
 	{
-	  if ((flags & LOOKUP_COMPLAIN) && (complain & tf_error))
+	  if (complain & tf_error)
 	    {
 	      op_error (loc, code, code2, arg1, arg2, arg3, TRUE);
 	      print_z_candidates (loc, candidates);
@@ -5379,7 +5380,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 +5414,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 +5453,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 +5524,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 +5537,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 +5693,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 +5721,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 +5860,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 +6026,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 +6108,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 +6345,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)
     {
@@ -6487,7 +6496,7 @@ build_over_call (struct z_candidate *cand, int fla
       if (flags & LOOKUP_SPECULATIVE)
 	{
 	  if (!speculative_access_check (cand->access_path, access_fn, fn,
-					 !!(flags & LOOKUP_COMPLAIN)))
+					 complain & tf_error))
 	    return error_mark_node;
 	}
       else
@@ -6500,13 +6509,13 @@ build_over_call (struct z_candidate *cand, int fla
     {
       if (DECL_DELETED_FN (fn))
 	{
-	  if (flags & LOOKUP_COMPLAIN)
+	  if (complain & tf_error)
 	    mark_used (fn);
 	  return error_mark_node;
 	}
       if (cand->viable == 1)
 	return fn;
-      else if (!(flags & LOOKUP_COMPLAIN))
+      else if (!(complain & tf_error))
 	/* Reject bad conversions now.  */
 	return error_mark_node;
       /* else continue to get conversion error.  */
Index: cp/cvt.c
===================================================================
--- cp/cvt.c	(revision 188251)
+++ 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
@@ -452,21 +456,26 @@ convert_to_reference (tree reftype, tree expr, int
   if (((convtype & CONV_STATIC) && can_convert (intype, type, complain))
       || ((convtype & CONV_IMPLICIT) && can_convert_intype_to_type))
     {
-      if (flags & LOOKUP_COMPLAIN)
-	{
-	  tree ttl = TREE_TYPE (reftype);
-	  tree ttr = lvalue_type (expr);
+      {
+	tree ttl = TREE_TYPE (reftype);
+	tree ttr = lvalue_type (expr);
 
-	  if (! real_lvalue_p (expr))
-	    warn_ref_binding (loc, reftype, intype, decl);
+	if ((complain & tf_warning)
+	    && ! real_lvalue_p (expr))
+	  warn_ref_binding (loc, reftype, intype, decl);
 
-	  if (! (convtype & CONV_CONST)
-		   && !at_least_as_qualified_p (ttl, ttr))
-	    permerror (loc, "conversion from %qT to %qT discards qualifiers",
-		       ttr, reftype);
-	}
+	if (! (convtype & CONV_CONST)
+	    && !at_least_as_qualified_p (ttl, ttr))
+	  {
+	    if (complain & tf_error)
+	      permerror (loc, "conversion from %qT to %qT discards qualifiers",
+			 ttr, reftype);
+	    else
+	      return error_mark_node;
+	  }
+      }
 
-      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,28 +486,29 @@ 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);
     }
   else
     {
       rval = convert_for_initialization (NULL_TREE, type, expr, flags,
-					 ICR_CONVERTING, 0, 0,
-                                         tf_warning_or_error);
+					 ICR_CONVERTING, 0, 0, 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)
@@ -507,7 +517,7 @@ convert_to_reference (tree reftype, tree expr, int
       return rval;
     }
 
-  if (flags & LOOKUP_COMPLAIN)
+  if (complain & tf_error)
     error_at (loc, "cannot convert type %qT to type %qT", intype, reftype);
 
   return error_mark_node;
@@ -595,9 +605,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 +618,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 +641,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 +659,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 +709,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 +727,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 +745,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 +759,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 +767,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 +789,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 +799,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 +814,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 +848,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 +1436,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,18 +1445,19 @@ 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);
 
   if (code == REFERENCE_TYPE)
     return (fold_if_not_in_template
-	    (convert_to_reference (type, e, CONV_C_CAST, LOOKUP_COMPLAIN,
-				   NULL_TREE)));
+	    (convert_to_reference (type, e, CONV_C_CAST, 0,
+				   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 +1468,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 188251)
+++ cp/cp-tree.h	(working copy)
@@ -4371,16 +4371,13 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, T
    behaviors relevant to them.  */
 /* Check for access violations.  */
 #define LOOKUP_PROTECT (1 << 0)
-/* Complain if no suitable member function matching the arguments is
-   found.  */
-#define LOOKUP_COMPLAIN (1 << 1)
-#define LOOKUP_NORMAL (LOOKUP_PROTECT | LOOKUP_COMPLAIN)
+#define LOOKUP_NORMAL (LOOKUP_PROTECT)
 /* Even if the function found by lookup is a virtual function, it
    should be called directly.  */
-#define LOOKUP_NONVIRTUAL (1 << 2)
+#define LOOKUP_NONVIRTUAL (1 << 1)
 /* Non-converting (i.e., "explicit") constructors are not tried.  This flag
    indicates that we are not performing direct-initialization.  */
-#define LOOKUP_ONLYCONVERTING (1 << 3)
+#define LOOKUP_ONLYCONVERTING (1 << 2)
 #define LOOKUP_IMPLICIT (LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING)
 /* If a temporary is created, it should be created so that it lives
    as long as the current variable bindings; otherwise it only lives
@@ -4388,20 +4385,20 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, T
    direct-initialization in cases where other parts of the compiler
    have already generated a temporary, such as reference
    initialization and the catch parameter.  */
-#define DIRECT_BIND (1 << 4)
+#define DIRECT_BIND (1 << 3)
 /* We're performing a user-defined conversion, so more user-defined
    conversions are not permitted (only built-in conversions).  */
-#define LOOKUP_NO_CONVERSION (1 << 5)
+#define LOOKUP_NO_CONVERSION (1 << 4)
 /* The user has explicitly called a destructor.  (Therefore, we do
    not need to check that the object is non-NULL before calling the
    destructor.)  */
-#define LOOKUP_DESTRUCTOR (1 << 6)
+#define LOOKUP_DESTRUCTOR (1 << 5)
 /* Do not permit references to bind to temporaries.  */
-#define LOOKUP_NO_TEMP_BIND (1 << 7)
+#define LOOKUP_NO_TEMP_BIND (1 << 6)
 /* Do not accept objects, and possibly namespaces.  */
-#define LOOKUP_PREFER_TYPES (1 << 8)
+#define LOOKUP_PREFER_TYPES (1 << 7)
 /* Do not accept objects, and possibly types.   */
-#define LOOKUP_PREFER_NAMESPACES (1 << 9)
+#define LOOKUP_PREFER_NAMESPACES (1 << 8)
 /* Accept types or namespaces.  */
 #define LOOKUP_PREFER_BOTH (LOOKUP_PREFER_TYPES | LOOKUP_PREFER_NAMESPACES)
 /* Return friend declarations and un-declared builtin functions.
@@ -4894,7 +4891,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 +5000,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 +5903,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);
Index: cp/name-lookup.c
===================================================================
--- cp/name-lookup.c	(revision 188251)
+++ cp/name-lookup.c	(working copy)
@@ -1854,7 +1854,7 @@ identifier_type_value_1 (tree id)
     return REAL_IDENTIFIER_TYPE_VALUE (id);
   /* Have to search for it. It must be on the global level, now.
      Ask lookup_name not to return non-types.  */
-  id = lookup_name_real (id, 2, 1, /*block_p=*/true, 0, LOOKUP_COMPLAIN);
+  id = lookup_name_real (id, 2, 1, /*block_p=*/true, 0, 0);
   if (id)
     return TREE_TYPE (id);
   return NULL_TREE;
@@ -4345,7 +4345,6 @@ lookup_qualified_name (tree scope, tree name, bool
     {
       struct scope_binding binding = EMPTY_SCOPE_BINDING;
 
-      flags |= LOOKUP_COMPLAIN;
       if (is_type_p)
 	flags |= LOOKUP_PREFER_TYPES;
       if (qualified_lookup_using_namespace (name, scope, &binding, flags))
@@ -4772,7 +4771,7 @@ lookup_name_real (tree name, int prefer_type, int
 tree
 lookup_name_nonclass (tree name)
 {
-  return lookup_name_real (name, 0, 1, /*block_p=*/true, 0, LOOKUP_COMPLAIN);
+  return lookup_name_real (name, 0, 1, /*block_p=*/true, 0, 0);
 }
 
 tree
@@ -4780,22 +4779,20 @@ lookup_function_nonclass (tree name, VEC(tree,gc)
 {
   return
     lookup_arg_dependent (name,
-			  lookup_name_real (name, 0, 1, block_p, 0,
-					    LOOKUP_COMPLAIN),
+			  lookup_name_real (name, 0, 1, block_p, 0, 0),
 			  args, false);
 }
 
 tree
 lookup_name (tree name)
 {
-  return lookup_name_real (name, 0, 0, /*block_p=*/true, 0, LOOKUP_COMPLAIN);
+  return lookup_name_real (name, 0, 0, /*block_p=*/true, 0, 0);
 }
 
 tree
 lookup_name_prefer_type (tree name, int prefer_type)
 {
-  return lookup_name_real (name, prefer_type, 0, /*block_p=*/true,
-			   0, LOOKUP_COMPLAIN);
+  return lookup_name_real (name, prefer_type, 0, /*block_p=*/true, 0, 0);
 }
 
 /* Look up NAME for type used in elaborated name specifier in

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-06  1:00                 ` Paolo Carlini
@ 2012-06-06  2:29                   ` Jason Merrill
  2012-06-06  9:33                     ` Paolo Carlini
  0 siblings, 1 reply; 19+ messages in thread
From: Jason Merrill @ 2012-06-06  2:29 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches

On 06/05/2012 08:23 PM, Paolo Carlini wrote:
> @@ -1695,6 +1695,8 @@ implicit_conversion (tree to, tree from, tree expr
>   	    |LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND|LOOKUP_PREFER_RVALUE
>   	    |LOOKUP_NO_NARROWING|LOOKUP_PROTECT);
>
> +  complain&= ~tf_error;

I don't think we want warnings from implicit_conversion, either.

> -	      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;

I don't think we need the last two lines anymore, we can use the usual 
pattern of return error if sfinae, permerror and continue otherwise.

BTW, I'm somewhat surprised that dropping LOOKUP_COMPLAIN from all the 
lookup_* functions works fine, but looking through the code myself I 
don't see anything that was using the flag.

Jason

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-06  2:29                   ` Jason Merrill
@ 2012-06-06  9:33                     ` Paolo Carlini
  2012-06-06 10:23                       ` Paolo Carlini
  0 siblings, 1 reply; 19+ messages in thread
From: Paolo Carlini @ 2012-06-06  9:33 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

Hi,

On 06/06/2012 03:57 AM, Jason Merrill wrote:
> On 06/05/2012 08:23 PM, Paolo Carlini wrote:
>> @@ -1695,6 +1695,8 @@ implicit_conversion (tree to, tree from, tree expr
>>           |LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND|LOOKUP_PREFER_RVALUE
>>           |LOOKUP_NO_NARROWING|LOOKUP_PROTECT);
>>
>> +  complain&= ~tf_error;
>
> I don't think we want warnings from implicit_conversion, either.
I thought we already somewhat discussed this issue (when I said that 
passing tf_warning instead of tf_none could work better, remember?), but 
now I see that I kept a lot of it for myself . If I do something like

     complain&= ~(tf_warning|tf_error);

then we regress on, eg, g++.old-deja/g++.benjamin/16077.C, that is, we 
don't produce any warnings anymore.
>
>> -          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;
>
> I don't think we need the last two lines anymore, we can use the usual 
> pattern of return error if sfinae, permerror and continue otherwise.
Sure.

Thanks,
Paolo.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-06  9:33                     ` Paolo Carlini
@ 2012-06-06 10:23                       ` Paolo Carlini
  2012-06-06 16:17                         ` Jason Merrill
  0 siblings, 1 reply; 19+ messages in thread
From: Paolo Carlini @ 2012-06-06 10:23 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jason Merrill

Hi again,

some additional details:

On 06/06/2012 11:20 AM, Paolo Carlini wrote:
> Hi,
>
> On 06/06/2012 03:57 AM, Jason Merrill wrote:
>> On 06/05/2012 08:23 PM, Paolo Carlini wrote:
>>> @@ -1695,6 +1695,8 @@ implicit_conversion (tree to, tree from, tree 
>>> expr
>>>           |LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND|LOOKUP_PREFER_RVALUE
>>>           |LOOKUP_NO_NARROWING|LOOKUP_PROTECT);
>>>
>>> +  complain&= ~tf_error;
>>
>> I don't think we want warnings from implicit_conversion, either.
> I thought we already somewhat discussed this issue (when I said that 
> passing tf_warning instead of tf_none could work better, remember?), 
> but now I see that I kept a lot of it for myself . If I do something like
>
>     complain&= ~(tf_warning|tf_error);
>
> then we regress on, eg, g++.old-deja/g++.benjamin/16077.C, that is, we 
> don't produce any warnings anymore.
The warning belongs to joust, called by tourney, called by 
build_user_type_conversion_1, called by implicit_conversion.

When a couple of days ago I mentioned my quick tests with hackish 
changes, I had just noticed that the testsuite was Ok if only in 
implicit_conversion I allowed tf_warning to be passed to 
reference_binding and build_user_type_conversion_1.

Then, later on, I thought that before these changes for 53567 nothing 
was preventing warnings to be emitted, thus maybe we only wanted to gate 
away hard errors, like before we gated away hard errors with the big 
flags &= line which wasn't including LOOKUP_COMPLAIN, and leave warnings 
(or any other tsubst_flags for that matter) alone in the whole 
implicit_conversion.

I see now, I didn't remember this detail, that besides Benjamin's, the 
only other testsuite regression with ~(tf_warning|tf_error) is:

     g++.old-deja/g++.other/overcnv2.C

which is again about the same warning in joust.

Paolo.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-06 10:23                       ` Paolo Carlini
@ 2012-06-06 16:17                         ` Jason Merrill
  2012-06-06 17:12                           ` Paolo Carlini
  0 siblings, 1 reply; 19+ messages in thread
From: Jason Merrill @ 2012-06-06 16:17 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches

On 06/06/2012 05:45 AM, Paolo Carlini wrote:
> The warning belongs to joust, called by tourney, called by
> build_user_type_conversion_1, called by implicit_conversion.

Hmm.  We really ought not to issue that warning until we know that we've 
committed to that conversion.  But I guess that doesn't need to happen 
in this patch, just add a FIXME comment to the ~tf_error line.

Jason

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-06 16:17                         ` Jason Merrill
@ 2012-06-06 17:12                           ` Paolo Carlini
  2012-06-06 18:48                             ` Jason Merrill
  0 siblings, 1 reply; 19+ messages in thread
From: Paolo Carlini @ 2012-06-06 17:12 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1059 bytes --]

Hi,

On 06/06/2012 06:12 PM, Jason Merrill wrote:
> On 06/06/2012 05:45 AM, Paolo Carlini wrote:
>> The warning belongs to joust, called by tourney, called by
>> build_user_type_conversion_1, called by implicit_conversion.
>
> Hmm.  We really ought not to issue that warning until we know that 
> we've committed to that conversion.  But I guess that doesn't need to 
> happen in this patch, just add a FIXME comment to the ~tf_error line.
I see, I just learned something more about those conversions, eh

And, I must admit, without LOOKUP_COMPLAIN all these bits of code become 
much neater, I even hope that implementing the access checking under 
SFINAE thing will become simpler (a while ago I started on it, and got 
some important cases working but also quite a few interesting special 
cases handled in weird ways: soon I will be sending over something concrete)

Anyway, I bootstrapped and I'm finishing testing (in v3 now) the below, 
which just adds your two last indications about flag_permissive and the 
FIXME.

Thanks,
Paolo.

/////////////////

[-- Attachment #2: CL_53567_14 --]
[-- Type: text/plain, Size: 2394 bytes --]

/cp
2012-06-06  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_1,
	build_new, build_vec_delete_1, build_vec_init, build_delete): Adjust.
	(construct_virtual_base): Adjust LOOKUP_COMPLAIN -> 0.
	* class.c (build_base_path): Adjust.
	* decl.c (compute_array_index_type, finish_destructor_body): Likewise.
	* method.c (synthesized_method_walk): Adjust flag and complain.
	* 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.
	* pt.c (tsubst_friend_class): Don't change flags.
	* semantics.c (finish_goto_stmt, handle_omp_for_class_iterator,
	finish_static_assert): Likewise.
	* parser.c (cp_parser_lookup_name): Just pass 0 as flags to
	lookup_name_real.
	* call.c (build_op_delete_call): Add tsubst_flags_t parameter.
	(convert_like_real, convert_arg_to_ellipsis, convert_for_arg_passing):
	Adjust.
	(standard_conversion): Adjust LOOKUP_COMPLAIN -> 0.
	(implicit_conversion): Mask out tf_error with a FIXME.
	(build_user_type_conversion_1, build_new_op_1, build_over_call): Use
	complain & tf_error instead of flags & LOOKUP_COMPLAIN.
	* 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.
	(convert_to_reference, ocp_convert): Use complain & tf_error instead
	of flags & LOOKUP_COMPLAIN.
	(convert_force): Adjust LOOKUP_COMPLAIN -> 0.
	* name-lookup.c (identifier_type_value_1, lookup_qualified_name,
	lookup_name_real, lookup_function_nonclass, lookup_name,
	lookup_name_prefer_type): Adjust LOOKUP_COMPLAIN -> 0.
	* cp-tree.h: Adjust prototypes; remove LOOKUP_COMPLAIN.

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

	PR c++/53567
	* g++.dg/cpp0x/alias-decl-19.C: New.

[-- Attachment #3: patch_53567_14 --]
[-- Type: text/plain, Size: 63166 bytes --]

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 188268)
+++ 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);
 }
 \f
@@ -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)
@@ -7723,10 +7757,8 @@ convert_for_assignment (tree type, tree rhs,
    latter (X(X&)).
 
    If using constructor make sure no conversion operator exists, if one does
-   exist, an ambiguity exists.
+   exist, an ambiguity exists.  */
 
-   If flags doesn't include LOOKUP_COMPLAIN, don't complain about anything.  */
-
 tree
 convert_for_initialization (tree exp, tree type, tree rhs, int flags,
 			    impl_conv_rhs errtype, tree fndecl, int parmnum,
Index: cp/optimize.c
===================================================================
--- cp/optimize.c	(revision 188268)
+++ 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 188268)
+++ 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));
 }
@@ -1250,7 +1250,7 @@ construct_virtual_base (tree vbase, tree arguments
   exp = convert_to_base_statically (current_class_ref, vbase);
 
   expand_aggr_init_1 (vbase, current_class_ref, exp, arguments,
-		      LOOKUP_COMPLAIN, tf_warning_or_error);
+		      0, tf_warning_or_error);
   finish_then_clause (inner_if_stmt);
   finish_if_stmt (inner_if_stmt);
 
@@ -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 188268)
+++ 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 188268)
+++ 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/method.c
===================================================================
--- cp/method.c	(revision 188268)
+++ cp/method.c	(working copy)
@@ -1228,17 +1228,10 @@ synthesized_method_walk (tree ctype, special_funct
 
   scope = push_scope (ctype);
 
-  if (diag)
-    {
-      flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
-      complain = tf_warning_or_error;
-    }
-  else
-    {
-      flags = LOOKUP_PROTECT|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
-      complain = tf_none;
-    }
+  flags = LOOKUP_NORMAL|LOOKUP_SPECULATIVE|LOOKUP_DEFAULTED;
 
+  complain = diag ? tf_warning_or_error : tf_none;
+
   if (const_p)
     quals = TYPE_QUAL_CONST;
   else
Index: cp/rtti.c
===================================================================
--- cp/rtti.c	(revision 188268)
+++ 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 188268)
+++ 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 188268)
+++ 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/pt.c
===================================================================
--- cp/pt.c	(revision 188268)
+++ cp/pt.c	(working copy)
@@ -8474,8 +8474,7 @@ tsubst_friend_class (tree friend_tmpl, tree args)
 
      both F templates are the same.  */
   tmpl = lookup_name_real (DECL_NAME (friend_tmpl), 0, 0,
-			   /*block_p=*/true, 0, 
-			   LOOKUP_COMPLAIN | LOOKUP_HIDDEN);
+			   /*block_p=*/true, 0, LOOKUP_HIDDEN);
 
   /* But, if we don't find one, it might be because we're in a
      situation like this:
Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 188268)
+++ 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/parser.c
===================================================================
--- cp/parser.c	(revision 188268)
+++ cp/parser.c	(working copy)
@@ -20320,13 +20320,9 @@ cp_parser_lookup_name (cp_parser *parser, tree nam
 		       tree *ambiguous_decls,
 		       location_t name_location)
 {
-  int flags = 0;
   tree decl;
   tree object_type = parser->context->object_type;
 
-  if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
-    flags |= LOOKUP_COMPLAIN;
-
   /* Assume that the lookup will be unambiguous.  */
   if (ambiguous_decls)
     *ambiguous_decls = NULL_TREE;
@@ -20498,7 +20494,7 @@ cp_parser_lookup_name (cp_parser *parser, tree nam
       /* Look it up in the enclosing context, too.  */
       decl = lookup_name_real (name, tag_type != none_type,
 			       /*nonclass=*/0,
-			       /*block_p=*/true, is_namespace, flags);
+			       /*block_p=*/true, is_namespace, 0);
       parser->object_scope = object_type;
       parser->qualifying_scope = NULL_TREE;
       if (object_decl)
@@ -20508,7 +20504,7 @@ cp_parser_lookup_name (cp_parser *parser, tree nam
     {
       decl = lookup_name_real (name, tag_type != none_type,
 			       /*nonclass=*/0,
-			       /*block_p=*/true, is_namespace, flags);
+			       /*block_p=*/true, is_namespace, 0);
       parser->qualifying_scope = NULL_TREE;
       parser->object_scope = NULL_TREE;
     }
Index: cp/call.c
===================================================================
--- cp/call.c	(revision 188268)
+++ cp/call.c	(working copy)
@@ -1695,6 +1695,13 @@ implicit_conversion (tree to, tree from, tree expr
 	    |LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND|LOOKUP_PREFER_RVALUE
 	    |LOOKUP_NO_NARROWING|LOOKUP_PROTECT);
 
+  /* FIXME: actually we don't want warnings either, but we can't just
+     have 'complain &= ~(tf_warning|tf_error)' because it would cause
+     the regression of, eg, g++.old-deja/g++.benjamin/16077.C.
+     We really ought not to issue that warning until we've committed
+     to that conversion.  */
+  complain &= ~tf_error;
+
   if (TREE_CODE (to) == REFERENCE_TYPE)
     conv = reference_binding (to, from, expr, c_cast_p, flags, complain);
   else
@@ -3607,8 +3614,7 @@ build_user_type_conversion_1 (tree totype, tree ex
   cand = tourney (candidates, complain);
   if (cand == 0)
     {
-      if ((flags & LOOKUP_COMPLAIN)
-	  && (complain & tf_error))
+      if (complain & tf_error)
 	{
 	  error ("conversion from %qT to %qT is ambiguous",
 		 fromtype, totype);
@@ -5098,7 +5104,7 @@ build_new_op_1 (location_t loc, enum tree_code cod
 	     distinguish between prefix and postfix ++ and
 	     operator++() was used for both, so we allow this with
 	     -fpermissive.  */
-	  if (flags & LOOKUP_COMPLAIN)
+	  else
 	    {
 	      const char *msg = (flag_permissive) 
 		? G_("no %<%D(int)%> declared for postfix %qs,"
@@ -5127,7 +5133,7 @@ build_new_op_1 (location_t loc, enum tree_code cod
 	  break;
 
 	default:
-	  if ((flags & LOOKUP_COMPLAIN) && (complain & tf_error))
+	  if (complain & tf_error)
 	    {
 		/* If one of the arguments of the operator represents
 		   an invalid use of member function pointer, try to report
@@ -5153,7 +5159,7 @@ build_new_op_1 (location_t loc, enum tree_code cod
       cand = tourney (candidates, complain);
       if (cand == 0)
 	{
-	  if ((flags & LOOKUP_COMPLAIN) && (complain & tf_error))
+	  if (complain & tf_error)
 	    {
 	      op_error (loc, code, code2, arg1, arg2, arg3, TRUE);
 	      print_z_candidates (loc, candidates);
@@ -5379,7 +5385,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 +5419,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 +5458,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 +5529,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 +5542,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 +5698,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 +5726,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 +5865,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 +6031,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 +6113,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 +6350,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)
     {
@@ -6487,7 +6501,7 @@ build_over_call (struct z_candidate *cand, int fla
       if (flags & LOOKUP_SPECULATIVE)
 	{
 	  if (!speculative_access_check (cand->access_path, access_fn, fn,
-					 !!(flags & LOOKUP_COMPLAIN)))
+					 complain & tf_error))
 	    return error_mark_node;
 	}
       else
@@ -6500,13 +6514,13 @@ build_over_call (struct z_candidate *cand, int fla
     {
       if (DECL_DELETED_FN (fn))
 	{
-	  if (flags & LOOKUP_COMPLAIN)
+	  if (complain & tf_error)
 	    mark_used (fn);
 	  return error_mark_node;
 	}
       if (cand->viable == 1)
 	return fn;
-      else if (!(flags & LOOKUP_COMPLAIN))
+      else if (!(complain & tf_error))
 	/* Reject bad conversions now.  */
 	return error_mark_node;
       /* else continue to get conversion error.  */
Index: cp/cvt.c
===================================================================
--- cp/cvt.c	(revision 188268)
+++ 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
@@ -452,21 +456,26 @@ convert_to_reference (tree reftype, tree expr, int
   if (((convtype & CONV_STATIC) && can_convert (intype, type, complain))
       || ((convtype & CONV_IMPLICIT) && can_convert_intype_to_type))
     {
-      if (flags & LOOKUP_COMPLAIN)
-	{
-	  tree ttl = TREE_TYPE (reftype);
-	  tree ttr = lvalue_type (expr);
+      {
+	tree ttl = TREE_TYPE (reftype);
+	tree ttr = lvalue_type (expr);
 
-	  if (! real_lvalue_p (expr))
-	    warn_ref_binding (loc, reftype, intype, decl);
+	if ((complain & tf_warning)
+	    && ! real_lvalue_p (expr))
+	  warn_ref_binding (loc, reftype, intype, decl);
 
-	  if (! (convtype & CONV_CONST)
-		   && !at_least_as_qualified_p (ttl, ttr))
-	    permerror (loc, "conversion from %qT to %qT discards qualifiers",
-		       ttr, reftype);
-	}
+	if (! (convtype & CONV_CONST)
+	    && !at_least_as_qualified_p (ttl, ttr))
+	  {
+	    if (complain & tf_error)
+	      permerror (loc, "conversion from %qT to %qT discards qualifiers",
+			 ttr, reftype);
+	    else
+	      return error_mark_node;
+	  }
+      }
 
-      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,28 +486,29 @@ 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);
     }
   else
     {
       rval = convert_for_initialization (NULL_TREE, type, expr, flags,
-					 ICR_CONVERTING, 0, 0,
-                                         tf_warning_or_error);
+					 ICR_CONVERTING, 0, 0, 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)
@@ -507,7 +517,7 @@ convert_to_reference (tree reftype, tree expr, int
       return rval;
     }
 
-  if (flags & LOOKUP_COMPLAIN)
+  if (complain & tf_error)
     error_at (loc, "cannot convert type %qT to type %qT", intype, reftype);
 
   return error_mark_node;
@@ -595,9 +605,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 +618,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 +641,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 +659,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 +709,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 +727,9 @@ tree
 	       && ! (convtype & CONV_STATIC))
 	      || TREE_CODE (intype) == POINTER_TYPE)
 	    {
-	      if (flags & LOOKUP_COMPLAIN)
+	      if (complain & tf_error)
 		permerror (loc, "conversion from %q#T to %q#T", intype, type);
-	      if (!flag_permissive)
+	      else
 		return error_mark_node;
 	    }
 
@@ -727,7 +740,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 +754,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 +762,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 +784,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 +794,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 +809,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 +843,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 +1431,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,18 +1440,19 @@ 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);
 
   if (code == REFERENCE_TYPE)
     return (fold_if_not_in_template
-	    (convert_to_reference (type, e, CONV_C_CAST, LOOKUP_COMPLAIN,
-				   NULL_TREE)));
+	    (convert_to_reference (type, e, CONV_C_CAST, 0,
+				   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 +1463,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 188268)
+++ cp/cp-tree.h	(working copy)
@@ -4371,16 +4371,13 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, T
    behaviors relevant to them.  */
 /* Check for access violations.  */
 #define LOOKUP_PROTECT (1 << 0)
-/* Complain if no suitable member function matching the arguments is
-   found.  */
-#define LOOKUP_COMPLAIN (1 << 1)
-#define LOOKUP_NORMAL (LOOKUP_PROTECT | LOOKUP_COMPLAIN)
+#define LOOKUP_NORMAL (LOOKUP_PROTECT)
 /* Even if the function found by lookup is a virtual function, it
    should be called directly.  */
-#define LOOKUP_NONVIRTUAL (1 << 2)
+#define LOOKUP_NONVIRTUAL (1 << 1)
 /* Non-converting (i.e., "explicit") constructors are not tried.  This flag
    indicates that we are not performing direct-initialization.  */
-#define LOOKUP_ONLYCONVERTING (1 << 3)
+#define LOOKUP_ONLYCONVERTING (1 << 2)
 #define LOOKUP_IMPLICIT (LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING)
 /* If a temporary is created, it should be created so that it lives
    as long as the current variable bindings; otherwise it only lives
@@ -4388,20 +4385,20 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, T
    direct-initialization in cases where other parts of the compiler
    have already generated a temporary, such as reference
    initialization and the catch parameter.  */
-#define DIRECT_BIND (1 << 4)
+#define DIRECT_BIND (1 << 3)
 /* We're performing a user-defined conversion, so more user-defined
    conversions are not permitted (only built-in conversions).  */
-#define LOOKUP_NO_CONVERSION (1 << 5)
+#define LOOKUP_NO_CONVERSION (1 << 4)
 /* The user has explicitly called a destructor.  (Therefore, we do
    not need to check that the object is non-NULL before calling the
    destructor.)  */
-#define LOOKUP_DESTRUCTOR (1 << 6)
+#define LOOKUP_DESTRUCTOR (1 << 5)
 /* Do not permit references to bind to temporaries.  */
-#define LOOKUP_NO_TEMP_BIND (1 << 7)
+#define LOOKUP_NO_TEMP_BIND (1 << 6)
 /* Do not accept objects, and possibly namespaces.  */
-#define LOOKUP_PREFER_TYPES (1 << 8)
+#define LOOKUP_PREFER_TYPES (1 << 7)
 /* Do not accept objects, and possibly types.   */
-#define LOOKUP_PREFER_NAMESPACES (1 << 9)
+#define LOOKUP_PREFER_NAMESPACES (1 << 8)
 /* Accept types or namespaces.  */
 #define LOOKUP_PREFER_BOTH (LOOKUP_PREFER_TYPES | LOOKUP_PREFER_NAMESPACES)
 /* Return friend declarations and un-declared builtin functions.
@@ -4894,7 +4891,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 +5000,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 +5903,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);
Index: cp/name-lookup.c
===================================================================
--- cp/name-lookup.c	(revision 188268)
+++ cp/name-lookup.c	(working copy)
@@ -1854,7 +1854,7 @@ identifier_type_value_1 (tree id)
     return REAL_IDENTIFIER_TYPE_VALUE (id);
   /* Have to search for it. It must be on the global level, now.
      Ask lookup_name not to return non-types.  */
-  id = lookup_name_real (id, 2, 1, /*block_p=*/true, 0, LOOKUP_COMPLAIN);
+  id = lookup_name_real (id, 2, 1, /*block_p=*/true, 0, 0);
   if (id)
     return TREE_TYPE (id);
   return NULL_TREE;
@@ -4345,7 +4345,6 @@ lookup_qualified_name (tree scope, tree name, bool
     {
       struct scope_binding binding = EMPTY_SCOPE_BINDING;
 
-      flags |= LOOKUP_COMPLAIN;
       if (is_type_p)
 	flags |= LOOKUP_PREFER_TYPES;
       if (qualified_lookup_using_namespace (name, scope, &binding, flags))
@@ -4772,7 +4771,7 @@ lookup_name_real (tree name, int prefer_type, int
 tree
 lookup_name_nonclass (tree name)
 {
-  return lookup_name_real (name, 0, 1, /*block_p=*/true, 0, LOOKUP_COMPLAIN);
+  return lookup_name_real (name, 0, 1, /*block_p=*/true, 0, 0);
 }
 
 tree
@@ -4780,22 +4779,20 @@ lookup_function_nonclass (tree name, VEC(tree,gc)
 {
   return
     lookup_arg_dependent (name,
-			  lookup_name_real (name, 0, 1, block_p, 0,
-					    LOOKUP_COMPLAIN),
+			  lookup_name_real (name, 0, 1, block_p, 0, 0),
 			  args, false);
 }
 
 tree
 lookup_name (tree name)
 {
-  return lookup_name_real (name, 0, 0, /*block_p=*/true, 0, LOOKUP_COMPLAIN);
+  return lookup_name_real (name, 0, 0, /*block_p=*/true, 0, 0);
 }
 
 tree
 lookup_name_prefer_type (tree name, int prefer_type)
 {
-  return lookup_name_real (name, prefer_type, 0, /*block_p=*/true,
-			   0, LOOKUP_COMPLAIN);
+  return lookup_name_real (name, prefer_type, 0, /*block_p=*/true, 0, 0);
 }
 
 /* Look up NAME for type used in elaborated name specifier in

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [C++ Patch] PR 53567
  2012-06-06 17:12                           ` Paolo Carlini
@ 2012-06-06 18:48                             ` Jason Merrill
  0 siblings, 0 replies; 19+ messages in thread
From: Jason Merrill @ 2012-06-06 18:48 UTC (permalink / raw)
  To: Paolo Carlini; +Cc: gcc-patches

OK, thanks.

Jason

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2012-06-06 18:42 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-04 14:17 [C++ Patch] PR 53567 Paolo Carlini
2012-06-04 18:12 ` Jason Merrill
2012-06-04 22:57   ` Paolo Carlini
2012-06-04 23:23     ` Jason Merrill
2012-06-04 23:47       ` Paolo Carlini
2012-06-05  0:24         ` Paolo Carlini
2012-06-05  2:11           ` Jason Merrill
2012-06-05 11:02             ` Paolo Carlini
2012-06-05 14:17               ` Jason Merrill
2012-06-05 16:18                 ` Paolo Carlini
2012-06-05 16:34                   ` Jason Merrill
2012-06-05 16:50                     ` Paolo Carlini
2012-06-06  1:00                 ` Paolo Carlini
2012-06-06  2:29                   ` Jason Merrill
2012-06-06  9:33                     ` Paolo Carlini
2012-06-06 10:23                       ` Paolo Carlini
2012-06-06 16:17                         ` Jason Merrill
2012-06-06 17:12                           ` Paolo Carlini
2012-06-06 18:48                             ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).