Patchwork [C++] PR 52363

login
register
mail settings
Submitter Paolo Carlini
Date April 18, 2012, 9:31 p.m.
Message ID <4F8F32CA.9000304@oracle.com>
Download mbox | patch
Permalink /patch/153606/
State New
Headers show

Comments

Paolo Carlini - April 18, 2012, 9:31 p.m.
Hi again,
> Thus, if I don't ear from you, I'm probably going to add complain to 
> build_user_type_conversion_1, hopefully I can manage, I remember that 
> earlier today I tried and was dragging in a lot of changes...
The below adds complain to build_user_type_conversion_1 and 
build_user_type_conversion too (besides perform_overload_resolution, 
etc) thus convert_like_real can propagate complain down to the former. 
This version too passes testing.

Thanks!
Paolo.

///////////////////////
/cp
2012-04-18  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):
	Add tsubst_flags_t parameter.
	(joust): Likewise, use it to handle SFINAE as if pedantic.
	(reference_binding, implicit_conversion,
	build_new_function_call, build_new_function_call,
	build_op_call_1, build_conditional_expr_1,
	build_new_op_1, convert_like_real, build_over_call,
	build_new_method_call_1): 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-18  Paolo Carlini  <paolo.carlini@oracle.com>

	PR c++/52363
	* testsuite/g++.dg/cpp0x/sfinae35.C: New.
	* testsuite/g++.dg/cpp0x/sfinae36.C: Likewise.

Patch

Index: testsuite/g++.dg/cpp0x/sfinae35.C
===================================================================
--- testsuite/g++.dg/cpp0x/sfinae35.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/sfinae35.C	(revision 0)
@@ -0,0 +1,13 @@ 
+// PR c++/52363
+// { dg-options -std=c++11 }
+
+#include <type_traits>
+
+struct proxy
+{
+  void operator=(int const&);
+  void operator=(int&&) const;
+};
+
+static_assert( !std::is_assignable<proxy, int>::value, "" );
+static_assert( std::is_assignable<const proxy, int>::value, "" );
Index: testsuite/g++.dg/cpp0x/sfinae36.C
===================================================================
--- testsuite/g++.dg/cpp0x/sfinae36.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/sfinae36.C	(revision 0)
@@ -0,0 +1,13 @@ 
+// PR c++/52363
+// { dg-options "-std=c++11 -pedantic" }
+
+#include <type_traits>
+
+struct proxy
+{
+  void operator=(int const&);
+  void operator=(int&&) const;
+};
+
+static_assert( !std::is_assignable<proxy, int>::value, "" );
+static_assert( std::is_assignable<const proxy, int>::value, "" );
Index: cp/init.c
===================================================================
--- cp/init.c	(revision 186573)
+++ 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 186573)
+++ 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);
@@ -1597,7 +1599,8 @@  reference_binding (tree rto, tree rfrom, tree expr
 
 	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,
+							tf_warning_or_error);
       if (cand)
 	return cand->second_conv;
     }
@@ -1748,7 +1751,8 @@  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,
+					   tf_warning_or_error);
       if (cand)
 	conv = cand->second_conv;
 
@@ -3389,7 +3393,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;
@@ -3582,13 +3587,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 +3634,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 +3649,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);
         }
     }
@@ -3763,7 +3770,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 +3807,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 +3879,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 +3926,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 +3936,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 +3952,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 +4011,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 +4116,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)
@@ -4584,7 +4594,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 +5123,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 +5150,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 +5780,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 +6394,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 +7329,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 +8024,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 +8088,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 +8134,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 +8297,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 +8325,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 +8371,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 +8382,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 +8412,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;
     }
Index: cp/cvt.c
===================================================================
--- cp/cvt.c	(revision 186573)
+++ 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 186573)
+++ 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);