public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [RFC,c++] fix PR 45329, provide information on overload resolution
@ 2010-11-17 21:32 Nathan Froyd
  2010-11-18  8:12 ` Mark Mitchell
  2010-11-19 23:31 ` Jason Merrill
  0 siblings, 2 replies; 12+ messages in thread
From: Nathan Froyd @ 2010-11-17 21:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: jason, mark, aaw

PR 45329 is a problem with GCC's overload resolution diagnostics.  For
the testcase:

struct S
{
 int x;
 int y;
};

int foo(int x, int y)
{
 return x+y;
}

int foo(const S &s)
{
 return s.x + s.y;
}

int foo2(int x)
{
 foo(x);
}

gcc prints:

./tst.cc: In function ‘int foo2(int)’:
./tst.cc:19:8: error: no matching function for call to ‘foo(int&)’
./tst.cc:7:5: note: candidates are: int foo(int, int)
./tst.cc:12:5: note:                 int foo(const S&)

and the bug reporter indicates it would be helpful if GCC provided some
information about why the candidate functions did not match.

The patch below addresses this.  At each point where we decide that a
candidate function loses, we record a rejection reason.  When we print
the candidates, we also print out the reasons, if any.  This scheme only
really deals with the "no matching function for" case; I can try to
piece something together for the ambiguous match case, though that will
be a bit harder.

We don't keep track of multiple rejection reasons.  It would be a
trivial modification to do so if people felt that was worthwhile.

There are two points at which I have not added rejection reasons.  One
of them--convert_class_to_reference--I have described in a comment.  The
second one is in add_function_candidate:

  /* Kludge: When looking for a function from a subobject while generating
     an implicit copy/move constructor/operator=, don't consider anything
     that takes (a reference to) an unrelated type.  See c++/44909.  */
  else if (parmlist
	   && ((flags & LOOKUP_SPECULATIVE)
	       || (current_function_decl
		   && DECL_DEFAULTED_FN (current_function_decl))))
    {
      if (DECL_CONSTRUCTOR_P (fn))
	i = 1;
      else if (DECL_ASSIGNMENT_OPERATOR_P (fn)
	       && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR)
	i = 2;
      else
	i = 0;
      if (i && len == i)
	{
	  parmnode = chain_index (i-1, parmlist);
	  if (!reference_related_p (non_reference (TREE_VALUE (parmnode)),
				    ctype))
	    viable = 0;
	}

I am clueless about what a decent reason is.  Comments welcome.

For the testcase above, a modified g++ prints:

pr45329.C: In function 'int foo2(int)':
pr45329.C:26:7: error: no matching function for call to 'foo(int&)'
cc1plus: note: candidates are:
pr45329.C:7:5: note: int foo(int, int)
pr45329.C:7:5: note: candidate expects 2 arguments, 1 provided
pr45329.C:19:5: note: int foo(const S&)
pr45329.C:19:5: note: no known conversion for argument 1 from 'int' to 'const S&'

which is a little friendlier.

Part of the reason for asking for comments here is that moving the
diagnostics around as above will require the modification of a bajillion
testcases; before I embark on that, I'd like comments on the approach
and whether the formatting seems reasonable.  I moved the formatting
around because leaving the formatting as before resulted in:

pr45329.C: In function 'int foo2(int)':
pr45329.C:26:7: error: no matching function for call to 'foo(int&)'
pr45329.C:7:5: note: candidates are: int foo(int, int)
pr45329.C:7:5: note: candidates are: candidate expects 2 arguments, 1 provided
pr45329.C:19:5: note:                 int foo(const S&)
pr45329.C:19:5: note:                 no known conversion for argument 1 from 'int' to 'const S&'

which IMHO takes up a lot of space for little gain.  I suppose one
obvious improvement to the proposed format might be something like:

pr45329.C: In function 'int foo2(int)':
pr45329.C:26:7: error: no matching function for call to 'foo(int&)'
cc1plus: note: candidates are:
pr45329.C:7:5: note: int foo(int, int)
pr45329.C:note: candidate expects 2 arguments, 1 provided
pr45329.C:19:5: note: int foo(const S&)
pr45329.C: note: no known conversion for argument 1 from 'int' to 'const S&'

though I wouldn't be thrilled about dg-message matching that.

I have gone through testlogs from check-g++ and the messages look
reasonable.

Comments?  Concerns?  Ollie, you reported the bug; what do you think
about the changes?

-Nathan

gcc/cp/
	PR c++/45329
	* cp-tree.h (location_at): Declare.
	* error.c (location_at): Export.
	* call.c (struct conversion): Document bad_p field.
	(enum rejection_reason_code): Define.
	(struct rejection_reason): Define.
	(struct z_candidate): Add `reason' field.
	(add_candidate): Add `reason' parameter.  Store it in CAND.
	(alloc_rejection, arity_rejection, arg_conversion_rejection):
	New functions.
	(bad_arg_conversion_rejection): New function.
	(convert_class_to_reference): Add comment.
	(add_function_candidate): Record rejection reason and pass it to
	add_candidate.
	(add_conv_candidate, build_builtin_candidate): Likewise.
	(add_template_candidate_real): Likewise.
	(print_z_candidate): Print CAND->REASON if it exists.  Adjust
	diagnostic strings.
	(print_z_candidates): Adjust calling sequence for print_z_candidate.
	Print header line directly.
	(build_user_type_conversion_1): Add reason for rejection to CAND.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index eb7247d..c69126d 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -84,6 +84,9 @@ struct conversion {
   BOOL_BITFIELD user_conv_p : 1;
   BOOL_BITFIELD ellipsis_p : 1;
   BOOL_BITFIELD this_p : 1;
+  /* True if this conversion would be permitted with a bending of
+     language standards, e.g. disregarding pointer qualifiers or
+     converting integers to pointers.  */
   BOOL_BITFIELD bad_p : 1;
   /* If KIND is ck_ref_bind ck_base_conv, true to indicate that a
      temporary should be created to hold the result of the
@@ -129,6 +132,7 @@ struct conversion {
 
 static struct obstack conversion_obstack;
 static bool conversion_obstack_initialized;
+struct rejection_reason;
 
 static struct z_candidate * tourney (struct z_candidate *);
 static int equal_functions (tree, tree);
@@ -190,7 +194,7 @@ static conversion *maybe_handle_ref_bind (conversion **);
 static void maybe_handle_implicit_object (conversion **);
 static struct z_candidate *add_candidate
 	(struct z_candidate **, tree, tree, const VEC(tree,gc) *, size_t,
-	 conversion **, tree, tree, int);
+	 conversion **, tree, tree, int, struct rejection_reason *);
 static tree source_type (conversion *);
 static void add_warning (struct z_candidate *, struct z_candidate *);
 static bool reference_compatible_p (tree, tree);
@@ -416,6 +420,45 @@ struct candidate_warning {
   candidate_warning *next;
 };
 
+/* Information for providing diagnostics about why overloading failed.  */
+
+enum rejection_reason_code {
+  rr_none,
+  rr_arity,
+  rr_arg_conversion,
+  rr_bad_arg_conversion
+};
+
+struct rejection_reason {
+  enum rejection_reason_code code;
+  union {
+    /* Information about an arity mismatch.  */
+    struct {
+      /* The expected number of arguments.  */
+      int expected;
+      /* The actual number of arguments in the call.  */
+      int actual;
+      /* Whether the call was a varargs call.  */
+      bool call_varargs_p;
+    } arity;
+    /* Information about an argument conversion mismatch.  */
+    struct {
+      /* The index of the argument, 0-based.  */
+      int n_arg;
+      /* The type of the actual argument.  */
+      tree from_type;
+      /* The type of the formal argument.  */
+      tree to_type;
+    } conversion;
+    /* Same, but for bad argument conversions.  */
+    struct {
+      int n_arg;
+      tree from_type;
+      tree to_type;
+    } bad_conversion;
+  } u;
+};
+
 struct z_candidate {
   /* The FUNCTION_DECL that will be called if this candidate is
      selected by overload resolution.  */
@@ -437,6 +480,7 @@ struct z_candidate {
      type.  */
   conversion *second_conv;
   int viable;
+  struct rejection_reason *reason;
   /* If FN is a member function, the binfo indicating the path used to
      qualify the name of FN at the call site.  This path is used to
      determine whether or not FN is accessible if it is selected by
@@ -518,6 +562,46 @@ conversion_obstack_alloc (size_t n)
   return p;
 }
 
+/* Allocate rejection reasons.  */
+
+static struct rejection_reason *
+alloc_rejection (enum rejection_reason_code code)
+{
+  struct rejection_reason *p;
+  p = (struct rejection_reason *) conversion_obstack_alloc (sizeof *p);
+  p->code = code;
+  return p;
+}
+
+static struct rejection_reason *
+arity_rejection (int expected, int actual)
+{
+  struct rejection_reason *r = alloc_rejection (rr_arity);
+  r->u.arity.expected = expected;
+  r->u.arity.actual = actual;
+  return r;
+}
+
+static struct rejection_reason *
+arg_conversion_rejection (int n_arg, tree from, tree to)
+{
+  struct rejection_reason *r = alloc_rejection (rr_arg_conversion);
+  r->u.conversion.n_arg = n_arg;
+  r->u.conversion.from_type = from;
+  r->u.conversion.to_type = to;
+  return r;
+}
+
+static struct rejection_reason *
+bad_arg_conversion_rejection (int n_arg, tree from, tree to)
+{
+  struct rejection_reason *r = alloc_rejection (rr_bad_arg_conversion);
+  r->u.bad_conversion.n_arg = n_arg;
+  r->u.bad_conversion.from_type = from;
+  r->u.bad_conversion.to_type = to;
+  return r;
+}
+
 /* Dynamically allocate a conversion.  */
 
 static conversion *
@@ -1149,6 +1233,10 @@ convert_class_to_reference (tree reference_type, tree s, tree expr, int flags)
 	  if (TREE_CODE (t2) != REFERENCE_TYPE
 	      || !reference_compatible_p (t, TREE_TYPE (t2)))
 	    {
+	      /* No need to set cand->reason here; this is most likely
+		 an ambiguous match.  If it's not, either this candidate
+		 will win, or we will have identified a reason for it
+		 losing already.  */
 	      cand->viable = 0;
 	    }
 	  else
@@ -1562,7 +1650,7 @@ add_candidate (struct z_candidate **candidates,
 	       tree fn, tree first_arg, const VEC(tree,gc) *args,
 	       size_t num_convs, conversion **convs,
 	       tree access_path, tree conversion_path,
-	       int viable)
+	       int viable, struct rejection_reason *reason)
 {
   struct z_candidate *cand = (struct z_candidate *)
     conversion_obstack_alloc (sizeof (struct z_candidate));
@@ -1575,12 +1663,28 @@ add_candidate (struct z_candidate **candidates,
   cand->access_path = access_path;
   cand->conversion_path = conversion_path;
   cand->viable = viable;
+  cand->reason = reason;
   cand->next = *candidates;
   *candidates = cand;
 
   return cand;
 }
 
+/* Return the number of remaining arguments in the parameter list
+   beginning with ARG.  */
+
+static int
+remaining_arguments (tree arg)
+{
+  int n;
+
+  for (n = 0; arg != NULL_TREE && arg != void_list_node;
+       arg = TREE_CHAIN (arg))
+    n++;
+
+  return n;
+}
+
 /* Create an overload candidate for the function or method FN called
    with the argument list FIRST_ARG/ARGS and add it to CANDIDATES.
    FLAGS is passed on to implicit_conversion.
@@ -1603,6 +1707,7 @@ add_function_candidate (struct z_candidate **candidates,
   tree orig_first_arg = first_arg;
   int skip;
   int viable = 1;
+  struct rejection_reason *reason = NULL;
 
   /* At this point we should not see any functions which haven't been
      explicitly declared, except for friend functions which will have
@@ -1643,11 +1748,19 @@ add_function_candidate (struct z_candidate **candidates,
     }
 
   if (i < len && parmnode)
-    viable = 0;
+    {
+      int remaining = remaining_arguments (parmnode);
+      viable = 0;
+      reason = arity_rejection (i + remaining, len);
+    }
 
   /* Make sure there are default args for the rest of the parms.  */
   else if (!sufficient_parms_p (parmnode))
-    viable = 0;
+    {
+      int remaining = remaining_arguments (parmnode);
+      viable = 0;
+      reason = arity_rejection (i + remaining, len);
+    }
 
   /* Kludge: When looking for a function from a subobject while generating
      an implicit copy/move constructor/operator=, don't consider anything
@@ -1684,7 +1797,7 @@ add_function_candidate (struct z_candidate **candidates,
 
   for (i = 0; i < len; ++i)
     {
-      tree arg, argtype;
+      tree arg, argtype, to_type;
       conversion *t;
       int is_this;
 
@@ -1751,11 +1864,13 @@ add_function_candidate (struct z_candidate **candidates,
 
 	  t = implicit_conversion (parmtype, argtype, arg,
 				   /*c_cast_p=*/false, lflags);
+	  to_type = parmtype;
 	}
       else
 	{
 	  t = build_identity_conv (argtype, arg);
 	  t->ellipsis_p = true;
+	  to_type = argtype;
 	}
 
       if (t && is_this)
@@ -1765,16 +1880,20 @@ add_function_candidate (struct z_candidate **candidates,
       if (! t)
 	{
 	  viable = 0;
+	  reason = arg_conversion_rejection (i, argtype, to_type);
 	  break;
 	}
 
       if (t->bad_p)
-	viable = -1;
+	{
+	  viable = -1;
+	  reason = bad_arg_conversion_rejection (i, argtype, to_type);
+	}
     }
 
  out:
   return add_candidate (candidates, fn, orig_first_arg, args, len, convs,
-			access_path, conversion_path, viable);
+			access_path, conversion_path, viable, reason);
 }
 
 /* Create an overload candidate for the conversion function FN which will
@@ -1798,6 +1917,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
   int i, len, viable, flags;
   tree parmlist, parmnode;
   conversion **convs;
+  struct rejection_reason *reason;
 
   for (parmlist = totype; TREE_CODE (parmlist) != FUNCTION_TYPE; )
     parmlist = TREE_TYPE (parmlist);
@@ -1808,6 +1928,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
   parmnode = parmlist;
   viable = 1;
   flags = LOOKUP_IMPLICIT;
+  reason = NULL;
 
   /* Don't bother looking up the same type twice.  */
   if (*candidates && (*candidates)->fn == totype)
