From patchwork Wed May 25 18:15:32 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nathan Froyd X-Patchwork-Id: 97395 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 A5D2EB6F97 for ; Thu, 26 May 2011 04:16:24 +1000 (EST) Received: (qmail 14976 invoked by alias); 25 May 2011 18:16:23 -0000 Received: (qmail 14957 invoked by uid 22791); 25 May 2011 18:16:15 -0000 X-SWARE-Spam-Status: No, hits=-0.7 required=5.0 tests=AWL, BAYES_40, TW_CP, 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; Wed, 25 May 2011 18:15:53 +0000 Received: (qmail 18693 invoked from network); 25 May 2011 18:15:36 -0000 Received: from unknown (HELO codesourcery.com) (froydnj@127.0.0.2) by mail.codesourcery.com with ESMTPA; 25 May 2011 18:15:36 -0000 Date: Wed, 25 May 2011 14:15:32 -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: <20110525181526.GA17555@nightcrawler> References: <20110509224933.GR23480@codesourcery.com> <4DC99B34.7070301@redhat.com> <20110516173938.GA779@nightcrawler> <4DD405D0.4090108@redhat.com> <4DD41733.2020501@codesourcery.com> <4DD42299.2000206@redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <4DD42299.2000206@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 Wed, May 18, 2011 at 03:48:41PM -0400, Jason Merrill wrote: > On 05/18/2011 03:00 PM, Nathan Froyd wrote: > >Thank you for the review. I'll go back and try things the way you suggest; > >before I go off and do that, I've taken your comments to mean that: > > > >- fn_type_unification/type_unification_real and associated callers should take > > a boolean `explain' parameter, which is normally false; > > > >- failed calls to fn_type_unification should save the arguments for the call > > for future explanation; > > > >- printing diagnostic messages should call fn_type_unification with the saved > > arguments and a true `explain' parameter. > > Yes, that's what I had in mind. Though I think you can reconstruct > the arguments rather than save them. The patch below implements just such an idea. The only twist is that the `explain' parameter is actually a `location_t *' so that when we provide explanations that aren't produced via tf_warning_or_error blocks, the explanations are attached to the template itself rather than the call, as would be done with input_location. Requests for non-explanation are accomplished with a NULL argument. I'm not totally attached to this; it's almost too cute, and since tf_warning_or_error messsages tend to be attached to the call anyway, it's arguably inconsistent. I didn't see what you intended by "reconstructing" the arguments, so I implemented the more straightforward saving. The testsuite needs a little more fixing up, though surprisingly not as much as you might think. The oddest result is the change to variadic105.C, where we now output a sorry during overload explanation. But if I understand the test correctly, that is the expected result currently. The patch does not totally address PR 48934; we are not explaining ourselves in all cases. I plan to hunt this down in a followup patch and attempt to say something intelligent. Tested on x86_64-unknown-linux-gnu. OK to commit? -Nathan gcc/cp/ PR c++/45329 PR c++/48934 * cp-tree.h (fn_type_unification): Add `location_t *' parameter. * pt.c (enum template_base_result): Define. (unify_success, unify_unknown): Define. (unify_parameter_deduction_failure): Define. (unify_invalid, 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_method_type_error, unify_arity): Likewise. (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_inconsistent_template_template_parameters): Define. (unify_template_deduction_failure): Define. (unify_template_parameter_mismatch): Define. (unify_template_argument_mismatch): Define. (deduction_tsubst_fntype): Add `complain' parameter'. Pass it to tsubst. (unify): Add `explain_p' parameter. Pass to all relevant calls. Call above status functions when appropriate. (resolve_overloaded_unification, try_one_overload): Likewise. (type_unification, type_unification_real): 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. (convert_nontype_argument): Likewise. (fn_type_unification): Likewise. Rerun functions for diagnostics if necessary. (get_template_base): Add `explain_p' parameter and pass it to try_class_unification. Return an enum template_base_result. * class.c (resolve_address_of_overloaded_function): Pass NULL to fn_type_unification. * call.c (enum rejection_reason_code): Add new codes. (struct rejection_reason): Add template_unification field. Add template_instantiation field. (template_unification_rejection): Define. (template_instantiation_rejection): Define. (invalid_copy_with_fn_template_rejection): Define. (add_template_candidate): Pass NULL 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/lambda/lambda-ice2.C: Adjust. * g++.dg/cpp0x/pr31434.C: Adjust. * g++.dg/cpp0x/sfinae11.C: Adjust. * g++.dg/cpp0x/variadic105.C: Adjust. * g++.dg/other/ptrmem10.C: Adjust. * g++.dg/other/ptrmem11.C: Adjust. * g++.dg/template/incomplete2.C: Adjust. * g++.dg/template/local4.C: Adjust. * g++.dg/template/unify11.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 ff3dc06..9888261 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,24 @@ struct rejection_reason { struct conversion_info conversion; /* Same, but for bad argument conversions. */ struct conversion_info bad_conversion; + /* Information about template unification failures. These are the + parameters passed to fn_type_unification. */ + struct { + tree tmpl; + tree explicit_targs; + tree targs; + const tree *args; + unsigned int nargs; + tree return_type; + unification_kind_t strict; + int flags; + } template_unification; + /* Information about template instantiation failures. These are the + parameters passed to instantiate_template. */ + struct { + tree tmpl; + tree targs; + } template_instantiation; } u; }; @@ -607,6 +628,44 @@ bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to) return r; } +static struct rejection_reason * +template_unification_rejection (tree tmpl, tree explicit_targs, tree targs, + const tree *args, unsigned int nargs, + tree return_type, unification_kind_t strict, + int flags) +{ + size_t args_n_bytes = sizeof (*args) * nargs; + tree *args1 = (tree *) conversion_obstack_alloc (args_n_bytes); + struct rejection_reason *r = alloc_rejection (rr_template_unification); + r->u.template_unification.tmpl = tmpl; + r->u.template_unification.explicit_targs = explicit_targs; + r->u.template_unification.targs = targs; + /* Copy args to our own storage. */ + memcpy (args1, args, args_n_bytes); + r->u.template_unification.args = args1; + r->u.template_unification.nargs = nargs; + r->u.template_unification.return_type = return_type; + r->u.template_unification.strict = strict; + r->u.template_unification.flags = flags; + return r; +} + +static struct rejection_reason * +template_instantiation_rejection (tree tmpl, tree targs) +{ + struct rejection_reason *r = alloc_rejection (rr_template_instantiation); + r->u.template_instantiation.tmpl = tmpl; + r->u.template_instantiation.targs = targs; + 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 * @@ -2889,14 +2948,23 @@ 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, NULL); if (i != 0) - goto fail; + { + reason = template_unification_rejection (tmpl, explicit_targs, + targs, args_without_in_chrg, + nargs_without_in_chrg, + return_type, strict, flags); + goto fail; + } fn = instantiate_template (tmpl, targs, tf_none); if (fn == error_mark_node) - goto fail; + { + reason = template_instantiation_rejection (tmpl, targs); + goto fail; + } /* In [class.copy]: @@ -2925,7 +2993,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) @@ -3093,6 +3164,18 @@ 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 one overload candidate CANDIDATE. MSGSTR is the text to print before the candidate itself. @@ -3139,10 +3222,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); @@ -3150,6 +3231,29 @@ 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: + /* Re-run template unification with diagnostics. */ + fn_type_unification (r->u.template_unification.tmpl, + r->u.template_unification.explicit_targs, + r->u.template_unification.targs, + r->u.template_unification.args, + r->u.template_unification.nargs, + r->u.template_unification.return_type, + r->u.template_unification.strict, + r->u.template_unification.flags, + &loc); + break; + case rr_template_instantiation: + /* Re-run template instantiation with diagnostics. */ + instantiate_template (r->u.template_instantiation.tmpl, + r->u.template_instantiation.targs, + tf_warning_or_error); + break; + case rr_invalid_copy: + inform (loc, + " a constructor taking a single argument of its own " + "class type is invalid"); + 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 4e52b18..d0d3363 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -6527,7 +6527,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 ada01fb..d900d99 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5129,7 +5129,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, + location_t *); 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 dbff91e..add205e 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -109,13 +109,20 @@ static GTY(()) VEC(tree,gc) *canonical_template_parms; #define UNIFY_ALLOW_OUTER_MORE_CV_QUAL 32 #define UNIFY_ALLOW_OUTER_LESS_CV_QUAL 64 +enum template_base_result { + tbr_incomplete_type, + tbr_ambiguous_baseclass, + tbr_success +}; + 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, + location_t *); 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, location_t *); +static int unify (tree, tree, tree, tree, int, location_t *); static void add_pending_template (tree); static tree reopen_tinst_level (struct tinst_level *); static tree tsubst_initializer_list (tree, tree); @@ -129,7 +136,8 @@ 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, + location_t *); static void note_template_header (int); static tree convert_nontype_argument_function (tree, tree); static tree convert_nontype_argument (tree, tree, tsubst_flags_t); @@ -154,7 +162,8 @@ 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, location_t *); 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 +175,9 @@ 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 enum template_base_result get_template_base (tree, tree, tree, tree, + location_t *, tree *); +static tree try_class_unification (tree, tree, tree, tree, location_t *); 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,233 @@ has_value_dependent_address (tree op) return false; } +/* The next set of functions are used for providing helpful explanatory + diagnostics for failed overload resolution. Their messages should be + indented by two spaces for consistency with the messages in + call.c */ + +static int +unify_success (location_t *explain_p ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int +unify_unknown (location_t *explain_p ATTRIBUTE_UNUSED) +{ + return 1; +} + +static int +unify_parameter_deduction_failure (location_t *explain_p, tree parm) +{ + if (explain_p) + inform (*explain_p, + " couldn't deduce template parameter %qD", parm); + return 1; +} + +static int +unify_invalid (location_t *explain_p ATTRIBUTE_UNUSED) +{ + return 1; +} + +static int +unify_cv_qual_mismatch (location_t *explain_p, tree parm, tree arg) +{ + if (explain_p) + inform (*explain_p, + " types %qT and %qT have incompatible cv-qualifiers", + parm, arg); + return 1; +} + +static int +unify_type_mismatch (location_t *explain_p, tree parm, tree arg) +{ + if (explain_p) + inform (*explain_p, " mismatched types %qT and %qT", parm, arg); + return 1; +} + +static int +unify_parameter_pack_mismatch (location_t *explain_p, tree parm) +{ + if (explain_p) + { + inform (*explain_p, + " template parameter %qD is not a parameter pack", + parm); + inform (*explain_p, " please report this as a bug"); + gcc_unreachable (); + } + return 1; +} + +static int +unify_ptrmem_cst_mismatch (location_t *explain_p, tree parm, tree arg) +{ + if (explain_p) + inform (*explain_p, + " mismatched pointer-to-memory constants %qE and %qE", + parm, arg); + return 1; +} + +static int +unify_constant_mismatch (location_t *explain_p, tree parm, tree arg) +{ + if (explain_p) + inform (*explain_p, " %qE is a constant and %qE is not", + parm, arg); + return 1; +} + +static int +unify_constant_unequal (location_t *explain_p, tree parm, tree arg) +{ + if (explain_p) + inform (*explain_p, " %qE is not equal to %qE", parm, arg); + return 1; +} + +static int +unify_expression_unequal (location_t *explain_p, tree parm, tree arg) +{ + if (explain_p) + inform (*explain_p, " %qE is not equal to %qE", parm, arg); + return 1; +} + +static int +unify_parameter_pack_inconsistent (location_t *explain_p, + tree pack) +{ + if (explain_p) + inform (*explain_p, + " portions of parameter pack %qT could not be deduced", + pack); + return 1; +} + +static int +unify_inconsistency (location_t *explain_p, tree parm, tree first, tree second) +{ + if (explain_p) + inform (*explain_p, + " deduced conflicting types for parameter %qT (%qT and %qT)", + parm, first, second); + return 1; +} + +static int +unify_vla_arg (location_t *explain_p, tree arg) +{ + if (explain_p) + inform (*explain_p, + " variable-sized array type %qT is not " + "a valid template argument", + arg); + return 1; +} + +static int +unify_method_type_error (location_t *explain_p, tree arg) +{ + if (explain_p) + inform (*explain_p, + " method type %qT is not a valid template argument", arg); + return 1; +} + +static int +unify_arity (location_t *explain_p, int have, int wanted) +{ + if (explain_p) + inform_n (*explain_p, wanted, + " candidate expects %d argument, %d provided", + " candidate expects %d arguments, %d provided", + wanted, have); + return 1; +} + +static int +unify_too_many_parameters (location_t *explain_p, int have, int wanted) +{ + return unify_arity (explain_p, have, wanted); +} + +static int +unify_too_few_parameters (location_t *explain_p, int have, int wanted) +{ + return unify_arity (explain_p, have, wanted); +} + +static int +unify_arg_conversion (location_t *explain_p, tree to_type, + tree from_type, tree arg) +{ + if (explain_p) + inform (*explain_p, " cannot convert %qE (type %qT) to type %qT", + arg, from_type, to_type); + return 1; +} + +static int +unify_no_common_base (location_t *explain_p, enum template_base_result r, + tree parm, tree arg) +{ + if (explain_p) + switch (r) + { + case tbr_ambiguous_baseclass: + inform (*explain_p, " %qT is an ambiguous base class of %qT", + arg, parm); + break; + default: + inform (*explain_p, " %qT is not derived from %qT", arg, parm); + break; + } + return 1; +} + +static int +unify_inconsistent_template_template_parameters (location_t *explain_p) +{ + if (explain_p) + inform (*explain_p, " inconsistent template template parameters"); + return 1; +} + +static int +unify_template_deduction_failure (location_t *explain_p, tree parm, tree arg) +{ + if (explain_p) + inform (*explain_p, + " can't deduce a template for %qT from non-template type %qT", + parm, arg); + return 1; +} + +static int +unify_template_parameter_mismatch (location_t *explain_p, tree parm, tree tparm) +{ + if (explain_p) + inform (*explain_p, + " template parameter %qT does not match %qD", tparm, parm); + return 1; +} + +static int +unify_template_argument_mismatch (location_t *explain_p, tree parm, tree arg) +{ + if (explain_p) + inform (*explain_p, + " template argument %qE does not match %qD", arg, parm); + 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 @@ -13600,7 +13837,7 @@ static GTY((param_is (spec_entry))) htab_t current_deduction_htab; 0.5% of compile time. */ static tree -deduction_tsubst_fntype (tree fn, tree targs) +deduction_tsubst_fntype (tree fn, tree targs, tsubst_flags_t complain) { unsigned i; spec_entry **slot; @@ -13670,7 +13907,7 @@ deduction_tsubst_fntype (tree fn, tree targs) VEC_safe_push (spec_entry, gc, current_deduction_vec, &elt); } - r = tsubst (fntype, targs, tf_none, NULL_TREE); + r = tsubst (fntype, targs, complain, NULL_TREE); /* After doing the substitution, make sure we didn't hit it again. Note that we might have switched to a hash table during tsubst. */ @@ -13859,7 +14096,8 @@ fn_type_unification (tree fn, unsigned int nargs, tree return_type, unification_kind_t strict, - int flags) + int flags, + location_t *explain_p) { tree parms; tree fntype; @@ -13894,14 +14132,22 @@ fn_type_unification (tree fn, bool incomplete = false; if (explicit_targs == error_mark_node) - return 1; + return unify_invalid (explain_p); converted_args = (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none, /*require_all_args=*/false, /*use_default_args=*/false)); if (converted_args == error_mark_node) - return 1; + { + /* Run it for diagnostics. */ + if (explain_p) + coerce_template_parms (tparms, explicit_targs, NULL_TREE, + tf_warning_or_error, + /*require_all_args=*/false, + /*use_default_args=*/false); + return 1; + } /* Substitute the explicit args into the function type. This is necessary so that, for instance, explicitly declared function @@ -13958,11 +14204,20 @@ fn_type_unification (tree fn, incomplete = NUM_TMPL_ARGS (explicit_targs) != NUM_TMPL_ARGS (targs); processing_template_decl += incomplete; - fntype = deduction_tsubst_fntype (fn, converted_args); + fntype = deduction_tsubst_fntype (fn, converted_args, tf_none); processing_template_decl -= incomplete; if (fntype == error_mark_node) - return 1; + { + if (explain_p) + { + processing_template_decl += incomplete; + fntype = deduction_tsubst_fntype (fn, converted_args, + tf_warning_or_error); + processing_template_decl -= incomplete; + } + return 1; + } /* Place the explicitly specified arguments in TARGS. */ for (i = NUM_TMPL_ARGS (converted_args); i--;) @@ -13990,7 +14245,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, explain_p); /* Now that we have bindings for all of the template arguments, ensure that the arguments deduced for the template template @@ -14016,7 +14271,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 (explain_p); if (result == 0) /* All is well so far. Now, check: @@ -14029,9 +14284,13 @@ fn_type_unification (tree fn, substitution results in an invalid type, as described above, type deduction fails. */ { - tree substed = deduction_tsubst_fntype (fn, targs); + tree substed = deduction_tsubst_fntype (fn, targs, tf_none); if (substed == error_mark_node) - return 1; + { + if (explain_p) + deduction_tsubst_fntype (fn, targs, tf_warning_or_error); + return 1; + } /* 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 @@ -14046,7 +14305,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 (explain_p); } } @@ -14177,7 +14436,8 @@ type_unification_real (tree tparms, unsigned int xnargs, int subr, unification_kind_t strict, - int flags) + int flags, + location_t *explain_p) { tree parm, arg, arg_expr; int i; @@ -14235,7 +14495,7 @@ type_unification_real (tree tparms, arg_expr = NULL; if (arg == error_mark_node) - return 1; + return unify_invalid (explain_p); if (arg == unknown_type_node) /* We can't deduce anything from this, but we might get all the template args from other function args. */ @@ -14261,7 +14521,7 @@ type_unification_real (tree tparms, flags)) continue; - return 1; + return unify_arg_conversion (explain_p, parm, type, arg); } if (!TYPE_P (arg)) @@ -14277,15 +14537,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, explain_p)) continue; - return 1; + return unify_unknown (explain_p); } arg_expr = arg; arg = unlowered_expr_type (arg); if (arg == error_mark_node) - return 1; + return unify_invalid (explain_p); } { @@ -14297,7 +14557,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, explain_p)) + /* If unification failed, the recursive call will have updated + UI appropriately. */ return 1; } } @@ -14319,7 +14581,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, explain_p)) return 1; /* Advance to the end of the list of parameters. */ @@ -14329,11 +14591,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 (explain_p, 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 (explain_p, ia, count); + } if (!subr) { @@ -14391,7 +14662,14 @@ type_unification_real (tree tparms, arg = convert_template_argument (parm, arg, targs, tf_none, i, NULL_TREE); if (arg == error_mark_node) - return 1; + { + /* Give the user an informative error message. */ + if (explain_p) + convert_template_argument (parm, arg, targs, + tf_warning_or_error, + i, NULL_TREE); + return 1; + } else { TREE_VEC_ELT (targs, i) = arg; @@ -14425,7 +14703,7 @@ type_unification_real (tree tparms, continue; } - return 2; + return unify_parameter_deduction_failure (explain_p, tparm); } } #ifdef ENABLE_CHECKING @@ -14433,7 +14711,7 @@ type_unification_real (tree tparms, SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, TREE_VEC_LENGTH (targs)); #endif - return 0; + return unify_success (explain_p); } /* Subroutine of type_unification_real. Args are like the variables @@ -14448,7 +14726,8 @@ resolve_overloaded_unification (tree tparms, tree parm, tree arg, unification_kind_t strict, - int sub_strict) + int sub_strict, + location_t *explain_p) { tree tempargs = copy_node (targs); int good = 0; @@ -14499,7 +14778,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, explain_p) && (!goodfn || !decls_match (goodfn, elem))) { goodfn = elem; @@ -14519,7 +14798,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, explain_p) && (!goodfn || !decls_match (goodfn, OVL_CURRENT (arg)))) { goodfn = OVL_CURRENT (arg); @@ -14665,7 +14944,8 @@ try_one_overload (tree tparms, tree arg, unification_kind_t strict, int sub_strict, - bool addr_p) + bool addr_p, + location_t *explain_p) { int nargs; tree tempargs; @@ -14695,7 +14975,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, explain_p)) return 0; /* First make sure we didn't deduce anything that conflicts with @@ -14733,7 +15013,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, + location_t *explain_p) { tree copy_of_targs; @@ -14776,7 +15057,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, explain_p)) return NULL_TREE; return arg; @@ -14789,8 +15070,9 @@ try_class_unification (tree tparms, tree targs, tree parm, tree arg) a partial specialization, as well as a plain template type. Used by unify. */ -static tree -get_template_base (tree tparms, tree targs, tree parm, tree arg) +static enum template_base_result +get_template_base (tree tparms, tree targs, tree parm, tree arg, + location_t *explain_p, tree *result) { tree rval = NULL_TREE; tree binfo; @@ -14799,14 +15081,18 @@ get_template_base (tree tparms, tree targs, tree parm, tree arg) binfo = TYPE_BINFO (complete_type (arg)); if (!binfo) - /* The type could not be completed. */ - return NULL_TREE; + { + /* The type could not be completed. */ + *result = NULL_TREE; + return tbr_incomplete_type; + } /* Walk in inheritance graph order. The search order is not 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), explain_p); if (r) { @@ -14819,13 +15105,17 @@ get_template_base (tree tparms, tree targs, tree parm, tree arg) applies. */ if (rval && !same_type_p (r, rval)) - return NULL_TREE; + { + *result = NULL_TREE; + return tbr_ambiguous_baseclass; + } rval = r; } } - return rval; + *result = rval; + return tbr_success; } /* Returns the level of DECL, which declares a template parameter. */ @@ -14907,6 +15197,12 @@ template_parm_level_and_index (tree parm, int* level, int* index) } } +#define RECUR_AND_CHECK_FAILURE(TP, TA, P, A, S, EP) \ + do { \ + if (unify (TP, TA, P, A, S, EP)) \ + 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 @@ -14914,10 +15210,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, location_t *explain_p) { tree parm = TREE_VEC_ELT (packed_parms, TREE_VEC_LENGTH (packed_parms) - 1); @@ -15007,7 +15303,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, explain_p) != 0) return 1; skip_arg_p = true; @@ -15035,8 +15331,8 @@ 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, + explain_p); } } @@ -15130,10 +15426,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 (explain_p, old_pack); } - return 0; + return unify_success (explain_p); } /* Deduce the value of template parameters. TPARMS is the (innermost) @@ -15178,7 +15474,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, + location_t *explain_p) { int idx; tree targ; @@ -15193,19 +15490,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 (explain_p); 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 (explain_p); /* 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 (explain_p); /* Handle init lists early, so the rest of the function can assume we're dealing with a type. */ @@ -15224,7 +15521,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 (explain_p); elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (parm), 0); @@ -15233,7 +15530,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 (explain_p); if (!BRACE_ENCLOSED_INITIALIZER_P (elt)) { @@ -15245,8 +15542,8 @@ 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, + explain_p); } /* If the std::initializer_list deduction worked, replace the @@ -15258,7 +15555,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 (explain_p); } /* Immediately reject some pairs that won't unify because of @@ -15275,7 +15572,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 (explain_p, parm, arg); if (!(strict & UNIFY_ALLOW_OUTER_LEVEL) && TYPE_P (parm) && !CP_TYPE_CONST_P (parm)) @@ -15293,21 +15590,26 @@ 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 (explain_p); 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 (explain_p); 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. */ - return (TREE_CODE (arg) == TREE_CODE (parm) - && same_type_p (parm, arg)) ? 0 : 1; + { + if (TREE_CODE (arg) == TREE_CODE (parm) + && same_type_p (parm, arg)) + return unify_success (explain_p); + else + return unify_type_mismatch (explain_p, parm, arg); + } idx = TEMPLATE_TYPE_IDX (parm); targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx); tparm = TREE_VALUE (TREE_VEC_ELT (tparms, idx)); @@ -15317,7 +15619,8 @@ 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_template_parameter_mismatch (explain_p, + parm, tparm); if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM) { @@ -15325,7 +15628,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_template_deduction_failure (explain_p, parm, arg); { tree parmvec = TYPE_TI_ARGS (parm); @@ -15371,7 +15674,16 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) /*require_all_args=*/true, /*use_default_args=*/false) == error_mark_node) - return 1; + { + /* Run it for diagnostics. */ + if (explain_p) + coerce_template_parms (parm_parms, full_argvec, + TYPE_TI_TEMPLATE (parm), + tf_warning_or_error, + /*require_all_args=*/true, + /*use_default_args=*/false); + return 1; + } /* Deduce arguments T, i from TT or TT. We check each element of PARMVEC and ARGVEC individually @@ -15390,15 +15702,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 (explain_p, 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, explain_p); } if (parm_variadic_p @@ -15406,7 +15718,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, explain_p)) return 1; } arg = TYPE_TI_TEMPLATE (arg); @@ -15421,9 +15733,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 (explain_p); else if (targ) - return 1; + return unify_inconsistency (explain_p, parm, targ, arg); } else { @@ -15433,20 +15745,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 (explain_p, 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 (explain_p); /* Simple cases: Value already set, does match or doesn't. */ if (targ != NULL_TREE && same_type_p (targ, arg)) - return 0; + return unify_success (explain_p); else if (targ) - return 1; + return unify_inconsistency (explain_p, parm, targ, arg); /* Make sure that ARG is not a variable-sized array. (Note that were talking about variable-sized arrays (like @@ -15456,7 +15768,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 (explain_p, arg); /* Strip typedefs as in convert_template_argument. */ arg = strip_typedefs (arg); @@ -15466,35 +15778,45 @@ 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 (explain_p, 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_method_type_error (explain_p, arg); TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg; - return 0; + return unify_success (explain_p); case TEMPLATE_PARM_INDEX: tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0)); if (tparm == error_mark_node) - return 1; + return unify_invalid (explain_p); if (TEMPLATE_PARM_LEVEL (parm) != template_decl_level (tparm)) - /* The PARM is not one we're trying to unify. Just check - to see if it matches ARG. */ - return !(TREE_CODE (arg) == TREE_CODE (parm) - && cp_tree_equal (parm, arg)); + { + /* The PARM is not one we're trying to unify. Just check + to see if it matches ARG. */ + int result = !(TREE_CODE (arg) == TREE_CODE (parm) + && cp_tree_equal (parm, arg)); + if (result) + unify_template_parameter_mismatch (explain_p, parm, tparm); + return result; + } idx = TEMPLATE_PARM_IDX (parm); targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx); if (targ) - return !cp_tree_equal (targ, arg); + { + int x = !cp_tree_equal (targ, arg); + if (x) + unify_inconsistency (explain_p, parm, targ, arg); + return x; + } /* [temp.deduct.type] If, in the declaration of a function template with a non-type template-parameter, the non-type @@ -15521,25 +15843,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 (explain_p); else - return 1; + return unify_type_mismatch (explain_p, tparm, arg); /* 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 (explain_p, parm); TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg; - return 0; + return unify_success (explain_p); 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 (explain_p, parm, arg); /* Just unify the class member. It would be useless (and possibly wrong, depending on the strict flags) to unify also @@ -15552,13 +15874,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, explain_p); } case POINTER_TYPE: { if (TREE_CODE (arg) != POINTER_TYPE) - return 1; + return unify_type_mismatch (explain_p, parm, arg); /* [temp.deduct.call] @@ -15576,21 +15898,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, explain_p); } case REFERENCE_TYPE: if (TREE_CODE (arg) != REFERENCE_TYPE) - return 1; + return unify_type_mismatch (explain_p, parm, arg); return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg), - strict & UNIFY_ALLOW_MORE_CV_QUAL); + strict & UNIFY_ALLOW_MORE_CV_QUAL, explain_p); case ARRAY_TYPE: if (TREE_CODE (arg) != ARRAY_TYPE) - return 1; + return unify_type_mismatch (explain_p, parm, arg); if ((TYPE_DOMAIN (parm) == NULL_TREE) != (TYPE_DOMAIN (arg) == NULL_TREE)) - return 1; + return unify_type_mismatch (explain_p, parm, arg); if (TYPE_DOMAIN (parm) != NULL_TREE) { tree parm_max; @@ -15629,7 +15951,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) Here, the type of the ARG will be "int [g(i)]", and may be a SAVE_EXPR, etc. */ if (TREE_CODE (arg_max) != MINUS_EXPR) - return 1; + return unify_vla_arg (explain_p, arg); arg_max = TREE_OPERAND (arg_max, 0); } @@ -15646,11 +15968,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, explain_p); } return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg), - strict & UNIFY_ALLOW_MORE_CV_QUAL); + strict & UNIFY_ALLOW_MORE_CV_QUAL, explain_p); case REAL_TYPE: case COMPLEX_TYPE: @@ -15660,16 +15982,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 (explain_p, 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 (explain_p, parm, arg); /* As far as unification is concerned, this wins. Later checks will invalidate it if necessary. */ - return 0; + return unify_success (explain_p); /* Types INTEGER_CST and MINUS_EXPR can come from array bounds. */ /* Type INTEGER_CST can come from ordinary constant template args. */ @@ -15678,38 +16000,41 @@ 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 (explain_p, parm, arg); + return (tree_int_cst_equal (parm, arg) + ? unify_success (explain_p) + : unify_constant_unequal (explain_p, parm, arg)); case TREE_VEC: { int i; if (TREE_CODE (arg) != TREE_VEC) - return 1; + return unify_template_argument_mismatch (explain_p, parm, arg); if (TREE_VEC_LENGTH (parm) != TREE_VEC_LENGTH (arg)) - return 1; + return unify_arity (explain_p, TREE_VEC_LENGTH (arg), + TREE_VEC_LENGTH (parm)); 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, explain_p); + return unify_success (explain_p); } case RECORD_TYPE: case UNION_TYPE: if (TREE_CODE (arg) != TREE_CODE (parm)) - return 1; + return unify_type_mismatch (explain_p, parm, arg); if (TYPE_PTRMEMFUNC_P (parm)) { if (!TYPE_PTRMEMFUNC_P (arg)) - return 1; + return unify_type_mismatch (explain_p, parm, arg); return unify (tparms, targs, TYPE_PTRMEMFUNC_FN_TYPE (parm), TYPE_PTRMEMFUNC_FN_TYPE (arg), - strict); + strict, explain_p); } if (CLASSTYPE_TEMPLATE_INFO (parm)) @@ -15720,7 +16045,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, explain_p); if (!t) { @@ -15733,10 +16058,12 @@ 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); + enum template_base_result r; + r = get_template_base (tparms, targs, parm, arg, + explain_p, &t); if (!t) - return 1; + return unify_no_common_base (explain_p, r, parm, arg); } } else if (CLASSTYPE_TEMPLATE_INFO (arg) @@ -15747,14 +16074,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_type_mismatch (explain_p, parm, arg); return unify (tparms, targs, CLASSTYPE_TI_ARGS (parm), - CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE); + CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE, explain_p); } else if (!same_type_ignoring_top_level_qualifiers_p (parm, arg)) - return 1; - return 0; + return unify_type_mismatch (explain_p, parm, arg); + return unify_success (explain_p); case METHOD_TYPE: case FUNCTION_TYPE: @@ -15765,7 +16092,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 (explain_p, parm, arg); /* CV qualifications for methods can never be deduced, they must match exactly. We need to check them explicitly here, @@ -15776,11 +16103,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 (explain_p, 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, explain_p); nargs = list_length (TYPE_ARG_TYPES (arg)); args = XALLOCAVEC (tree, nargs); @@ -15792,7 +16118,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, explain_p); } case OFFSET_TYPE: @@ -15805,11 +16131,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 (explain_p, 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, explain_p); /* Determine the type of the function we are unifying against. */ method_type = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (arg)); @@ -15821,28 +16147,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, explain_p); } 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 (explain_p, parm, arg); + RECUR_AND_CHECK_FAILURE (tparms, targs, TYPE_OFFSET_BASETYPE (parm), + TYPE_OFFSET_BASETYPE (arg), + UNIFY_ALLOW_NONE, explain_p); return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg), - strict); + strict, explain_p); 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, explain_p); if (arg != integral_constant_value (parm)) - return 1; - return 0; + return unify_constant_mismatch (explain_p, parm, arg); + return unify_success (explain_p); case FIELD_DECL: case TEMPLATE_DECL: /* Matched cases are handled by the ARG == PARM test above. */ - return 1; + return unify_template_argument_mismatch (explain_p, parm, arg); case VAR_DECL: /* A non-type template parameter that is a variable should be a @@ -15872,7 +16198,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 (explain_p); } } @@ -15881,25 +16207,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 (explain_p, argslen, len); + if (argslen > len && !parm_variadic_p) + return unify_too_many_parameters (explain_p, 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, explain_p); } 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, explain_p); + return unify_success (explain_p); } break; @@ -15909,16 +16237,16 @@ 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 (explain_p); case ERROR_MARK: /* Unification fails if we hit an error node. */ - return 1; + return unify_invalid (explain_p); default: /* An unresolved overload is a nondeduced context. */ if (type_unknown_p (parm)) - return 0; + return unify_success (explain_p); gcc_assert (EXPR_P (parm)); /* We must be looking at an expression. This can happen with @@ -15942,11 +16270,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 (explain_p, parm, arg); else - return 0; + return unify_success (explain_p); } } +#undef RECUR_AND_CHECK_FAILURE /* Note that DECL can be defined in this translation unit, if required. */ @@ -16209,10 +16538,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, /*explain_p=*/NULL) + == 0); /* We cannot deduce in the other direction, because ARG1 is a pack expansion but ARG2 is not. */ @@ -16233,10 +16563,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, /*explain_p=*/NULL) + == 0); /* We cannot deduce in the other direction, because ARG2 is a pack expansion but ARG1 is not.*/ @@ -16247,8 +16578,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, /*explain_p=*/NULL) + == 0); + deduce2 = (unify (tparms2, targs2, arg2, arg1, + UNIFY_ALLOW_NONE, /*explain_p=*/NULL) + == 0); } /* If we couldn't deduce arguments for tparms1 to make arg1 match @@ -16462,7 +16797,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, /*explain_p=*/NULL)) return NULL_TREE; return targs; @@ -16504,7 +16839,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, /*explain_p=*/NULL)) return NULL_TREE; for (i = 0; i < ntparms; ++i) @@ -19237,8 +19572,11 @@ 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, + /*explain_p=*/NULL); if (val > 0) { if (type && type != error_mark_node) diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C index 352137a..120dfaa 100644 --- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C @@ -9,8 +9,9 @@ decltype(F()) run(F f) // { dg-message "note" } int main() { - auto l = []() { return 5; }; + auto l = []() { return 5; }; // { dg-error "lambda closure type" } run(l); // { dg-error "no match" } // { dg-message "candidate" "candidate note" { target *-*-* } 14 } + // { dg-error "use of deleted function" "candidate explanation" { target *-*-* } 14 } } 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/cpp0x/sfinae11.C b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C index a3ffc34..a525566 100644 --- a/gcc/testsuite/g++.dg/cpp0x/sfinae11.C +++ b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C @@ -50,7 +50,7 @@ int main() static_assert( noexcept( f2(y) ), "OK." ); // static_assert( noexcept( f3(y) ), "shall be ill-formed(OK)." ); - static_assert( noexcept( f1(z) ), "shall be ill-formed." ); // { dg-error "no match" } - static_assert( noexcept( f2(z) ), "shall be ill-formed." ); // { dg-error "no match" } - static_assert( !noexcept( f3(z) ), "shall be ill-formed." ); // { dg-error "no match" } + static_assert( noexcept( f1(z) ), "shall be ill-formed." ); // { dg-error "(no match|no member)" } + static_assert( noexcept( f2(z) ), "shall be ill-formed." ); // { dg-error "(no match|could not convert)" } + static_assert( !noexcept( f3(z) ), "shall be ill-formed." ); // { dg-error "(no match|no member)" } } diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic105.C b/gcc/testsuite/g++.dg/cpp0x/variadic105.C index 24d7e15..2729b31 100644 --- a/gcc/testsuite/g++.dg/cpp0x/variadic105.C +++ b/gcc/testsuite/g++.dg/cpp0x/variadic105.C @@ -21,4 +21,5 @@ struct call_sum { int main() { // This shouldn't be an error; this is bug 35722. reverse(1,2); // { dg-bogus "no match" "" { xfail *-*-* } } + // { dg-message "sorry, unimplemented" "candidate explanation" { target *-*-* } 23 } } diff --git a/gcc/testsuite/g++.dg/other/ptrmem10.C b/gcc/testsuite/g++.dg/other/ptrmem10.C index bc386ed..a17df7f 100644 --- a/gcc/testsuite/g++.dg/other/ptrmem10.C +++ b/gcc/testsuite/g++.dg/other/ptrmem10.C @@ -13,7 +13,7 @@ template static void bar(C *c, void (C::*m) ()) { - foo((void *)c);// { dg-error "(not a valid template arg|pointer-to-member|no matching fun)" } + foo((void *)c);// { dg-error "(not a valid template arg|pointer-to-member|no matching fun|could not convert)" } // { dg-message "candidate" "candidate note" { target *-*-* } 16 } } diff --git a/gcc/testsuite/g++.dg/other/ptrmem11.C b/gcc/testsuite/g++.dg/other/ptrmem11.C index 119cbb0..e73164e 100644 --- a/gcc/testsuite/g++.dg/other/ptrmem11.C +++ b/gcc/testsuite/g++.dg/other/ptrmem11.C @@ -14,7 +14,7 @@ template int bar(int T::* p) { - return foo

(0);// { dg-error "(not a valid template arg|no matching func|pointer-to-member)" } + return foo

(0);// { dg-error "(not a valid template arg|no matching func|pointer-to-member|could not convert)" } // { dg-message "candidate" "candidate note" { target *-*-* } 17 } } 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/incomplete2.C b/gcc/testsuite/g++.dg/template/incomplete2.C index d86ea06..b855569 100644 --- a/gcc/testsuite/g++.dg/template/incomplete2.C +++ b/gcc/testsuite/g++.dg/template/incomplete2.C @@ -9,6 +9,6 @@ A a; // { dg-error "incomplete type" } void bar() { - foo(); // { dg-error "no matching function" } + foo(); // { dg-error "(no matching function|could not convert)" } // { dg-message "candidate" "candidate note" { target *-*-* } 12 } } diff --git a/gcc/testsuite/g++.dg/template/local4.C b/gcc/testsuite/g++.dg/template/local4.C index 9a03c9a..d842076 100644 --- a/gcc/testsuite/g++.dg/template/local4.C +++ b/gcc/testsuite/g++.dg/template/local4.C @@ -5,6 +5,6 @@ template void foo() {} // { dg-message "note" } int main () { struct S {}; - foo (); // { dg-error "match" } + foo (); // { dg-error "(match|template argument for|trying to instantiate)" } // { dg-message "candidate" "candidate note" { target *-*-* } 8 } } 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++.dg/template/unify11.C b/gcc/testsuite/g++.dg/template/unify11.C index ed6b31c..25606dc 100644 --- a/gcc/testsuite/g++.dg/template/unify11.C +++ b/gcc/testsuite/g++.dg/template/unify11.C @@ -20,7 +20,7 @@ struct B C (U t) { A a; - A b = foo (this, a, t); // { dg-error "no matching function" } + A b = foo (this, a, t); // { dg-error "(no matching function|is not a)" } // { dg-message "candidate" "candidate note" { target *-*-* } 23 } } } c; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C index 560370a..c27d131 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C @@ -1,6 +1,6 @@ // { dg-do assemble } template -void f(int i); // { dg-message "note" } +void f(int i); // { dg-message "void f" } void g() { diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C index 85d3e73..8802e98 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C @@ -13,9 +13,9 @@ public: }; template -void g() {} // { dg-message "note" } +void g() {} // { dg-message "void g" } template -void h() {} // { dg-message "note" } +void h() {} // { dg-message "void h" } int main() {