Patchwork [C++] PR 52363

login
register
mail settings
Submitter Paolo Carlini
Date April 19, 2012, 12:45 p.m.
Message ID <4F9008E2.30404@oracle.com>
Download mbox | patch
Permalink /patch/153745/
State New
Headers show

Comments

Paolo Carlini - April 19, 2012, 12:45 p.m.
Hi,
> On 04/18/2012 08:30 PM, Paolo Carlini wrote:
>> Thus, it seems to me that with above change it's just that we don't have
>> any hope of fixing latent SFINAE bugs in turney called by
>> build_user_type_conversion_1 per the above. And, at this time, we don't
>> have any evidence of such bugs.
>
> We've just been dealing with SFINAE bugs in tourney; I would expect 
> that they can also occur for conversions using a single-argument 
> constructor.
Ok...
> I think you're right that we should just pass complain through 
> build_user_type_conversion_1.  Looking at the patch, I think we need 
> to pass it through implicit_conversion and reference_binding as well.
No big deal, here is a patch extending my last posted version to 
implicit_conversion and reference_binding. Booted and tested x86_64-linux.

Thanks!
Paolo.

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

	PR c++/52363
	* call.c (tourney, perform_overload_resolution,
	build_operator_new_call, build_user_type_conversion_1,
	build_user_type_conversion, perform_overload_resolution,
	implicit_conversion, reference_binding): Add tsubst_flags_t
	parameter.
	(joust): Likewise, use it to handle SFINAE as if pedantic.
	(build_list_conv, build_array_conv, build_complex_conv,
	add_function_candidate, add_conv_candidate,
	build_builtin_candidate, add_list_candidates,
	build_integral_nontype_arg_conv, perform_overload_resolution,
	build_new_function_call, build_operator_new_call,
	build_op_call_1, conditional_conversion,
	build_conditional_expr_1, build_new_op_1, convert_like_real,
	build_over_call, build_new_method_call_1, can_convert_arg,
	can_convert_arg_bad, perform_implicit_conversion_flags,
	perform_direct_initialization_if_possible,
	initialize_reference): Adjust.
	* init.c (build_new_1): Likewise.
	* cvt.c (ocp_convert, build_type_conversion,
	build_expr_type_conversion): Likewise.
	* cp-tree.h (build_user_type_conversion,
	build_operator_new_call): Adjust declaration.

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

	PR c++/52363
	* testsuite/g++.dg/cpp0x/sfinae35.C: New.
	* testsuite/g++.dg/cpp0x/sfinae36.C: Likewise.
Jason Merrill - April 19, 2012, 6:50 p.m.
On 04/19/2012 08:45 AM, Paolo Carlini wrote:
> @@ -812,7 +816,7 @@ build_list_conv (tree type, tree ctor, int flags)
>       {
>         conversion *sub
>   	= implicit_conversion (elttype, TREE_TYPE (val), val,
> -			       false, flags);
> +			       false, flags, tf_warning_or_error);

I'm still seeing several new occurrences of tf_warning_or_error in 
overload resolution code.  :)

Jason
Paolo Carlini - April 19, 2012, 7 p.m.
Hi,

> On 04/19/2012 08:45 AM, Paolo Carlini wrote:
>> @@ -812,7 +816,7 @@ build_list_conv (tree type, tree ctor, int flags)
>>      {
>>        conversion *sub
>>      = implicit_conversion (elttype, TREE_TYPE (val), val,
>> -                   false, flags);
>> +                   false, flags, tf_warning_or_error);
> 
> I'm still seeing several new occurrences of tf_warning_or_error in overload resolution code.  :)

Yes, that's life ;) Seriously, if we want to avoid all those having to do with implicit_conversion in one swoop, the eventual patch will be pretty big, should I just go on and on?

Paolo
Jason Merrill - April 19, 2012, 7:20 p.m.
On 04/19/2012 03:00 PM, Paolo Carlini wrote:
> Yes, that's life ;) Seriously, if we want to avoid all those having to do with implicit_conversion in one swoop, the eventual patch will be pretty big, should I just go on and on?

I think so.  Once we start down this road, we should follow it to the end.

Jason

Patch

