diff mbox series

C++: special-case single non-viable candidate (more PR c++/85110)

Message ID 1536160111-18463-1-git-send-email-dmalcolm@redhat.com
State New
Headers show
Series C++: special-case single non-viable candidate (more PR c++/85110) | expand

Commit Message

David Malcolm Sept. 5, 2018, 3:08 p.m. UTC
On Thu, 2018-08-30 at 18:18 -0400, Jason Merrill wrote:
> On Thu, Aug 23, 2018 at 2:08 PM, David Malcolm <dmalcolm@redhat.com>
> wrote:
> > This is a followup to:
> >
> >   "[PATCH] C++: underline param in print_conversion_rejection (more
> > PR c++/85110)"
> >      https://gcc.gnu.org/ml/gcc-patches/2018-08/msg01480.html
> >
> > to highlight the pertinent argument in a unmatched function call
> > for which there is one candidate.
> >
> > It updates the output from:
> >
> > demo.cc: In function 'int test_4(int, const char*, float)':
> > demo.cc:5:44: error: no matching function for call to
> > 's4::member_1(int&, const char*&, float&)'
> > 5 |   return s4::member_1 (first, second, third);
> >   |                                            ^
> > demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const
> > char**, float)'
> > 1 | struct s4 { static int member_1 (int one, const char **two,
> > float three); };
> >   |                        ^~~~~~~~
> > demo.cc:1:56: note:   no known conversion for argument 2 from
> > 'const char*' to 'const char**'
> > 1 | struct s4 { static int member_1 (int one, const char **two,
> > float three); };
> >   |                                           ~~~~~~~~~~~~~^~~
> >
> > to:
> >
> > demo.cc: In function 'int test_4(int, const char*, float)':
> > demo.cc:5:31: error: no matching function for call to
> > 's4::member_1(int&, const char*&, float&)'
> > 5 |   return s4::member_1 (first, second, third);
> >   |                               ^~~~~~
>
> Hmm, it seems pretty subtle to just change the highlighting when the
> message talks about the call as a whole.  I think if we're going to
> focus in this way we might change the diagnostic to something like
>
> error: no known conversion for argument 2 from 'const char*' to
> 'const char**'
> note: in call to 'static int s4::member_1(int, const char**, float)'
>
> or whatever the messages are from
> convert_arguments/convert_for_initialization which already deal with
> the single-candidate case for non-member functions.
>
> Jason

Thanks.

Here's an updated version of the patch.

I broke out the "no viable candidates" case in build_new_method_call_1
into a subroutine, and added special-case handling for when there's
a single non-viable candidate where there's an argument conversion
error.  I turned the error-handling from convert_for_assignment into
a subroutine, calling it from this new special-case.

This converts:

demo.cc: In function 'int test_4(int, const char*, float)':
demo.cc:5:44: error: no matching function for call to 's4::member_1(int&, const char*&, float&)'
5 |   return s4::member_1 (first, second, third);
  |                                            ^
demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const char**, float)'
1 | struct s4 { static int member_1 (int one, const char **two, float three); };
  |                        ^~~~~~~~
demo.cc:1:56: note:   no known conversion for argument 2 from 'const char*' to 'const char**'
1 | struct s4 { static int member_1 (int one, const char **two, float three); };
  |                                           ~~~~~~~~~~~~~^~~

to:

demo.cc: In function 'int test_4(int, const char*, float)':
demo.cc:5:31: error: cannot convert 'const char*' to 'const char**'
5 |   return s4::member_1 (first, second, third);
  |                               ^~~~~~
  |                               |
  |                               const char*
demo.cc:1:56: note:   initializing argument 2 of 'static int s4::member_1(int, const char**, float)'
1 | struct s4 { static int member_1 (int one, const char **two, float three); };
  |                                           ~~~~~~~~~~~~~^~~

thus highlighting the problematic argument at the callsite (and its type).

BTW, updating the test cases shows that some of our messages are worded:
  "could not convert"
and sometimes:
  "cannot convert"
(see e.g. g++.old-deja/g++.jason/conversion11.C which would now
have two of them side-by-side).  I'm not sure that this is a problem
(maybe save for a followup?  If it is an issue, it's presumably a
pre-existing one)

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.

OK for trunk?

