From patchwork Mon Nov 8 16:40:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthias Kretz X-Patchwork-Id: 47222 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BB8BE385843D for ; Mon, 8 Nov 2021 16:41:50 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from lxmtout1.gsi.de (lxmtout1.gsi.de [140.181.3.111]) by sourceware.org (Postfix) with ESMTPS id 4B2EC3858020 for ; Mon, 8 Nov 2021 16:40:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4B2EC3858020 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gsi.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gsi.de Received: from localhost (localhost [127.0.0.1]) by lxmtout1.gsi.de (Postfix) with ESMTP id 99A5D2050D05; Mon, 8 Nov 2021 17:40:45 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at lxmtout1.gsi.de Received: from lxmtout1.gsi.de ([127.0.0.1]) by localhost (lxmtout1.gsi.de [127.0.0.1]) (amavisd-new, port 10024) with LMTP id QSrwjHINXoRR; Mon, 8 Nov 2021 17:40:45 +0100 (CET) Received: from srvex3.campus.gsi.de (unknown [10.10.4.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) by lxmtout1.gsi.de (Postfix) with ESMTPS id 7BB902050D00; Mon, 8 Nov 2021 17:40:45 +0100 (CET) Received: from excalibur.localnet (140.181.3.12) by srvex3.campus.gsi.de (10.10.4.16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2242.12; Mon, 8 Nov 2021 17:40:44 +0100 From: Matthias Kretz To: , Jason Merrill Subject: [RFC] c++: Print function template parms when relevant (was: [PATCH v4] c++: Add gnu::diagnose_as attribute) Date: Mon, 8 Nov 2021 17:40:44 +0100 Message-ID: <1694479.jsd7nNDzyu@excalibur> Organization: GSI Helmholtzzentrum =?utf-8?q?f=C3=BCr?= Schwerionenforschung In-Reply-To: References: <4361366.VLH7GnMWUR@minbar> <4019800.7NyaFmOyK0@excalibur> MIME-Version: 1.0 X-Originating-IP: [140.181.3.12] X-ClientProxiedBy: srvex4.Campus.gsi.de (10.10.4.36) To srvex3.campus.gsi.de (10.10.4.16) X-Spam-Status: No, score=-10.5 required=5.0 tests=BAYES_00, BODY_8BITS, GIT_PATCH_0, KAM_DMARC_STATUS, RCVD_IN_MSPIKE_H2, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" On Tuesday, 17 August 2021 20:31:54 CET Jason Merrill wrote: > > 2. Given a DECL_TI_ARGS tree, can I query whether an argument was deduced > > or explicitly specified? I'm asking because I still consider diagnostics > > of function templates unfortunate. `template void f()` is fine, > > as is `void f(T) [with T = float]`, but `void f() [with T = float]` could > > be better. I.e. if the template parameter appears somewhere in the > > function parameter list, dump_template_parms would only produce noise. > > If, however, the template parameter was given explicitly, it would be > > nice if it could show up accordingly in diagnostics. > > NON_DEFAULT_TEMPLATE_ARGS_COUNT has that information, though there are > some issues with it. Attached is my WIP from May to improve it > somewhat, if that's interesting. It is interesting. I used your patch to come up with the attached. Patch. I must say, I didn't try to read through all the cp/pt.c code to understand all of what you did there (which is why my ChangeLog entry says "Jason?"), but it works for me (and all of `make check`). Anyway, I'd like to propose the following before finishing my diagnose_as patch. I believe it's useful to fix this part first. The diagnostic/default- template-args-[12].C tests show a lot of examples of the intent of this patch. And the remaining changes to the testsuite show how it changes diagnostic output. ---------------------- 8< -------------------- The choice when to print a function template parameter was still suboptimal. That's because sometimes the function template parameter list only adds noise, while in other situations the lack of a function template parameter list makes diagnostic messages hard to understand. The general idea of this change is to print template parms wherever they would appear in the source code as well. Thus, the diagnostics code needs to know whether any template parameter was given explicitly. Signed-off-by: Matthias Kretz gcc/testsuite/ChangeLog: * g++.dg/debug/dwarf2/template-params-12n.C: Optionally, allow DW_AT_default_value. * g++.dg/diagnostic/default-template-args-1.C: New. * g++.dg/diagnostic/default-template-args-2.C: New. * g++.dg/diagnostic/param-type-mismatch-2.C: Expect template parms in diagnostic. * g++.dg/ext/pretty1.C: Expect function template specialization to not pretty-print template parms. * g++.old-deja/g++.ext/pretty3.C: Ditto. * g++.old-deja/g++.pt/memtemp77.C: Ditto. * g++.dg/goacc/template.C: Expect function template parms for explicit arguments. * g++.dg/gomp/declare-variant-7.C: Expect no function template parms for deduced arguments. * g++.dg/template/error40.C: Expect only non-default template arguments in diagnostic. gcc/cp/ChangeLog: * cp-tree.h (GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT): Return absolute value of stored constant. (EXPLICIT_TEMPLATE_ARGS_P): New. (SET_EXPLICIT_TEMPLATE_ARGS_P): New. (TFF_AS_PRIMARY): New constant. * error.c (get_non_default_template_args_count): Avoid GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT if NON_DEFAULT_TEMPLATE_ARGS_COUNT is a NULL_TREE. Make independent of flag_pretty_templates. (dump_template_bindings): Add flags parameter to be passed to get_non_default_template_args_count. Print only non-default template arguments. (dump_function_decl): Call dump_function_name and dump_type of the DECL_CONTEXT with specialized template and set TFF_AS_PRIMARY for their flags. (dump_function_name): Add and document conditions for calling dump_template_parms. (dump_template_parms): Print only non-default template parameters. * pt.c (determine_specialization): Jason? (template_parms_level_to_args): Jason? (copy_template_args): Jason? (fn_type_unification): Set EXPLICIT_TEMPLATE_ARGS_P on the template arguments tree if any template parameter was explicitly given. (type_unification_real): Jason? (get_partial_spec_bindings): Jason? (tsubst_template_args): Determine number of defaulted arguments from new argument vector, if possible. --- gcc/cp/cp-tree.h | 18 +++- gcc/cp/error.c | 83 ++++++++++++++----- gcc/cp/pt.c | 58 +++++++++---- .../g++.dg/debug/dwarf2/template-params-12n.C | 2 +- .../diagnostic/default-template-args-1.C | 73 ++++++++++++++++ .../diagnostic/default-template-args-2.C | 37 +++++++++ .../g++.dg/diagnostic/param-type-mismatch-2.C | 2 +- gcc/testsuite/g++.dg/ext/pretty1.C | 2 +- gcc/testsuite/g++.dg/goacc/template.C | 8 +- gcc/testsuite/g++.dg/gomp/declare-variant-7.C | 4 +- gcc/testsuite/g++.dg/template/error40.C | 6 +- gcc/testsuite/g++.old-deja/g++.ext/pretty3.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C | 2 +- 13 files changed, 242 insertions(+), 55 deletions(-) create mode 100644 gcc/testsuite/g++.dg/diagnostic/default-template-args-1.C create mode 100644 gcc/testsuite/g++.dg/diagnostic/default-template-args-2.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f387b5036d2..27f11e12812 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3686,7 +3686,8 @@ struct GTY(()) lang_decl { TREE_LANG_FLAG_1 (TEMPLATE_INFO_CHECK (NODE)) /* For a given TREE_VEC containing a template argument list, this property contains the number of arguments that are not - defaulted. */ + defaulted. The sign of the number is negative for function templates with + explicitly given template arguments (i.e. neither deduced nor defaulted). */ #define NON_DEFAULT_TEMPLATE_ARGS_COUNT(NODE) \ TREE_CHAIN (TREE_VEC_CHECK (NODE)) @@ -3696,14 +3697,21 @@ struct GTY(()) lang_decl { NON_DEFAULT_TEMPLATE_ARGS_COUNT(NODE) = build_int_cst (NULL_TREE, INT_VALUE) #if CHECKING_P #define GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT(NODE) \ - int_cst_value (NON_DEFAULT_TEMPLATE_ARGS_COUNT (NODE)) + abs (int_cst_value (NON_DEFAULT_TEMPLATE_ARGS_COUNT (NODE))) #else #define GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT(NODE) \ NON_DEFAULT_TEMPLATE_ARGS_COUNT (NODE) \ - ? int_cst_value (NON_DEFAULT_TEMPLATE_ARGS_COUNT (NODE)) \ + ? abs (int_cst_value (NON_DEFAULT_TEMPLATE_ARGS_COUNT (NODE))) \ : TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS (NODE)) #endif +#define EXPLICIT_TEMPLATE_ARGS_P(NODE) \ + (int_cst_value (NON_DEFAULT_TEMPLATE_ARGS_COUNT (NODE)) < 0) + +#define SET_EXPLICIT_TEMPLATE_ARGS_P(NODE) \ + SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT \ + (NODE, -GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (NODE)) + /* The list of access checks that were deferred during parsing which need to be performed at template instantiation time. @@ -5938,7 +5946,8 @@ enum auto_deduction_context identical to their defaults. TFF_NO_TEMPLATE_BINDINGS: do not print information about the template arguments for a function template specialization. - TFF_POINTER: we are printing a pointer type. */ + TFF_POINTER: we are printing a pointer type. + TFF_AS_PRIMARY: show the template like a primary template. */ #define TFF_PLAIN_IDENTIFIER (0) #define TFF_SCOPE (1) @@ -5956,6 +5965,7 @@ enum auto_deduction_context #define TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS (1 << 12) #define TFF_NO_TEMPLATE_BINDINGS (1 << 13) #define TFF_POINTER (1 << 14) +#define TFF_AS_PRIMARY (1 << 15) /* These constants can be used as bit flags to control strip_typedefs. diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 012a4ecddf4..86e9d12103a 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -87,7 +87,7 @@ static void dump_template_argument (cxx_pretty_printer *, tree, int); static void dump_template_argument_list (cxx_pretty_printer *, tree, int); static void dump_template_parameter (cxx_pretty_printer *, tree, int); static void dump_template_bindings (cxx_pretty_printer *, tree, tree, - vec *); + vec *, int); static void dump_scope (cxx_pretty_printer *, tree, int); static void dump_template_parms (cxx_pretty_printer *, tree, int, int); static int get_non_default_template_args_count (tree, int); @@ -278,7 +278,8 @@ dump_template_argument (cxx_pretty_printer *pp, tree arg, int flags) static int get_non_default_template_args_count (tree args, int flags) { - int n = TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS (args)); + args = INNERMOST_TEMPLATE_ARGS (args); + int n = TREE_VEC_LENGTH (args); if (/* We use this flag when generating debug information. We don't want to expand templates at this point, for this may generate @@ -286,10 +287,10 @@ get_non_default_template_args_count (tree args, int flags) turn cause codegen differences between compilations with and without -g. */ (flags & TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS) != 0 - || !flag_pretty_templates) + || !NON_DEFAULT_TEMPLATE_ARGS_COUNT (args)) return n; - return GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (INNERMOST_TEMPLATE_ARGS (args)); + return GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args); } /* Dump a template-argument-list ARGS (always a TREE_VEC) under control @@ -369,7 +370,7 @@ dump_template_parameter (cxx_pretty_printer *pp, tree parm, int flags) static void dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args, - vec *typenames) + vec *typenames, int flags) { /* Print "[with" and ']', conditional on whether anything is printed at all. This is tied to whether a semicolon is needed to separate multiple template @@ -411,11 +412,16 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args, int i; tree lvl_args = NULL_TREE; + int len = TREE_VEC_LENGTH (p); /* Don't crash if we had an invalid argument list. */ if (TMPL_ARGS_DEPTH (args) >= lvl) - lvl_args = TMPL_ARGS_LEVEL (args, lvl); + { + lvl_args = TMPL_ARGS_LEVEL (args, lvl); + len = MIN (len, + get_non_default_template_args_count (lvl_args, flags)); + } - for (i = 0; i < TREE_VEC_LENGTH (p); ++i) + for (i = 0; i < len; ++i) { tree arg = NULL_TREE; @@ -1635,7 +1641,8 @@ dump_substitution (cxx_pretty_printer *pp, && !(flags & TFF_NO_TEMPLATE_BINDINGS)) { vec *typenames = t ? find_typenames (t) : NULL; - dump_template_bindings (pp, template_parms, template_args, typenames); + dump_template_bindings (pp, template_parms, template_args, typenames, + flags); } } @@ -1688,8 +1695,15 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) /* Likewise for the constexpr specifier, in case t is a specialization. */ constexpr_p = DECL_DECLARED_CONSTEXPR_P (t); - /* Pretty print template instantiations only. */ - if (DECL_USE_TEMPLATE (t) && DECL_TEMPLATE_INFO (t) + /* Keep t before the following branch makes t point to a more general + template. Without the specialized template, the information about defaulted + template arguments is lost. */ + tree specialized_t = t; + int specialized_flags = 0; + + /* Pretty print only template instantiations. Don't pretty print explicit + specializations like 'template <> void fun (int)'. */ + if (DECL_TEMPLATE_INSTANTIATION (t) && DECL_TEMPLATE_INFO (t) && !(flags & TFF_NO_TEMPLATE_BINDINGS) && flag_pretty_templates) { @@ -1701,6 +1715,9 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) { template_parms = DECL_TEMPLATE_PARMS (tmpl); t = tmpl; + /* The "[with ...]" clause is printed, thus dump functions printing + SPECIALIZED_T need to add TFF_AS_PRIMARY to their flags. */ + specialized_flags = TFF_AS_PRIMARY; } } @@ -1710,8 +1727,8 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) fntype = TREE_TYPE (t); parmtypes = FUNCTION_FIRST_USER_PARMTYPE (t); - if (DECL_CLASS_SCOPE_P (t)) - cname = DECL_CONTEXT (t); + if (DECL_CLASS_SCOPE_P (specialized_t)) + cname = DECL_CONTEXT (specialized_t); /* This is for partially instantiated template methods. */ else if (TREE_CODE (fntype) == METHOD_TYPE) cname = TREE_TYPE (TREE_VALUE (parmtypes)); @@ -1749,13 +1766,14 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags) /* Nothing. */; else if (cname) { - dump_type (pp, cname, flags); + dump_type (pp, cname, flags | specialized_flags); pp_cxx_colon_colon (pp); } else dump_scope (pp, CP_DECL_CONTEXT (t), flags); - dump_function_name (pp, t, dump_function_name_flags); + dump_function_name (pp, specialized_t, + dump_function_name_flags | specialized_flags); if (!(flags & TFF_NO_FUNCTION_ARGUMENTS)) { @@ -1968,13 +1986,35 @@ dump_function_name (cxx_pretty_printer *pp, tree t, int flags) dump_module_suffix (pp, t); +/* Print function template parameters if: + 1. t is template, and + 2. flags did not request "show only template-name", and + 3. t is a specialization of a template (Why is this needed? This was present + since 1999 via !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION: "Don't crash if + given a friend pseudo-instantiation". The DECL_USE_TEMPLATE should likely + inform the PRIMARY parameter of dump_template_parms.), and + 4. either + - flags requests to show no function arguments, in which case deduced + types could be hidden, or + - at least one function template argument was given explicitly, or + - we're printing a DWARF name, + and + 5. either + - t is a member friend template of a template class (see DECL_TI_TEMPLATE + documentation), or + - + */ if (DECL_TEMPLATE_INFO (t) && !(flags & TFF_TEMPLATE_NAME) - && !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (t) + && DECL_USE_TEMPLATE (t) + && ((flags & TFF_NO_FUNCTION_ARGUMENTS) + || (DECL_TI_ARGS (t) + && EXPLICIT_TEMPLATE_ARGS_P (INNERMOST_TEMPLATE_ARGS + (DECL_TI_ARGS (t)))) + || (pp->flags & pp_c_flag_gnu_v3) != 0) && (TREE_CODE (DECL_TI_TEMPLATE (t)) != TEMPLATE_DECL || PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t)))) - dump_template_parms (pp, DECL_TEMPLATE_INFO (t), !DECL_USE_TEMPLATE (t), - flags); + dump_template_parms (pp, DECL_TEMPLATE_INFO (t), false, flags); } /* Dump the template parameters from the template info INFO under control of @@ -1989,6 +2029,8 @@ dump_template_parms (cxx_pretty_printer *pp, tree info, { tree args = info ? TI_ARGS (info) : NULL_TREE; + if (flags & TFF_AS_PRIMARY) + primary = true; if (primary && flags & TFF_TEMPLATE_NAME) return; flags &= ~(TFF_CLASS_KEY_OR_ENUM | TFF_TEMPLATE_NAME); @@ -1998,10 +2040,11 @@ dump_template_parms (cxx_pretty_printer *pp, tree info, to crash producing error messages. */ if (args && !primary) { - int len, ix; - len = get_non_default_template_args_count (args, flags); + int ix; args = INNERMOST_TEMPLATE_ARGS (args); + const int len = MIN (NUM_TMPL_ARGS (args), + get_non_default_template_args_count (args, flags)); for (ix = 0; ix != len; ix++) { tree arg = TREE_VEC_ELT (args, ix); @@ -2028,6 +2071,8 @@ dump_template_parms (cxx_pretty_printer *pp, tree info, parms = TREE_CODE (parms) == TREE_LIST ? TREE_VALUE (parms) : NULL_TREE; len = parms ? TREE_VEC_LENGTH (parms) : 0; + if (args) + len = MIN (len, get_non_default_template_args_count (args, flags)); for (ix = 0; ix != len; ix++) { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 66040035b2f..800249f0933 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2504,7 +2504,7 @@ determine_specialization (tree template_id, if (candidates) { tree fn = TREE_VALUE (candidates); - *targs_out = copy_node (DECL_TI_ARGS (fn)); + *targs_out = copy_template_args (DECL_TI_ARGS (fn)); /* Propagate the candidate's constraints to the declaration. */ if (tsk != tsk_template) @@ -4828,11 +4828,16 @@ template_parms_level_to_args (tree parms) { tree a = copy_node (parms); TREE_TYPE (a) = NULL_TREE; + int nondefault = 0; for (int i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i) - TREE_VEC_ELT (a, i) = template_parm_to_arg (TREE_VEC_ELT (a, i)); + { + tree elt = TREE_VEC_ELT (a, i); + TREE_VEC_ELT (a, i) = template_parm_to_arg (elt); + if (!elt || elt == error_mark_node || !TREE_PURPOSE (elt)) + ++nondefault; + } - if (CHECKING_P) - SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a)); + SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, nondefault); return a; } @@ -13332,8 +13337,9 @@ copy_template_args (tree t) TREE_VEC_ELT (new_vec, i) = elt; } - NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_vec) - = NON_DEFAULT_TEMPLATE_ARGS_COUNT (t); + if (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS (t)) + NON_DEFAULT_TEMPLATE_ARGS_COUNT (new_vec) + = NON_DEFAULT_TEMPLATE_ARGS_COUNT (t); return new_vec; } @@ -13433,7 +13439,13 @@ tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl) if it doesn't contain any nested TREE_VEC. */ if (NON_DEFAULT_TEMPLATE_ARGS_COUNT (orig_t)) { - int count = GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (orig_t); + /* If ARGS defines a number for the defaulted argument count then that's + the correct number to propagate. Otherwise, assume the number of + defaulted arguments after substitution equals the number of default + arguments before substitution (i.e. ORIG_T). */ + int count = args && NON_DEFAULT_TEMPLATE_ARGS_COUNT (args) + ? GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args) + : GET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (orig_t); count += expanded_len_adjust; SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (t, count); } @@ -21874,6 +21886,12 @@ fn_type_unification (tree fn, excessive_deduction_depth = false; } + /* If all template parameters were explicitly given, treat them like default + template arguments for diagnostics. NON_DEFAULT_TEMPLATE_ARGS_COUNT must be + present for SET_EXPLICIT_TEMPLATE_ARGS_P. */ + if (explicit_targs && NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs)) + SET_EXPLICIT_TEMPLATE_ARGS_P (targs); + return r; } @@ -22516,9 +22534,17 @@ type_unification_real (tree tparms, be NULL_TREE or ERROR_MARK_NODE, so we do not need to explicitly check cxx_dialect here. */ if (TREE_PURPOSE (TREE_VEC_ELT (tparms, i))) - /* OK, there is a default argument. Wait until after the - conversion check to do substitution. */ - continue; + { + /* The position of the first default template argument, + is also the number of non-defaulted arguments in TARGS. + Record that. */ + if (!NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs)) + SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, i); + + /* OK, there is a default argument. Wait until after the + conversion check to do substitution. */ + continue; + } /* If the type parameter is a parameter pack, then it will be deduced to an empty parameter pack. */ @@ -22621,14 +22647,7 @@ type_unification_real (tree tparms, if (arg == error_mark_node) return 1; else if (arg) - { - TREE_VEC_ELT (targs, i) = arg; - /* The position of the first default template argument, - is also the number of non-defaulted arguments in TARGS. - Record that. */ - if (!NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs)) - SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, i); - } + TREE_VEC_ELT (targs, i) = arg; } if (saw_undeduced++ == 1) @@ -24998,6 +25017,9 @@ get_partial_spec_bindings (tree tmpl, tree spec_tmpl, tree args) if (!template_template_parm_bindings_ok_p (tparms, deduced_args)) return NULL_TREE; + if (CHECKING_P) + SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (deduced_args, ntparms); + return deduced_args; } diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-12n.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-12n.C index d3c1f589f87..b88bf7d4b34 100644 --- a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-12n.C +++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-12n.C @@ -1,6 +1,6 @@ // { dg-options "-gdwarf-2 -dA" } // { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_template_value_param" 1 } } -// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_template_value_param\[^\n\]*\n\[^\n\]* DW_AT_name\n\[^\n\]* DW_AT_type\n\[^\n\]* DW_AT_const_value" 1 } } +// { dg-final { scan-assembler-times "DIE \\(\[^\n\]*\\) DW_TAG_template_value_param\[^\n\]*\n\[^\n\]* DW_AT_name\n\[^\n\]* DW_AT_type\n(?:\[^\n\]* DW_AT_default_value\n)?\[^\n\]* DW_AT_const_value" 1 } } #include "template-params-12.H" /* We get const_value for NULL pointers to member functions. */ #if __cplusplus > 199711L // Ugh, C++98 barfs at both the cast and the overload. diff --git a/gcc/testsuite/g++.dg/diagnostic/default-template-args-1.C b/gcc/testsuite/g++.dg/diagnostic/default-template-args-1.C new file mode 100644 index 00000000000..7a535515740 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/default-template-args-1.C @@ -0,0 +1,73 @@ +// { dg-options "-fpretty-templates" } +// { dg-do compile { target c++11 } } + +template + [[deprecated]] void f0(); // { dg-message "'template void f0\\(\\)'" } + +template + [[deprecated]] void f1(); // { dg-message "'template void f1\\(\\)'" } + +template + [[deprecated]] void f2(); // { dg-message "'template void f2\\(\\)'" } + +template + [[deprecated]] void f3(a); // { dg-message "'template void f3\\(a\\)'" } + +template + [[deprecated]] void f4(a); // { dg-message "'template void f4\\(a\\)'" } + +template <> + [[deprecated]] void f4(int); + +template <> + [[deprecated]] void f4(float); + +template + [[deprecated]] void f5(a); + +template void f5(float); // { dg-error "'void f5\\(a\\) .with a = float.'" } + +template + struct c + { + template + [[deprecated]] static void f(d); + }; + +template +struct B { typedef T X; }; + +template +struct D +{ + template ::X> + [[deprecated]] static void foo (typename B::X); +}; + +int main() +{ + f0(); // { dg-warning "'void f0\\(\\)'" } + f1<1>(); // { dg-warning "'void f1\\(\\) .with int a = 1.'" } + f2(); // { dg-warning "'void f2\\(\\) .with a = int.'" } + f3(1); // { dg-warning "'void f3\\(a\\) .with a = int.'" } + f3(1); // { dg-warning "'void f3\\(a\\) .with a = float.'" } + f3(1); // { dg-warning "'void f3\\(a\\) .with a = float; int b = 2.'" } + f4(1.); // { dg-warning "'void f4\\(a\\) .with a = double.'" } + f4(1); // { dg-warning "'void f4\\(int\\)'" } + f4(1.f); // { dg-warning "'void f4\\(float\\)'" } + + f0(0); // { dg-error "" } + f1(0); // { dg-error "" } + f2(0); // { dg-error "" } + f3(); // { dg-error "" } + f4(); // { dg-error "" } + + c::f(1.); // { dg-warning "'static void c::f\\(d\\) .with d = double; a = int.'" } + c::f(1); // { dg-warning "'static void c::f\\(d\\) .with d = int; a = int.'" } + c::f(1.f); // { dg-warning "'static void c::f\\(d\\) .with d = float; e = int; a = int.'" } + c::f(1.); // { dg-warning "'static void c::f\\(d\\) .with d = double; a = float; b = int.'" } + c::f(1); // { dg-warning "'static void c::f\\(d\\) .with d = int; a = float; b = int.'" } + c::f(1.f); // { dg-warning "'static void c::f\\(d\\) .with d = float; e = int; a = float; b = int.'" } + + D::foo(1); // { dg-warning "'static void D::foo\\(typename B::X\\) .with U = int; typename B::X = int.'" } +} diff --git a/gcc/testsuite/g++.dg/diagnostic/default-template-args-2.C b/gcc/testsuite/g++.dg/diagnostic/default-template-args-2.C new file mode 100644 index 00000000000..a82709f5785 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/default-template-args-2.C @@ -0,0 +1,37 @@ +// { dg-options "-fno-pretty-templates" } +// { dg-do compile { target c++11 } } + +template + [[deprecated]] void f0(); + +template + [[deprecated]] void f1(); + +template + [[deprecated]] void f2(); + +template + [[deprecated]] void f3(a); + +template + [[deprecated]] void f4(a); + +template <> + [[deprecated]] void f4(int); + +template + [[deprecated]] void f5(a); + +template void f5(float); // { dg-error "'void f5\\(float\\)'" } + +int main() +{ + f0(); // { dg-warning "'void f0\\(\\)'" } + f1<1>(); // { dg-warning "'void f1<1>\\(\\)'" } + f2(); // { dg-warning "'void f2\\(\\)'" } + f3(1); // { dg-warning "'void f3\\(int\\)'" } + f3(1); // { dg-warning "'void f3\\(float\\)'" } + f3(1); // { dg-warning "'void f3\\(float\\)'" } + f4(1.); // { dg-warning "'void f4\\(double\\)'" } + f4(1); // { dg-warning "'void f4\\(int\\)'" } +} diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C index de7570a6efa..0aa45404283 100644 --- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C +++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch-2.C @@ -141,7 +141,7 @@ int test_7 (int first, const char *second, float third) | const char* { dg-end-multiline-output "" } */ - // { dg-message "initializing argument 2 of 'int test_7\\(int, T, float\\) .with T = const char\\*\\*.'" "" { target *-*-* } test_7_decl } + // { dg-message "initializing argument 2 of 'int test_7\\(int, T, float\\) .with T = const char\\*\\*.'" "" { target *-*-* } test_7_decl } /* { dg-begin-multiline-output "" } int test_7 (int one, T two, float three); ~~^~~ diff --git a/gcc/testsuite/g++.dg/ext/pretty1.C b/gcc/testsuite/g++.dg/ext/pretty1.C index 06608ae30eb..c5bfd6082a7 100644 --- a/gcc/testsuite/g++.dg/ext/pretty1.C +++ b/gcc/testsuite/g++.dg/ext/pretty1.C @@ -60,7 +60,7 @@ __assert_fail (const char *cond, const char *file, unsigned int line, abort (); } -// { dg-final { scan-assembler "int bar\\(T\\).*with T = int" } } +// { dg-final { scan-assembler "int bar\\(int\\)" } } // { dg-final { scan-assembler "top level" } } // { dg-final { scan-assembler "int main\\(\\)" } } // { dg-final { scan-assembler "int bar\\(T\\).*with T = double" } } diff --git a/gcc/testsuite/g++.dg/goacc/template.C b/gcc/testsuite/g++.dg/goacc/template.C index 10d3f446da7..4fcd88bfc56 100644 --- a/gcc/testsuite/g++.dg/goacc/template.C +++ b/gcc/testsuite/g++.dg/goacc/template.C @@ -157,12 +157,12 @@ main () } /* { dg-final { scan-tree-dump-times {(?n)^OpenACC routine '[^']+' has 'nohost' clause\.$} 4 oaccloops } } - { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble\(int\) \[with T = char\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } } + { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble\(int\) \[with T = char\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } } { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'accDouble\(int\)char' has 'nohost' clause\.$} 1 oaccloops { target offloading_enabled } } } - { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble\(int\) \[with T = int\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } } + { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble\(int\) \[with T = int\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } } { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'accDouble\(int\)int' has 'nohost' clause\.$} 1 oaccloops { target offloading_enabled } } } - { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble\(int\) \[with T = float\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } } + { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble\(int\) \[with T = float\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } } { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'accDouble\(int\)float' has 'nohost' clause\.$} 1 oaccloops { target offloading_enabled } } } - { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble\(int\) \[with T = double\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } } + { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'T accDouble\(int\) \[with T = double\]' has 'nohost' clause\.$} 1 oaccloops { target { ! offloading_enabled } } } } { dg-final { scan-tree-dump-times {(?n)^OpenACC routine 'accDouble\(int\)double' has 'nohost' clause\.$} 1 oaccloops { target offloading_enabled } } } TODO See PR101551 for 'offloading_enabled' differences. */ diff --git a/gcc/testsuite/g++.dg/gomp/declare-variant-7.C b/gcc/testsuite/g++.dg/gomp/declare-variant-7.C index 7dda899578a..9cb654cb5e6 100644 --- a/gcc/testsuite/g++.dg/gomp/declare-variant-7.C +++ b/gcc/testsuite/g++.dg/gomp/declare-variant-7.C @@ -70,6 +70,6 @@ test () s.f12 (0.0); // { dg-final { scan-tree-dump-times "S<1>::f11 \\\(&s, 0.0\\\);" 1 "gimple" } } s.f14 (0LL); // { dg-final { scan-tree-dump-times "S<1>::f13 \\\(&s, 0\\\);" 1 "gimple" } } T<0> t; - t.f16 (s); // { dg-final { scan-tree-dump-times "T<0>::f16 > \\\(&t, s\\\);" 1 "gimple" } } - t.f18 (s); // { dg-final { scan-tree-dump-times "T<0>::f18 > \\\(&t, s\\\);" 1 "gimple" } } + t.f16 (s); // { dg-final { scan-tree-dump-times "T<0>::f16 \\\(&t, s\\\);" 1 "gimple" } } + t.f18 (s); // { dg-final { scan-tree-dump-times "T<0>::f18 \\\(&t, s\\\);" 1 "gimple" } } } diff --git a/gcc/testsuite/g++.dg/template/error40.C b/gcc/testsuite/g++.dg/template/error40.C index c5df56fc1be..16a44d1819f 100644 --- a/gcc/testsuite/g++.dg/template/error40.C +++ b/gcc/testsuite/g++.dg/template/error40.C @@ -8,11 +8,11 @@ struct A void foo(void) { - A a = 0; // { dg-error "A" } + A a = 0; // { dg-error "A" } } -template T f(T); // { dg-message "int f.int." } -template T f(T, int = 0); // { dg-message "" } +template T f(T); // { dg-message "int f.int." } +template T f(T, int = 0); // { dg-message "int f.int, int." } template struct B diff --git a/gcc/testsuite/g++.old-deja/g++.ext/pretty3.C b/gcc/testsuite/g++.old-deja/g++.ext/pretty3.C index 6348ae1ee67..30c7ecd5065 100644 --- a/gcc/testsuite/g++.old-deja/g++.ext/pretty3.C +++ b/gcc/testsuite/g++.old-deja/g++.ext/pretty3.C @@ -35,7 +35,7 @@ template<> void f1 (int) if (strcmp (function, "f1")) bad = true; - if (strcmp (pretty, "void f1(T) [with T = int]")) + if (strcmp (pretty, "void f1(int)")) bad = true; } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C b/gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C index 6dd4b546c0c..93dbf4b489f 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/memtemp77.C @@ -19,7 +19,7 @@ const char* S3::h(int) { return __PRETTY_FUNCTION__; } int main() { if (strcmp (S3::h(7), - "static const char* S3::h(U) [with U = int; T = double]") == 0) + "static const char* S3::h(int)") == 0) return 0; else return 1;