Index: cp/init.c
===================================================================
--- cp/init.c	(revision 186586)
+++ cp/init.c	(working copy)
@@ -2381,7 +2381,7 @@  build_new_1 (VEC(tree,gc) **placement, tree type,
 
 	  alloc_call = build_operator_new_call (fnname, placement,
 						&size, &cookie_size,
-						&alloc_fn);
+						&alloc_fn, complain);
 	}
     }
 
Index: cp/call.c
===================================================================
--- cp/call.c	(revision 186586)
+++ cp/call.c	(working copy)
@@ -142,9 +142,10 @@  static struct obstack conversion_obstack;
 static bool conversion_obstack_initialized;
 struct rejection_reason;
 
-static struct z_candidate * tourney (struct z_candidate *);
+static struct z_candidate * tourney (struct z_candidate *, tsubst_flags_t);
 static int equal_functions (tree, tree);
-static int joust (struct z_candidate *, struct z_candidate *, bool);
+static int joust (struct z_candidate *, struct z_candidate *, bool,
+		  tsubst_flags_t);
 static int compare_ics (conversion *, conversion *);
 static tree build_over_call (struct z_candidate *, int, tsubst_flags_t);
 static tree build_java_interface_fn_ref (tree, tree);
@@ -160,7 +161,8 @@  static tree convert_like_real (conversion *, tree,
 			       bool, tsubst_flags_t);
 static void op_error (enum tree_code, enum tree_code, tree, tree,
 		      tree, bool);
-static struct z_candidate *build_user_type_conversion_1 (tree, tree, int);
+static struct z_candidate *build_user_type_conversion_1 (tree, tree, int,
+							 tsubst_flags_t);
 static void print_z_candidate (const char *, struct z_candidate *);
 static void print_z_candidates (location_t, struct z_candidate *);
 static tree build_this (tree);
@@ -191,9 +193,11 @@  static struct z_candidate *add_conv_candidate
 static struct z_candidate *add_function_candidate
 	(struct z_candidate **, tree, tree, tree, const VEC(tree,gc) *, tree,
 	 tree, int);
-static conversion *implicit_conversion (tree, tree, tree, bool, int);
+static conversion *implicit_conversion (tree, tree, tree, bool, int,
+					tsubst_flags_t);
 static conversion *standard_conversion (tree, tree, tree, bool, int);
-static conversion *reference_binding (tree, tree, tree, bool, int);
+static conversion *reference_binding (tree, tree, tree, bool, int,
+				      tsubst_flags_t);
 static conversion *build_conv (conversion_kind, tree, conversion *);
 static conversion *build_list_conv (tree, tree, int);
 static conversion *next_conversion (conversion *);
@@ -812,7 +816,7 @@  build_list_conv (tree type, tree ctor, int flags)
     {
       conversion *sub
 	= implicit_conversion (elttype, TREE_TYPE (val), val,
-			       false, flags);
+			       false, flags, tf_warning_or_error);
       if (sub == NULL)
 	return NULL;
 
@@ -957,7 +961,7 @@  build_array_conv (tree type, tree ctor, int flags)
     {
       conversion *sub
 	= implicit_conversion (elttype, TREE_TYPE (val), val,
-			       false, flags);
+			       false, flags, tf_warning_or_error);
       if (sub == NULL)
 	return NULL;
 
