From patchwork Mon May 16 17:39:40 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Froyd X-Patchwork-Id: 95792 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 6554EB6EE7 for ; Tue, 17 May 2011 03:40:24 +1000 (EST) Received: (qmail 32510 invoked by alias); 16 May 2011 17:40:19 -0000 Received: (qmail 32468 invoked by uid 22791); 16 May 2011 17:40:10 -0000 X-SWARE-Spam-Status: No, hits=-0.3 required=5.0 tests=AWL, BAYES_50, TW_DF, TW_FN, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 16 May 2011 17:39:49 +0000 Received: (qmail 777 invoked from network); 16 May 2011 17:39:42 -0000 Received: from unknown (HELO codesourcery.com) (froydnj@127.0.0.2) by mail.codesourcery.com with ESMTPA; 16 May 2011 17:39:42 -0000 Date: Mon, 16 May 2011 13:39:40 -0400 From: Nathan Froyd To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: Re: [PATCH, c++] describe reasons for function template overload resolution failure Message-ID: <20110516173938.GA779@nightcrawler> References: <20110509224933.GR23480@codesourcery.com> <4DC99B34.7070301@redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <4DC99B34.7070301@redhat.com> User-Agent: Mutt/1.5.20 (2009-06-14) X-IsSubscribed: yes 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 On Tue, May 10, 2011 at 04:08:20PM -0400, Jason Merrill wrote: > In general, my preference is to have diagnostics collocated with the > tests that lead to them, and just run through the same code a second > time if we decide that we want to give a diagnostic. For instance, > that's what I did in joust and synthesized_method_walk. Saving > information ahead of time about why we reject a particular candidate > creates overhead that is useless in the vast majority of cases, > since most compiles succeed. FWIW, this is why I chose to permit NULL unification_info arguments. Thanks for the background; I will keep the principle in mind. IMHO, in a case like this where we're logically printing one diagnostic (one error and then some number of explanatory notes) keeping all the logic for the diagnostic centralized makes more sense. > This doesn't compile. Were you testing a previous version of the patch? > > I guess I'll stop reviewing the patch now and wait for an update. Apologies for the mostly-not-reviewed and edited-in-the-email garbage that I attempted to pass off as a patch. How about this version? Tested in the same way (g++/libstdc++), and including an actual gcc/testsuite/ ChangeLog. -Nathan gcc/cp/ PR c++/45329 PR c++/48934 * cp-tree.h (enum unification_result): Define. (struct unification_info): Define. (fn_type_unification): Add struct unification_info parameter. * pt.c (unify_success, unify_unknown): Define. (unify_parameter_deduction_failure): Define. (unify_invalid, unify_mismatch_1): Define. (unify_cv_qual_mismatch, unify_type_mismatch): Define. (unify_parameter_pack_mismatch): Define. (unify_parameter_pack_inconsistent): Define. (unify_ptrmem_cst_mismatch, unify_vla_arg): Define. (unify_constant_mismatch, unify_constant_unequal): Define. (unify_expression_unequal, unify_inconsistency): Define. (unify_too_many_parameters, unify_too_few_parameters): Define. (unify_arg_conversion, unify_no_common_base): Define. (unify_illformed_ptrmem_cst_expr): Define. (unify_substitution_failure): Define. (unify_invalid_explicit_argument): Define. (unify_inconsistent_template_template_parameters): Define. (unify): Add struct unification_info parameter. Pass to all relevant calls. Call above status functions when appropriate. (resolve_overloaded_unification): Likewise. (try_one_overload, unify): Likewise. (coerce_template_parms): Likewise. (coerce_template_parameter_pack): Likewise. (convert_template_argument): Likewise. (type_unification, type_unification_real): Likewise. (fn_type_unification, convert_nontype_argument): Likewise. (unify_pack_expansion): Likewise. (get_template_base, try_class_unification): Likewise. (get_bindings, more_specialized_fn): Pass NULL to unification calls. (get_class_bindings, do_auto_deduction): Likewise. * class.c (resolve_address_of_overloaded_function): Likewise. * call.c (enum rejection_reason_code): Add new codes. (struct rejection_reason): Add template_unification field. (template_unification_rejection): Define. (template_instantiation_rejection): Define. (invalid_copy_with_fn_template_rejection): Define. (add_template_candidate): Pass a struct unification_info to unify. Provide more rejection reasons when possible. (print_template_unification_rejection): Define. (print_arity_rejection): Define, split out from... (print_z_candidate): ...here. Add cases for new rejection reasons. gcc/testsuite/ PR c++/45329 PR c++/48934 * g++.dg/cpp0x/pr31434.C: Adjust. * g++.old-deja/g++.pt/explicit41.C: Adjust. * g++.old-deja/g++.pt/ptrmem6.C: Adjust. * g++.dg/overload/template5.C: New testcase. * g++.dg/template/overload12.C: New testcase. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 09ad4ae..f5cb7f3 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -430,7 +430,10 @@ enum rejection_reason_code { rr_none, rr_arity, rr_arg_conversion, - rr_bad_arg_conversion + rr_bad_arg_conversion, + rr_template_unification, + rr_template_instantiation, + rr_invalid_copy }; struct conversion_info { @@ -458,6 +461,8 @@ struct rejection_reason { struct conversion_info conversion; /* Same, but for bad argument conversions. */ struct conversion_info bad_conversion; + /* Information about template unification failures. */ + struct unification_info template_unification; } u; }; @@ -607,6 +612,28 @@ bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to) return r; } +static struct rejection_reason * +template_unification_rejection (struct unification_info *ui) +{ + struct rejection_reason *r = alloc_rejection (rr_template_unification); + r->u.template_unification = *ui; + return r; +} + +static struct rejection_reason * +template_instantiation_rejection (void) +{ + struct rejection_reason *r = alloc_rejection (rr_template_instantiation); + return r; +} + +static struct rejection_reason * +invalid_copy_with_fn_template_rejection (void) +{ + struct rejection_reason *r = alloc_rejection (rr_invalid_copy); + return r; +} + /* Dynamically allocate a conversion. */ static conversion * @@ -2844,6 +2871,9 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, int i; tree fn; struct rejection_reason *reason = NULL; + struct unification_info ui; + + ui.result = ur_unknown; /* We don't do deduction on the in-charge parameter, the VTT parameter or 'this'. */ @@ -2889,14 +2919,20 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, i = fn_type_unification (tmpl, explicit_targs, targs, args_without_in_chrg, nargs_without_in_chrg, - return_type, strict, flags); + return_type, strict, flags, &ui); if (i != 0) - goto fail; + { + reason = template_unification_rejection (&ui); + goto fail; + } fn = instantiate_template (tmpl, targs, tf_none); if (fn == error_mark_node) - goto fail; + { + reason = template_instantiation_rejection (); + goto fail; + } /* In [class.copy]: @@ -2925,7 +2961,10 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl, tree arg_types = FUNCTION_FIRST_USER_PARMTYPE (fn); if (arg_types && same_type_p (TYPE_MAIN_VARIANT (TREE_VALUE (arg_types)), ctype)) - goto fail; + { + reason = invalid_copy_with_fn_template_rejection (); + goto fail; + } } if (obj != NULL_TREE) @@ -3088,6 +3127,107 @@ print_conversion_rejection (location_t loc, struct conversion_info *info) info->n_arg+1, info->from_type, info->to_type); } +/* Print information about a candidate with WANT parameters and we found + HAVE. */ + +static void +print_arity_information (location_t loc, unsigned int have, unsigned int want) +{ + inform_n (loc, want, + " candidate expects %d argument, %d provided", + " candidate expects %d arguments, %d provided", + want, have); +} + +/* Print information about a candidate being rejected due to UI. */ + +static void +print_template_unification_rejection (location_t loc, + struct unification_info *ui) +{ + switch (ui->result) + { + case ur_invalid: + inform (loc, + " template argument deduction attempted with invalid input"); + break; + case ur_unification_inconsistency: + inform (loc, + " deduced conflicting types for parameter %qT (%qT and %qT)", + ui->u.inconsistent.template_parm, + ui->u.inconsistent.earlier, + ui->u.inconsistent.later); + break; + case ur_cv_qual_mismatch: + inform (loc, + " types %qT and %qT differ in their qualifiers", + ui->u.mismatch.parm, + ui->u.mismatch.arg); + break; + case ur_type_mismatch: + inform (loc, " mismatched types %qT and %qT", + ui->u.mismatch.parm, + ui->u.mismatch.arg); + break; + case ur_vla_arg: + inform (loc, " variable-sized array type %qT is not permitted", + ui->u.vla_arg.array_type); + break; + case ur_too_many_parameters: + case ur_too_few_parameters: + print_arity_information (loc, ui->u.arity.have, ui->u.arity.wanted); + break; + case ur_arg_conversion: + inform (loc, " cannot convert %qE (type %qT) to type %qT", + ui->u.arg_conversion.arg, ui->u.arg_conversion.from_type, + ui->u.arg_conversion.to_type); + break; + case ur_no_common_base: + inform (loc, " %qT is not derived from %qT", + ui->u.common_base.arg, ui->u.common_base.potential_base); + break; + case ur_illformed_ptrmem_cst_expr: + inform (loc, " %qE is not a valid pointer-to-member of type %qT", + ui->u.illformed_ptrmem_cst.expr, + ui->u.illformed_ptrmem_cst.type); + break; + case ur_parameter_deduction_failure: + inform (loc, " couldn't deduce template argument %qD", ui->u.parm); + break; + case ur_substitution_failure: + inform (loc, " substitution failure"); + break; + case ur_invalid_explicit_arg: + if (DECL_P (ui->u.invalid_explicit_arg.parm) + && DECL_NAME (ui->u.invalid_explicit_arg.parm)) + inform (loc, " invalid explicit argument for template parameter %qD", + ui->u.invalid_explicit_arg.parm); + else + inform (loc, " invalid explicit argument for template parameter %d", + ui->u.invalid_explicit_arg.parm_index + 1); + break; + case ur_inconsistent_template_template_parameters: + inform (loc, " inconsistent template template parameters"); + break; + case ur_parameter_pack_mismatch: + inform (loc, " template parmeter %qD is not a parameter pack", + ui->u.mismatch.parm); + break; + case ur_unknown: + /* Template deduction and instantiation fails for a multitude of + reasons. In the worst case, don't print anything, as we might + not have caught all of the cases. */ + break; + case ur_success: + /* We should never see this; it means we forgot to provide a + rejection reason someplace else (probably from template + instantiation). */ + /* Fallthrough. */ + default: + gcc_unreachable (); + } +} + /* Print information about one overload candidate CANDIDATE. MSGSTR is the text to print before the candidate itself. @@ -3134,10 +3274,8 @@ print_z_candidate (const char *msgstr, struct z_candidate *candidate) 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); + print_arity_information (loc, r->u.arity.actual, + r->u.arity.expected); break; case rr_arg_conversion: print_conversion_rejection (loc, &r->u.conversion); @@ -3145,6 +3283,18 @@ print_z_candidate (const char *msgstr, struct z_candidate *candidate) case rr_bad_arg_conversion: print_conversion_rejection (loc, &r->u.bad_conversion); break; + case rr_template_unification: + print_template_unification_rejection (loc, + &r->u.template_unification); + break; + case rr_template_instantiation: + inform (loc, " failed to instantiate template"); + break; + case rr_invalid_copy: + inform (loc, + " cannot instantiate member function templates to " + "copy class objects to their class type"); + break; case rr_none: default: /* This candidate didn't have any issues or we failed to diff --git a/gcc/cp/class.c b/gcc/cp/class.c index dc2c509..e7d629b 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -6515,7 +6515,7 @@ resolve_address_of_overloaded_function (tree target_type, targs = make_tree_vec (DECL_NTPARMS (fn)); if (fn_type_unification (fn, explicit_targs, targs, args, nargs, target_ret_type, DEDUCE_EXACT, - LOOKUP_NORMAL)) + LOOKUP_NORMAL, NULL)) /* Argument deduction failed. */ continue; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index c0b5290..7dd8aa8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5097,6 +5097,105 @@ extern tree locate_ctor (tree); extern bool maybe_clone_body (tree); /* in pt.c */ +/* Status codes for the result of unification. */ +enum unification_result { + /* Unification succeeded. */ + ur_success = 0, + /* Unification failed for an unknown reason. */ + ur_unknown, + /* Failed to deduce a particular parameters. */ + ur_parameter_deduction_failure, + /* Error due to ill-formed input. */ + ur_invalid, + /* CV-qualification mismatch. */ + ur_cv_qual_mismatch, + /* Argument is a parameter pack/expansion and parm isn't. */ + ur_parameter_pack_mismatch, + /* Argument is a variable-sized array. */ + ur_vla_arg, + /* Parameter is a pointer-to-member constant, arg isn't. */ + ur_ptrmem_cst_mismatch, + /* Types of parameter and argument do not match. */ + ur_type_mismatch, + /* Parameter is a constant, arg isn't. */ + ur_constant_mismatch, + /* Parameter and argument are unequal constants. */ + ur_constant_unequal, + /* Unequal expressions. */ + ur_expression_unequal, + /* Unification of parameter packs produced inconsistencies. */ + ur_parameter_pack_inconsistent, + /* Unification of earlier parameters produced inconsistencies with + later ones. */ + ur_unification_inconsistency, + /* Too many parameters. */ + ur_too_many_parameters, + /* Too few parameters. */ + ur_too_few_parameters, + /* Failed argument conversion. */ + ur_arg_conversion, + ur_no_common_base, + ur_illformed_ptrmem_cst_expr, + /* Substitution failed in some way at some expression. */ + ur_substitution_failure, + /* Explicit template arguments are invalid. */ + ur_invalid_explicit_arg, + /* Template parameters that are templates cannot be deduced. */ + ur_inconsistent_template_template_parameters +}; + +/* Information gathered during the unification process. */ +struct unification_info { + /* Status code. Also indicates which member of U, below, is valid. */ + enum unification_result result; + union { + tree invalid; /* For ur_invalid_*. */ + tree parm; /* For generic failure. */ + /* For anything where we found differences between PARM and ARG. */ + struct { + tree parm; + tree arg; + } mismatch; + /* For inconsistent unifications. */ + struct { + tree template_parm; + tree earlier; + tree later; + } inconsistent; + /* For variably-sized array types appearing in templates. */ + struct { + tree parm; + tree array_type; + } vla_arg; + /* For arity issues. */ + struct { + unsigned int have; + unsigned int wanted; + } arity; + /* For ur_arg_conversion. */ + struct { + tree to_type; + tree from_type; + tree arg; + } arg_conversion; + /* For ur_no_common_base. */ + struct { + tree potential_base; + tree arg; + } common_base; + struct { + tree expr; + tree type; + } illformed_ptrmem_cst; + struct { + tree parm; + /* We ought to be able to get this from TEMPLATE_PARM_IDX + (DECL_INITIAL (parm)), but parm might not be a decl. */ + int parm_index; + } invalid_explicit_arg; + } u; +}; + extern bool check_template_shadow (tree); extern tree get_innermost_template_args (tree, int); extern void maybe_begin_member_template_processing (tree); @@ -5135,7 +5234,8 @@ extern tree instantiate_class_template (tree); extern tree instantiate_template (tree, tree, tsubst_flags_t); extern int fn_type_unification (tree, tree, tree, const tree *, unsigned int, - tree, unification_kind_t, int); + tree, unification_kind_t, int, + struct unification_info *); extern void mark_decl_instantiated (tree, int); extern int more_specialized_fn (tree, tree, int); extern void do_decl_instantiation (tree, tree); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index e441a70..d61f3ab 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -112,16 +112,19 @@ static GTY(()) VEC(tree,gc) *canonical_template_parms; static void push_access_scope (tree); static void pop_access_scope (tree); static bool resolve_overloaded_unification (tree, tree, tree, tree, - unification_kind_t, int); + unification_kind_t, int, + struct unification_info *); static int try_one_overload (tree, tree, tree, tree, tree, - unification_kind_t, int, bool); -static int unify (tree, tree, tree, tree, int); + unification_kind_t, int, bool, + struct unification_info *); +static int unify (tree, tree, tree, tree, int, struct unification_info *); static void add_pending_template (tree); static tree reopen_tinst_level (struct tinst_level *); static tree tsubst_initializer_list (tree, tree); static tree get_class_bindings (tree, tree, tree); static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t, - bool, bool); + bool, bool, + struct unification_info *); static void tsubst_enum (tree, tree, tree); static tree add_to_template_args (tree, tree); static tree add_outermost_template_args (tree, tree); @@ -129,12 +132,15 @@ static bool check_instantiated_args (tree, tree, tsubst_flags_t); static int maybe_adjust_types_for_deduction (unification_kind_t, tree*, tree*, tree); static int type_unification_real (tree, tree, tree, const tree *, - unsigned int, int, unification_kind_t, int); + unsigned int, int, unification_kind_t, int, + struct unification_info *ui); static void note_template_header (int); static tree convert_nontype_argument_function (tree, tree); -static tree convert_nontype_argument (tree, tree, tsubst_flags_t); +static tree convert_nontype_argument (tree, tree, tsubst_flags_t, + struct unification_info *); static tree convert_template_argument (tree, tree, tree, - tsubst_flags_t, int, tree); + tsubst_flags_t, int, tree, + struct unification_info *); static int for_each_template_parm (tree, tree_fn_t, void*, struct pointer_set_t*, bool); static tree expand_template_argument_pack (tree); @@ -154,7 +160,9 @@ static tree get_bindings (tree, tree, tree, bool); static int template_decl_level (tree); static int check_cv_quals_for_unify (int, tree, tree); static void template_parm_level_and_index (tree, int*, int*); -static int unify_pack_expansion (tree, tree, tree, tree, int, bool, bool); +static int unify_pack_expansion (tree, tree, tree, + tree, int, bool, bool, + struct unification_info *); static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree); static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree); static tree tsubst_template_parms (tree, tree, tsubst_flags_t); @@ -166,8 +174,10 @@ static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree); static bool check_specialization_scope (void); static tree process_partial_specialization (tree); static void set_current_access_from_decl (tree); -static tree get_template_base (tree, tree, tree, tree); -static tree try_class_unification (tree, tree, tree, tree); +static tree get_template_base (tree, tree, tree, tree, + struct unification_info *); +static tree try_class_unification (tree, tree, tree, tree, + struct unification_info *); static int coerce_template_template_parms (tree, tree, tsubst_flags_t, tree, tree); static bool template_template_parm_bindings_ok_p (tree, tree); @@ -5265,6 +5275,231 @@ has_value_dependent_address (tree op) return false; } +/* The next set of functions fill in their provided UI parameter (if it + is not NULL) with useful information about why template deduction + failed. */ + +static int +unify_success (struct unification_info *ui) +{ + if (ui) + ui->result = ur_success; + return 0; +} + +static int +unify_unknown (struct unification_info *ui) +{ + if (ui) + ui->result = ur_unknown; + return 1; +} + +static int +unify_parameter_deduction_failure (struct unification_info *ui, tree parm) +{ + if (ui) + { + ui->result = ur_parameter_deduction_failure; + ui->u.parm = parm; + } + return 1; +} + +static int +unify_invalid (struct unification_info *ui) +{ + if (ui) + ui->result = ur_invalid; + return 1; +} + +static int +unify_mismatch_1 (enum unification_result ur, struct unification_info *ui, + tree parm, tree arg) +{ + if (ui) + { + ui->result = ur; + ui->u.mismatch.parm = parm; + ui->u.mismatch.arg = arg; + } + return 1; +} + +static int +unify_cv_qual_mismatch (struct unification_info *ui, tree parm, tree arg) +{ + return unify_mismatch_1 (ur_cv_qual_mismatch, ui, parm, arg); +} + +static int +unify_type_mismatch (struct unification_info *ui, tree parm, tree arg) +{ + return unify_mismatch_1 (ur_type_mismatch, ui, parm, arg); +} + +static int +unify_parameter_pack_mismatch (struct unification_info *ui, tree parm) +{ + return unify_mismatch_1 (ur_parameter_pack_mismatch, ui, parm, NULL_TREE); +} + +static int +unify_ptrmem_cst_mismatch (struct unification_info *ui, tree parm, tree arg) +{ + return unify_mismatch_1 (ur_ptrmem_cst_mismatch, ui, parm, arg); +} + +static int +unify_constant_mismatch (struct unification_info *ui, tree parm, tree arg) +{ + return unify_mismatch_1 (ur_constant_mismatch, ui, parm, arg); +} + +static int +unify_constant_unequal (struct unification_info *ui, tree parm, tree arg) +{ + return unify_mismatch_1 (ur_constant_unequal, ui, parm, arg); +} + +static int +unify_expression_unequal (struct unification_info *ui, tree parm, tree arg) +{ + return unify_mismatch_1 (ur_expression_unequal, ui, parm, arg); +} + +static int +unify_parameter_pack_inconsistent (struct unification_info *ui, tree pack) +{ + if (ui) + { + ui->result = ur_parameter_pack_inconsistent; + ui->u.parm = pack; + } + return 1; +} + +static int +unify_inconsistency (struct unification_info *ui, tree parm, + tree first, tree second) +{ + if (ui) + { + ui->result = ur_unification_inconsistency; + ui->u.inconsistent.template_parm = parm; + ui->u.inconsistent.earlier = first; + ui->u.inconsistent.later = second; + } + return 1; +} + +static int +unify_vla_arg (struct unification_info *ui, tree parm, tree arg) +{ + if (ui) + { + ui->result = ur_vla_arg; + ui->u.vla_arg.parm = parm; + ui->u.vla_arg.array_type = arg; + } + return 1; +} + +static int +unify_too_many_parameters (struct unification_info *ui, unsigned int have, + unsigned int wanted) +{ + if (ui) + { + ui->result = ur_too_many_parameters; + ui->u.arity.have = have; + ui->u.arity.wanted = wanted; + } + return 1; +} + +static int +unify_too_few_parameters (struct unification_info *ui, unsigned int have, + unsigned int wanted) +{ + if (ui) + { + ui->result = ur_too_few_parameters; + ui->u.arity.have = have; + ui->u.arity.wanted = wanted; + } + return 1; +} + +static int +unify_arg_conversion (struct unification_info *ui, tree to_type, + tree from_type, tree arg) +{ + if (ui) + { + ui->result = ur_arg_conversion; + ui->u.arg_conversion.to_type = to_type; + ui->u.arg_conversion.from_type = from_type; + ui->u.arg_conversion.arg = arg; + } + return 1; +} + +static int +unify_no_common_base (struct unification_info *ui, tree parm, tree arg) +{ + if (ui) + { + ui->result = ur_no_common_base; + ui->u.common_base.potential_base = parm; + ui->u.common_base.arg = arg; + } + return 1; +} + +static int +unify_illformed_ptrmem_cst_expr (struct unification_info *ui, + tree expr, tree type) +{ + if (ui) + { + ui->result = ur_illformed_ptrmem_cst_expr; + ui->u.illformed_ptrmem_cst.expr = expr; + ui->u.illformed_ptrmem_cst.type = type; + } + return 1; +} + +static int +unify_substitution_failure (struct unification_info *ui) +{ + if (ui) + ui->result = ur_substitution_failure; + return 1; +} + +static int +unify_invalid_explicit_argument (struct unification_info *ui, tree parm, + int parm_index) +{ + if (ui) + { + ui->result = ur_invalid_explicit_arg; + ui->u.invalid_explicit_arg.parm = parm; + ui->u.invalid_explicit_arg.parm_index = parm_index; + } + return 1; +} + +static int +unify_inconsistent_template_template_parameters (struct unification_info *ui) +{ + if (ui) + ui->result = ur_inconsistent_template_template_parameters; + return 1; +} + /* Attempt to convert the non-type template parameter EXPR to the indicated TYPE. If the conversion is successful, return the converted value. If the conversion is unsuccessful, return @@ -5286,7 +5521,8 @@ has_value_dependent_address (tree op) hacks can go away after we fix the double coercion problem. */ static tree -convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) +convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain, + struct unification_info *ui) { tree expr_type; @@ -5610,7 +5846,10 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) /* [temp.arg.nontype] bullet 1 says the pointer to member expression must be a pointer-to-member constant. */ if (!check_valid_ptrmem_cst_expr (type, expr, complain)) - return error_mark_node; + { + unify_illformed_ptrmem_cst_expr (ui, expr, type); + return error_mark_node; + } /* There is no way to disable standard conversions in resolve_address_of_overloaded_function (called by @@ -5642,7 +5881,10 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) /* [temp.arg.nontype] bullet 1 says the pointer to member expression must be a pointer-to-member constant. */ if (!check_valid_ptrmem_cst_expr (type, expr, complain)) - return error_mark_node; + { + unify_illformed_ptrmem_cst_expr (ui, expr, type); + return error_mark_node; + } expr = perform_qualification_conversions (type, expr); if (expr == error_mark_node) @@ -5927,7 +6169,8 @@ convert_template_argument (tree parm, tree args, tsubst_flags_t complain, int i, - tree in_decl) + tree in_decl, + struct unification_info *ui) { tree orig_arg; tree val; @@ -6120,7 +6363,7 @@ convert_template_argument (tree parm, conversions can occur is part of determining which function template to call, or whether a given explicit argument specification is valid. */ - val = convert_nontype_argument (t, orig_arg, complain); + val = convert_nontype_argument (t, orig_arg, complain, ui); else val = orig_arg; @@ -6156,7 +6399,8 @@ coerce_template_parameter_pack (tree parms, tree new_args, int* lost, tree in_decl, - tsubst_flags_t complain) + tsubst_flags_t complain, + struct unification_info *ui) { tree parm = TREE_VEC_ELT (parms, parm_idx); int nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0; @@ -6238,7 +6482,7 @@ coerce_template_parameter_pack (tree parms, if (arg != error_mark_node) arg = convert_template_argument (actual_parm, arg, new_args, complain, parm_idx, - in_decl); + in_decl, ui); if (arg == error_mark_node) (*lost)++; TREE_VEC_ELT (packed_args, arg_idx - parm_idx) = arg; @@ -6281,7 +6525,8 @@ coerce_template_parms (tree parms, tree in_decl, tsubst_flags_t complain, bool require_all_args, - bool use_default_args) + bool use_default_args, + struct unification_info *ui) { int nparms, nargs, parm_idx, arg_idx, lost = 0; tree inner_args; @@ -6343,6 +6588,13 @@ coerce_template_parms (tree parms, if (in_decl) error ("provided for %q+D", in_decl); } + else + { + if (nargs > nparms) + unify_too_many_parameters (ui, nargs, nparms); + else + unify_too_few_parameters (ui, nargs, nparms); + } return error_mark_node; } @@ -6359,6 +6611,7 @@ coerce_template_parms (tree parms, { tree arg; tree parm; + int last_lost = lost; /* Get the Ith template parameter. */ parm = TREE_VEC_ELT (parms, parm_idx); @@ -6383,7 +6636,7 @@ coerce_template_parms (tree parms, arg = coerce_template_parameter_pack (parms, parm_idx, args, inner_args, arg_idx, new_args, &lost, - in_decl, complain); + in_decl, complain, ui); /* Store this argument. */ if (arg == error_mark_node) @@ -6446,10 +6699,12 @@ coerce_template_parms (tree parms, else arg = convert_template_argument (TREE_VALUE (parm), arg, new_args, complain, - parm_idx, in_decl); + parm_idx, in_decl, ui); if (arg == error_mark_node) lost++; + if (last_lost == 0 && lost) + unify_invalid_explicit_argument (ui, TREE_VALUE (parm), parm_idx); TREE_VEC_ELT (new_inner_args, arg_idx) = arg; } cp_unevaluated_operand = saved_unevaluated_operand; @@ -6806,7 +7061,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, arglist2 = coerce_template_parms (parmlist, arglist, templ, complain, /*require_all_args=*/true, - /*use_default_args=*/true); + /*use_default_args=*/true, NULL); if (arglist2 == error_mark_node || (!uses_template_parms (arglist2) && check_instantiated_args (templ, arglist2, complain))) @@ -6879,7 +7134,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, arglist, gen_tmpl, complain, /*require_all_args=*/true, - /*use_default_args=*/true); + /*use_default_args=*/true, NULL); else /* Outer levels should have already been coerced. */ a = TMPL_ARGS_LEVEL (arglist, i); @@ -6913,7 +7168,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context, gen_tmpl, complain, /*require_all_args=*/true, - /*use_default_args=*/true); + /*use_default_args=*/true, NULL); if (arglist == error_mark_node) /* We were unable to bind the arguments. */ @@ -13737,7 +13992,8 @@ fn_type_unification (tree fn, unsigned int nargs, tree return_type, unification_kind_t strict, - int flags) + int flags, + struct unification_info *ui) { tree parms; tree fntype; @@ -13772,12 +14028,12 @@ fn_type_unification (tree fn, bool incomplete = false; if (explicit_targs == error_mark_node) - return 1; + return unify_invalid (ui); converted_args = (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none, /*require_all_args=*/false, - /*use_default_args=*/false)); + /*use_default_args=*/false, ui)); if (converted_args == error_mark_node) return 1; @@ -13840,7 +14096,7 @@ fn_type_unification (tree fn, processing_template_decl -= incomplete; if (fntype == error_mark_node) - return 1; + return unify_substitution_failure (ui); /* Place the explicitly specified arguments in TARGS. */ for (i = NUM_TMPL_ARGS (converted_args); i--;) @@ -13868,7 +14124,7 @@ fn_type_unification (tree fn, event. */ result = type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn), targs, parms, args, nargs, /*subr=*/0, - strict, flags); + strict, flags, ui); /* Now that we have bindings for all of the template arguments, ensure that the arguments deduced for the template template @@ -13894,7 +14150,7 @@ fn_type_unification (tree fn, if (result == 0 && !template_template_parm_bindings_ok_p (DECL_INNERMOST_TEMPLATE_PARMS (fn), targs)) - return 1; + return unify_inconsistent_template_template_parameters (ui); if (result == 0) /* All is well so far. Now, check: @@ -13909,7 +14165,7 @@ fn_type_unification (tree fn, { tree substed = deduction_tsubst_fntype (fn, targs); if (substed == error_mark_node) - return 1; + return unify_substitution_failure (ui); /* If we're looking for an exact match, check that what we got is indeed an exact match. It might not be if some template @@ -13924,7 +14180,7 @@ fn_type_unification (tree fn, sarg = tree_cons (NULL_TREE, TREE_TYPE (substed), sarg); for (i = 0; i < nargs && sarg; ++i, sarg = TREE_CHAIN (sarg)) if (!same_type_p (args[i], TREE_VALUE (sarg))) - return 1; + return unify_unknown (ui); } } @@ -14055,7 +14311,8 @@ type_unification_real (tree tparms, unsigned int xnargs, int subr, unification_kind_t strict, - int flags) + int flags, + struct unification_info *ui) { tree parm, arg, arg_expr; int i; @@ -14113,7 +14370,7 @@ type_unification_real (tree tparms, arg_expr = NULL; if (arg == error_mark_node) - return 1; + return unify_invalid (ui); if (arg == unknown_type_node) /* We can't deduce anything from this, but we might get all the template args from other function args. */ @@ -14139,7 +14396,7 @@ type_unification_real (tree tparms, flags)) continue; - return 1; + return unify_arg_conversion (ui, parm, type, arg); } if (!TYPE_P (arg)) @@ -14155,15 +14412,15 @@ type_unification_real (tree tparms, function templates and at most one of a set of overloaded functions provides a unique match. */ if (resolve_overloaded_unification - (tparms, targs, parm, arg, strict, sub_strict)) + (tparms, targs, parm, arg, strict, sub_strict, ui)) continue; - return 1; + return unify_unknown (ui); } arg_expr = arg; arg = unlowered_expr_type (arg); if (arg == error_mark_node) - return 1; + return unify_invalid (ui); } { @@ -14175,7 +14432,9 @@ type_unification_real (tree tparms, if (arg == init_list_type_node && arg_expr) arg = arg_expr; - if (unify (tparms, targs, parm, arg, arg_strict)) + if (unify (tparms, targs, parm, arg, arg_strict, ui)) + /* If unification failed, the recursive call will have updated + UI appropriately. */ return 1; } } @@ -14197,7 +14456,7 @@ type_unification_real (tree tparms, /* Copy the parameter into parmvec. */ TREE_VEC_ELT (parmvec, 0) = TREE_VALUE (parms); if (unify_pack_expansion (tparms, targs, parmvec, argvec, strict, - /*call_args_p=*/true, /*subr=*/subr)) + /*call_args_p=*/true, /*subr=*/subr, ui)) return 1; /* Advance to the end of the list of parameters. */ @@ -14207,11 +14466,20 @@ type_unification_real (tree tparms, /* Fail if we've reached the end of the parm list, and more args are present, and the parm list isn't variadic. */ if (ia < nargs && parms == void_list_node) - return 1; + return unify_too_many_parameters (ui, nargs, ia); /* Fail if parms are left and they don't have default values. */ if (parms && parms != void_list_node && TREE_PURPOSE (parms) == NULL_TREE) - return 1; + { + unsigned int count = nargs; + tree p = parms; + while (p && p != void_list_node) + { + count++; + p = TREE_CHAIN (p); + } + return unify_too_few_parameters (ui, ia, count); + } if (!subr) { @@ -14267,9 +14535,9 @@ type_unification_real (tree tparms, tree arg = TREE_PURPOSE (TREE_VEC_ELT (tparms, i)); arg = tsubst_template_arg (arg, targs, tf_none, NULL_TREE); arg = convert_template_argument (parm, arg, targs, tf_none, - i, NULL_TREE); + i, NULL_TREE, ui); if (arg == error_mark_node) - return 1; + return unify_parameter_deduction_failure (ui, parm); else { TREE_VEC_ELT (targs, i) = arg; @@ -14303,7 +14571,7 @@ type_unification_real (tree tparms, continue; } - return 2; + return unify_parameter_deduction_failure (ui, tparm); } } #ifdef ENABLE_CHECKING @@ -14311,7 +14579,7 @@ type_unification_real (tree tparms, SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, TREE_VEC_LENGTH (targs)); #endif - return 0; + return unify_success (ui); } /* Subroutine of type_unification_real. Args are like the variables @@ -14326,7 +14594,8 @@ resolve_overloaded_unification (tree tparms, tree parm, tree arg, unification_kind_t strict, - int sub_strict) + int sub_strict, + struct unification_info *ui) { tree tempargs = copy_node (targs); int good = 0; @@ -14377,7 +14646,7 @@ resolve_overloaded_unification (tree tparms, { elem = tsubst (TREE_TYPE (fn), subargs, tf_none, NULL_TREE); if (try_one_overload (tparms, targs, tempargs, parm, - elem, strict, sub_strict, addr_p) + elem, strict, sub_strict, addr_p, ui) && (!goodfn || !decls_match (goodfn, elem))) { goodfn = elem; @@ -14397,7 +14666,7 @@ resolve_overloaded_unification (tree tparms, for (; arg; arg = OVL_NEXT (arg)) if (try_one_overload (tparms, targs, tempargs, parm, TREE_TYPE (OVL_CURRENT (arg)), - strict, sub_strict, addr_p) + strict, sub_strict, addr_p, ui) && (!goodfn || !decls_match (goodfn, OVL_CURRENT (arg)))) { goodfn = OVL_CURRENT (arg); @@ -14543,7 +14812,8 @@ try_one_overload (tree tparms, tree arg, unification_kind_t strict, int sub_strict, - bool addr_p) + bool addr_p, + struct unification_info *ui) { int nargs; tree tempargs; @@ -14573,7 +14843,7 @@ try_one_overload (tree tparms, nargs = TREE_VEC_LENGTH (targs); tempargs = make_tree_vec (nargs); - if (unify (tparms, tempargs, parm, arg, sub_strict) != 0) + if (unify (tparms, tempargs, parm, arg, sub_strict, ui)) return 0; /* First make sure we didn't deduce anything that conflicts with @@ -14611,7 +14881,8 @@ try_one_overload (tree tparms, TARGS are as for unify. */ static tree -try_class_unification (tree tparms, tree targs, tree parm, tree arg) +try_class_unification (tree tparms, tree targs, tree parm, tree arg, + struct unification_info *ui) { tree copy_of_targs; @@ -14654,7 +14925,7 @@ try_class_unification (tree tparms, tree targs, tree parm, tree arg) /* If unification failed, we're done. */ if (unify (tparms, copy_of_targs, CLASSTYPE_TI_ARGS (parm), - CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE)) + CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE, ui)) return NULL_TREE; return arg; @@ -14668,7 +14939,8 @@ try_class_unification (tree tparms, tree targs, tree parm, tree arg) by unify. */ static tree -get_template_base (tree tparms, tree targs, tree parm, tree arg) +get_template_base (tree tparms, tree targs, tree parm, tree arg, + struct unification_info *ui) { tree rval = NULL_TREE; tree binfo; @@ -14684,7 +14956,8 @@ get_template_base (tree tparms, tree targs, tree parm, tree arg) important, and this avoids multiple walks of virtual bases. */ for (binfo = TREE_CHAIN (binfo); binfo; binfo = TREE_CHAIN (binfo)) { - tree r = try_class_unification (tparms, targs, parm, BINFO_TYPE (binfo)); + tree r = try_class_unification (tparms, targs, parm, + BINFO_TYPE (binfo), ui); if (r) { @@ -14785,6 +15058,12 @@ template_parm_level_and_index (tree parm, int* level, int* index) } } +#define RECUR_AND_CHECK_FAILURE(TP, TA, P, A, S, UI) \ + do { \ + if (unify (TP, TA, P, A, S, UI)) \ + return 1; \ + } while (0); + /* Unifies the remaining arguments in PACKED_ARGS with the pack expansion at the end of PACKED_PARMS. Returns 0 if the type deduction succeeds, 1 otherwise. STRICT is the same as in @@ -14792,10 +15071,10 @@ template_parm_level_and_index (tree parm, int* level, int* index) call argument list. We'll need to adjust the arguments to make them types. SUBR tells us if this is from a recursive call to type_unification_real. */ -int +static int unify_pack_expansion (tree tparms, tree targs, tree packed_parms, tree packed_args, int strict, bool call_args_p, - bool subr) + bool subr, struct unification_info *ui) { tree parm = TREE_VEC_ELT (packed_parms, TREE_VEC_LENGTH (packed_parms) - 1); @@ -14885,7 +15164,7 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms, if (resolve_overloaded_unification (tparms, targs, parm, arg, (unification_kind_t) strict, - sub_strict) + sub_strict, ui) != 0) return 1; skip_arg_p = true; @@ -14913,8 +15192,7 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms, /* For deduction from an init-list we need the actual list. */ if (arg_expr && BRACE_ENCLOSED_INITIALIZER_P (arg_expr)) arg = arg_expr; - if (unify (tparms, targs, parm, arg, arg_strict)) - return 1; + RECUR_AND_CHECK_FAILURE (tparms, targs, parm, arg, arg_strict, ui); } } @@ -15008,10 +15286,10 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms, else if (!comp_template_args (ARGUMENT_PACK_ARGS (old_pack), new_args)) /* Inconsistent unification of this parameter pack. */ - return 1; + return unify_parameter_pack_inconsistent (ui, old_pack); } - return 0; + return unify_success (ui); } /* Deduce the value of template parameters. TPARMS is the (innermost) @@ -15056,7 +15334,8 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms, qualified at this point. */ static int -unify (tree tparms, tree targs, tree parm, tree arg, int strict) +unify (tree tparms, tree targs, tree parm, tree arg, int strict, + struct unification_info *ui) { int idx; tree targ; @@ -15071,19 +15350,19 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) parm = TREE_OPERAND (parm, 0); if (arg == error_mark_node) - return 1; + return unify_invalid (ui); if (arg == unknown_type_node || arg == init_list_type_node) /* We can't deduce anything from this, but we might get all the template args from other function args. */ - return 0; + return unify_success (ui); /* If PARM uses template parameters, then we can't bail out here, even if ARG == PARM, since we won't record unifications for the template parameters. We might need them if we're trying to figure out which of two things is more specialized. */ if (arg == parm && !uses_template_parms (parm)) - return 0; + return unify_success (ui); /* Handle init lists early, so the rest of the function can assume we're dealing with a type. */ @@ -15102,7 +15381,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) /* We can only deduce from an initializer list argument if the parameter is std::initializer_list; otherwise this is a non-deduced context. */ - return 0; + return unify_success (ui); elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (parm), 0); @@ -15111,7 +15390,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) int elt_strict = strict; if (elt == error_mark_node) - return 1; + return unify_invalid (ui); if (!BRACE_ENCLOSED_INITIALIZER_P (elt)) { @@ -15123,8 +15402,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) elt = type; } - if (unify (tparms, targs, elttype, elt, elt_strict)) - return 1; + RECUR_AND_CHECK_FAILURE (tparms, targs, elttype, elt, elt_strict, ui); } /* If the std::initializer_list deduction worked, replace the @@ -15136,7 +15414,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) targ = listify (targ); TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = targ; } - return 0; + return unify_success (ui); } /* Immediately reject some pairs that won't unify because of @@ -15153,7 +15431,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) is more specialized, for example. */ && TREE_CODE (arg) != TEMPLATE_TYPE_PARM && !check_cv_quals_for_unify (strict_in, arg, parm)) - return 1; + return unify_cv_qual_mismatch (ui, parm, arg); if (!(strict & UNIFY_ALLOW_OUTER_LEVEL) && TYPE_P (parm) && !CP_TYPE_CONST_P (parm)) @@ -15171,19 +15449,20 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) /* In a type which contains a nested-name-specifier, template argument values cannot be deduced for template parameters used within the nested-name-specifier. */ - return 0; + return unify_success (ui); case TEMPLATE_TYPE_PARM: case TEMPLATE_TEMPLATE_PARM: case BOUND_TEMPLATE_TEMPLATE_PARM: tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0)); if (tparm == error_mark_node) - return 1; + return unify_invalid (ui); if (TEMPLATE_TYPE_LEVEL (parm) != template_decl_level (tparm)) /* The PARM is not one we're trying to unify. Just check to see if it matches ARG. */ + /* FIXME: What to return here? */ return (TREE_CODE (arg) == TREE_CODE (parm) && same_type_p (parm, arg)) ? 0 : 1; idx = TEMPLATE_TYPE_IDX (parm); @@ -15195,7 +15474,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) && TREE_CODE (tparm) != TYPE_DECL) || (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM && TREE_CODE (tparm) != TEMPLATE_DECL)) - return 1; + return unify_parameter_deduction_failure (ui, parm); if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM) { @@ -15203,7 +15482,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) template parameter. */ if (TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM && !CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (arg)) - return 1; + return unify_parameter_deduction_failure (ui, parm); { tree parmvec = TYPE_TI_ARGS (parm); @@ -15247,7 +15526,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) TYPE_TI_TEMPLATE (parm), tf_none, /*require_all_args=*/true, - /*use_default_args=*/false) + /*use_default_args=*/false, ui) == error_mark_node) return 1; @@ -15268,15 +15547,15 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) parm_variadic_p = 1; if (TREE_VEC_LENGTH (argvec) < len - parm_variadic_p) - return 1; + return unify_too_few_parameters (ui, TREE_VEC_LENGTH (argvec), + len); for (i = 0; i < len - parm_variadic_p; ++i) { - if (unify (tparms, targs, - TREE_VEC_ELT (parmvec, i), - TREE_VEC_ELT (argvec, i), - UNIFY_ALLOW_NONE)) - return 1; + RECUR_AND_CHECK_FAILURE (tparms, targs, + TREE_VEC_ELT (parmvec, i), + TREE_VEC_ELT (argvec, i), + UNIFY_ALLOW_NONE, ui); } if (parm_variadic_p @@ -15284,7 +15563,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) parmvec, argvec, UNIFY_ALLOW_NONE, /*call_args_p=*/false, - /*subr=*/false)) + /*subr=*/false, ui)) return 1; } arg = TYPE_TI_TEMPLATE (arg); @@ -15299,9 +15578,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) /* Simple cases: Value already set, does match or doesn't. */ if (targ != NULL_TREE && template_args_equal (targ, arg)) - return 0; + return unify_success (ui); else if (targ) - return 1; + return unify_inconsistency (ui, parm, targ, arg); } else { @@ -15311,20 +15590,20 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) that binds `const int' to `T'. */ if (!check_cv_quals_for_unify (strict_in | UNIFY_ALLOW_LESS_CV_QUAL, arg, parm)) - return 1; + return unify_cv_qual_mismatch (ui, parm, arg); /* Consider the case where ARG is `const volatile int' and PARM is `const T'. Then, T should be `volatile int'. */ arg = cp_build_qualified_type_real (arg, cp_type_quals (arg) & ~cp_type_quals (parm), tf_none); if (arg == error_mark_node) - return 1; + return unify_invalid (ui); /* Simple cases: Value already set, does match or doesn't. */ if (targ != NULL_TREE && same_type_p (targ, arg)) - return 0; + return unify_success (ui); else if (targ) - return 1; + return unify_inconsistency (ui, parm, targ, arg); /* Make sure that ARG is not a variable-sized array. (Note that were talking about variable-sized arrays (like @@ -15334,7 +15613,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) instantiation. Besides, such types are not allowed in ISO C++, so we can do as we please here. */ if (variably_modified_type_p (arg, NULL_TREE)) - return 1; + return unify_vla_arg (ui, parm, arg); /* Strip typedefs as in convert_template_argument. */ arg = strip_typedefs (arg); @@ -15344,22 +15623,22 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) against it unless PARM is also a parameter pack. */ if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg)) && !template_parameter_pack_p (parm)) - return 1; + return unify_parameter_pack_mismatch (ui, parm); /* If the argument deduction results is a METHOD_TYPE, then there is a problem. METHOD_TYPE doesn't map to any real C++ type the result of the deduction can not be of that type. */ if (TREE_CODE (arg) == METHOD_TYPE) - return 1; + return unify_parameter_deduction_failure (ui, parm); TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg; - return 0; + return unify_success (ui); case TEMPLATE_PARM_INDEX: tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0)); if (tparm == error_mark_node) - return 1; + return unify_invalid (ui); if (TEMPLATE_PARM_LEVEL (parm) != template_decl_level (tparm)) @@ -15399,25 +15678,25 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) else if (uses_template_parms (tparm)) /* We haven't deduced the type of this parameter yet. Try again later. */ - return 0; + return unify_success (ui); else - return 1; + return unify_parameter_deduction_failure (ui, parm); /* If ARG is a parameter pack or an expansion, we cannot unify against it unless PARM is also a parameter pack. */ if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg)) && !TEMPLATE_PARM_PARAMETER_PACK (parm)) - return 1; + return unify_parameter_pack_mismatch (ui, parm); TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg; - return 0; + return unify_success (ui); case PTRMEM_CST: { /* A pointer-to-member constant can be unified only with another constant. */ if (TREE_CODE (arg) != PTRMEM_CST) - return 1; + return unify_ptrmem_cst_mismatch (ui, parm, arg); /* Just unify the class member. It would be useless (and possibly wrong, depending on the strict flags) to unify also @@ -15430,13 +15709,13 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) Unification of &A::x and &B::x must succeed. */ return unify (tparms, targs, PTRMEM_CST_MEMBER (parm), - PTRMEM_CST_MEMBER (arg), strict); + PTRMEM_CST_MEMBER (arg), strict, ui); } case POINTER_TYPE: { if (TREE_CODE (arg) != POINTER_TYPE) - return 1; + return unify_type_mismatch (ui, parm, arg); /* [temp.deduct.call] @@ -15454,21 +15733,21 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) strict |= (strict_in & UNIFY_ALLOW_DERIVED); return unify (tparms, targs, TREE_TYPE (parm), - TREE_TYPE (arg), strict); + TREE_TYPE (arg), strict, ui); } case REFERENCE_TYPE: if (TREE_CODE (arg) != REFERENCE_TYPE) - return 1; + return unify_type_mismatch (ui, parm, arg); return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg), - strict & UNIFY_ALLOW_MORE_CV_QUAL); + strict & UNIFY_ALLOW_MORE_CV_QUAL, ui); case ARRAY_TYPE: if (TREE_CODE (arg) != ARRAY_TYPE) - return 1; + return unify_type_mismatch (ui, parm, arg); if ((TYPE_DOMAIN (parm) == NULL_TREE) != (TYPE_DOMAIN (arg) == NULL_TREE)) - return 1; + return unify_type_mismatch (ui, parm, arg); if (TYPE_DOMAIN (parm) != NULL_TREE) { tree parm_max; @@ -15524,11 +15803,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) arg_max, integer_one_node); - if (unify (tparms, targs, parm_max, arg_max, UNIFY_ALLOW_INTEGER)) - return 1; + RECUR_AND_CHECK_FAILURE (tparms, targs, parm_max, arg_max, + UNIFY_ALLOW_INTEGER, ui); } return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg), - strict & UNIFY_ALLOW_MORE_CV_QUAL); + strict & UNIFY_ALLOW_MORE_CV_QUAL, ui); case REAL_TYPE: case COMPLEX_TYPE: @@ -15538,16 +15817,16 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) case ENUMERAL_TYPE: case VOID_TYPE: if (TREE_CODE (arg) != TREE_CODE (parm)) - return 1; + return unify_type_mismatch (ui, parm, arg); /* We have already checked cv-qualification at the top of the function. */ if (!same_type_ignoring_top_level_qualifiers_p (arg, parm)) - return 1; + return unify_type_mismatch (ui, parm, arg); /* As far as unification is concerned, this wins. Later checks will invalidate it if necessary. */ - return 0; + return unify_success (ui); /* Types INTEGER_CST and MINUS_EXPR can come from array bounds. */ /* Type INTEGER_CST can come from ordinary constant template args. */ @@ -15556,8 +15835,10 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) arg = TREE_OPERAND (arg, 0); if (TREE_CODE (arg) != INTEGER_CST) - return 1; - return !tree_int_cst_equal (parm, arg); + return unify_constant_mismatch (ui, parm, arg); + return (tree_int_cst_equal (parm, arg) + ? unify_success (ui) + : unify_constant_unequal (ui, parm, arg)); case TREE_VEC: { @@ -15567,27 +15848,27 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) if (TREE_VEC_LENGTH (parm) != TREE_VEC_LENGTH (arg)) return 1; for (i = 0; i < TREE_VEC_LENGTH (parm); ++i) - if (unify (tparms, targs, - TREE_VEC_ELT (parm, i), TREE_VEC_ELT (arg, i), - UNIFY_ALLOW_NONE)) - return 1; - return 0; + RECUR_AND_CHECK_FAILURE (tparms, targs, + TREE_VEC_ELT (parm, i), + TREE_VEC_ELT (arg, i), + UNIFY_ALLOW_NONE, ui); + return unify_success (ui); } case RECORD_TYPE: case UNION_TYPE: if (TREE_CODE (arg) != TREE_CODE (parm)) - return 1; + return unify_type_mismatch (ui, parm, arg); if (TYPE_PTRMEMFUNC_P (parm)) { if (!TYPE_PTRMEMFUNC_P (arg)) - return 1; + return unify_type_mismatch (ui, parm, arg); return unify (tparms, targs, TYPE_PTRMEMFUNC_FN_TYPE (parm), TYPE_PTRMEMFUNC_FN_TYPE (arg), - strict); + strict, ui); } if (CLASSTYPE_TEMPLATE_INFO (parm)) @@ -15598,7 +15879,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) { /* First, we try to unify the PARM and ARG directly. */ t = try_class_unification (tparms, targs, - parm, arg); + parm, arg, ui); if (!t) { @@ -15611,10 +15892,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) a class of the form template-id, A can be a pointer to a derived class pointed to by the deduced A. */ - t = get_template_base (tparms, targs, parm, arg); + t = get_template_base (tparms, targs, parm, arg, ui); + /* FIXME: Is this clobbering information in UI? */ if (!t) - return 1; + return unify_no_common_base (ui, parm, arg); } } else if (CLASSTYPE_TEMPLATE_INFO (arg) @@ -15625,14 +15907,14 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) t = arg; else /* There's no chance of unification succeeding. */ - return 1; + return unify_parameter_deduction_failure (ui, parm); return unify (tparms, targs, CLASSTYPE_TI_ARGS (parm), - CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE); + CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE, ui); } else if (!same_type_ignoring_top_level_qualifiers_p (parm, arg)) - return 1; - return 0; + return unify_type_mismatch (ui, parm, arg); + return unify_success (ui); case METHOD_TYPE: case FUNCTION_TYPE: @@ -15643,7 +15925,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) unsigned int i; if (TREE_CODE (arg) != TREE_CODE (parm)) - return 1; + return unify_type_mismatch (ui, parm, arg); /* CV qualifications for methods can never be deduced, they must match exactly. We need to check them explicitly here, @@ -15654,11 +15936,10 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) (UNIFY_ALLOW_NONE, class_of_this_parm (arg), class_of_this_parm (parm)))) - return 1; + return unify_cv_qual_mismatch (ui, parm, arg); - if (unify (tparms, targs, TREE_TYPE (parm), - TREE_TYPE (arg), UNIFY_ALLOW_NONE)) - return 1; + RECUR_AND_CHECK_FAILURE (tparms, targs, TREE_TYPE (parm), + TREE_TYPE (arg), UNIFY_ALLOW_NONE, ui); nargs = list_length (TYPE_ARG_TYPES (arg)); args = XALLOCAVEC (tree, nargs); @@ -15670,7 +15951,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm), args, nargs, 1, DEDUCE_EXACT, - LOOKUP_NORMAL); + LOOKUP_NORMAL, ui); } case OFFSET_TYPE: @@ -15683,11 +15964,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) /* Check top-level cv qualifiers */ if (!check_cv_quals_for_unify (UNIFY_ALLOW_NONE, arg, parm)) - return 1; + return unify_cv_qual_mismatch (ui, parm, arg); - if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm), - TYPE_PTRMEMFUNC_OBJECT_TYPE (arg), UNIFY_ALLOW_NONE)) - return 1; + RECUR_AND_CHECK_FAILURE (tparms, targs, TYPE_OFFSET_BASETYPE (parm), + TYPE_PTRMEMFUNC_OBJECT_TYPE (arg), + UNIFY_ALLOW_NONE, ui); /* Determine the type of the function we are unifying against. */ method_type = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (arg)); @@ -15699,28 +15980,28 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) implicit object parameter and place them on the function type to be restored later. */ fntype = apply_memfn_quals (fntype, type_memfn_quals (method_type)); - return unify (tparms, targs, TREE_TYPE (parm), fntype, strict); + return unify (tparms, targs, TREE_TYPE (parm), fntype, strict, ui); } if (TREE_CODE (arg) != OFFSET_TYPE) - return 1; - if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm), - TYPE_OFFSET_BASETYPE (arg), UNIFY_ALLOW_NONE)) - return 1; + return unify_type_mismatch (ui, parm, arg); + RECUR_AND_CHECK_FAILURE (tparms, targs, TYPE_OFFSET_BASETYPE (parm), + TYPE_OFFSET_BASETYPE (arg), + UNIFY_ALLOW_NONE, ui); return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg), - strict); + strict, ui); case CONST_DECL: if (DECL_TEMPLATE_PARM_P (parm)) - return unify (tparms, targs, DECL_INITIAL (parm), arg, strict); + return unify (tparms, targs, DECL_INITIAL (parm), arg, strict, ui); if (arg != integral_constant_value (parm)) - return 1; - return 0; + return unify_constant_mismatch (ui, parm, arg); + return unify_success (ui); case FIELD_DECL: case TEMPLATE_DECL: /* Matched cases are handled by the ARG == PARM test above. */ - return 1; + return unify_parameter_deduction_failure (ui, parm); case VAR_DECL: /* A non-type template parameter that is a variable should be a @@ -15750,7 +16031,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) /* Since there is something following the pack expansion, we cannot unify this template argument list. */ - return 0; + return unify_success (ui); } } @@ -15759,25 +16040,27 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) (not counting the pack expression at the end), or we have too many arguments for a parameter list that doesn't end in a pack expression, we can't unify. */ - if (argslen < (len - parm_variadic_p) - || (argslen > len && !parm_variadic_p)) - return 1; + if (argslen < (len - parm_variadic_p)) + return unify_too_few_parameters (ui, argslen, len); + if (argslen > len && !parm_variadic_p) + return unify_too_many_parameters (ui, argslen, len); /* Unify all of the parameters that precede the (optional) pack expression. */ for (i = 0; i < len - parm_variadic_p; ++i) { - if (unify (tparms, targs, TREE_VEC_ELT (packed_parms, i), - TREE_VEC_ELT (packed_args, i), strict)) - return 1; + RECUR_AND_CHECK_FAILURE (tparms, targs, + TREE_VEC_ELT (packed_parms, i), + TREE_VEC_ELT (packed_args, i), + strict, ui); } if (parm_variadic_p) return unify_pack_expansion (tparms, targs, packed_parms, packed_args, strict, /*call_args_p=*/false, - /*subr=*/false); - return 0; + /*subr=*/false, ui); + return unify_success (ui); } break; @@ -15787,11 +16070,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) case UNDERLYING_TYPE: /* Cannot deduce anything from TYPEOF_TYPE, DECLTYPE_TYPE, or UNDERLYING_TYPE nodes. */ - return 0; + return unify_success (ui); case ERROR_MARK: /* Unification fails if we hit an error node. */ - return 1; + return unify_invalid (ui); default: /* An unresolved overload is a nondeduced context. */ @@ -15820,11 +16103,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) if (!uses_template_parms (parm) && !template_args_equal (parm, arg)) - return 1; + return unify_expression_unequal (ui, parm, arg); else - return 0; + return unify_success (ui); } } +#undef RECUR_AND_CHECK_FAILURE /* Note that DECL can be defined in this translation unit, if required. */ @@ -16087,10 +16371,11 @@ more_specialized_fn (tree pat1, tree pat2, int len) for (i = 0; i < len2; i++, ta = TREE_CHAIN (ta)) TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta); - deduce1 = !unify_pack_expansion (tparms1, targs1, parmvec, + deduce1 = (unify_pack_expansion (tparms1, targs1, parmvec, argvec, UNIFY_ALLOW_NONE, /*call_args_p=*/false, - /*subr=*/0); + /*subr=*/0, NULL) + == 0); /* We cannot deduce in the other direction, because ARG1 is a pack expansion but ARG2 is not. */ @@ -16111,10 +16396,11 @@ more_specialized_fn (tree pat1, tree pat2, int len) for (i = 0; i < len1; i++, ta = TREE_CHAIN (ta)) TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta); - deduce2 = !unify_pack_expansion (tparms2, targs2, parmvec, + deduce2 = (unify_pack_expansion (tparms2, targs2, parmvec, argvec, UNIFY_ALLOW_NONE, /*call_args_p=*/false, - /*subr=*/0); + /*subr=*/0, NULL) + == 0); /* We cannot deduce in the other direction, because ARG2 is a pack expansion but ARG1 is not.*/ @@ -16125,8 +16411,12 @@ more_specialized_fn (tree pat1, tree pat2, int len) { /* The normal case, where neither argument is a pack expansion. */ - deduce1 = !unify (tparms1, targs1, arg1, arg2, UNIFY_ALLOW_NONE); - deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE); + deduce1 = (unify (tparms1, targs1, arg1, arg2, + UNIFY_ALLOW_NONE, NULL) + == 0); + deduce2 = (unify (tparms2, targs2, arg2, arg1, + UNIFY_ALLOW_NONE, NULL) + == 0); } /* If we couldn't deduce arguments for tparms1 to make arg1 match @@ -16316,7 +16606,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype) explicit_args, NULL_TREE, tf_none, /*require_all_args=*/false, - /*use_default_args=*/false); + /*use_default_args=*/false, NULL); if (converted_args == error_mark_node) return NULL_TREE; @@ -16340,7 +16630,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype) args, ix, (check_rettype || DECL_CONV_FN_P (fn) ? TREE_TYPE (decl_type) : NULL_TREE), - DEDUCE_EXACT, LOOKUP_NORMAL)) + DEDUCE_EXACT, LOOKUP_NORMAL, NULL)) return NULL_TREE; return targs; @@ -16382,7 +16672,7 @@ get_class_bindings (tree tparms, tree spec_args, tree args) if (unify (tparms, deduced_args, INNERMOST_TEMPLATE_ARGS (spec_args), INNERMOST_TEMPLATE_ARGS (args), - UNIFY_ALLOW_NONE)) + UNIFY_ALLOW_NONE, NULL)) return NULL_TREE; for (i = 0; i < ntparms; ++i) @@ -16619,7 +16909,7 @@ most_specialized_class (tree type, tree tmpl, tsubst_flags_t complain) partial_spec_args), tmpl, tf_none, /*require_all_args=*/true, - /*use_default_args=*/true); + /*use_default_args=*/true, NULL); --processing_template_decl; @@ -19110,8 +19400,10 @@ do_auto_deduction (tree type, tree init, tree auto_node) targs = make_tree_vec (1); TREE_VEC_ELT (tparms, 0) = build_tree_list (NULL_TREE, TYPE_NAME (auto_node)); + /* FIXME: Should we pass in unification information and then use that + to elaborate on the error messages below? */ val = type_unification_real (tparms, targs, parms, args, 1, 0, - DEDUCE_CALL, LOOKUP_NORMAL); + DEDUCE_CALL, LOOKUP_NORMAL, NULL); if (val > 0) { if (type && type != error_mark_node) diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31434.C b/gcc/testsuite/g++.dg/cpp0x/pr31434.C index 97ad079..231c027 100644 --- a/gcc/testsuite/g++.dg/cpp0x/pr31434.C +++ b/gcc/testsuite/g++.dg/cpp0x/pr31434.C @@ -1,5 +1,6 @@ // { dg-options "-std=gnu++0x" } template int foo(const T&) // { dg-error "not expanded with|T" } +// { dg-message "cannot convert" "overload failure" { target *-*-* } 2 } { union { T t; }; // { dg-error "not expanded with|T" } return t; @@ -8,5 +9,5 @@ template int foo(const T&) // { dg-error "not expanded with|T" } void bar() { foo(0); // { dg-error "no matching" } - // { dg-message "candidate" "candidate note" { target *-*-* } 10 } + // { dg-message "candidate" "candidate note" { target *-*-* } 11 } } diff --git a/gcc/testsuite/g++.dg/overload/template5.C b/gcc/testsuite/g++.dg/overload/template5.C new file mode 100644 index 0000000..5bde8b4 --- /dev/null +++ b/gcc/testsuite/g++.dg/overload/template5.C @@ -0,0 +1,17 @@ +// { dg-do compile } + +template +int low(T a, T b, T c) { return a + b + c; } // { dg-message "template" } +// { dg-message "expects 3 arguments, 2 provided" "arity" { target *-*-* } 4 } + +template +int high(T a, T b, T c) { return a + b + c; } // { dg-message "template" } +// { dg-message "expects 3 arguments, 4 provided" "arity" { target *-*-* } 8 } + +int test (void) +{ + low (5, 6); // { dg-error "no matching function" } + // { dg-message "candidate" "" { target *-*-* } 13 } + high (5, 6, 7, 8); // { dg-error "no matching function" } + // { dg-message "candidate" "" { target *-*-* } 15 } +} diff --git a/gcc/testsuite/g++.dg/template/overload12.C b/gcc/testsuite/g++.dg/template/overload12.C new file mode 100644 index 0000000..d21f5f4 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/overload12.C @@ -0,0 +1,19 @@ +// { dg-do compile } + +struct S {int x; int y;}; +template +int foo(T a, T b) {return a + b;} // { dg-message "template" } +// { dg-message "deduced conflicting types for parameter" "deduction" { target *-*-* } 5 } +template +int foo(T a, T2& b, T2 c) {return a + b;} // { dg-message "template" } +// { dg-message "deduced conflicting types for parameter" "deduction" { target *-*-* } 8 } +int foo(char*, S&); // { dg-message "foo" } +// { dg-message "candidate expects 2 arguments, 3 provided" "arity" { target *-*-* } 10 } + +int foo2(int x) +{ + S s={1,2}; + char c; + foo(c, 2, c); // { dg-error "no matching function" } + // { dg-message "candidate" "candidate note" { target *-*-* } 17 } +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C index 560370a..56d9b44 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C @@ -1,10 +1,11 @@ // { dg-do assemble } template -void f(int i); // { dg-message "note" } +void f(int i); // { dg-message "void f" } +// { dg-message "invalid explicit argument for template parameter 'I'" "argument note" { target *-*-* } 3 } void g() { int i; f(7); // { dg-error "" } template argument 1 is invalid. - // { dg-message "candidate" "candidate note" { target *-*-* } 8 } + // { dg-message "candidate" "candidate note" { target *-*-* } 9 } } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C index 85d3e73..8933038 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C @@ -13,30 +13,32 @@ public: }; template -void g() {} // { dg-message "note" } +void g() {} // { dg-message "void g" } +// { dg-message "invalid explicit argument for template parameter 1" "info" { target *-*-* } 16 } template -void h() {} // { dg-message "note" } +void h() {} // { dg-message "void h" } +// { dg-message "invalid explicit argument for template parameter 1" "info" { target *-*-* } 19 } int main() { g<&A::f>(); h<&A::i>(); g<&B::f>(); // { dg-error "" } - // { dg-message "candidate" "candidate note" { target *-*-* } 24 } - h<&B::j>(); // { dg-error "" } // { dg-message "candidate" "candidate note" { target *-*-* } 26 } - g<(void (A::*)()) &A::f>(); // { dg-error "" } + h<&B::j>(); // { dg-error "" } // { dg-message "candidate" "candidate note" { target *-*-* } 28 } - h<(int A::*) &A::i>(); // { dg-error "" } + g<(void (A::*)()) &A::f>(); // { dg-error "" } // { dg-message "candidate" "candidate note" { target *-*-* } 30 } - g<(void (A::*)()) &B::f>(); // { dg-error "" } + h<(int A::*) &A::i>(); // { dg-error "" } // { dg-message "candidate" "candidate note" { target *-*-* } 32 } - h<(int A::*) &B::j>(); // { dg-error "" } + g<(void (A::*)()) &B::f>(); // { dg-error "" } // { dg-message "candidate" "candidate note" { target *-*-* } 34 } - g<(void (A::*)()) 0>(); // { dg-error "" } + h<(int A::*) &B::j>(); // { dg-error "" } // { dg-message "candidate" "candidate note" { target *-*-* } 36 } - h<(int A::*) 0>(); // { dg-error "" } + g<(void (A::*)()) 0>(); // { dg-error "" } // { dg-message "candidate" "candidate note" { target *-*-* } 38 } + h<(int A::*) 0>(); // { dg-error "" } + // { dg-message "candidate" "candidate note" { target *-*-* } 40 } return 0; }