@@ -1815,7 +1936,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
 
   for (i = 0; i < len; ++i)
     {
-      tree arg, argtype;
+      tree arg, argtype, convert_type = NULL_TREE;
       conversion *t;
 
       if (i == 0)
@@ -1828,17 +1949,24 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
       argtype = lvalue_type (arg);
 
       if (i == 0)
-	t = implicit_conversion (totype, argtype, arg, /*c_cast_p=*/false,
-				 flags);
+	{
+	  t = implicit_conversion (totype, argtype, arg, /*c_cast_p=*/false,
+				   flags);
+	  convert_type = totype;
+	}
       else if (parmnode == void_list_node)
 	break;
       else if (parmnode)
-	t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg,
-				 /*c_cast_p=*/false, flags);
+	{
+	  t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg,
+				   /*c_cast_p=*/false, flags);
+	  convert_type = TREE_VALUE (parmnode);
+	}
       else
 	{
 	  t = build_identity_conv (argtype, arg);
 	  t->ellipsis_p = true;
+	  convert_type = argtype;
 	}
 
       convs[i] = t;
@@ -1846,7 +1974,10 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
 	break;
 
       if (t->bad_p)
-	viable = -1;
+	{
+	  viable = -1;
+	  reason = bad_arg_conversion_rejection (i, argtype, convert_type);
+	}
 
       if (i == 0)
 	continue;
@@ -1856,13 +1987,21 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
     }
 
   if (i < len)
-    viable = 0;
+    {
+      int remaining = remaining_arguments (parmnode);
+      viable = 0;
+      reason = arity_rejection (i + remaining, len);
+    }
 
   if (!sufficient_parms_p (parmnode))
-    viable = 0;
+    {
+      int remaining = remaining_arguments (parmnode);
+      viable = 0;
+      reason = arity_rejection (i + remaining, len);
+    }
 
   return add_candidate (candidates, totype, first_arg, arglist, len, convs,
-			access_path, conversion_path, viable);
+			access_path, conversion_path, viable, reason);
 }
 
 static void
@@ -1875,6 +2014,7 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
   size_t num_convs;
   int viable = 1, i;
   tree types[2];
+  struct rejection_reason *reason = NULL;
 
   types[0] = type1;
   types[1] = type2;
@@ -1902,9 +2042,13 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
 	  viable = 0;
 	  /* We need something for printing the candidate.  */
 	  t = build_identity_conv (types[i], NULL_TREE);
+	  reason = arg_conversion_rejection (i, argtypes[i], types[i]);
 	}
       else if (t->bad_p)
-	viable = 0;
+	{
+	  viable = 0;
+	  reason = bad_arg_conversion_rejection (i, argtypes[i], types[i]);
+	}
       convs[i] = t;
     }
 
@@ -1918,14 +2062,18 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
       if (t)
 	convs[0] = t;
       else
-	viable = 0;
+	{
+	  viable = 0;
+	  reason = arg_conversion_rejection (0, argtypes[2],
+					     boolean_type_node);
+	}
     }
 
   add_candidate (candidates, fnname, /*first_arg=*/NULL_TREE, /*args=*/NULL,
 		 num_convs, convs,
 		 /*access_path=*/NULL_TREE,
 		 /*conversion_path=*/NULL_TREE,
-		 viable);
+		 viable, reason);
 }
 
 static bool
@@ -2577,6 +2725,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
   struct z_candidate *cand;
   int i;
   tree fn;
+  struct rejection_reason *reason = NULL;
 
   /* We don't do deduction on the in-charge parameter, the VTT
      parameter or 'this'.  */
@@ -2695,7 +2844,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
   return cand;
  fail:
   return add_candidate (candidates, tmpl, first_arg, arglist, nargs, NULL,
-			access_path, conversion_path, 0);
+			access_path, conversion_path, 0, reason);
 }
 
 