gcc/cp/ChangeLog:
	PR c++/85110
	* call.c (struct conversion_info): Add "loc" field.
	(arg_conversion_rejection): Add "loc" param, using it to
	initialize the new field.
	(bad_arg_conversion_rejection): Likewise.
	(explicit_conversion_rejection): Initialize the new field to
	UNKNOWN_LOCATION.
	(template_conversion_rejection): Likewise.
	(add_function_candidate): Pass on the argument location to the new
	param of arg_conversion_rejection.
	(add_conv_candidate): Likewise.
	(build_builtin_candidate): Likewise.
	(build_user_type_conversion_1): Likewise.
	(single_z_candidate): New function.
	(maybe_get_bad_conversion_for_unmatched_call): New function.
	(complain_about_bad_argument): New function, based on part of
	convert_for_assignment.
	(build_new_method_call_1): Split out handling of the "no viable
	candidates" case into...
	(complain_about_no_candidates_for_method_call): ...this new
	function, and use the new functions above to special-case the
	handling of a single non-viable candidate due to a bad argument.
	* cp-tree.h (complain_about_bad_argument): New decl.
	* typeck.c (convert_for_assignment): Split out one error-handling
	case into complain_about_bad_argument.

gcc/testsuite/ChangeLog:
	PR c++/85110
	* g++.dg/cpp0x/explicit4.C: Update expected output to reflect
	special-casing of diagnostic for a single non-viable candidate due
	to a bad argument.
	* g++.dg/diagnostic/param-type-mismatch-2.C: Likewise.
	Add test coverage for an unmatched overloaded operator.
	* g++.dg/expr/pmf-1.C: Likewise.
	* g++.old-deja/g++.bugs/900330_02.C: Likewise.
	* g++.old-deja/g++.jason/conversion11.C: Likewise.
	* g++.old-deja/g++.law/arg11.C: Likewise.
	* g++.old-deja/g++.law/arm9.C: Likewise.
	* g++.old-deja/g++.robertl/eb131.C: Likewise.
---
 gcc/cp/call.c                                      | 192 +++++++++++++++++----
 gcc/cp/cp-tree.h                                   |   3 +
 gcc/cp/typeck.c                                    |  20 +--
 gcc/testsuite/g++.dg/cpp0x/explicit4.C             |   2 +-
 .../g++.dg/diagnostic/param-type-mismatch-2.C      |  90 +++++-----
 gcc/testsuite/g++.dg/expr/pmf-1.C                  |   2 +-
 gcc/testsuite/g++.old-deja/g++.bugs/900330_02.C    |   2 +-
 .../g++.old-deja/g++.jason/conversion11.C          |   4 +-
 gcc/testsuite/g++.old-deja/g++.law/arg11.C         |   2 +-
 gcc/testsuite/g++.old-deja/g++.law/arm9.C          |   2 +-
 gcc/testsuite/g++.old-deja/g++.robertl/eb131.C     |   4 +-
 11 files changed, 220 insertions(+), 103 deletions(-)

Comments