@@ -1000,7 +1004,7 @@  build_complex_conv (tree type, tree ctor, int flag
     {
       conversion *sub
 	= implicit_conversion (elttype, TREE_TYPE (val), val,
-			       false, flags);
+			       false, flags, tf_warning_or_error);
       if (sub == NULL)
 	return NULL;
 
@@ -1438,7 +1442,8 @@  direct_reference_binding (tree type, conversion *c
    conversion is coming from a C-style cast.  */
 
 static conversion *
-reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
+reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
+		   tsubst_flags_t complain)
 {
   conversion *conv = NULL;
   tree to = TREE_TYPE (rto);
@@ -1461,7 +1466,7 @@  static conversion *
     {
       maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
       conv = implicit_conversion (to, from, expr, c_cast_p,
-				  flags);
+				  flags, complain);
       if (!CLASS_TYPE_P (to)
 	  && CONSTRUCTOR_NELTS (expr) == 1)
 	{
@@ -1597,7 +1602,8 @@  static conversion *
 
 	the reference is bound to the lvalue result of the conversion
 	in the second case.  */
-      z_candidate *cand = build_user_type_conversion_1 (rto, expr, flags);
+      z_candidate *cand = build_user_type_conversion_1 (rto, expr, flags,
+							complain);
       if (cand)
 	return cand->second_conv;
     }
@@ -1652,7 +1658,7 @@  static conversion *
 
   if (!conv)
     conv = implicit_conversion (to, from, expr, c_cast_p,
-				flags);
+				flags, complain);
   if (!conv)
     return NULL;
 
@@ -1672,7 +1678,7 @@  static conversion *
 
 static conversion *
 implicit_conversion (tree to, tree from, tree expr, bool c_cast_p,
-		     int flags)
+		     int flags, tsubst_flags_t complain)
 {
   conversion *conv;
 
@@ -1687,7 +1693,7 @@  implicit_conversion (tree to, tree from, tree expr
 	    |LOOKUP_NO_NARROWING|LOOKUP_PROTECT);
 
   if (TREE_CODE (to) == REFERENCE_TYPE)
-    conv = reference_binding (to, from, expr, c_cast_p, flags);
+    conv = reference_binding (to, from, expr, c_cast_p, flags, complain);
   else
     conv = standard_conversion (to, from, expr, c_cast_p, flags);
 
@@ -1722,7 +1728,7 @@  implicit_conversion (tree to, tree from, tree expr
 	    elt = error_mark_node;
 
 	  conv = implicit_conversion (to, TREE_TYPE (elt), elt,
-				      c_cast_p, flags);
+				      c_cast_p, flags, complain);
 	  if (conv)
 	    {
 	      conv->check_narrowing = true;
@@ -1748,7 +1754,7 @@  implicit_conversion (tree to, tree from, tree expr
 	  && !CLASSTYPE_NON_AGGREGATE (complete_type (to)))
 	return build_aggr_conv (to, expr, flags);
 
-      cand = build_user_type_conversion_1 (to, expr, flags);
+      cand = build_user_type_conversion_1 (to, expr, flags, complain);
       if (cand)
 	conv = cand->second_conv;
 
@@ -1977,7 +1983,8 @@  add_function_candidate (struct z_candidate **candi
 	    lflags |= LOOKUP_ONLYCONVERTING;
 
 	  t = implicit_conversion (parmtype, argtype, arg,
-				   /*c_cast_p=*/false, lflags);
+				   /*c_cast_p=*/false, lflags,
+				   tf_warning_or_error);
 	  to_type = parmtype;
 	}
       else
@@ -2065,7 +2072,7 @@  add_conv_candidate (struct z_candidate **candidate
       if (i == 0)
 	{
 	  t = implicit_conversion (totype, argtype, arg, /*c_cast_p=*/false,
-				   flags);
+				   flags, tf_warning_or_error);
 	  convert_type = totype;
 	}
       else if (parmnode == void_list_node)
@@ -2073,7 +2080,8 @@  add_conv_candidate (struct z_candidate **candidate
       else if (parmnode)
 	{
 	  t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg,
-				   /*c_cast_p=*/false, flags);
+				   /*c_cast_p=*/false, flags,
+				   tf_warning_or_error);
 	  convert_type = TREE_VALUE (parmnode);
 	}
       else