@@ -2816,38 +2965,73 @@ equal_functions (tree fn1, tree fn2)
 static void
 print_z_candidate (const char *msgstr, struct z_candidate *candidate)
 {
+  const char *msg = (msgstr == NULL
+		     ? ""
+		     : ACONCAT ((msgstr, " ", NULL)));
+
   if (TREE_CODE (candidate->fn) == IDENTIFIER_NODE)
     {
       if (candidate->num_convs == 3)
-	inform (input_location, "%s %D(%T, %T, %T) <built-in>", msgstr, candidate->fn,
+	inform (input_location, "%s%D(%T, %T, %T) <built-in>", msg, candidate->fn,
 		candidate->convs[0]->type,
 		candidate->convs[1]->type,
 		candidate->convs[2]->type);
       else if (candidate->num_convs == 2)
-	inform (input_location, "%s %D(%T, %T) <built-in>", msgstr, candidate->fn,
+	inform (input_location, "%s%D(%T, %T) <built-in>", msg, candidate->fn,
 		candidate->convs[0]->type,
 		candidate->convs[1]->type);
       else
-	inform (input_location, "%s %D(%T) <built-in>", msgstr, candidate->fn,
+	inform (input_location, "%s%D(%T) <built-in>", msg, candidate->fn,
 		candidate->convs[0]->type);
     }
   else if (TYPE_P (candidate->fn))
-    inform (input_location, "%s %T <conversion>", msgstr, candidate->fn);
+    inform (input_location, "%s%T <conversion>", msg, candidate->fn);
   else if (candidate->viable == -1)
-    inform (input_location, "%s %+#D <near match>", msgstr, candidate->fn);
+    inform (input_location, "%s%+#D <near match>", msg, candidate->fn);
   else if (DECL_DELETED_FN (STRIP_TEMPLATE (candidate->fn)))
-    inform (input_location, "%s %+#D <deleted>", msgstr, candidate->fn);
+    inform (input_location, "%s%+#D <deleted>", msg, candidate->fn);
   else
-    inform (input_location, "%s %+#D", msgstr, candidate->fn);
+    inform (input_location, "%s%+#D", msg, candidate->fn);
+  /* Give the user some information about why this candidate failed.  */
+  if (candidate->reason != NULL)
+    {
+      struct rejection_reason *r = candidate->reason;
+      location_t loc = location_of (candidate->fn);
+
+      switch (r->code)
+	{
+	case rr_arity:
+	  inform_n (loc, r->u.arity.expected,
+		    "candidate expects %d argument, %d provided",
+		    "candidate expects %d arguments, %d provided",
+		    r->u.arity.expected, r->u.arity.actual);
+	  break;
+	case rr_arg_conversion:
+	  inform (loc,
+		  "no known conversion for argument %d from %qT to %qT",
+		  r->u.conversion.n_arg+1, r->u.conversion.from_type,
+		  r->u.conversion.to_type);
+	  break;
+	case rr_bad_arg_conversion:
+	  inform (loc,
+		  "no known conversion for argument %d from %qT to %qT",
+		  r->u.bad_conversion.n_arg+1, r->u.bad_conversion.from_type,
+		  r->u.bad_conversion.to_type);
+	  break;
+	case rr_none:
+	default:
+	  /* This candidate didn't have any issues or we failed to
+	     handle a particular code.  Either way...  */
+	  gcc_unreachable ();
+	}
+    }
 }
 
 static void
 print_z_candidates (struct z_candidate *candidates)
 {
-  const char *str;
   struct z_candidate *cand1;
   struct z_candidate **cand2;
-  char *spaces;
 
   if (!candidates)
     return;
@@ -2889,14 +3073,10 @@ print_z_candidates (struct z_candidate *candidates)
 	}
     }
 
-  str = candidates->next ? _("candidates are:") :  _("candidate is:");
-  spaces = NULL;
+  inform (UNKNOWN_LOCATION,
+	  candidates->next ? _("candidates are:") :  _("candidate is:"));
   for (; candidates; candidates = candidates->next)
-    {
-      print_z_candidate (spaces ? spaces : str, candidates);
-      spaces = spaces ? spaces : get_spaces (str);
-    }
-  free (spaces);
+    print_z_candidate (NULL, candidates);
 }
 
 /* USER_SEQ is a user-defined conversion sequence, beginning with a
@@ -3134,9 +3314,18 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
 	  cand->second_conv = ics;
 
 	  if (!ics)
-	    cand->viable = 0;
+	    {
+	      tree rettype = TREE_TYPE (TREE_TYPE (cand->fn));
+	      cand->viable = 0;
+	      cand->reason = arg_conversion_rejection (-1, rettype, totype);
+	    }
 	  else if (cand->viable == 1 && ics->bad_p)
-	    cand->viable = -1;
+	    {
+	      tree rettype = TREE_TYPE (TREE_TYPE (cand->fn));
+	      cand->viable = -1;
+	      cand->reason
+		= bad_arg_conversion_rejection (-1, rettype, totype);
+	    }
 	}
     }
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 67f4f93..792c6db 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4907,6 +4907,7 @@ extern void print_instantiation_context		(void);
 extern void maybe_warn_variadic_templates       (void);
 extern void maybe_warn_cpp0x			(cpp0x_warn_str str);
 extern bool pedwarn_cxx98                       (location_t, int, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
+extern location_t location_of                   (tree);
 
 /* in except.c */
 extern void init_exception_processing		(void);
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 1560fc6..49e6341 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -98,7 +98,6 @@ static void cp_print_error_function (diagnostic_context *, diagnostic_info *);
 
 static bool cp_printer (pretty_printer *, text_info *, const char *,
 			int, bool, bool, bool);
-static location_t location_of (tree);
 
 void
 init_error (void)
@@ -2459,7 +2458,7 @@ lang_decl_name (tree decl, int v, bool translate)
 
 /* Return the location of a tree passed to %+ formats.  */
 
-static location_t
+location_t
 location_of (tree t)
 {
   if (TREE_CODE (t) == PARM_DECL && DECL_CONTEXT (t))

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

* Re: [RFC,c++] fix PR 45329, provide information on overload resolution
  2010-11-17 21:32 [RFC,c++] fix PR 45329, provide information on overload resolution Nathan Froyd
@ 2010-11-18  8:12 ` Mark Mitchell
  2010-11-19 23:31 ` Jason Merrill
  1 sibling, 0 replies; 12+ messages in thread
From: Mark Mitchell @ 2010-11-18  8:12 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: gcc-patches, jason, aaw

On 11/17/2010 12:46 PM, Nathan Froyd wrote:

> The patch below addresses this.  At each point where we decide that
> a candidate function loses, we record a rejection reason.

I like this.

> I can try to piece something together for the ambiguous match case,
> though that will be a bit harder.

That's going to be very hard in full generality.  But, I think you could
at least print the best cases.  Trying to actually explain which
parameters match which arguments with which level of match is going to
be hard, and incredibly arcane; the bottom line is that only a computer
can actually understand some of the more complex overload rules.

> We don't keep track of multiple rejection reasons.  It would be a 
> trivial modification to do so if people felt that was worthwhile.

Naw.

> /* Kludge: When looking for a function from a subobject while
> generating an implicit copy/move constructor/operator=, don't
> consider anything that takes (a reference to) an unrelated type.  See
> c++/44909.  */ 

> I am clueless about what a decent reason is.  Comments welcome.

I don't grok that either; I hope Nathan can help.

> For the testcase above, a modified g++ prints:

I think your output is fine.  Give Jason and Gaby a day or two to
comment, though, before you go whole-hog with the implementation.

> +struct rejection_reason {

I think GNU style is:

  struct rejection_reason
  {
    ...
  };

The overall patch looks pretty sane to me.  If Jason doesn't have
comments, please come back to me and I'll do a complete review.

Thank you,

-- 
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

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

* Re: [RFC,c++] fix PR 45329, provide information on overload resolution
  2010-11-17 21:32 [RFC,c++] fix PR 45329, provide information on overload resolution Nathan Froyd
  2010-11-18  8:12 ` Mark Mitchell
@ 2010-11-19 23:31 ` Jason Merrill
  2010-11-19 23:52   ` Jason Merrill
                     ` (2 more replies)
  1 sibling, 3 replies; 12+ messages in thread
From: Jason Merrill @ 2010-11-19 23:31 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: gcc-patches, mark, aaw

On 11/17/2010 03:46 PM, Nathan Froyd wrote:
> The patch below addresses this.  At each point where we decide that a
> candidate function loses, we record a rejection reason.  When we print
> the candidates, we also print out the reasons, if any.  This scheme only
> really deals with the "no matching function for" case; I can try to
> piece something together for the ambiguous match case, though that will
> be a bit harder.

Recently it occurred to me that it would be nice to have an 
-fdump-overload-resolution flag to print out full information about the 
overload resolution logic.  What do you think of that?  I don't suggest 
that instead of this change, but as another possible improvement.

> There are two points at which I have not added rejection reasons.  One
> of them--convert_class_to_reference--I have described in a comment.  The
> second one is in add_function_candidate:
>
>    /* Kludge: When looking for a function from a subobject while generating
>       an implicit copy/move constructor/operator=, don't consider anything
>       that takes (a reference to) an unrelated type.  See c++/44909.  */

This should never lead to an error message, so I don't think we need to 
worry about it.  Well, it shouldn't once we re-enable implicit 
declaration of the copy constructor even with an explicit move constructor.

> I am clueless about what a decent reason is.  Comments welcome.
>
> For the testcase above, a modified g++ prints:
>
> pr45329.C: In function 'int foo2(int)':
> pr45329.C:26:7: error: no matching function for call to 'foo(int&)'
> cc1plus: note: candidates are:
> pr45329.C:7:5: note: int foo(int, int)
> pr45329.C:7:5: note: candidate expects 2 arguments, 1 provided
> pr45329.C:19:5: note: int foo(const S&)
> pr45329.C:19:5: note: no known conversion for argument 1 from 'int' to 'const S&'
>
> which is a little friendlier.

Yes, but the cc1plus: line should have the source position of the call, 
and the rejection reason should be indented.

Jason

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

* Re: [RFC,c++] fix PR 45329, provide information on overload resolution
  2010-11-19 23:31 ` Jason Merrill
@ 2010-11-19 23:52   ` Jason Merrill
  2010-11-20  1:39   ` Mark Mitchell
  2010-12-02 22:10   ` Nathan Froyd
  2 siblings, 0 replies; 12+ messages in thread
From: Jason Merrill @ 2010-11-19 23:52 UTC (permalink / raw)
  To: gcc-patches; +Cc: gcc-patches, mark, aaw

On 11/17/2010 03:46 PM, Nathan Froyd wrote:
> The patch below addresses this.  At each point where we decide that a
> candidate function loses, we record a rejection reason.  When we print
> the candidates, we also print out the reasons, if any.  This scheme only
> really deals with the "no matching function for" case; I can try to
> piece something together for the ambiguous match case, though that will
> be a bit harder.

Recently it occurred to me that it would be nice to have an 
-fdump-overload-resolution flag to print out full information about the 
overload resolution logic.  What do you think of that?  I don't suggest 
that instead of this change, but as another possible improvement.

> There are two points at which I have not added rejection reasons.  One
> of them--convert_class_to_reference--I have described in a comment.  The
> second one is in add_function_candidate:
>
>    /* Kludge: When looking for a function from a subobject while generating
>       an implicit copy/move constructor/operator=, don't consider anything
>       that takes (a reference to) an unrelated type.  See c++/44909.  */

This should never lead to an error message, so I don't think we need to 
worry about it.  Well, it shouldn't once we re-enable implicit 
declaration of the copy constructor even with an explicit move constructor.

> I am clueless about what a decent reason is.  Comments welcome.
>
> For the testcase above, a modified g++ prints:
>
> pr45329.C: In function 'int foo2(int)':
> pr45329.C:26:7: error: no matching function for call to 'foo(int&)'
> cc1plus: note: candidates are:
> pr45329.C:7:5: note: int foo(int, int)
> pr45329.C:7:5: note: candidate expects 2 arguments, 1 provided
> pr45329.C:19:5: note: int foo(const S&)
> pr45329.C:19:5: note: no known conversion for argument 1 from 'int' to 'const S&'
>
> which is a little friendlier.

Yes, but the cc1plus: line should have the source position of the call, 
and the rejection reason should be indented.

Jason

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

* Re: [RFC,c++] fix PR 45329, provide information on overload resolution
  2010-11-19 23:31 ` Jason Merrill
  2010-11-19 23:52   ` Jason Merrill
@ 2010-11-20  1:39   ` Mark Mitchell
  2010-12-02 22:10   ` Nathan Froyd
  2 siblings, 0 replies; 12+ messages in thread
From: Mark Mitchell @ 2010-11-20  1:39 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Nathan Froyd, gcc-patches, aaw

On 11/19/2010 2:42 PM, Jason Merrill wrote:

> Recently it occurred to me that it would be nice to have an
> -fdump-overload-resolution flag to print out full information about the
> overload resolution logic.  What do you think of that?  I don't suggest
> that instead of this change, but as another possible improvement.

I've thought of that too.  I've also considered the same thing for
template instantiation/matching.  Ideally, the output would be
structured so that it would be machine readable; I've wanted the ability
to build a tool to debug the compile-time code generation process.  So, +1.

-- 
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

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

* Re: [RFC,c++] fix PR 45329, provide information on overload resolution
  2010-11-19 23:31 ` Jason Merrill
  2010-11-19 23:52   ` Jason Merrill
  2010-11-20  1:39   ` Mark Mitchell
@ 2010-12-02 22:10   ` Nathan Froyd
  2010-12-03 16:59     ` Jason Merrill
  2 siblings, 1 reply; 12+ messages in thread
From: Nathan Froyd @ 2010-12-02 22:10 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, mark, aaw

On Fri, Nov 19, 2010 at 05:42:30PM -0500, Jason Merrill wrote:
> On 11/17/2010 03:46 PM, Nathan Froyd wrote:
> >There are two points at which I have not added rejection reasons.  One
> >of them--convert_class_to_reference--I have described in a comment.  The
> >second one is in add_function_candidate:
> >
> >   /* Kludge: When looking for a function from a subobject while generating
> >      an implicit copy/move constructor/operator=, don't consider anything
> >      that takes (a reference to) an unrelated type.  See c++/44909.  */
> 
> This should never lead to an error message, so I don't think we need
> to worry about it.  Well, it shouldn't once we re-enable implicit
> declaration of the copy constructor even with an explicit move
> constructor.

OK, thanks.  I will just leave it alone, then.

> >For the testcase above, a modified g++ prints:
> >
> >pr45329.C: In function 'int foo2(int)':
> >pr45329.C:26:7: error: no matching function for call to 'foo(int&)'
> >cc1plus: note: candidates are:
> >pr45329.C:7:5: note: int foo(int, int)
> >pr45329.C:7:5: note: candidate expects 2 arguments, 1 provided
> >pr45329.C:19:5: note: int foo(const S&)
> >pr45329.C:19:5: note: no known conversion for argument 1 from 'int' to 'const S&'
> >
> >which is a little friendlier.
> 
> Yes, but the cc1plus: line should have the source position of the
> call, and the rejection reason should be indented.

Yes, I noticed that the cc1plus bit looked a little funny.  The patch
below handles this by adding a location_t argument to print_z_candidates.

When you say "indented", do you mean like this:

pr45329.C: In function 'int foo2(int)':
pr45329.C:26:7: error: no matching function for call to 'foo(int&)'
pr45329.C:26:7: note: candidates are:
pr45329.C:7:5: note: int foo(int, int)
pr45329.C:7:5: note:   candidate expects 2 arguments, 1 provided
pr45329.C:19:5: note: int foo(const S&)
pr45329.C:19:5: note:   no known conversion for argument 1 from 'int' to 'const S&'

or do you mean something more radical?

Comments on the revised patch before I start tweaking testcases?

-Nathan

	PR c++/45329
	* cp-tree.h (location_at): Declare.
	* error.c (location_at): Export.
	* call.c (struct conversion): Document bad_p field.
	(enum rejection_reason_code): Define.
	(struct rejection_reason): Define.
	(struct z_candidate): Add `reason' field.
	(add_candidate): Add `reason' parameter.  Store it in CAND.
	(alloc_rejection, arity_rejection, arg_conversion_rejection):
	New functions.
	(bad_arg_conversion_rejection): New function.
	(convert_class_to_reference): Add comment.
	(add_function_candidate): Record rejection reason and pass it to
	add_candidate.
	(add_conv_candidate, build_builtin_candidate): Likewise.
	(add_template_candidate_real): Likewise.
	(print_z_candidate): Print CAND->REASON if it exists.  Adjust
	diagnostic strings.
	(print_z_candidates): Add location_t argument.  Adjust calling
	sequence for print_z_candidate. Print header line directly.
	(build_user_type_conversion_1): Add reason for rejection to
	CAND.  Adjust call to print_z_candidates.
	(build_new_function_call): Adjust call to print_z_candidates.
	(build_operator_new_call): Likewise.
	(build_op_call): Likewise.
	(build_conditional_expr): Likewise.
	(build_new_op): Likewise.
	(build_new_method_call): Likewise.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 6a11217..02037f6 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -84,6 +84,9 @@ struct conversion {
   BOOL_BITFIELD user_conv_p : 1;
   BOOL_BITFIELD ellipsis_p : 1;
   BOOL_BITFIELD this_p : 1;
+  /* True if this conversion would be permitted with a bending of
+     language standards, e.g. disregarding pointer qualifiers or
+     converting integers to pointers.  */
   BOOL_BITFIELD bad_p : 1;
   /* If KIND is ck_ref_bind ck_base_conv, true to indicate that a
      temporary should be created to hold the result of the
@@ -129,6 +132,7 @@ struct conversion {
 
 static struct obstack conversion_obstack;
 static bool conversion_obstack_initialized;
+struct rejection_reason;
 
 static struct z_candidate * tourney (struct z_candidate *);
 static int equal_functions (tree, tree);
@@ -151,7 +155,7 @@ static void op_error (enum tree_code, enum tree_code, tree, tree,
 static VEC(tree,gc) *resolve_args (VEC(tree,gc) *);
 static struct z_candidate *build_user_type_conversion_1 (tree, tree, int);
 static void print_z_candidate (const char *, struct z_candidate *);
-static void print_z_candidates (struct z_candidate *);
+static void print_z_candidates (location_t, struct z_candidate *);
 static tree build_this (tree);
 static struct z_candidate *splice_viable (struct z_candidate *, bool, bool *);
 static bool any_strictly_viable (struct z_candidate *);
@@ -190,7 +194,7 @@ static conversion *maybe_handle_ref_bind (conversion **);
 static void maybe_handle_implicit_object (conversion **);
 static struct z_candidate *add_candidate
 	(struct z_candidate **, tree, tree, const VEC(tree,gc) *, size_t,
-	 conversion **, tree, tree, int);
+	 conversion **, tree, tree, int, struct rejection_reason *);
 static tree source_type (conversion *);
 static void add_warning (struct z_candidate *, struct z_candidate *);
 static bool reference_compatible_p (tree, tree);
@@ -416,6 +420,45 @@ struct candidate_warning {
   candidate_warning *next;
 };
 
+/* Information for providing diagnostics about why overloading failed.  */
+
+enum rejection_reason_code {
+  rr_none,
+  rr_arity,
+  rr_arg_conversion,
+  rr_bad_arg_conversion
+};
+
+struct rejection_reason {
+  enum rejection_reason_code code;
+  union {
+    /* Information about an arity mismatch.  */
+    struct {
+      /* The expected number of arguments.  */
+      int expected;
+      /* The actual number of arguments in the call.  */
+      int actual;
+      /* Whether the call was a varargs call.  */
+      bool call_varargs_p;
+    } arity;
+    /* Information about an argument conversion mismatch.  */
+    struct {
+      /* The index of the argument, 0-based.  */
+      int n_arg;
+      /* The type of the actual argument.  */
+      tree from_type;
+      /* The type of the formal argument.  */
+      tree to_type;
+    } conversion;
+    /* Same, but for bad argument conversions.  */
+    struct {
+      int n_arg;
+      tree from_type;
+      tree to_type;
+    } bad_conversion;
+  } u;
+};
+
 struct z_candidate {
   /* The FUNCTION_DECL that will be called if this candidate is
      selected by overload resolution.  */
@@ -437,6 +480,7 @@ struct z_candidate {
      type.  */
   conversion *second_conv;
   int viable;
+  struct rejection_reason *reason;
   /* If FN is a member function, the binfo indicating the path used to
      qualify the name of FN at the call site.  This path is used to
      determine whether or not FN is accessible if it is selected by
@@ -518,6 +562,46 @@ conversion_obstack_alloc (size_t n)
   return p;
 }
 
+/* Allocate rejection reasons.  */
+
+static struct rejection_reason *
+alloc_rejection (enum rejection_reason_code code)
+{
+  struct rejection_reason *p;
+  p = (struct rejection_reason *) conversion_obstack_alloc (sizeof *p);
+  p->code = code;
+  return p;
+}
+
+static struct rejection_reason *
+arity_rejection (int expected, int actual)
+{
+  struct rejection_reason *r = alloc_rejection (rr_arity);
+  r->u.arity.expected = expected;
+  r->u.arity.actual = actual;
+  return r;
+}
+
+static struct rejection_reason *
+arg_conversion_rejection (int n_arg, tree from, tree to)
+{
+  struct rejection_reason *r = alloc_rejection (rr_arg_conversion);
+  r->u.conversion.n_arg = n_arg;
+  r->u.conversion.from_type = from;
+  r->u.conversion.to_type = to;
+  return r;
+}
+
+static struct rejection_reason *
+bad_arg_conversion_rejection (int n_arg, tree from, tree to)
+{
+  struct rejection_reason *r = alloc_rejection (rr_bad_arg_conversion);
+  r->u.bad_conversion.n_arg = n_arg;
+  r->u.bad_conversion.from_type = from;
+  r->u.bad_conversion.to_type = to;
+  return r;
+}
+
 /* Dynamically allocate a conversion.  */
 
 static conversion *
@@ -1147,6 +1231,10 @@ convert_class_to_reference (tree reference_type, tree s, tree expr, int flags)
 	  if (TREE_CODE (t2) != REFERENCE_TYPE
 	      || !reference_compatible_p (t, TREE_TYPE (t2)))
 	    {
+	      /* No need to set cand->reason here; this is most likely
+		 an ambiguous match.  If it's not, either this candidate
+		 will win, or we will have identified a reason for it
+		 losing already.  */
 	      cand->viable = 0;
 	    }
 	  else
@@ -1557,7 +1645,7 @@ add_candidate (struct z_candidate **candidates,
 	       tree fn, tree first_arg, const VEC(tree,gc) *args,
 	       size_t num_convs, conversion **convs,
 	       tree access_path, tree conversion_path,
-	       int viable)
+	       int viable, struct rejection_reason *reason)
 {
   struct z_candidate *cand = (struct z_candidate *)
     conversion_obstack_alloc (sizeof (struct z_candidate));
@@ -1570,12 +1658,28 @@ add_candidate (struct z_candidate **candidates,
   cand->access_path = access_path;
   cand->conversion_path = conversion_path;
   cand->viable = viable;
+  cand->reason = reason;
   cand->next = *candidates;
   *candidates = cand;
 
   return cand;
 }
 
+/* Return the number of remaining arguments in the parameter list
+   beginning with ARG.  */
+
+static int
+remaining_arguments (tree arg)
+{
+  int n;
+
+  for (n = 0; arg != NULL_TREE && arg != void_list_node;
+       arg = TREE_CHAIN (arg))
+    n++;
+
+  return n;
+}
+
 /* Create an overload candidate for the function or method FN called
    with the argument list FIRST_ARG/ARGS and add it to CANDIDATES.
    FLAGS is passed on to implicit_conversion.
@@ -1598,6 +1702,7 @@ add_function_candidate (struct z_candidate **candidates,
   tree orig_first_arg = first_arg;
   int skip;
   int viable = 1;
+  struct rejection_reason *reason = NULL;
 
   /* At this point we should not see any functions which haven't been
      explicitly declared, except for friend functions which will have
@@ -1638,11 +1743,19 @@ add_function_candidate (struct z_candidate **candidates,
     }
 
   if (i < len && parmnode)
-    viable = 0;
+    {
+      int remaining = remaining_arguments (parmnode);
+      viable = 0;
+      reason = arity_rejection (i + remaining, len);
+    }
 
   /* Make sure there are default args for the rest of the parms.  */
   else if (!sufficient_parms_p (parmnode))
-    viable = 0;
+    {
+      int remaining = remaining_arguments (parmnode);
+      viable = 0;
+      reason = arity_rejection (i + remaining, len);
+    }
 
   /* Kludge: When looking for a function from a subobject while generating
      an implicit copy/move constructor/operator=, don't consider anything
@@ -1679,7 +1792,7 @@ add_function_candidate (struct z_candidate **candidates,
 
   for (i = 0; i < len; ++i)
     {
-      tree arg, argtype;
+      tree arg, argtype, to_type;
       conversion *t;
       int is_this;
 
@@ -1746,11 +1859,13 @@ add_function_candidate (struct z_candidate **candidates,
 
 	  t = implicit_conversion (parmtype, argtype, arg,
 				   /*c_cast_p=*/false, lflags);
+	  to_type = parmtype;
 	}
       else
 	{
 	  t = build_identity_conv (argtype, arg);
 	  t->ellipsis_p = true;
+	  to_type = argtype;
 	}
 
       if (t && is_this)
@@ -1760,16 +1875,20 @@ add_function_candidate (struct z_candidate **candidates,
       if (! t)
 	{
 	  viable = 0;
+	  reason = arg_conversion_rejection (i, argtype, to_type);
 	  break;
 	}
 
       if (t->bad_p)
-	viable = -1;
+	{
+	  viable = -1;
+	  reason = bad_arg_conversion_rejection (i, argtype, to_type);
+	}
     }
 
  out:
   return add_candidate (candidates, fn, orig_first_arg, args, len, convs,
-			access_path, conversion_path, viable);
+			access_path, conversion_path, viable, reason);
 }
 
 /* Create an overload candidate for the conversion function FN which will
@@ -1793,6 +1912,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
   int i, len, viable, flags;
   tree parmlist, parmnode;
   conversion **convs;
+  struct rejection_reason *reason;
 
   for (parmlist = totype; TREE_CODE (parmlist) != FUNCTION_TYPE; )
     parmlist = TREE_TYPE (parmlist);
@@ -1803,6 +1923,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
   parmnode = parmlist;
   viable = 1;
   flags = LOOKUP_IMPLICIT;
+  reason = NULL;
 
   /* Don't bother looking up the same type twice.  */
   if (*candidates && (*candidates)->fn == totype)
@@ -1810,7 +1931,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
 
   for (i = 0; i < len; ++i)
     {
-      tree arg, argtype;
+      tree arg, argtype, convert_type = NULL_TREE;
       conversion *t;
 
       if (i == 0)
@@ -1823,17 +1944,24 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
       argtype = lvalue_type (arg);
 
       if (i == 0)
-	t = implicit_conversion (totype, argtype, arg, /*c_cast_p=*/false,
-				 flags);
+	{
+	  t = implicit_conversion (totype, argtype, arg, /*c_cast_p=*/false,
+				   flags);
+	  convert_type = totype;
+	}
       else if (parmnode == void_list_node)
 	break;
       else if (parmnode)
-	t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg,
-				 /*c_cast_p=*/false, flags);
+	{
+	  t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg,
+				   /*c_cast_p=*/false, flags);
+	  convert_type = TREE_VALUE (parmnode);
+	}
       else
 	{
 	  t = build_identity_conv (argtype, arg);
 	  t->ellipsis_p = true;
+	  convert_type = argtype;
 	}
 
       convs[i] = t;
@@ -1841,7 +1969,10 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
 	break;
 
       if (t->bad_p)
-	viable = -1;
+	{
+	  viable = -1;
+	  reason = bad_arg_conversion_rejection (i, argtype, convert_type);
+	}
 
       if (i == 0)
 	continue;
@@ -1851,13 +1982,21 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
     }
 
   if (i < len)
-    viable = 0;
+    {
+      int remaining = remaining_arguments (parmnode);
+      viable = 0;
+      reason = arity_rejection (i + remaining, len);
+    }
 
   if (!sufficient_parms_p (parmnode))
-    viable = 0;
+    {
+      int remaining = remaining_arguments (parmnode);
+      viable = 0;
+      reason = arity_rejection (i + remaining, len);
+    }
 
   return add_candidate (candidates, totype, first_arg, arglist, len, convs,
-			access_path, conversion_path, viable);
+			access_path, conversion_path, viable, reason);
 }
 
 static void
@@ -1870,6 +2009,7 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
   size_t num_convs;
   int viable = 1, i;
   tree types[2];
+  struct rejection_reason *reason = NULL;
 
   types[0] = type1;
   types[1] = type2;
@@ -1897,9 +2037,13 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
 	  viable = 0;
 	  /* We need something for printing the candidate.  */
 	  t = build_identity_conv (types[i], NULL_TREE);
+	  reason = arg_conversion_rejection (i, argtypes[i], types[i]);
 	}
       else if (t->bad_p)
-	viable = 0;
+	{
+	  viable = 0;
+	  reason = bad_arg_conversion_rejection (i, argtypes[i], types[i]);
+	}
       convs[i] = t;
     }
 
@@ -1913,14 +2057,18 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
       if (t)
 	convs[0] = t;
       else
-	viable = 0;
+	{
+	  viable = 0;
+	  reason = arg_conversion_rejection (0, argtypes[2],
+					     boolean_type_node);
+	}
     }
 
   add_candidate (candidates, fnname, /*first_arg=*/NULL_TREE, /*args=*/NULL,
 		 num_convs, convs,
 		 /*access_path=*/NULL_TREE,
 		 /*conversion_path=*/NULL_TREE,
-		 viable);
+		 viable, reason);
 }
 
 static bool
@@ -2572,6 +2720,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
   struct z_candidate *cand;
   int i;
   tree fn;
+  struct rejection_reason *reason = NULL;
 
   /* We don't do deduction on the in-charge parameter, the VTT
      parameter or 'this'.  */
@@ -2690,7 +2839,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
   return cand;
  fail:
   return add_candidate (candidates, tmpl, first_arg, arglist, nargs, NULL,
-			access_path, conversion_path, 0);
+			access_path, conversion_path, 0, reason);
 }
 
 
@@ -2811,38 +2960,74 @@ equal_functions (tree fn1, tree fn2)
 static void
 print_z_candidate (const char *msgstr, struct z_candidate *candidate)
 {
+  const char *msg = (msgstr == NULL
+		     ? ""
+		     : ACONCAT ((msgstr, " ", NULL)));
+
   if (TREE_CODE (candidate->fn) == IDENTIFIER_NODE)
     {
       if (candidate->num_convs == 3)
-	inform (input_location, "%s %D(%T, %T, %T) <built-in>", msgstr, candidate->fn,
+	inform (input_location, "%s%D(%T, %T, %T) <built-in>", msg, candidate->fn,
 		candidate->convs[0]->type,
 		candidate->convs[1]->type,
 		candidate->convs[2]->type);
       else if (candidate->num_convs == 2)
-	inform (input_location, "%s %D(%T, %T) <built-in>", msgstr, candidate->fn,
+	inform (input_location, "%s%D(%T, %T) <built-in>", msg, candidate->fn,
 		candidate->convs[0]->type,
 		candidate->convs[1]->type);
       else
-	inform (input_location, "%s %D(%T) <built-in>", msgstr, candidate->fn,
+	inform (input_location, "%s%D(%T) <built-in>", msg, candidate->fn,
 		candidate->convs[0]->type);
     }
   else if (TYPE_P (candidate->fn))
-    inform (input_location, "%s %T <conversion>", msgstr, candidate->fn);
+    inform (input_location, "%s%T <conversion>", msg, candidate->fn);
   else if (candidate->viable == -1)
-    inform (input_location, "%s %+#D <near match>", msgstr, candidate->fn);
+    inform (input_location, "%s%+#D <near match>", msg, candidate->fn);
   else if (DECL_DELETED_FN (STRIP_TEMPLATE (candidate->fn)))
-    inform (input_location, "%s %+#D <deleted>", msgstr, candidate->fn);
+    inform (input_location, "%s%+#D <deleted>", msg, candidate->fn);
   else
-    inform (input_location, "%s %+#D", msgstr, candidate->fn);
+    inform (input_location, "%s%+#D", msg, candidate->fn);
+  /* Give the user some information about why this candidate failed.  */
+  if (candidate->reason != NULL)
+    {
+      struct rejection_reason *r = candidate->reason;
+      location_t loc = location_of (candidate->fn);
+
+      switch (r->code)
+	{
+	case rr_arity:
+	  inform_n (loc, r->u.arity.expected,
+		    "  candidate expects %d argument, %d provided",
+		    "  candidate expects %d arguments, %d provided",
+		    r->u.arity.expected, r->u.arity.actual);
+	  break;
+	case rr_arg_conversion:
+	  inform (loc,
+		  "  no known conversion for argument %d from %qT to %qT",
+		  r->u.conversion.n_arg+1, r->u.conversion.from_type,
+		  r->u.conversion.to_type);
+	  break;
+	case rr_bad_arg_conversion:
+	  inform (loc,
+		  "  no known conversion for argument %d from %qT to %qT",
+		  r->u.bad_conversion.n_arg+1, r->u.bad_conversion.from_type,
+		  r->u.bad_conversion.to_type);
+	  break;
+	case rr_none:
+	default:
+	  /* This candidate didn't have any issues or we failed to
+	     handle a particular code.  Either way...  */
+	  gcc_unreachable ();
+	}
+    }
 }
 
 static void
-print_z_candidates (struct z_candidate *candidates)
+print_z_candidates (location_t loc, struct z_candidate *candidates)
 {
-  const char *str;
   struct z_candidate *cand1;
   struct z_candidate **cand2;
-  char *spaces;
+  int n_candidates;
 
   if (!candidates)
     return;
@@ -2884,14 +3069,12 @@ print_z_candidates (struct z_candidate *candidates)
 	}
     }
 
-  str = candidates->next ? _("candidates are:") :  _("candidate is:");
-  spaces = NULL;
+  for (n_candidates = 0, cand1 = candidates; cand1; cand1 = cand1->next)
+    n_candidates++;
+
+  inform_n (loc, n_candidates, "candidate is:", "candidates are:");
   for (; candidates; candidates = candidates->next)
-    {
-      print_z_candidate (spaces ? spaces : str, candidates);
-      spaces = spaces ? spaces : get_spaces (str);
-    }
-  free (spaces);
+    print_z_candidate (NULL, candidates);
 }
 
 /* USER_SEQ is a user-defined conversion sequence, beginning with a
@@ -3128,9 +3311,18 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
 	  cand->second_conv = ics;
 
 	  if (!ics)
-	    cand->viable = 0;
+	    {
+	      tree rettype = TREE_TYPE (TREE_TYPE (cand->fn));
+	      cand->viable = 0;
+	      cand->reason = arg_conversion_rejection (-1, rettype, totype);
+	    }
 	  else if (cand->viable == 1 && ics->bad_p)
-	    cand->viable = -1;
+	    {
+	      tree rettype = TREE_TYPE (TREE_TYPE (cand->fn));
+	      cand->viable = -1;
+	      cand->reason
+		= bad_arg_conversion_rejection (-1, rettype, totype);
+	    }
 	}
     }
 
@@ -3145,7 +3337,7 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
 	{
 	  error ("conversion from %qT to %qT is ambiguous",
 		    fromtype, totype);
-	  print_z_candidates (candidates);
+	  print_z_candidates (location_of (expr), candidates);
 	}
 
       cand = candidates;	/* any one will do */
@@ -3392,19 +3584,21 @@ build_new_function_call (tree fn, VEC(tree,gc) **args, bool koenig_p,
     {
       if (complain & tf_error)
 	{
+	  tree name;
 	  if (!any_viable_p && candidates && ! candidates->next
 	      && (TREE_CODE (candidates->fn) == FUNCTION_DECL))
 	    return cp_build_function_call_vec (candidates->fn, args, complain);
 	  if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
 	    fn = TREE_OPERAND (fn, 0);
+	  name = DECL_NAME (OVL_CURRENT (fn));
 	  if (!any_viable_p)
 	    error ("no matching function for call to %<%D(%A)%>",
-		   DECL_NAME (OVL_CURRENT (fn)), build_tree_list_vec (*args));
+		   name, build_tree_list_vec (*args));
 	  else
 	    error ("call of overloaded %<%D(%A)%> is ambiguous",
-		   DECL_NAME (OVL_CURRENT (fn)), build_tree_list_vec (*args));
+		   name, build_tree_list_vec (*args));
 	  if (candidates)
-	    print_z_candidates (candidates);
+	    print_z_candidates (location_of (name), candidates);
 	}
       result = error_mark_node;
     }
@@ -3462,14 +3656,15 @@ build_operator_new_call (tree fnname, VEC(tree,gc) **args,
      and give up.  */
   if (!cand)
     {
+      tree name = DECL_NAME (OVL_CURRENT (fns));
       if (!any_viable_p)
 	error ("no matching function for call to %<%D(%A)%>",
-	       DECL_NAME (OVL_CURRENT (fns)), build_tree_list_vec (*args));
+	       name, build_tree_list_vec (*args));
       else
 	error ("call of overloaded %<%D(%A)%> is ambiguous",
-	       DECL_NAME (OVL_CURRENT (fns)), build_tree_list_vec (*args));
+	       name, build_tree_list_vec (*args));
       if (candidates)
-	print_z_candidates (candidates);
+	print_z_candidates (location_of (name), candidates);
       return error_mark_node;
     }
 
@@ -3619,7 +3814,7 @@ build_op_call (tree obj, VEC(tree,gc) **args, tsubst_flags_t complain)
         {
           error ("no match for call to %<(%T) (%A)%>", TREE_TYPE (obj),
 		 build_tree_list_vec (*args));
-          print_z_candidates (candidates);
+          print_z_candidates (location_of (TREE_TYPE (obj)), candidates);
         }
       result = error_mark_node;
     }
@@ -3632,7 +3827,7 @@ build_op_call (tree obj, VEC(tree,gc) **args, tsubst_flags_t complain)
             {
               error ("call of %<(%T) (%A)%> is ambiguous", 
                      TREE_TYPE (obj), build_tree_list_vec (*args));
-              print_z_candidates (candidates);
+              print_z_candidates (location_of (TREE_TYPE (obj)), candidates);
             }
 	  result = error_mark_node;
 	}
@@ -4051,7 +4246,7 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3,
           if (complain & tf_error)
             {
               op_error (COND_EXPR, NOP_EXPR, arg1, arg2, arg3, FALSE);
-              print_z_candidates (candidates);
+              print_z_candidates (location_of (arg1), candidates);
             }
 	  return error_mark_node;
 	}
@@ -4061,7 +4256,7 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3,
           if (complain & tf_error)
             {
               op_error (COND_EXPR, NOP_EXPR, arg1, arg2, arg3, FALSE);
-              print_z_candidates (candidates);
+              print_z_candidates (location_of (arg1), candidates);
             }
 	  return error_mark_node;
 	}
@@ -4580,7 +4775,7 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
 		    /* ... Otherwise, report the more generic
 		       "no matching operator found" error */
 		    op_error (code, code2, arg1, arg2, arg3, FALSE);
-		    print_z_candidates (candidates);
+		    print_z_candidates (location_of (arg1), candidates);
 		  }
 	    }
 	  result = error_mark_node;
@@ -4595,7 +4790,7 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
 	  if ((flags & LOOKUP_COMPLAIN) && (complain & tf_error))
 	    {
 	      op_error (code, code2, arg1, arg2, arg3, TRUE);
-	      print_z_candidates (candidates);
+	      print_z_candidates (location_of (arg1), candidates);
 	    }
 	  result = error_mark_node;
 	}
@@ -6655,7 +6850,7 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
 	      if (free_p)
 		free (pretty_name);
 	    }
-	  print_z_candidates (candidates);
+	  print_z_candidates (location_of (name), candidates);
 	}
       call = error_mark_node;
     }
@@ -6676,7 +6871,7 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
 		arglist = TREE_CHAIN (arglist);
 	      error ("call of overloaded %<%s(%A)%> is ambiguous", pretty_name,
 		     arglist);
-	      print_z_candidates (candidates);
+	      print_z_candidates (location_of (name), candidates);
 	      if (free_p)
 		free (pretty_name);
 	    }
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 23f594c..0a5afdf 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4907,6 +4907,7 @@ extern void print_instantiation_context		(void);
 extern void maybe_warn_variadic_templates       (void);
 extern void maybe_warn_cpp0x			(cpp0x_warn_str str);
 extern bool pedwarn_cxx98                       (location_t, int, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
+extern location_t location_of                   (tree);
 
 /* in except.c */
 extern void init_exception_processing		(void);
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 2676966..614e462 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -97,7 +97,6 @@ static void cp_print_error_function (diagnostic_context *, diagnostic_info *);
 
 static bool cp_printer (pretty_printer *, text_info *, const char *,
 			int, bool, bool, bool);
-static location_t location_of (tree);
 
 void
 init_error (void)
@@ -2458,7 +2457,7 @@ lang_decl_name (tree decl, int v, bool translate)
 
 /* Return the location of a tree passed to %+ formats.  */
 
-static location_t
+location_t
 location_of (tree t)
 {
   if (TREE_CODE (t) == PARM_DECL && DECL_CONTEXT (t))

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

* Re: [RFC,c++] fix PR 45329, provide information on overload resolution
  2010-12-02 22:10   ` Nathan Froyd
@ 2010-12-03 16:59     ` Jason Merrill
  2010-12-08 15:13       ` Nathan Froyd
  0 siblings, 1 reply; 12+ messages in thread
From: Jason Merrill @ 2010-12-03 16:59 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: gcc-patches, mark, aaw

On 12/02/2010 05:09 PM, Nathan Froyd wrote:
> When you say "indented", do you mean like this:
>
> pr45329.C: In function 'int foo2(int)':
> pr45329.C:26:7: error: no matching function for call to 'foo(int&)'
> pr45329.C:26:7: note: candidates are:
> pr45329.C:7:5: note: int foo(int, int)
> pr45329.C:7:5: note:   candidate expects 2 arguments, 1 provided
> pr45329.C:19:5: note: int foo(const S&)
> pr45329.C:19:5: note:   no known conversion for argument 1 from 'int' to 'const S&'

Yep.

Jason

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

* Re: [RFC,c++] fix PR 45329, provide information on overload resolution
  2010-12-03 16:59     ` Jason Merrill
@ 2010-12-08 15:13       ` Nathan Froyd
  2010-12-08 19:45         ` Mark Mitchell
  2010-12-09  3:10         ` H.J. Lu
  0 siblings, 2 replies; 12+ messages in thread
From: Nathan Froyd @ 2010-12-08 15:13 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches, mark, aaw

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

On Fri, Dec 03, 2010 at 11:59:37AM -0500, Jason Merrill wrote:
> On 12/02/2010 05:09 PM, Nathan Froyd wrote:
> >When you say "indented", do you mean like this:
> >
> >pr45329.C: In function 'int foo2(int)':
> >pr45329.C:26:7: error: no matching function for call to 'foo(int&)'
> >pr45329.C:26:7: note: candidates are:
> >pr45329.C:7:5: note: int foo(int, int)
> >pr45329.C:7:5: note:   candidate expects 2 arguments, 1 provided
> >pr45329.C:19:5: note: int foo(const S&)
> >pr45329.C:19:5: note:   no known conversion for argument 1 from 'int' to 'const S&'
> 
> Yep.

OK, thanks.

A revised patch is below, with testsuite modifications.  The changes are
mainly due to examining testsuite output; previous revisions had
off-by-one errors when pointing out arguments in some cases or had
unusual location information.  The testsuite modifications are large and
relatively boring; I've attached the compressed diff to gcc/testsuite
and just included the cp/ changes below.

I looked at the comments in the PR; I think the indentation addresses
structuring of the list of candidates and I think printing the candidate
and reason separately is more appropriate (and slightly more
structured).  Someday when diagnostic formatting is separated into its
own program, people can write their own formatters...

Tested on x86_64-unknown-linux-gnu.  OK to commit?

-Nathan

gcc/cp/
	PR c++/45329
	* call.c (struct conversion): Document bad_p field.
	(enum rejection_reason_code): Define.
	(struct conversion_info): Define.
	(struct rejection_reason): Define.
	(struct z_candidate): Add `reason' field.
	(add_candidate): Add `reason' parameter.  Store it in CAND.
	(alloc_rejection, arity_rejection, arg_conversion_rejection):
	New functions.
	(bad_arg_conversion_rejection): New function.
	(convert_class_to_reference): Add comment.
	(remaining_arguments): New function.
	(add_function_candidate): Record rejection reason and pass it to
	add_candidate.
	(add_conv_candidate, build_builtin_candidate): Likewise.
	(add_template_candidate_real): Likewise.
	(print_conversion_rejection): New function.
	(print_z_candidate): Print CAND->REASON if it exists.  Adjust
	diagnostic strings.
	(print_z_candidates): Add location_t argument.  Adjust calling
	sequence for print_z_candidate. Print header line directly.
	(build_user_type_conversion_1): Add reason for rejection to
	CAND.  Adjust call to print_z_candidates.
	(print_error_for_call_failure): New function.
	(build_new_function_call): Call it.  Adjust call to
	print_z_candidates.
	(build_operator_new_call): Likewise.
	(build_op_call): Likewise.
	(build_conditional_expr): Likewise.
	(build_new_op): Likewise.
	(build_new_method_call): Likewise.

gcc/testsuite/
	* testsuite/g++.dg/conversion/ambig1.C: Adjust.
	* testsuite/g++.dg/conversion/op1.C: Adjust.
	* testsuite/g++.dg/conversion/simd1.C: Adjust.
	* testsuite/g++.dg/cpp0x/defaulted14.C: Adjust.
	* testsuite/g++.dg/cpp0x/defaulted18.C: Adjust.
	* testsuite/g++.dg/cpp0x/defaulted20.C: Adjust.
	* testsuite/g++.dg/cpp0x/explicit3.C: Adjust.
	* testsuite/g++.dg/cpp0x/explicit4.C: Adjust.
	* testsuite/g++.dg/cpp0x/implicit4.C: Adjust.
	* testsuite/g++.dg/cpp0x/nullptr15.C: Adjust.
	* testsuite/g++.dg/cpp0x/nullptr19.C: Adjust.
	* testsuite/g++.dg/cpp0x/pr31431-2.C: Adjust.
	* testsuite/g++.dg/cpp0x/pr31431.C: Adjust.
	* testsuite/g++.dg/cpp0x/pr31434.C: Adjust.
	* testsuite/g++.dg/cpp0x/pr31437.C: Adjust.
	* testsuite/g++.dg/cpp0x/rv2n.C: Adjust.
	* testsuite/g++.dg/cpp0x/rv3n.C: Adjust.
	* testsuite/g++.dg/cpp0x/rv4n.C: Adjust.
	* testsuite/g++.dg/cpp0x/rv5n.C: Adjust.
	* testsuite/g++.dg/cpp0x/rv6n.C: Adjust.
	* testsuite/g++.dg/cpp0x/rv7n.C: Adjust.
	* testsuite/g++.dg/cpp0x/temp_default2.C: Adjust.
	* testsuite/g++.dg/cpp0x/trailing4.C: Adjust.
	* testsuite/g++.dg/cpp0x/variadic-ex3.C: Adjust.
	* testsuite/g++.dg/cpp0x/variadic-ex4.C: Adjust.
	* testsuite/g++.dg/cpp0x/variadic35.C: Adjust.
	* testsuite/g++.dg/cpp0x/vt-35147.C: Adjust.
	* testsuite/g++.dg/cpp0x/vt-37737-2.C: Adjust.
	* testsuite/g++.dg/expr/cond9.C: Adjust.
	* testsuite/g++.dg/expr/pmf-1.C: Adjust.
	* testsuite/g++.dg/ext/label5.C: Adjust.
	* testsuite/g++.dg/ext/visibility/anon8.C: Adjust.
	* testsuite/g++.dg/ext/vla2.C: Adjust.
	* testsuite/g++.dg/gomp/pr26690-1.C: Adjust.
	* testsuite/g++.dg/gomp/pr26690-2.C: Adjust.
	* testsuite/g++.dg/init/synth2.C: Adjust.
	* testsuite/g++.dg/lookup/conv-1.C: Adjust.
	* testsuite/g++.dg/lookup/new1.C: Adjust.
	* testsuite/g++.dg/lookup/using9.C: Adjust.
	* testsuite/g++.dg/other/error13.C: Adjust.
	* testsuite/g++.dg/other/error20.C: Adjust.
	* testsuite/g++.dg/other/error31.C: Adjust.
	* testsuite/g++.dg/other/pr28114.C: Adjust.
	* testsuite/g++.dg/other/ptrmem10.C: Adjust.
	* testsuite/g++.dg/other/ptrmem11.C: Adjust.
	* testsuite/g++.dg/overload/ambig1.C: Adjust.
	* testsuite/g++.dg/overload/arg3.C: Adjust.
	* testsuite/g++.dg/overload/builtin1.C: Adjust.
	* testsuite/g++.dg/overload/copy1.C: Adjust.
	* testsuite/g++.dg/overload/new1.C: Adjust.
	* testsuite/g++.dg/overload/template4.C: Adjust.
	* testsuite/g++.dg/overload/unknown1.C: Adjust.
	* testsuite/g++.dg/overload/using2.C: Adjust.
	* testsuite/g++.dg/parse/crash5.C: Adjust.
	* testsuite/g++.dg/parse/error19.C: Adjust.
	* testsuite/g++.dg/parse/error28.C: Adjust.
	* testsuite/g++.dg/parse/template7.C: Adjust.
	* testsuite/g++.dg/parse/typename7.C: Adjust.
	* testsuite/g++.dg/rtti/typeid6.C: Adjust.
	* testsuite/g++.dg/tc1/dr152.C: Adjust.
	* testsuite/g++.dg/template/conv11.C: Adjust.
	* testsuite/g++.dg/template/copy1.C: Adjust.
	* testsuite/g++.dg/template/crash37.C: Adjust.
	* testsuite/g++.dg/template/deduce3.C: Adjust.
	* testsuite/g++.dg/template/dependent-expr5.C: Adjust.
	* testsuite/g++.dg/template/error38.C: Adjust.
	* testsuite/g++.dg/template/error40.C: Adjust.
	* testsuite/g++.dg/template/friend.C: Adjust.
	* testsuite/g++.dg/template/incomplete2.C: Adjust.
	* testsuite/g++.dg/template/instantiate5.C: Adjust.
	* testsuite/g++.dg/template/local4.C: Adjust.
	* testsuite/g++.dg/template/local6.C: Adjust.
	* testsuite/g++.dg/template/new3.C: Adjust.
	* testsuite/g++.dg/template/operator9.C: Adjust.
	* testsuite/g++.dg/template/overload6.C: Adjust.
	* testsuite/g++.dg/template/ptrmem2.C: Adjust.
	* testsuite/g++.dg/template/ptrmem20.C: Adjust.
	* testsuite/g++.dg/template/ptrmem4.C: Adjust.
	* testsuite/g++.dg/template/ptrmem8.C: Adjust.
	* testsuite/g++.dg/template/qualttp5.C: Adjust.
	* testsuite/g++.dg/template/sfinae2.C: Adjust.
	* testsuite/g++.dg/template/spec22.C: Adjust.
	* testsuite/g++.dg/template/spec23.C: Adjust.
	* testsuite/g++.dg/template/ttp25.C: Adjust.
	* testsuite/g++.dg/template/typedef4.C: Adjust.
	* testsuite/g++.dg/template/unify10.C: Adjust.
	* testsuite/g++.dg/template/unify11.C: Adjust.
	* testsuite/g++.dg/template/unify6.C: Adjust.
	* testsuite/g++.dg/template/unify7.C: Adjust.
	* testsuite/g++.dg/template/unify9.C: Adjust.
	* testsuite/g++.dg/template/varmod1.C: Adjust.
	* testsuite/g++.old-deja/g++.benjamin/15799.C: Adjust.
	* testsuite/g++.old-deja/g++.benjamin/15800-1.C: Adjust.
	* testsuite/g++.old-deja/g++.brendan/ambiguity1.C: Adjust.
	* testsuite/g++.old-deja/g++.brendan/crash29.C: Adjust.
	* testsuite/g++.old-deja/g++.brendan/crash48.C: Adjust.
	* testsuite/g++.old-deja/g++.brendan/crash56.C: Adjust.
	* testsuite/g++.old-deja/g++.brendan/cvt3.C: Adjust.
	* testsuite/g++.old-deja/g++.brendan/overload1.C: Adjust.
	* testsuite/g++.old-deja/g++.brendan/overload4.C: Adjust.
	* testsuite/g++.old-deja/g++.brendan/overload9.C: Adjust.
	* testsuite/g++.old-deja/g++.bugs/900127_01.C: Adjust.
	* testsuite/g++.old-deja/g++.bugs/900205_04.C: Adjust.
	* testsuite/g++.old-deja/g++.bugs/900330_02.C: Adjust.
	* testsuite/g++.old-deja/g++.bugs/900404_03.C: Adjust.
	* testsuite/g++.old-deja/g++.bugs/900514_03.C: Adjust.
	* testsuite/g++.old-deja/g++.eh/ctor1.C: Adjust.
	* testsuite/g++.old-deja/g++.jason/conversion11.C: Adjust.
	* testsuite/g++.old-deja/g++.jason/crash3.C: Adjust.
	* testsuite/g++.old-deja/g++.jason/overload16.C: Adjust.
	* testsuite/g++.old-deja/g++.jason/overload28.C: Adjust.
	* testsuite/g++.old-deja/g++.jason/scoping10.C: Adjust.
	* testsuite/g++.old-deja/g++.jason/template30.C: Adjust.
	* testsuite/g++.old-deja/g++.jason/temporary2.C: Adjust.
	* testsuite/g++.old-deja/g++.law/arg1.C: Adjust.
	* testsuite/g++.old-deja/g++.law/arg11.C: Adjust.
	* testsuite/g++.old-deja/g++.law/arm9.C: Adjust.
	* testsuite/g++.old-deja/g++.law/ctors11.C: Adjust.
	* testsuite/g++.old-deja/g++.law/ctors17.C: Adjust.
	* testsuite/g++.old-deja/g++.law/ctors5.C: Adjust.
	* testsuite/g++.old-deja/g++.law/ctors9.C: Adjust.
	* testsuite/g++.old-deja/g++.law/enum4.C: Adjust.
	* testsuite/g++.old-deja/g++.law/missed-error2.C: Adjust.
	* testsuite/g++.old-deja/g++.law/operators32.C: Adjust.
	* testsuite/g++.old-deja/g++.law/operators9.C: Adjust.
	* testsuite/g++.old-deja/g++.mike/net2.C: Adjust.
	* testsuite/g++.old-deja/g++.mike/net22.C: Adjust.
	* testsuite/g++.old-deja/g++.mike/p11110.C: Adjust.
	* testsuite/g++.old-deja/g++.mike/p1989.C: Adjust.
	* testsuite/g++.old-deja/g++.mike/p2431.C: Adjust.
	* testsuite/g++.old-deja/g++.mike/p438.C: Adjust.
	* testsuite/g++.old-deja/g++.mike/p807a.C: Adjust.
	* testsuite/g++.old-deja/g++.mike/p9068.C: Adjust.
	* testsuite/g++.old-deja/g++.niklas/t120.C: Adjust.
	* testsuite/g++.old-deja/g++.niklas/t121.C: Adjust.
	* testsuite/g++.old-deja/g++.niklas/t128.C: Adjust.
	* testsuite/g++.old-deja/g++.ns/overload2.C: Adjust.
	* testsuite/g++.old-deja/g++.ns/using12.C: Adjust.
	* testsuite/g++.old-deja/g++.other/crash24.C: Adjust.
	* testsuite/g++.old-deja/g++.other/expr1.C: Adjust.
	* testsuite/g++.old-deja/g++.other/overload11.C: Adjust.
	* testsuite/g++.old-deja/g++.other/pmf3.C: Adjust.
	* testsuite/g++.old-deja/g++.other/volatile1.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/auto_ptr.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/crash28.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/crash60.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/explicit38.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/explicit39.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/explicit41.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/explicit67.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/explicit77.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/expr2.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/ptrmem10.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/ptrmem6.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/spec35.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/spec5.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/spec6.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/t05.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/t24.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/unify4.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/unify6.C: Adjust.
	* testsuite/g++.old-deja/g++.pt/unify8.C: Adjust.
	* testsuite/g++.old-deja/g++.robertl/eb109.C: Adjust.
	* testsuite/g++.old-deja/g++.robertl/eb119.C: Adjust.
	* testsuite/g++.old-deja/g++.robertl/eb131.C: Adjust.
	* testsuite/g++.old-deja/g++.robertl/eb22.C: Adjust.
	* testsuite/g++.old-deja/g++.robertl/eb69.C: Adjust.
	* testsuite/g++.old-deja/g++.robertl/eb98.C: Adjust.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index d538cf2..a1f596d 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -85,6 +85,9 @@ struct conversion {
   BOOL_BITFIELD user_conv_p : 1;
   BOOL_BITFIELD ellipsis_p : 1;
   BOOL_BITFIELD this_p : 1;
+  /* True if this conversion would be permitted with a bending of
+     language standards, e.g. disregarding pointer qualifiers or
+     converting integers to pointers.  */
   BOOL_BITFIELD bad_p : 1;
   /* If KIND is ck_ref_bind ck_base_conv, true to indicate that a
      temporary should be created to hold the result of the
@@ -130,6 +133,7 @@ struct conversion {
 
 static struct obstack conversion_obstack;
 static bool conversion_obstack_initialized;
+struct rejection_reason;
 
 static struct z_candidate * tourney (struct z_candidate *);
 static int equal_functions (tree, tree);
@@ -152,7 +156,7 @@ static void op_error (enum tree_code, enum tree_code, tree, tree,
 static VEC(tree,gc) *resolve_args (VEC(tree,gc) *);
 static struct z_candidate *build_user_type_conversion_1 (tree, tree, int);
 static void print_z_candidate (const char *, struct z_candidate *);
-static void print_z_candidates (struct z_candidate *);
+static void print_z_candidates (location_t, struct z_candidate *);
 static tree build_this (tree);
 static struct z_candidate *splice_viable (struct z_candidate *, bool, bool *);
 static bool any_strictly_viable (struct z_candidate *);
@@ -191,7 +195,7 @@ static conversion *maybe_handle_ref_bind (conversion **);
 static void maybe_handle_implicit_object (conversion **);
 static struct z_candidate *add_candidate
 	(struct z_candidate **, tree, tree, const VEC(tree,gc) *, size_t,
-	 conversion **, tree, tree, int);
+	 conversion **, tree, tree, int, struct rejection_reason *);
 static tree source_type (conversion *);
 static void add_warning (struct z_candidate *, struct z_candidate *);
 static bool reference_compatible_p (tree, tree);
@@ -417,6 +421,43 @@ struct candidate_warning {
   candidate_warning *next;
 };
 
+/* Information for providing diagnostics about why overloading failed.  */
+
+enum rejection_reason_code {
+  rr_none,
+  rr_arity,
+  rr_arg_conversion,
+  rr_bad_arg_conversion
+};
+
+struct conversion_info {
+  /* The index of the argument, 0-based.  */
+  int n_arg;
+  /* The type of the actual argument.  */
+  tree from_type;
+  /* The type of the formal argument.  */
+  tree to_type;
+};
+  
+struct rejection_reason {
+  enum rejection_reason_code code;
+  union {
+    /* Information about an arity mismatch.  */
+    struct {
+      /* The expected number of arguments.  */
+      int expected;
+      /* The actual number of arguments in the call.  */
+      int actual;
+      /* Whether the call was a varargs call.  */
+      bool call_varargs_p;
+    } arity;
+    /* Information about an argument conversion mismatch.  */
+    struct conversion_info conversion;
+    /* Same, but for bad argument conversions.  */
+    struct conversion_info bad_conversion;
+  } u;
+};
+
 struct z_candidate {
   /* The FUNCTION_DECL that will be called if this candidate is
      selected by overload resolution.  */
@@ -438,6 +479,7 @@ struct z_candidate {
      type.  */
   conversion *second_conv;
   int viable;
+  struct rejection_reason *reason;
   /* If FN is a member function, the binfo indicating the path used to
      qualify the name of FN at the call site.  This path is used to
      determine whether or not FN is accessible if it is selected by
@@ -519,6 +561,49 @@ conversion_obstack_alloc (size_t n)
   return p;
 }
 
+/* Allocate rejection reasons.  */
+
+static struct rejection_reason *
+alloc_rejection (enum rejection_reason_code code)
+{
+  struct rejection_reason *p;
+  p = (struct rejection_reason *) conversion_obstack_alloc (sizeof *p);
+  p->code = code;
+  return p;
+}
+
+static struct rejection_reason *
+arity_rejection (tree first_arg, int expected, int actual)
+{
+  struct rejection_reason *r = alloc_rejection (rr_arity);
+  int adjust = first_arg != NULL_TREE;
+  r->u.arity.expected = expected - adjust;
+  r->u.arity.actual = actual - adjust;
+  return r;
+}
+
+static struct rejection_reason *
+arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to)
+{
+  struct rejection_reason *r = alloc_rejection (rr_arg_conversion);
+  int adjust = first_arg != NULL_TREE;
+  r->u.conversion.n_arg = n_arg - adjust;
+  r->u.conversion.from_type = from;
+  r->u.conversion.to_type = to;
+  return r;
+}
+
+static struct rejection_reason *
+bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to)
+{
+  struct rejection_reason *r = alloc_rejection (rr_bad_arg_conversion);
+  int adjust = first_arg != NULL_TREE;
+  r->u.bad_conversion.n_arg = n_arg - adjust;
+  r->u.bad_conversion.from_type = from;
+  r->u.bad_conversion.to_type = to;
+  return r;
+}
+
 /* Dynamically allocate a conversion.  */
 
 static conversion *
@@ -1148,6 +1233,10 @@ convert_class_to_reference (tree reference_type, tree s, tree expr, int flags)
 	  if (TREE_CODE (t2) != REFERENCE_TYPE
 	      || !reference_compatible_p (t, TREE_TYPE (t2)))
 	    {
+	      /* No need to set cand->reason here; this is most likely
+		 an ambiguous match.  If it's not, either this candidate
+		 will win, or we will have identified a reason for it
+		 losing already.  */
 	      cand->viable = 0;
 	    }
 	  else
@@ -1558,7 +1647,7 @@ add_candidate (struct z_candidate **candidates,
 	       tree fn, tree first_arg, const VEC(tree,gc) *args,
 	       size_t num_convs, conversion **convs,
 	       tree access_path, tree conversion_path,
-	       int viable)
+	       int viable, struct rejection_reason *reason)
 {
   struct z_candidate *cand = (struct z_candidate *)
     conversion_obstack_alloc (sizeof (struct z_candidate));
@@ -1571,12 +1660,28 @@ add_candidate (struct z_candidate **candidates,
   cand->access_path = access_path;
   cand->conversion_path = conversion_path;
   cand->viable = viable;
+  cand->reason = reason;
   cand->next = *candidates;
   *candidates = cand;
 
   return cand;
 }
 
+/* Return the number of remaining arguments in the parameter list
+   beginning with ARG.  */
+
+static int
+remaining_arguments (tree arg)
+{
+  int n;
+
+  for (n = 0; arg != NULL_TREE && arg != void_list_node;
+       arg = TREE_CHAIN (arg))
+    n++;
+
+  return n;
+}
+
 /* Create an overload candidate for the function or method FN called
    with the argument list FIRST_ARG/ARGS and add it to CANDIDATES.
    FLAGS is passed on to implicit_conversion.
@@ -1599,6 +1704,7 @@ add_function_candidate (struct z_candidate **candidates,
   tree orig_first_arg = first_arg;
   int skip;
   int viable = 1;
+  struct rejection_reason *reason = NULL;
 
   /* At this point we should not see any functions which haven't been
      explicitly declared, except for friend functions which will have
@@ -1638,13 +1744,14 @@ add_function_candidate (struct z_candidate **candidates,
       parmnode = TREE_CHAIN (parmnode);
     }
 
-  if (i < len && parmnode)
-    viable = 0;
-
-  /* Make sure there are default args for the rest of the parms.  */
-  else if (!sufficient_parms_p (parmnode))
-    viable = 0;
-
+  if ((i < len && parmnode)
+      /* Make sure there are default args for the rest of the parms.  */
+      || !sufficient_parms_p (parmnode))
+    {
+      int remaining = remaining_arguments (parmnode);
+      viable = 0;
+      reason = arity_rejection (first_arg, i + remaining, len);
+    }
   /* Kludge: When looking for a function from a subobject while generating
      an implicit copy/move constructor/operator=, don't consider anything
      that takes (a reference to) an unrelated type.  See c++/44909.  */
@@ -1680,7 +1787,7 @@ add_function_candidate (struct z_candidate **candidates,
 
   for (i = 0; i < len; ++i)
     {
-      tree arg, argtype;
+      tree arg, argtype, to_type;
       conversion *t;
       int is_this;
 
@@ -1747,11 +1854,13 @@ add_function_candidate (struct z_candidate **candidates,
 
 	  t = implicit_conversion (parmtype, argtype, arg,
 				   /*c_cast_p=*/false, lflags);
+	  to_type = parmtype;
 	}
       else
 	{
 	  t = build_identity_conv (argtype, arg);
 	  t->ellipsis_p = true;
+	  to_type = argtype;
 	}
 
       if (t && is_this)
@@ -1761,16 +1870,20 @@ add_function_candidate (struct z_candidate **candidates,
       if (! t)
 	{
 	  viable = 0;
+	  reason = arg_conversion_rejection (first_arg, i, argtype, to_type);
 	  break;
 	}
 
       if (t->bad_p)
-	viable = -1;
+	{
+	  viable = -1;
+	  reason = bad_arg_conversion_rejection (first_arg, i, argtype, to_type);
+	}
     }
 
  out:
   return add_candidate (candidates, fn, orig_first_arg, args, len, convs,
-			access_path, conversion_path, viable);
+			access_path, conversion_path, viable, reason);
 }
 
 /* Create an overload candidate for the conversion function FN which will
@@ -1794,6 +1907,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
   int i, len, viable, flags;
   tree parmlist, parmnode;
   conversion **convs;
+  struct rejection_reason *reason;
 
   for (parmlist = totype; TREE_CODE (parmlist) != FUNCTION_TYPE; )
     parmlist = TREE_TYPE (parmlist);
@@ -1804,6 +1918,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
   parmnode = parmlist;
   viable = 1;
   flags = LOOKUP_IMPLICIT;
+  reason = NULL;
 
   /* Don't bother looking up the same type twice.  */
   if (*candidates && (*candidates)->fn == totype)
@@ -1811,7 +1926,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
 
   for (i = 0; i < len; ++i)
     {
-      tree arg, argtype;
+      tree arg, argtype, convert_type = NULL_TREE;
       conversion *t;
 
       if (i == 0)
@@ -1824,17 +1939,24 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
       argtype = lvalue_type (arg);
 
       if (i == 0)
-	t = implicit_conversion (totype, argtype, arg, /*c_cast_p=*/false,
-				 flags);
+	{
+	  t = implicit_conversion (totype, argtype, arg, /*c_cast_p=*/false,
+				   flags);
+	  convert_type = totype;
+	}
       else if (parmnode == void_list_node)
 	break;
       else if (parmnode)
-	t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg,
-				 /*c_cast_p=*/false, flags);
+	{
+	  t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg,
+				   /*c_cast_p=*/false, flags);
+	  convert_type = TREE_VALUE (parmnode);
+	}
       else
 	{
 	  t = build_identity_conv (argtype, arg);
 	  t->ellipsis_p = true;
+	  convert_type = argtype;
 	}
 
       convs[i] = t;
@@ -1842,7 +1964,10 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
 	break;
 
       if (t->bad_p)
-	viable = -1;
+	{
+	  viable = -1;
+	  reason = bad_arg_conversion_rejection (NULL_TREE, i, argtype, convert_type);
+	}
 
       if (i == 0)
 	continue;
@@ -1851,14 +1976,16 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
 	parmnode = TREE_CHAIN (parmnode);
     }
 
-  if (i < len)
-    viable = 0;
-
-  if (!sufficient_parms_p (parmnode))
-    viable = 0;
+  if (i < len
+      || ! sufficient_parms_p (parmnode))
+    {
+      int remaining = remaining_arguments (parmnode);
+      viable = 0;
+      reason = arity_rejection (NULL_TREE, i + remaining, len);
+    }
 
   return add_candidate (candidates, totype, first_arg, arglist, len, convs,
-			access_path, conversion_path, viable);
+			access_path, conversion_path, viable, reason);
 }
 
 static void