Jason Merrill Sept. 6, 2018, 12:19 a.m. UTC | #1
On Wed, Sep 5, 2018 at 11:08 AM, David Malcolm <dmalcolm@redhat.com> wrote:
> On Thu, 2018-08-30 at 18:18 -0400, Jason Merrill wrote:
>> On Thu, Aug 23, 2018 at 2:08 PM, David Malcolm <dmalcolm@redhat.com>
>> wrote:
>> > This is a followup to:
>> >
>> >   "[PATCH] C++: underline param in print_conversion_rejection (more
>> > PR c++/85110)"
>> >      https://gcc.gnu.org/ml/gcc-patches/2018-08/msg01480.html
>> >
>> > to highlight the pertinent argument in a unmatched function call
>> > for which there is one candidate.
>> >
>> > It updates the output from:
>> >
>> > demo.cc: In function 'int test_4(int, const char*, float)':
>> > demo.cc:5:44: error: no matching function for call to
>> > 's4::member_1(int&, const char*&, float&)'
>> > 5 |   return s4::member_1 (first, second, third);
>> >   |                                            ^
>> > demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const
>> > char**, float)'
>> > 1 | struct s4 { static int member_1 (int one, const char **two,
>> > float three); };
>> >   |                        ^~~~~~~~
>> > demo.cc:1:56: note:   no known conversion for argument 2 from
>> > 'const char*' to 'const char**'
>> > 1 | struct s4 { static int member_1 (int one, const char **two,
>> > float three); };
>> >   |                                           ~~~~~~~~~~~~~^~~
>> >
>> > to:
>> >
>> > demo.cc: In function 'int test_4(int, const char*, float)':
>> > demo.cc:5:31: error: no matching function for call to
>> > 's4::member_1(int&, const char*&, float&)'
>> > 5 |   return s4::member_1 (first, second, third);
>> >   |                               ^~~~~~
>>
>> Hmm, it seems pretty subtle to just change the highlighting when the
>> message talks about the call as a whole.  I think if we're going to
>> focus in this way we might change the diagnostic to something like
>>
>> error: no known conversion for argument 2 from 'const char*' to
>> 'const char**'
>> note: in call to 'static int s4::member_1(int, const char**, float)'
>>
>> or whatever the messages are from
>> convert_arguments/convert_for_initialization which already deal with
>> the single-candidate case for non-member functions.
>>
>> Jason
>
> Thanks.
>
> Here's an updated version of the patch.
>
> I broke out the "no viable candidates" case in build_new_method_call_1
> into a subroutine, and added special-case handling for when there's
> a single non-viable candidate where there's an argument conversion
> error.  I turned the error-handling from convert_for_assignment into
> a subroutine, calling it from this new special-case.
>
> This converts:
>
> demo.cc: In function 'int test_4(int, const char*, float)':
> demo.cc:5:44: error: no matching function for call to 's4::member_1(int&, const char*&, float&)'
> 5 |   return s4::member_1 (first, second, third);
>   |                                            ^
> demo.cc:1:24: note: candidate: 'static int s4::member_1(int, const char**, float)'
> 1 | struct s4 { static int member_1 (int one, const char **two, float three); };
>   |                        ^~~~~~~~
> demo.cc:1:56: note:   no known conversion for argument 2 from 'const char*' to 'const char**'
> 1 | struct s4 { static int member_1 (int one, const char **two, float three); };
>   |                                           ~~~~~~~~~~~~~^~~
>
> to:
>
> demo.cc: In function 'int test_4(int, const char*, float)':
> demo.cc:5:31: error: cannot convert 'const char*' to 'const char**'
> 5 |   return s4::member_1 (first, second, third);
>   |                               ^~~~~~
>   |                               |
>   |                               const char*
> demo.cc:1:56: note:   initializing argument 2 of 'static int s4::member_1(int, const char**, float)'
> 1 | struct s4 { static int member_1 (int one, const char **two, float three); };
>   |                                           ~~~~~~~~~~~~~^~~
>
> thus highlighting the problematic argument at the callsite (and its type).

OK, thanks.

> BTW, updating the test cases shows that some of our messages are worded:
>   "could not convert"
> and sometimes:
>   "cannot convert"
> (see e.g. g++.old-deja/g++.jason/conversion11.C which would now
> have two of them side-by-side).  I'm not sure that this is a problem
> (maybe save for a followup?  If it is an issue, it's presumably a
> pre-existing one)

Indeed, a pre-existing issue.  I assume that we want to unify on
present tense; does that sound right to you?

Jason
diff mbox series

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index a156702..ab14715 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -436,6 +436,8 @@  struct conversion_info {
   tree from;
   /* The type of the parameter.  */
   tree to_type;
+  /* The location of the argument.  */
+  location_t loc;
 };
   
 struct rejection_reason {
@@ -627,24 +629,28 @@  arity_rejection (tree first_arg, int expected, int actual)
 }
 
 static struct rejection_reason *
-arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to)
+arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to,
+			  location_t loc)
 {
   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 = from;
   r->u.conversion.to_type = to;
+  r->u.conversion.loc = loc;
   return r;
 }
 
 static struct rejection_reason *
-bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to)
+bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to,
+			      location_t loc)
 {
   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 = from;
   r->u.bad_conversion.to_type = to;
+  r->u.bad_conversion.loc = loc;
   return r;
 }
 
@@ -655,6 +661,7 @@  explicit_conversion_rejection (tree from, tree to)
   r->u.conversion.n_arg = 0;
   r->u.conversion.from = from;
   r->u.conversion.to_type = to;
+  r->u.conversion.loc = UNKNOWN_LOCATION;
   return r;
 }
 
@@ -665,6 +672,7 @@  template_conversion_rejection (tree from, tree to)
   r->u.conversion.n_arg = 0;
   r->u.conversion.from = from;
   r->u.conversion.to_type = to;
+  r->u.conversion.loc = UNKNOWN_LOCATION;
   return r;
 }
 
@@ -2254,14 +2262,17 @@  add_function_candidate (struct z_candidate **candidates,
       if (! t)
 	{
 	  viable = 0;
-	  reason = arg_conversion_rejection (first_arg, i, argtype, to_type);
+	  reason = arg_conversion_rejection (first_arg, i, argtype, to_type,
+					     EXPR_LOCATION (arg));
 	  break;
 	}
 
       if (t->bad_p)
 	{
 	  viable = -1;
-	  reason = bad_arg_conversion_rejection (first_arg, i, arg, to_type);
+	  reason = bad_arg_conversion_rejection (first_arg, i, arg, to_type,
+						 EXPR_LOCATION (arg));
+
 	}
     }
 
