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);
  |                               ^~~~~~
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); };
  |                                           ~~~~~~~~~~~~~^~~

updating the location of the "error" to use that of the argument with
the mismatching type.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu; adds a
further 33 PASS results to g++.sum.

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.
        (get_location_for_arg_conversion): New function.
        (get_location_for_unmatched_call): New function.
        (build_new_method_call_1): Call get_location_for_unmatched_call
        when reporting on unmatched functions, and use it for the error's
        location.

gcc/testsuite/ChangeLog:
        PR c++/85110
        * g++.dg/diagnostic/param-type-mismatch-2.C: Update expected
        results to underline the pertinent argument in the initial
        error for unmatched calls in which there is a single candidate.
        Add test coverage for an unmatched overloaded operator.
---
 gcc/cp/call.c                                      | 107 ++++++++++++++++++---
 .../g++.dg/diagnostic/param-type-mismatch-2.C      |  37 ++++++-
 2 files changed, 123 insertions(+), 21 deletions(-)

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index ef445e0..3bc42f5 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)
@@ -9157,6 +9173,61 @@ name_as_c_string (tree name, tree type, bool *free_p)
   return CONST_CAST (char *, pretty_name);
 }
 
+/* Subroutine of get_location_for_unmatched_call.
+   Return the location of the pertinent argument in INFO, if
+   available.
+   Otherwise, return DEFAULT_LOCATION.  */
+
+static location_t
+get_location_for_arg_conversion (conversion_info *info,
+                                location_t default_location)
+{
+  if (info->loc == UNKNOWN_LOCATION)
+    return default_location;
+  return info->loc;
+}
+
+/* Get the best location to use when reporting a function call
+   for which there are no valid candidates.
+
+   If there is just one candidate, and it is invalid due to the
+   argument type, use the location of the pertinent argument.
+
+   Otherwise, use DEFAULT_LOCATION.  */
+
+static location_t
+get_location_for_unmatched_call (z_candidate *candidates,
+                                location_t default_location)
+{
+  if (!candidates)
+    return default_location;
+
+  /* Must be exactly one candidate.  */
+  if (candidates->next)
+    return default_location;
+
+  /* Must be an rr_arg_conversion or rr_bad_arg_conversion.  */
+  z_candidate *candidate = candidates;
+  rejection_reason *r = candidate->reason;
+
+  if (r == NULL)
+    return default_location;
+
+  switch (r->code)
+    {
+    default:
+      return default_location;
+
+    case rr_arg_conversion:
+      return get_location_for_arg_conversion (&r->u.conversion,
+                                             default_location);
+
+    case rr_bad_arg_conversion:
+      return get_location_for_arg_conversion (&r->u.bad_conversion,
+                                             default_location);
+    }
+}
+
 /* 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.  */
@@ -9375,13 +9446,16 @@ build_new_method_call_1 (tree instance, tree fns, 
vec<tree, va_gc> **args,
     {
       if (complain & tf_error)
        {
+         location_t loc = get_location_for_unmatched_call (candidates,
+                                                           input_location);
          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));
+           error_at (loc,
+                     "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);
@@ -9396,9 +9470,10 @@ build_new_method_call_1 (tree instance, tree fns, 
vec<tree, va_gc> **args,
                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));
+             error_at (loc,
+                       "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);
        }
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..8fb167a 100644
--- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
+++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C
@@ -74,7 +74,7 @@ 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&\\)'" }
   /* { dg-begin-multiline-output "" }
    return s4::member_1 (first, second, third);
-                                            ^
+                               ^~~~~~
      { dg-end-multiline-output "" } */
   // { dg-message "candidate: 'static int s4::member_1\\(int, const 
char\\*\\*, float\\)'" "" { target *-*-* } s4_member_1 }
   /* { dg-begin-multiline-output "" }
@@ -98,7 +98,7 @@ int test_5 (int first, const char *second, float third)
   return inst.member_1 (first, second, third); // { dg-error "no matching 
function for call to 's5::member_1\\(int&, const char\\*&, float&\\)'" }
   /* { dg-begin-multiline-output "" }
    return inst.member_1 (first, second, third);
-                                             ^
+                                ^~~~~~
      { dg-end-multiline-output "" } */
   // { dg-message "candidate: 'int s5::member_1\\(int, const char\\*\\*, 
float\\)'" "" { target *-*-* } s5_member_1 }
   /* { dg-begin-multiline-output "" }
@@ -121,7 +121,7 @@ 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&\\)'" }
   /* { dg-begin-multiline-output "" }
    return ptr->member_1 (first, second, third);
-                                             ^
+                                ^~~~~~
      { dg-end-multiline-output "" } */
   // { dg-message "candidate: 'int s6::member_1\\(int, const char\\*\\*, 
float\\)'" "" { target *-*-* } s6_member_1 }
   /* { dg-begin-multiline-output "" }
@@ -171,7 +171,7 @@ 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&\\)'" }
   /* { 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 "" }
@@ -196,7 +196,7 @@ int test_9 (int first, const char *second, float third)
   return inst.member_1 (first, second, third); // { dg-error "no matching 
function for call to 's9<const char\\*\\*>::member_1\\(int&, const char\\*&, 
float&\\)'" }
   /* { dg-begin-multiline-output "" }
    return inst.member_1 (first, second, third);
-                                             ^
+                                ^~~~~~
      { dg-end-multiline-output "" } */
   // { dg-message "candidate: 'int s9<T>::member_1\\(int, T, float\\)" "" { 
target *-*-* } s9_member_1 }
   /* { dg-begin-multiline-output "" }
@@ -209,3 +209,30 @@ int test_9 (int first, const char *second, float third)
                                     ~~^~~
      { dg-end-multiline-output "" } */
 }
+
+/* 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 "" }
+   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 "" } */
+}
-- 
1.8.5.3

Reply via email to