@@ -1871,6 +1998,7 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
   size_t num_convs;
   int viable = 1, i;
   tree types[2];
+  struct rejection_reason *reason = NULL;
 
   types[0] = type1;
   types[1] = type2;
@@ -1898,9 +2026,13 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
 	  viable = 0;
 	  /* We need something for printing the candidate.  */
 	  t = build_identity_conv (types[i], NULL_TREE);
+	  reason = arg_conversion_rejection (NULL_TREE, i, argtypes[i], types[i]);
 	}
       else if (t->bad_p)
-	viable = 0;
+	{
+	  viable = 0;
+	  reason = bad_arg_conversion_rejection (NULL_TREE, i, argtypes[i], types[i]);
+	}
       convs[i] = t;
     }
 
@@ -1914,14 +2046,18 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
       if (t)
 	convs[0] = t;
       else
-	viable = 0;
+	{
+	  viable = 0;
+	  reason = arg_conversion_rejection (NULL_TREE, 0, argtypes[2],
+					     boolean_type_node);
+	}
     }
 
   add_candidate (candidates, fnname, /*first_arg=*/NULL_TREE, /*args=*/NULL,
 		 num_convs, convs,
 		 /*access_path=*/NULL_TREE,
 		 /*conversion_path=*/NULL_TREE,
-		 viable);
+		 viable, reason);
 }
 
 static bool