@@ -2350,7 +2361,8 @@  add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
       if (t->bad_p)
 	{
 	  viable = -1;
-	  reason = bad_arg_conversion_rejection (NULL_TREE, i, arg, convert_type);
+	  reason = bad_arg_conversion_rejection (NULL_TREE, i, arg, convert_type,
+						 EXPR_LOCATION (arg));
 	}
 
       if (i == 0)
@@ -2411,13 +2423,14 @@  build_builtin_candidate (struct z_candidate **candidates, tree fnname,
 	  /* 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]);
+					     types[i], EXPR_LOCATION (args[i]));
 	}
       else if (t->bad_p)
 	{
 	  viable = 0;
 	  reason = bad_arg_conversion_rejection (NULL_TREE, i, args[i],
-						 types[i]);
+						 types[i],
+						 EXPR_LOCATION (args[i]));
 	}
       convs[i] = t;
     }
@@ -2436,7 +2449,8 @@  build_builtin_candidate (struct z_candidate **candidates, tree fnname,
 	{
 	  viable = 0;
 	  reason = arg_conversion_rejection (NULL_TREE, 0, argtypes[2],
-					     boolean_type_node);
+					     boolean_type_node,
+					     EXPR_LOCATION (args[2]));
 	}
     }
 
@@ -3927,7 +3941,8 @@  build_user_type_conversion_1 (tree totype, tree expr, int flags,
 	    {
 	      cand->viable = 0;
 	      cand->reason = arg_conversion_rejection (NULL_TREE, -2,
-						       rettype, totype);
+						       rettype, totype,
+						       EXPR_LOCATION (expr));
 	    }
 	  else if (DECL_NONCONVERTING_P (cand->fn)
 		   && ics->rank > cr_exact)
@@ -3947,7 +3962,8 @@  build_user_type_conversion_1 (tree totype, tree expr, int flags,
 	      cand->viable = -1;
 	      cand->reason
 		= bad_arg_conversion_rejection (NULL_TREE, -2,
-						rettype, totype);
+						rettype, totype,
+						EXPR_LOCATION (expr));
 	    }
 	  else if (primary_template_specialization_p (cand->fn)
 		   && ics->rank > cr_exact)
@@ -9156,6 +9172,129 @@  name_as_c_string (tree name, tree type, bool *free_p)
   return CONST_CAST (char *, pretty_name);
 }
 
+/* If CANDIDATES contains exactly one candidate, return it, otherwise
+   return NULL.  */
+
+static z_candidate *
+single_z_candidate (z_candidate *candidates)
+{
+  if (candidates == NULL)
+    return NULL;
+
+  if (candidates->next)
+    return NULL;
+
+  return candidates;
+}
+
+/* If CANDIDATE is invalid due to a bad argument type, return the
+   pertinent conversion_info.
+
+   Otherwise, return NULL.  */
+
+static const conversion_info *
+maybe_get_bad_conversion_for_unmatched_call (const z_candidate *candidate)
+{
+  /* Must be an rr_arg_conversion or rr_bad_arg_conversion.  */
+  rejection_reason *r = candidate->reason;
+
+  if (r == NULL)
+    return NULL;
+
+  switch (r->code)
+    {
+    default:
+      return NULL;
+
+    case rr_arg_conversion:
+      return &r->u.conversion;
+
+    case rr_bad_arg_conversion:
+      return &r->u.bad_conversion;
+    }
+}
+
+/* Issue an error and note complaining about a bad argument type at a
+   callsite with a single candidate FNDECL.
+
+   ARG_LOC is the location of the argument (or UNKNOWN_LOCATION, in which
+   case input_location is used).
+   FROM_TYPE is the type of the actual argument; TO_TYPE is the type of
+   the formal parameter.  */
+
+void
+complain_about_bad_argument (location_t arg_loc,
+			     tree from_type, tree to_type,
+			     tree fndecl, int parmnum)
+{
+  auto_diagnostic_group d;
+  range_label_for_type_mismatch rhs_label (from_type, to_type);
+  range_label *label = &rhs_label;
+  if (arg_loc == UNKNOWN_LOCATION)
+    {
+      arg_loc = input_location;
+      label = NULL;
+    }
+  gcc_rich_location richloc (arg_loc, label);
+  error_at (&richloc,
+	    "cannot convert %qH to %qI",
+	    from_type, to_type);
+  inform (get_fndecl_argument_location (fndecl, parmnum),
+	  "  initializing argument %P of %qD", parmnum, fndecl);
+}
+
+/* Subroutine of build_new_method_call_1, for where there are no viable
+   candidates for the call.  */
+
+static void
+complain_about_no_candidates_for_method_call (tree instance,
+					      z_candidate *candidates,
+					      tree explicit_targs,
+					      tree basetype,
+					      tree optype, tree name,
+					      bool skip_first_for_error,
+					      vec<tree, va_gc> *user_args)
+{
+  auto_diagnostic_group d;
+  if (!COMPLETE_OR_OPEN_TYPE_P (basetype))
+    cxx_incomplete_type_error (instance, basetype);
+  else if (optype)
+    error ("no matching function for call to %<%T::operator %T(%A)%#V%>",
+	   basetype, optype, build_tree_list_vec (user_args),
+	   TREE_TYPE (instance));
+  else
+    {
+      /* Special-case for when there's a single candidate that's failing
+	 due to a bad argument type.  */
+      if (z_candidate *candidate = single_z_candidate (candidates))
+	  if (const conversion_info *conv
+		= maybe_get_bad_conversion_for_unmatched_call (candidate))
+	    {
+	      complain_about_bad_argument (conv->loc,
+					   conv->from, conv->to_type,
+					   candidate->fn, conv->n_arg);
+	      return;
+	    }
+
+      tree arglist = build_tree_list_vec (user_args);
+      tree errname = name;
+      bool twiddle = false;
+      if (IDENTIFIER_CDTOR_P (errname))
+	{
+	  twiddle = IDENTIFIER_DTOR_P (errname);
+	  errname = constructor_name (basetype);
+	}
+      if (explicit_targs)
+	errname = lookup_template_function (errname, explicit_targs);
+      if (skip_first_for_error)
+	arglist = TREE_CHAIN (arglist);
+      error ("no matching function for call to %<%T::%s%E(%A)%#V%>",
+	     basetype, &"~"[!twiddle], errname, arglist,
+	     TREE_TYPE (instance));
+    }
+  print_z_candidates (location_of (name), candidates);
+}
+
 /* Build a call to "INSTANCE.FN (ARGS)".  If FN_P is non-NULL, it will
    be set, upon return, to the function called.  ARGS may be NULL.
    This may change ARGS.  */
@@ -9373,34 +9512,11 @@  build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
   if (!any_viable_p)
     {
       if (complain & tf_error)
-	{
-	  auto_diagnostic_group d;
-	  if (!COMPLETE_OR_OPEN_TYPE_P (basetype))
-	    cxx_incomplete_type_error (instance, basetype);
-	  else if (optype)
-	    error ("no matching function for call to %<%T::operator %T(%A)%#V%>",
-		   basetype, optype, build_tree_list_vec (user_args),
-		   TREE_TYPE (instance));
-	  else
-	    {
-	      tree arglist = build_tree_list_vec (user_args);
-	      tree errname = name;
-	      bool twiddle = false;
-	      if (IDENTIFIER_CDTOR_P (errname))
-		{
-		  twiddle = IDENTIFIER_DTOR_P (errname);
-		  errname = constructor_name (basetype);
-		}
-	      if (explicit_targs)
-		errname = lookup_template_function (errname, explicit_targs);
-	      if (skip_first_for_error)
-		arglist = TREE_CHAIN (arglist);
-	      error ("no matching function for call to %<%T::%s%E(%A)%#V%>",
-		     basetype, &"~"[!twiddle], errname, arglist,
-		     TREE_TYPE (instance));
-	    }
-	  print_z_candidates (location_of (name), candidates);
-	}
+	complain_about_no_candidates_for_method_call (instance, candidates,
+						      explicit_targs, basetype,
+						      optype, name,
+						      skip_first_for_error,
+						      user_args);
       call = error_mark_node;
     }
   else
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 43e452c..f612e97 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6087,6 +6087,9 @@  extern bool can_convert_arg_bad			(tree, tree, tree, int,
 extern int conv_flags				(int, int, tree, tree, int);
 extern struct conversion * good_conversion	(tree, tree, tree, int, tsubst_flags_t);
 extern location_t get_fndecl_argument_location  (tree, int);
+extern void complain_about_bad_argument	(location_t arg_loc,
+						 tree from_type, tree to_type,
+						 tree fndecl, int parmnum);
 
 
 /* A class for recording information about access failures (e.g. private
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index ab088a9..9cb2271 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -8818,23 +8818,9 @@  convert_for_assignment (tree type, tree rhs,
 						   parmnum, complain, flags);
 		}
 	      else if (fndecl)
-		{
-		  auto_diagnostic_group d;
-		  location_t loc = cp_expr_location (rhs);
-		  range_label_for_type_mismatch rhs_label (rhstype, type);
-		  range_label *label = &rhs_label;
-		  if (loc == UNKNOWN_LOCATION)
-		    {
-		      loc = input_location;
-		      label = NULL;
-		    }
-		  gcc_rich_location richloc (loc, label);
-		  error_at (&richloc,
-			    "cannot convert %qH to %qI",
-			    rhstype, type);
-		  inform (get_fndecl_argument_location (fndecl, parmnum),
-			  "  initializing argument %P of %qD", parmnum, fndecl);
-		}
+		complain_about_bad_argument (cp_expr_location (rhs),
+					     rhstype, type,
+					     fndecl, parmnum);
 	      else
 		switch (errtype)
 		  {
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit4.C b/gcc/testsuite/g++.dg/cpp0x/explicit4.C
index 346a6e2..065a473 100644
--- a/gcc/testsuite/g++.dg/cpp0x/explicit4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit4.C
@@ -13,5 +13,5 @@  int main()
 {
   B b;
   (A(b));			// OK
-  (A(b,1));			// { dg-error "no match" }
+  (A(b,1));			// { dg-error "cannot convert" }
 }
diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
index 4957f61..f74f8d3 100644
--- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
+++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
@@ -71,17 +71,14 @@  struct s4 { static int member_1 (int one, const char **two, float three); }; //
 
 int test_4 (int first, const char *second, float third)
 {
-  return s4::member_1 (first, second, third); // { dg-error "no matching function for call to 's4::member_1\\(int&, const char\\*&, float&\\)'" }
+  return s4::member_1 (first, second, third); // { dg-error "31: cannot convert 'const char\\*' to 'const char\\*\\*'" }
   /* { dg-begin-multiline-output "" }
    return s4::member_1 (first, second, third);
-                                            ^
+                               ^~~~~~
+                               |
+                               const char*
      { dg-end-multiline-output "" } */
-  // { dg-message "candidate: 'static int s4::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s4_member_1 }
-  /* { dg-begin-multiline-output "" }
- struct s4 { static int member_1 (int one, const char **two, float three); };
-                        ^~~~~~~~
-     { dg-end-multiline-output "" } */
-  // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s4_member_1 }
+  // { dg-message "initializing argument 2 of 'static int s4::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s4_member_1 } 
   /* { dg-begin-multiline-output "" } 
  struct s4 { static int member_1 (int one, const char **two, float three); };
                                            ~~~~~~~~~~~~~^~~
@@ -95,19 +92,16 @@  struct s5 { int member_1 (int one, const char **two, float three); }; // { dg-li
 int test_5 (int first, const char *second, float third)
 {
   s5 inst;
-  return inst.member_1 (first, second, third); // { dg-error "no matching function for call to 's5::member_1\\(int&, const char\\*&, float&\\)'" }
+  return inst.member_1 (first, second, third); // { dg-error "32: cannot convert 'const char\\*' to 'const char\\*\\*'" }
   /* { dg-begin-multiline-output "" }
    return inst.member_1 (first, second, third);
-                                             ^
+                                ^~~~~~
+                                |
+                                const char*
      { dg-end-multiline-output "" } */
-  // { dg-message "candidate: 'int s5::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s5_member_1 }
+  // { dg-message "initializing argument 2 of 'int s5::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s5_member_1 } 
   /* { dg-begin-multiline-output "" }
  struct s5 { int member_1 (int one, const char **two, float three); };
-                 ^~~~~~~~
-     { dg-end-multiline-output "" } */
-  // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s5_member_1 }
-  /* { dg-begin-multiline-output "" } 
- struct s5 { int member_1 (int one, const char **two, float three); };
                                     ~~~~~~~~~~~~~^~~
      { dg-end-multiline-output "" } */
 }
@@ -118,17 +112,14 @@  struct s6 { int member_1 (int one, const char **two, float three); }; // { dg-li
 
 int test_6 (int first, const char *second, float third, s6 *ptr)
 {
-  return ptr->member_1 (first, second, third); // { dg-error "no matching function for call to 's6::member_1\\(int&, const char\\*&, float&\\)'" }
+  return ptr->member_1 (first, second, third); // { dg-error "32: cannot convert 'const char\\*' to 'const char\\*\\*'" }
   /* { dg-begin-multiline-output "" }
    return ptr->member_1 (first, second, third);
-                                             ^
+                                ^~~~~~
+                                |
+                                const char*
      { dg-end-multiline-output "" } */
-  // { dg-message "candidate: 'int s6::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s6_member_1 }
-  /* { dg-begin-multiline-output "" }
- struct s6 { int member_1 (int one, const char **two, float three); };
-                 ^~~~~~~~
-     { dg-end-multiline-output "" } */
-  // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s6_member_1 }
+  // { dg-message "initializing argument 2 of 'int s6::member_1\\(int, const char\\*\\*, float\\)'" "" { target *-*-* } s6_member_1 } 
   /* { dg-begin-multiline-output "" } 
  struct s6 { int member_1 (int one, const char **two, float three); };
                                     ~~~~~~~~~~~~~^~~
@@ -168,17 +159,14 @@  struct s8 { static int member_1 (int one, T two, float three); }; // { dg-line s
 
 int test_8 (int first, const char *second, float third)
 {
-  return s8 <const char **>::member_1 (first, second, third); // { dg-error "no matching function for call to 's8<const char\\*\\*>::member_1\\(int&, const char\\*&, float&\\)'" }
+  return s8 <const char **>::member_1 (first, second, third); // { dg-error "47: cannot convert 'const char\\*' to 'const char\\*\\*'" }
   /* { dg-begin-multiline-output "" }
    return s8 <const char **>::member_1 (first, second, third);
-                                                            ^
-     { dg-end-multiline-output "" } */
-  // { dg-message "candidate: 'static int s8<T>::member_1\\(int, T, float\\)" "" { target *-*-* } s8_member_1 }
-  /* { dg-begin-multiline-output "" }
- struct s8 { static int member_1 (int one, T two, float three); };
-                        ^~~~~~~~
+                                               ^~~~~~
+                                               |
+                                               const char*
      { dg-end-multiline-output "" } */
-  // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s8_member_1 }
+  // { dg-message "initializing argument 2 of 'static int s8<T>::member_1\\(int, T, float\\) .with T = const char\\*\\*.'" "" { target *-*-* } s8_member_1 } 
   /* { dg-begin-multiline-output "" }
  struct s8 { static int member_1 (int one, T two, float three); };
                                            ~~^~~
@@ -193,19 +181,43 @@  struct s9 { int member_1 (int one, T two, float three); }; // { dg-line s9_membe
 int test_9 (int first, const char *second, float third)
 {
   s9 <const char **> inst;
-  return inst.member_1 (first, second, third); // { dg-error "no matching function for call to 's9<const char\\*\\*>::member_1\\(int&, const char\\*&, float&\\)'" }
+  return inst.member_1 (first, second, third); // { dg-error "32: cannot convert 'const char\\*' to 'const char\\*\\*'" }
   /* { dg-begin-multiline-output "" }
    return inst.member_1 (first, second, third);
-                                             ^
+                                ^~~~~~
+                                |
+                                const char*
      { dg-end-multiline-output "" } */
-  // { dg-message "candidate: 'int s9<T>::member_1\\(int, T, float\\)" "" { target *-*-* } s9_member_1 }
+  // { dg-message "initializing argument 2 of 'int s9<T>::member_1\\(int, T, float\\) .with T = const char\\*\\*.'" "" { target *-*-* } s9_member_1 } 
   /* { dg-begin-multiline-output "" }
  struct s9 { int member_1 (int one, T two, float three); };
-                 ^~~~~~~~
+                                    ~~^~~
      { dg-end-multiline-output "" } */
-  // { dg-message "no known conversion for argument 2 from 'const char\\*' to 'const char\\*\\*'" "" { target *-*-* } s9_member_1 }
+}
+
+/* Overloaded operator (with one candidate).  */
+
+struct s10 {};
+
+extern int operator- (const s10&, int); // { dg-line s10_operator }
+
+int test_10 ()
+{
+  s10 v10_a, v10_b;
+
+  return v10_a - v10_b; // { dg-error "no match for" }
   /* { dg-begin-multiline-output "" }
- struct s9 { int member_1 (int one, T two, float three); };
-                                    ~~^~~
+   return v10_a - v10_b;
+          ~~~~~~^~~~~~~
+     { dg-end-multiline-output "" } */
+  // { dg-message "candidate" "" { target *-*-* } s10_operator }
+  /* { dg-begin-multiline-output "" }
+ extern int operator- (const s10&, int);
+            ^~~~~~~~
+     { dg-end-multiline-output "" } */
+  // { dg-message "no known conversion for argument 2 from" "" { target *-*-* } s10_operator }
+  /* { dg-begin-multiline-output "" }
+ extern int operator- (const s10&, int);
+                                   ^~~
      { dg-end-multiline-output "" } */
 }
diff --git a/gcc/testsuite/g++.dg/expr/pmf-1.C b/gcc/testsuite/g++.dg/expr/pmf-1.C
index e6b7219..35ebe52 100644
--- a/gcc/testsuite/g++.dg/expr/pmf-1.C
+++ b/gcc/testsuite/g++.dg/expr/pmf-1.C
@@ -14,6 +14,6 @@  struct A
   {
     void (A::*p)() = &A::f;
     void (A::*q)() = &(A::f);       // { dg-error "parenthesized" }
-    foo(&g<int>);                   // { dg-error "no matching" }
+    foo(&g<int>);                   // { dg-error "cannot convert" }
   }
 };
