From patchwork Thu Aug 23 18:08:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 961541 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-484324-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="oGmO95fa"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41xB795S5bz9s5b for ; Fri, 24 Aug 2018 03:22:28 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=xox4oT75ESroRIxTZCVcSPnuf64dQlhmaC9GGtremUGVXtTf6pAzW LVfeMpYQULB5OFW5m+miZlKdSEOMaBzqTXllwHURkXhCAxaTJOtOgBam/hEuAaHi 2iAEtzGRXA/7Q+6x2D13NG8ZVqSC6qsYrI1femnnKRiLJMH3dKrKGI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references; s= default; bh=SDyOvsaiAMwSvtZUJttR8Oz7EAc=; b=oGmO95faknjRcSHRVAdt re+lf1+UVWkb3XqKXbT1aQ239IlHDsaa+Bu5XEpjuqulbSw49eatGmvvYBmRU4Pq jSauDCWmlb/M4NG8vyDNfIxvfcp6Ji0vy3pPUfmmEyQZ22p15SAh/I75n95BkdVW AT+TiRqtfmzCLdjXs+mehI8= Received: (qmail 94930 invoked by alias); 23 Aug 2018 17:22:19 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 94915 invoked by uid 89); 23 Aug 2018 17:22:19 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, KAM_SHORT, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=viable, errname, ics X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 23 Aug 2018 17:22:16 +0000 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 95C7E5F732 for ; Thu, 23 Aug 2018 17:22:15 +0000 (UTC) Received: from c64.redhat.com (ovpn-112-25.phx2.redhat.com [10.3.112.25]) by smtp.corp.redhat.com (Postfix) with ESMTP id 451B17F643; Thu, 23 Aug 2018 17:22:13 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org, Jason Merrill Cc: David Malcolm Subject: [PATCH] C++: highlight bad argument in some users of print_z_candidates (more PR c++/85110) Date: Thu, 23 Aug 2018 14:08:20 -0400 Message-Id: <1535047700-27258-1-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1535036493-32590-1-git-send-email-dmalcolm@redhat.com> References: <1535036493-32590-1-git-send-email-dmalcolm@redhat.com> X-IsSubscribed: yes 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 **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 **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 ::member_1 (first, second, third); // { dg-error "no matching function for call to 's8::member_1\\(int&, const char\\*&, float&\\)'" } /* { dg-begin-multiline-output "" } return s8 ::member_1 (first, second, third); - ^ + ^~~~~~ { dg-end-multiline-output "" } */ // { dg-message "candidate: 'static int s8::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::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::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 "" } */ +}