@@ -2573,6 +2709,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
   struct z_candidate *cand;
   int i;
   tree fn;
+  struct rejection_reason *reason = NULL;
 
   /* We don't do deduction on the in-charge parameter, the VTT
      parameter or 'this'.  */
@@ -2691,7 +2828,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
   return cand;
  fail:
   return add_candidate (candidates, tmpl, first_arg, arglist, nargs, NULL,
-			access_path, conversion_path, 0);
+			access_path, conversion_path, 0, reason);
 }
 
 
@@ -2802,6 +2939,20 @@ equal_functions (tree fn1, tree fn2)
   return fn1 == fn2;
 }
 
+/* Print information about a candidate being rejected due to INFO.  */
+
+static void
+print_conversion_rejection (location_t loc, struct conversion_info *info)
+{
+  if (info->n_arg == -1)
+    /* Conversion of implicit `this' argument failed.  */
+    inform (loc, "no known conversion for implicit %<this%> parameter from %qT to %qT",
+	    info->from_type, info->to_type);
+  else
+    inform (loc, "no known conversion for argument %d from %qT to %qT",
+	    info->n_arg+1, info->from_type, info->to_type);
+}
+
 /* Print information about one overload candidate CANDIDATE.  MSGSTR
    is the text to print before the candidate itself.
 
@@ -2812,38 +2963,68 @@ equal_functions (tree fn1, tree fn2)
 static void
 print_z_candidate (const char *msgstr, struct z_candidate *candidate)
 {
+  const char *msg = (msgstr == NULL
+		     ? ""
+		     : ACONCAT ((msgstr, " ", NULL)));
+  location_t loc = location_of (candidate->fn);
+
   if (TREE_CODE (candidate->fn) == IDENTIFIER_NODE)
     {
       if (candidate->num_convs == 3)
-	inform (input_location, "%s %D(%T, %T, %T) <built-in>", msgstr, candidate->fn,
+	inform (input_location, "%s%D(%T, %T, %T) <built-in>", msg, candidate->fn,
 		candidate->convs[0]->type,
 		candidate->convs[1]->type,
 		candidate->convs[2]->type);
       else if (candidate->num_convs == 2)
-	inform (input_location, "%s %D(%T, %T) <built-in>", msgstr, candidate->fn,
+	inform (input_location, "%s%D(%T, %T) <built-in>", msg, candidate->fn,
 		candidate->convs[0]->type,
 		candidate->convs[1]->type);
       else
-	inform (input_location, "%s %D(%T) <built-in>", msgstr, candidate->fn,
+	inform (input_location, "%s%D(%T) <built-in>", msg, candidate->fn,
 		candidate->convs[0]->type);
     }
   else if (TYPE_P (candidate->fn))
-    inform (input_location, "%s %T <conversion>", msgstr, candidate->fn);
+    inform (input_location, "%s%T <conversion>", msg, candidate->fn);
   else if (candidate->viable == -1)
-    inform (input_location, "%s %+#D <near match>", msgstr, candidate->fn);
+    inform (loc, "%s%#D <near match>", msg, candidate->fn);
   else if (DECL_DELETED_FN (STRIP_TEMPLATE (candidate->fn)))
-    inform (input_location, "%s %+#D <deleted>", msgstr, candidate->fn);
+    inform (loc, "%s%#D <deleted>", msg, candidate->fn);
   else
-    inform (input_location, "%s %+#D", msgstr, candidate->fn);
+    inform (loc, "%s%#D", msg, candidate->fn);
+  /* Give the user some information about why this candidate failed.  */
+  if (candidate->reason != NULL)
+    {
+      struct rejection_reason *r = candidate->reason;
+
+      switch (r->code)
+	{
+	case rr_arity:
+	  inform_n (loc, r->u.arity.expected,
+		    "  candidate expects %d argument, %d provided",
+		    "  candidate expects %d arguments, %d provided",
+		    r->u.arity.expected, r->u.arity.actual);
+	  break;
+	case rr_arg_conversion:
+	  print_conversion_rejection (loc, &r->u.conversion);
+	  break;
+	case rr_bad_arg_conversion:
+	  print_conversion_rejection (loc, &r->u.bad_conversion);
+	  break;
+	case rr_none:
+	default:
+	  /* This candidate didn't have any issues or we failed to
+	     handle a particular code.  Either way...  */
+	  gcc_unreachable ();
+	}
+    }
 }
 
 static void