diff --git a/gcc/testsuite/g++.old-deja/g++.bugs/900330_02.C b/gcc/testsuite/g++.old-deja/g++.bugs/900330_02.C
index 588251d..f1591b2 100644
--- a/gcc/testsuite/g++.old-deja/g++.bugs/900330_02.C
+++ b/gcc/testsuite/g++.old-deja/g++.bugs/900330_02.C
@@ -24,7 +24,7 @@  struct D : public B {
 
 void h(D* pd)
 {
-  pd->f(1);		// { dg-error "no matching" } D::f(struct B) hides B::f(int)
+  pd->f(1);		// { dg-error "cannot convert" } D::f(struct B) hides B::f(int)
 }
 
 int main () { return 0; }
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/conversion11.C b/gcc/testsuite/g++.old-deja/g++.jason/conversion11.C
index a7c0fbe..ccbd1f5 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/conversion11.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/conversion11.C
@@ -22,6 +22,6 @@  void DoSomething(Ding A);
 void foo(Something* pX)
 {
   DoSomething(1);		// { dg-error "could not convert" }
-  pX->DoSomething(1);		// { dg-error "no matching" } 
-  (*pX).DoSomething(1);		// { dg-error "no matching" } 
+  pX->DoSomething(1);		// { dg-error "cannot convert" } 
+  (*pX).DoSomething(1);		// { dg-error "cannot convert" } 
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.law/arg11.C b/gcc/testsuite/g++.old-deja/g++.law/arg11.C
index bd88844..d68f184 100644
--- a/gcc/testsuite/g++.old-deja/g++.law/arg11.C
+++ b/gcc/testsuite/g++.old-deja/g++.law/arg11.C
@@ -17,6 +17,6 @@  int
 foo(S *o)
 { // Neither call has a usable constructor for conversions of char[5] to Ack.
   function("adsf");// { dg-error "could not convert" }
-  o->method("adsf");// { dg-error "no matching" } 
+  o->method("adsf");// { dg-error "cannot convert" } 
   return 0;
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.law/arm9.C b/gcc/testsuite/g++.old-deja/g++.law/arm9.C
index c603aab..ab18189 100644
--- a/gcc/testsuite/g++.old-deja/g++.law/arm9.C
+++ b/gcc/testsuite/g++.old-deja/g++.law/arm9.C
@@ -23,7 +23,7 @@  void B::set (f2 f) { std::cout << "called B\n|no known conversion";} // { dg-mes
 
 int main() {
     B b;
-    b.set(F1); // ARM page 309: should call A.set(f1) and that what g++ does,// { dg-error "match" }
+    b.set(F1); // ARM page 309: should call A.set(f1) and that what g++ does,// { dg-error "cannot convert" }
                // but 13.1 of ARM clearly states that it should call B::set()
                // or generate an error because overloading works only for
                // functions within the same scope (first page of chapter 13)
diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb131.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb131.C
index 6a0f1c3..c2377fb 100644
--- a/gcc/testsuite/g++.old-deja/g++.robertl/eb131.C
+++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb131.C
@@ -15,6 +15,6 @@  struct a {
 
 a::a()
 {
-	foo( &junk ); // { dg-error "match" } junk is an unqualified-id.
-	foo( &bar );  // { dg-error "match" } bar is an unqualified-id.
+	foo( &junk ); // { dg-error "cannot convert" } junk is an unqualified-id.
+	foo( &bar );  // { dg-error "cannot convert" } bar is an unqualified-id.
 }