@@ -2144,7 +2152,8 @@  build_builtin_candidate (struct z_candidate **cand
 	break;
 
       t = implicit_conversion (types[i], argtypes[i], args[i],
-			       /*c_cast_p=*/false, flags);
+			       /*c_cast_p=*/false, flags,
+			       tf_warning_or_error);
       if (! t)
 	{
 	  viable = 0;
@@ -2166,7 +2175,8 @@  build_builtin_candidate (struct z_candidate **cand
       convs[2] = convs[1];
       convs[1] = convs[0];
       t = implicit_conversion (boolean_type_node, argtypes[2], args[2],
-			       /*c_cast_p=*/false, flags);
+			       /*c_cast_p=*/false, flags,
+			       tf_warning_or_error);
       if (t)
 	convs[0] = t;
       else
@@ -3389,7 +3399,8 @@  add_list_candidates (tree fns, tree first_arg,
    per [dcl.init.ref], so we ignore temporary bindings.  */
 
 static struct z_candidate *
-build_user_type_conversion_1 (tree totype, tree expr, int flags)
+build_user_type_conversion_1 (tree totype, tree expr, int flags,
+			      tsubst_flags_t complain)
 {
   struct z_candidate *candidates, *cand;
   tree fromtype;
@@ -3517,7 +3528,8 @@  static struct z_candidate *
 	    = implicit_conversion (totype,
 				   rettype,
 				   0,
-				   /*c_cast_p=*/false, convflags);
+				   /*c_cast_p=*/false, convflags,
+				   complain);
 
 	  /* If LOOKUP_NO_TEMP_BIND isn't set, then this is
 	     copy-initialization.  In that case, "The result of the
@@ -3582,13 +3594,14 @@  static struct z_candidate *
       return NULL;
     }
 
-  cand = tourney (candidates);
+  cand = tourney (candidates, complain);
   if (cand == 0)
     {
-      if (flags & LOOKUP_COMPLAIN)
+      if ((flags & LOOKUP_COMPLAIN)
+	  && (complain & tf_error))
 	{
 	  error ("conversion from %qT to %qT is ambiguous",
-		    fromtype, totype);
+		 fromtype, totype);
 	  print_z_candidates (location_of (expr), candidates);
 	}
 
@@ -3628,13 +3641,14 @@  static struct z_candidate *
 /* Wrapper for above. */
 
 tree
-build_user_type_conversion (tree totype, tree expr, int flags)
+build_user_type_conversion (tree totype, tree expr, int flags,
+			    tsubst_flags_t complain)
 {
   struct z_candidate *cand;
   tree ret;
 
   bool subtime = timevar_cond_start (TV_OVERLOAD);
-  cand = build_user_type_conversion_1 (totype, expr, flags);
+  cand = build_user_type_conversion_1 (totype, expr, flags, complain);
 
   if (cand)
     {
@@ -3642,7 +3656,7 @@  tree
 	ret = error_mark_node;
       else
         {
-          expr = convert_like (cand->second_conv, expr, tf_warning_or_error);
+          expr = convert_like (cand->second_conv, expr, complain);
           ret = convert_from_reference (expr);
         }
     }
@@ -3679,7 +3693,7 @@  build_integral_nontype_arg_conv (tree type, tree e
 
   conv = implicit_conversion (type, TREE_TYPE (expr), expr,
 			      /*c_cast_p=*/false,
-			      LOOKUP_IMPLICIT);
+			      LOOKUP_IMPLICIT, complain);
 
   /* for a non-type template-parameter of integral or
      enumeration type, integral promotions (4.5) and integral
@@ -3763,7 +3777,7 @@  static struct z_candidate *
 perform_overload_resolution (tree fn,
 			     const VEC(tree,gc) *args,
 			     struct z_candidate **candidates,
-			     bool *any_viable_p)
+			     bool *any_viable_p, tsubst_flags_t complain)
 {
   struct z_candidate *cand;
   tree explicit_targs;
@@ -3800,7 +3814,7 @@  perform_overload_resolution (tree fn,
 
   *candidates = splice_viable (*candidates, pedantic, any_viable_p);
   if (*any_viable_p)
-    cand = tourney (*candidates);
+    cand = tourney (*candidates, complain);
   else
     cand = NULL;
 
@@ -3872,7 +3886,8 @@  build_new_function_call (tree fn, VEC(tree,gc) **a
   /* Get the high-water mark for the CONVERSION_OBSTACK.  */
   p = conversion_obstack_alloc (0);
 
-  cand = perform_overload_resolution (fn, *args, &candidates, &any_viable_p);
+  cand = perform_overload_resolution (fn, *args, &candidates, &any_viable_p,
+				      complain);
 
   if (!cand)
     {
@@ -3918,7 +3933,7 @@  build_new_function_call (tree fn, VEC(tree,gc) **a
 tree
 build_operator_new_call (tree fnname, VEC(tree,gc) **args,
 			 tree *size, tree *cookie_size,
-			 tree *fn)
+			 tree *fn, tsubst_flags_t complain)
 {
   tree fns;
   struct z_candidate *candidates;
@@ -3928,7 +3943,7 @@  build_operator_new_call (tree fnname, VEC(tree,gc)
   if (fn)
     *fn = NULL_TREE;
   VEC_safe_insert (tree, gc, *args, 0, *size);
-  *args = resolve_args (*args, tf_warning_or_error);
+  *args = resolve_args (*args, complain);
   if (*args == NULL)
     return error_mark_node;
 
@@ -3944,13 +3959,15 @@  build_operator_new_call (tree fnname, VEC(tree,gc)
   fns = lookup_function_nonclass (fnname, *args, /*block_p=*/false);
 
   /* Figure out what function is being called.  */
-  cand = perform_overload_resolution (fns, *args, &candidates, &any_viable_p);
+  cand = perform_overload_resolution (fns, *args, &candidates, &any_viable_p,
+				      complain);
 
   /* If no suitable function could be found, issue an error message
      and give up.  */
   if (!cand)
     {
-      print_error_for_call_failure (fns, *args, any_viable_p, candidates);
+      if (complain & tf_error)
+	print_error_for_call_failure (fns, *args, any_viable_p, candidates);
       return error_mark_node;
     }
 
@@ -4001,7 +4018,7 @@  build_operator_new_call (tree fnname, VEC(tree,gc)
      *fn = cand->fn;
 
    /* Build the CALL_EXPR.  */
-   return build_over_call (cand, LOOKUP_NORMAL, tf_warning_or_error);
+   return build_over_call (cand, LOOKUP_NORMAL, complain);
 }
 
 /* Build a new call to operator().  This may change ARGS.  */
@@ -4106,7 +4123,7 @@  build_op_call_1 (tree obj, VEC(tree,gc) **args, ts
     }
   else
     {
-      cand = tourney (candidates);
+      cand = tourney (candidates, complain);
       if (cand == 0)
 	{
           if (complain & tf_error)
@@ -4271,7 +4288,8 @@  conditional_conversion (tree e1, tree e2)
 				  e1,
 				  /*c_cast_p=*/false,
 				  LOOKUP_NO_TEMP_BIND|LOOKUP_NO_RVAL_BIND
-				  |LOOKUP_ONLYCONVERTING);
+				  |LOOKUP_ONLYCONVERTING,
+				  tf_warning_or_error);
       if (conv)
 	return conv;
     }
@@ -4309,7 +4327,7 @@  conditional_conversion (tree e1, tree e2)
        converted to the type that expression E2 would have if E2 were
        converted to an rvalue (or the type it has, if E2 is an rvalue).  */
     return implicit_conversion (t2, t1, e1, /*c_cast_p=*/false,
-				LOOKUP_IMPLICIT);
+				LOOKUP_IMPLICIT, tf_warning_or_error);
 }
 
 /* Implement [expr.cond].  ARG1, ARG2, and ARG3 are the three
@@ -4584,7 +4602,7 @@  build_conditional_expr_1 (tree arg1, tree arg2, tr
             }
 	  return error_mark_node;
 	}
-      cand = tourney (candidates);
+      cand = tourney (candidates, complain);
       if (!cand)
 	{
           if (complain & tf_error)
@@ -5113,7 +5131,7 @@  build_new_op_1 (enum tree_code code, int flags, tr
     }
   else
     {
-      cand = tourney (candidates);
+      cand = tourney (candidates, complain);
       if (cand == 0)
 	{
 	  if ((flags & LOOKUP_COMPLAIN) && (complain & tf_error))
@@ -5140,7 +5158,7 @@  build_new_op_1 (enum tree_code code, int flags, tr
 	    {
 	      struct candidate_warning *w;
 	      for (w = cand->warnings; w; w = w->next)
-		joust (cand, w->loser, 1);
+		joust (cand, w->loser, 1, complain);
 	    }
 
 	  /* Check for comparison of different enum types.  */
@@ -5770,7 +5788,8 @@  convert_like_real (conversion *convs, tree expr, t
       if (complain & tf_error)
 	{
 	  /* Call build_user_type_conversion again for the error.  */
-	  build_user_type_conversion (totype, convs->u.expr, LOOKUP_NORMAL);
+	  build_user_type_conversion (totype, convs->u.expr, LOOKUP_NORMAL,
+				      complain);
 	  if (fn)
 	    error ("  initializing argument %P of %q+D", argnum, fn);
 	}
@@ -6383,7 +6402,7 @@  build_over_call (struct z_candidate *cand, int fla
     {
       struct candidate_warning *w;
       for (w = cand->warnings; w; w = w->next)
-	joust (cand, w->loser, 1);
+	joust (cand, w->loser, 1, complain);
     }
 
   /* Make =delete work with SFINAE.  */
@@ -7318,7 +7337,7 @@  build_new_method_call_1 (tree instance, tree fns,
     }
   else
     {
-      cand = tourney (candidates);
+      cand = tourney (candidates, complain);
       if (cand == 0)
 	{
 	  char *pretty_name;
@@ -8013,7 +8032,8 @@  add_warning (struct z_candidate *winner, struct z_
       0: cand1 and cand2 are indistinguishable */
 
 static int
-joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn)
+joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
+       tsubst_flags_t complain)
 {
   int winner = 0;
   int off1 = 0, off2 = 0;
@@ -8076,7 +8096,8 @@  static int
 
       if (comp != 0)
 	{
-	  if (warn_sign_promo
+	  if ((complain & tf_warning)
+	      && warn_sign_promo
 	      && (CONVERSION_RANK (t1) + CONVERSION_RANK (t2)
 		  == cr_std + cr_promotion)
 	      && t1->kind == ck_std
@@ -8121,7 +8142,8 @@  static int
   /* warn about confusing overload resolution for user-defined conversions,
      either between a constructor and a conversion op, or between two
      conversion ops.  */
-  if (winner && warn_conversion && cand1->second_conv
+  if ((complain & tf_warning)
+      && winner && warn_conversion && cand1->second_conv
       && (!DECL_CONSTRUCTOR_P (cand1->fn) || !DECL_CONSTRUCTOR_P (cand2->fn))
       && winner != compare_ics (cand1->second_conv, cand2->second_conv))
     {
@@ -8283,12 +8305,18 @@  static int
 	    {
 	      if (warn)
 		{
-		  permerror (input_location, "default argument mismatch in "
-			     "overload resolution");
-		  inform (input_location,
-			  " candidate 1: %q+#F", cand1->fn);
-		  inform (input_location,
-			  " candidate 2: %q+#F", cand2->fn);
+		  if (complain & tf_error)
+		    {
+		      permerror (input_location,
+				 "default argument mismatch in "
+				 "overload resolution");
+		      inform (input_location,
+			      " candidate 1: %q+#F", cand1->fn);
+		      inform (input_location,
+			      " candidate 2: %q+#F", cand2->fn);
+		    }
+		  else
+		    return 0;
 		}
 	      else
 		add_warning (cand1, cand2);
@@ -8305,7 +8333,7 @@  tweak:
 
   /* Extension: If the worst conversion for one candidate is worse than the
      worst conversion for the other, take the first.  */
-  if (!pedantic)
+  if (!pedantic && (complain & tf_warning_or_error))
     {
       conversion_rank rank1 = cr_identity, rank2 = cr_identity;
       struct z_candidate *w = 0, *l = 0;
@@ -8351,7 +8379,7 @@  tweak:
    algorithm.  */
 
 static struct z_candidate *
-tourney (struct z_candidate *candidates)
+tourney (struct z_candidate *candidates, tsubst_flags_t complain)
 {
   struct z_candidate *champ = candidates, *challenger;
   int fate;
@@ -8362,7 +8390,7 @@  static struct z_candidate *
 
   for (challenger = champ->next; challenger; )
     {
-      fate = joust (champ, challenger, 0);
+      fate = joust (champ, challenger, 0, complain);
       if (fate == 1)
 	challenger = challenger->next;
       else
@@ -8392,7 +8420,7 @@  static struct z_candidate *
 	 && !(champ_compared_to_predecessor && challenger->next == champ);
        challenger = challenger->next)
     {
-      fate = joust (champ, challenger, 0);
+      fate = joust (champ, challenger, 0, complain);
       if (fate != 1)
 	return NULL;
     }
@@ -8421,7 +8449,7 @@  can_convert_arg (tree to, tree from, tree arg, int
   p = conversion_obstack_alloc (0);
 
   t  = implicit_conversion (to, from, arg, /*c_cast_p=*/false,
-			    flags);
+			    flags, tf_warning_or_error);
   ok_p = (t && !t->bad_p);
 
   /* Free all the conversions we allocated.  */
@@ -8442,7 +8470,7 @@  can_convert_arg_bad (tree to, tree from, tree arg,
   p = conversion_obstack_alloc (0);
   /* Try to perform the conversion.  */
   t  = implicit_conversion (to, from, arg, /*c_cast_p=*/false,
-			    flags);
+			    flags, tf_warning_or_error);
   /* Free all the conversions we allocated.  */
   obstack_free (&conversion_obstack, p);
 
@@ -8469,7 +8497,7 @@  perform_implicit_conversion_flags (tree type, tree
 
   conv = implicit_conversion (type, TREE_TYPE (expr), expr,
 			      /*c_cast_p=*/false,
-			      flags);
+			      flags, complain);
 
   if (!conv)
     {
@@ -8554,7 +8582,7 @@  perform_direct_initialization_if_possible (tree ty
 
   conv = implicit_conversion (type, TREE_TYPE (expr), expr,
 			      c_cast_p,
-			      LOOKUP_NORMAL);
+			      LOOKUP_NORMAL, complain);
   if (!conv || conv->bad_p)
     expr = NULL_TREE;
   else
@@ -8768,7 +8796,7 @@  initialize_reference (tree type, tree expr,
   p = conversion_obstack_alloc (0);
 
   conv = reference_binding (type, TREE_TYPE (expr), expr, /*c_cast_p=*/false,
-			    flags);
+			    flags, complain);
   if (!conv || conv->bad_p)
     {
       if (complain & tf_error)
Index: cp/cvt.c
===================================================================
--- cp/cvt.c	(revision 186586)
+++ cp/cvt.c	(working copy)
@@ -821,7 +821,8 @@  ocp_convert (tree type, tree expr, int convtype, i
 	/* 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);
+	ctor = build_user_type_conversion (type, ctor, flags,
+					   tf_warning_or_error);
       else
 	{
 	  VEC(tree,gc) *ctor_vec = make_tree_vector_single (ctor);
@@ -1451,7 +1452,8 @@  build_type_conversion (tree xtype, tree expr)
 {
   /* C++: check to see if we can convert this aggregate type
      into the required type.  */
-  return build_user_type_conversion (xtype, expr, LOOKUP_NORMAL);
+  return build_user_type_conversion (xtype, expr, LOOKUP_NORMAL,
+				     tf_warning_or_error);
 }
 
 /* Convert the given EXPR to one of a group of types suitable for use in an
@@ -1609,7 +1611,8 @@  build_expr_type_conversion (int desires, tree expr
   if (winner)
     {
       tree type = non_reference (TREE_TYPE (TREE_TYPE (winner)));
-      return build_user_type_conversion (type, expr, LOOKUP_NORMAL);
+      return build_user_type_conversion (type, expr, LOOKUP_NORMAL,
+					 tf_warning_or_error);
     }
 
   return NULL_TREE;
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 186586)
+++ cp/cp-tree.h	(working copy)
@@ -4862,11 +4862,13 @@  extern bool null_ptr_cst_p			(tree);
 extern bool null_member_pointer_value_p		(tree);
 extern bool sufficient_parms_p			(const_tree);
 extern tree type_decays_to			(tree);
-extern tree build_user_type_conversion		(tree, tree, int);
+extern tree build_user_type_conversion		(tree, tree, int,
+						 tsubst_flags_t);
 extern tree build_new_function_call		(tree, VEC(tree,gc) **, bool, 
 						 tsubst_flags_t);
 extern tree build_operator_new_call		(tree, VEC(tree,gc) **, tree *,
-						 tree *, tree *);
+						 tree *, tree *,
+						 tsubst_flags_t);
 extern tree build_new_method_call		(tree, tree, VEC(tree,gc) **,
 						 tree, int, tree *,
 						 tsubst_flags_t);