-print_z_candidates (struct z_candidate *candidates)
+print_z_candidates (location_t loc, struct z_candidate *candidates)
 {
-  const char *str;
   struct z_candidate *cand1;
   struct z_candidate **cand2;
-  char *spaces;
+  int n_candidates;
 
   if (!candidates)
     return;
@@ -2885,14 +3066,12 @@ print_z_candidates (struct z_candidate *candidates)
 	}
     }
 
-  str = candidates->next ? _("candidates are:") :  _("candidate is:");
-  spaces = NULL;
+  for (n_candidates = 0, cand1 = candidates; cand1; cand1 = cand1->next)
+    n_candidates++;
+
+  inform_n (loc, n_candidates, "candidate is:", "candidates are:");
   for (; candidates; candidates = candidates->next)
-    {
-      print_z_candidate (spaces ? spaces : str, candidates);
-      spaces = spaces ? spaces : get_spaces (str);
-    }
-  free (spaces);
+    print_z_candidate (NULL, candidates);
 }
 
 /* USER_SEQ is a user-defined conversion sequence, beginning with a
@@ -3129,9 +3308,20 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
 	  cand->second_conv = ics;
 
 	  if (!ics)
-	    cand->viable = 0;
+	    {
+	      tree rettype = TREE_TYPE (TREE_TYPE (cand->fn));
+	      cand->viable = 0;
+	      cand->reason = arg_conversion_rejection (NULL_TREE, -1,
+						       rettype, totype);
+	    }
 	  else if (cand->viable == 1 && ics->bad_p)
-	    cand->viable = -1;
+	    {
+	      tree rettype = TREE_TYPE (TREE_TYPE (cand->fn));
+	      cand->viable = -1;
+	      cand->reason
+		= bad_arg_conversion_rejection (NULL_TREE, -1,
+						rettype, totype);
+	    }
 	}
     }
 
@@ -3146,7 +3336,7 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
 	{
 	  error ("conversion from %qT to %qT is ambiguous",
 		    fromtype, totype);
-	  print_z_candidates (candidates);
+	  print_z_candidates (location_of (expr), candidates);
 	}
 
       cand = candidates;	/* any one will do */
@@ -3346,6 +3536,28 @@ perform_overload_resolution (tree fn,
   return cand;
 }
 
+/* Print an error message about being unable to build a call to FN with
+   ARGS.  ANY_VIABLE_P indicates whether any candidate functions could
+   be located; CANDIDATES is a possibly empty list of such
+   functions.  */
+
+static void
+print_error_for_call_failure (tree fn, VEC(tree,gc) *args, bool any_viable_p,
+			      struct z_candidate *candidates)
+{
+  tree name = DECL_NAME (OVL_CURRENT (fn));
+  location_t loc = location_of (name);
+
+  if (!any_viable_p)
+    error_at (loc, "no matching function for call to %<%D(%A)%>",
+	      name, build_tree_list_vec (args));
+  else
+    error_at (loc, "call of overloaded %<%D(%A)%> is ambiguous",
+	      name, build_tree_list_vec (args));
+  if (candidates)
+    print_z_candidates (loc, candidates);
+}
+
 /* Return an expression for a call to FN (a namespace-scope function,
    or a static member function) with the ARGS.  This may change
    ARGS.  */
@@ -3377,9 +3589,7 @@ build_new_function_call (tree fn, VEC(tree,gc) **args, bool koenig_p,
       if (!fn)
 	{
 	  if (complain & tf_error)
-	    error ("no matching function for call to %<%D(%A)%>",
-		   DECL_NAME (OVL_CURRENT (orig_fn)),
-		   build_tree_list_vec (*args));
+	    print_error_for_call_failure (orig_fn, *args, false, NULL);
 	  return error_mark_node;
 	}
     }
@@ -3398,14 +3608,7 @@ build_new_function_call (tree fn, VEC(tree,gc) **args, bool koenig_p,
 	    return cp_build_function_call_vec (candidates->fn, args, complain);
 	  if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
 	    fn = TREE_OPERAND (fn, 0);
-	  if (!any_viable_p)
-	    error ("no matching function for call to %<%D(%A)%>",
-		   DECL_NAME (OVL_CURRENT (fn)), build_tree_list_vec (*args));
-	  else
-	    error ("call of overloaded %<%D(%A)%> is ambiguous",
-		   DECL_NAME (OVL_CURRENT (fn)), build_tree_list_vec (*args));
-	  if (candidates)
-	    print_z_candidates (candidates);
+	  print_error_for_call_failure (fn, *args, any_viable_p, candidates);
 	}
       result = error_mark_node;
     }
@@ -3463,14 +3666,7 @@ build_operator_new_call (tree fnname, VEC(tree,gc) **args,
      and give up.  */
   if (!cand)
     {
-      if (!any_viable_p)
-	error ("no matching function for call to %<%D(%A)%>",
-	       DECL_NAME (OVL_CURRENT (fns)), build_tree_list_vec (*args));
-      else
-	error ("call of overloaded %<%D(%A)%> is ambiguous",
-	       DECL_NAME (OVL_CURRENT (fns)), build_tree_list_vec (*args));
-      if (candidates)
-	print_z_candidates (candidates);
+      print_error_for_call_failure (fns, *args, any_viable_p, candidates);
       return error_mark_node;
     }
 
@@ -3620,7 +3816,7 @@ build_op_call (tree obj, VEC(tree,gc) **args, tsubst_flags_t complain)
         {
           error ("no match for call to %<(%T) (%A)%>", TREE_TYPE (obj),
 		 build_tree_list_vec (*args));
-          print_z_candidates (candidates);
+          print_z_candidates (location_of (TREE_TYPE (obj)), candidates);
         }
       result = error_mark_node;
     }
@@ -3633,7 +3829,7 @@ build_op_call (tree obj, VEC(tree,gc) **args, tsubst_flags_t complain)
             {
               error ("call of %<(%T) (%A)%> is ambiguous", 
                      TREE_TYPE (obj), build_tree_list_vec (*args));
-              print_z_candidates (candidates);
+              print_z_candidates (location_of (TREE_TYPE (obj)), candidates);
             }
 	  result = error_mark_node;
 	}
@@ -4052,7 +4248,7 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3,
           if (complain & tf_error)
             {
               op_error (COND_EXPR, NOP_EXPR, arg1, arg2, arg3, FALSE);
-              print_z_candidates (candidates);
+              print_z_candidates (location_of (arg1), candidates);
             }
 	  return error_mark_node;
 	}
@@ -4062,7 +4258,7 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3,
           if (complain & tf_error)
             {
               op_error (COND_EXPR, NOP_EXPR, arg1, arg2, arg3, FALSE);
-              print_z_candidates (candidates);
+              print_z_candidates (location_of (arg1), candidates);
             }
 	  return error_mark_node;
 	}
@@ -4581,7 +4777,7 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
 		    /* ... Otherwise, report the more generic
 		       "no matching operator found" error */
 		    op_error (code, code2, arg1, arg2, arg3, FALSE);
-		    print_z_candidates (candidates);
+		    print_z_candidates (input_location, candidates);
 		  }
 	    }
 	  result = error_mark_node;
@@ -4596,7 +4792,7 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
 	  if ((flags & LOOKUP_COMPLAIN) && (complain & tf_error))
 	    {
 	      op_error (code, code2, arg1, arg2, arg3, TRUE);
-	      print_z_candidates (candidates);
+	      print_z_candidates (input_location, candidates);
 	    }
 	  result = error_mark_node;
 	}
@@ -6656,7 +6852,7 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
 	      if (free_p)
 		free (pretty_name);
 	    }
-	  print_z_candidates (candidates);
+	  print_z_candidates (location_of (name), candidates);
 	}
       call = error_mark_node;
     }
@@ -6677,7 +6873,7 @@ build_new_method_call (tree instance, tree fns, VEC(tree,gc) **args,
 		arglist = TREE_CHAIN (arglist);
 	      error ("call of overloaded %<%s(%A)%> is ambiguous", pretty_name,
 		     arglist);
-	      print_z_candidates (candidates);
+	      print_z_candidates (location_of (name), candidates);
 	      if (free_p)
 		free (pretty_name);
 	    }

[-- Attachment #2: testsuite-changes.diff.gz --]
[-- Type: application/octet-stream, Size: 31029 bytes --]

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

* Re: [RFC,c++] fix PR 45329, provide information on overload resolution
  2010-12-08 15:13       ` Nathan Froyd
@ 2010-12-08 19:45         ` Mark Mitchell
  2010-12-09  3:10         ` H.J. Lu
  1 sibling, 0 replies; 12+ messages in thread
From: Mark Mitchell @ 2010-12-08 19:45 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: Jason Merrill, gcc-patches, aaw

On 12/8/2010 6:58 AM, Nathan Froyd wrote:

> gcc/cp/
> 	PR c++/45329
> 	* call.c (struct conversion): Document bad_p field.

OK.

-- 
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

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

* Re: [RFC,c++] fix PR 45329, provide information on overload resolution
  2010-12-08 15:13       ` Nathan Froyd
  2010-12-08 19:45         ` Mark Mitchell
@ 2010-12-09  3:10         ` H.J. Lu
  2010-12-09  5:49           ` Nathan Froyd
  1 sibling, 1 reply; 12+ messages in thread
From: H.J. Lu @ 2010-12-09  3:10 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: Jason Merrill, gcc-patches, mark, aaw

On Wed, Dec 8, 2010 at 6:58 AM, Nathan Froyd <froydnj@codesourcery.com> wrote:
> On Fri, Dec 03, 2010 at 11:59:37AM -0500, Jason Merrill wrote:
>> On 12/02/2010 05:09 PM, Nathan Froyd wrote:
>> >When you say "indented", do you mean like this:
>> >
>> >pr45329.C: In function 'int foo2(int)':
>> >pr45329.C:26:7: error: no matching function for call to 'foo(int&)'
>> >pr45329.C:26:7: note: candidates are:
>> >pr45329.C:7:5: note: int foo(int, int)
>> >pr45329.C:7:5: note:   candidate expects 2 arguments, 1 provided
>> >pr45329.C:19:5: note: int foo(const S&)
>> >pr45329.C:19:5: note:   no known conversion for argument 1 from 'int' to 'const S&'
>>
>> Yep.
>
> OK, thanks.
>
> A revised patch is below, with testsuite modifications.  The changes are
> mainly due to examining testsuite output; previous revisions had
> off-by-one errors when pointing out arguments in some cases or had
> unusual location information.  The testsuite modifications are large and
> relatively boring; I've attached the compressed diff to gcc/testsuite
> and just included the cp/ changes below.
>
> I looked at the comments in the PR; I think the indentation addresses
> structuring of the list of candidates and I think printing the candidate
> and reason separately is more appropriate (and slightly more
> structured).  Someday when diagnostic formatting is separated into its
> own program, people can write their own formatters...
>
> Tested on x86_64-unknown-linux-gnu.  OK to commit?
>
> -Nathan
>
> gcc/cp/
>        PR c++/45329
>        * call.c (struct conversion): Document bad_p field.
>        (enum rejection_reason_code): Define.
>        (struct conversion_info): Define.
>        (struct rejection_reason): Define.
>        (struct z_candidate): Add `reason' field.
>        (add_candidate): Add `reason' parameter.  Store it in CAND.
>        (alloc_rejection, arity_rejection, arg_conversion_rejection):
>        New functions.
>        (bad_arg_conversion_rejection): New function.
>        (convert_class_to_reference): Add comment.
>        (remaining_arguments): New function.
>        (add_function_candidate): Record rejection reason and pass it to
>        add_candidate.
>        (add_conv_candidate, build_builtin_candidate): Likewise.
>        (add_template_candidate_real): Likewise.
>        (print_conversion_rejection): New function.
>        (print_z_candidate): Print CAND->REASON if it exists.  Adjust
>        diagnostic strings.
>        (print_z_candidates): Add location_t argument.  Adjust calling
>        sequence for print_z_candidate. Print header line directly.
>        (build_user_type_conversion_1): Add reason for rejection to
>        CAND.  Adjust call to print_z_candidates.
>        (print_error_for_call_failure): New function.
>        (build_new_function_call): Call it.  Adjust call to
>        print_z_candidates.
>        (build_operator_new_call): Likewise.
>        (build_op_call): Likewise.
>        (build_conditional_expr): Likewise.
>        (build_new_op): Likewise.
>        (build_new_method_call): Likewise.
>

This caused:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46860


-- 
H.J.

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

* Re: [RFC,c++] fix PR 45329, provide information on overload resolution
  2010-12-09  3:10         ` H.J. Lu
@ 2010-12-09  5:49           ` Nathan Froyd
  2010-12-09  5:51             ` Mark Mitchell
  0 siblings, 1 reply; 12+ messages in thread
From: Nathan Froyd @ 2010-12-09  5:49 UTC (permalink / raw)
  To: H.J. Lu; +Cc: Jason Merrill, gcc-patches, mark, libstdc++

On Wed, Dec 08, 2010 at 04:32:39PM -0800, H.J. Lu wrote:
> On Wed, Dec 8, 2010 at 6:58 AM, Nathan Froyd <froydnj@codesourcery.com> wrote:
> > gcc/cp/
> >        PR c++/45329
> 
> This caused:
> 
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46860

Oops.  Sorry about that.  Here's a patch to fix the overlooked libstdc++
test cases.

Tested on x86_64-unknown-linux-gnu.  OK to commit?

-Nathan

libstdc++-v3/
	PR testsuite/46860
	* testsuite/20_util/auto_ptr/assign_neg.cc: Adjust.
	* testsuite/20_util/unique_ptr/assign/assign_neg.cc: Adjust.
	* testsuite/20_util/weak_ptr/comparison/cmp_neg.cc: Adjust.

diff --git a/libstdc++-v3/testsuite/20_util/auto_ptr/assign_neg.cc b/libstdc++-v3/testsuite/20_util/auto_ptr/assign_neg.cc
index 1f6e673..0fea060 100644
--- a/libstdc++-v3/testsuite/20_util/auto_ptr/assign_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/auto_ptr/assign_neg.cc
@@ -37,6 +37,7 @@ test01()
 {
   std::auto_ptr<Base> ptr2;
   ptr2 = new Base; // { dg-error "no match" }
+  // { dg-error "candidate" "candidate note" { target *-*-* } 39 }
   return 0;
 }
 
@@ -46,6 +47,6 @@ main()
   test01();
   return 0;
 }
-// { dg-error "candidates" "" { target *-*-* } 134 } 
+// { dg-error "::auto_ptr|no known conversion" "" { target *-*-* } 134 } 
 // { dg-error "note" "" { target *-*-* } 152 }
-// { dg-error "::auto_ptr" "" { target *-*-* } 262 } 
+// { dg-error "::auto_ptr|no known conversion" "" { target *-*-* } 262 } 
diff --git a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/assign_neg.cc b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/assign_neg.cc
index 95c1d5d..501bad3 100644
--- a/libstdc++-v3/testsuite/20_util/unique_ptr/assign/assign_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/unique_ptr/assign/assign_neg.cc
@@ -46,6 +46,7 @@ void
 test03()
 {
   std::unique_ptr<int[2]> p1(new int[3]); // { dg-error "no match" }
+  // { dg-error "candidate" "candidate-note" { target *-*-* } 48 }
   std::unique_ptr<int[2]> p2 = p1; // { dg-error "deleted" }
 }
 
diff --git a/libstdc++-v3/testsuite/20_util/weak_ptr/comparison/cmp_neg.cc b/libstdc++-v3/testsuite/20_util/weak_ptr/comparison/cmp_neg.cc
index 019f5f7..c26b09d 100644
--- a/libstdc++-v3/testsuite/20_util/weak_ptr/comparison/cmp_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/weak_ptr/comparison/cmp_neg.cc
@@ -31,6 +31,7 @@ test01()
 {
   std::weak_ptr<A> p1;
   p1 < p1;  // { dg-error "no match" }
+  // { dg-error "candidate" "candidate note" { target *-*-* } 33 }
   return 0;
 }
 

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

* Re: [RFC,c++] fix PR 45329, provide information on overload resolution
  2010-12-09  5:49           ` Nathan Froyd
@ 2010-12-09  5:51             ` Mark Mitchell
  0 siblings, 0 replies; 12+ messages in thread
From: Mark Mitchell @ 2010-12-09  5:51 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: H.J. Lu, Jason Merrill, gcc-patches, libstdc++

On 12/8/2010 8:23 PM, Nathan Froyd wrote:

> Tested on x86_64-unknown-linux-gnu.  OK to commit?

OK.

-- 
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

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

end of thread, other threads:[~2010-12-09  4:24 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-11-17 21:32 [RFC,c++] fix PR 45329, provide information on overload resolution Nathan Froyd
2010-11-18  8:12 ` Mark Mitchell
2010-11-19 23:31 ` Jason Merrill
2010-11-19 23:52   ` Jason Merrill
2010-11-20  1:39   ` Mark Mitchell
2010-12-02 22:10   ` Nathan Froyd
2010-12-03 16:59     ` Jason Merrill
2010-12-08 15:13       ` Nathan Froyd
2010-12-08 19:45         ` Mark Mitchell
2010-12-09  3:10         ` H.J. Lu
2010-12-09  5:49           ` Nathan Froyd
2010-12-09  5:51             ` Mark Mitchell

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