From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1888) id 5A1A83858415; Wed, 9 Mar 2022 13:44:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5A1A83858415 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Patrick Palka To: gcc-cvs@gcc.gnu.org Subject: [gcc r12-7562] c++: merge default targs for function templates [PR65396] X-Act-Checkin: gcc X-Git-Author: Patrick Palka X-Git-Refname: refs/heads/master X-Git-Oldrev: 4470e813b0b46d2e579b9e3d69a41a7192709c50 X-Git-Newrev: fe548eb8436f3906e6a3c6e3e8707d24e60ec0fa Message-Id: <20220309134412.5A1A83858415@sourceware.org> Date: Wed, 9 Mar 2022 13:44:12 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 09 Mar 2022 13:44:12 -0000 https://gcc.gnu.org/g:fe548eb8436f3906e6a3c6e3e8707d24e60ec0fa commit r12-7562-gfe548eb8436f3906e6a3c6e3e8707d24e60ec0fa Author: Patrick Palka Date: Wed Mar 9 08:42:19 2022 -0500 c++: merge default targs for function templates [PR65396] We currently merge default template arguments for class templates, but not for function templates. This patch fixes this by factoring out the argument merging logic in redeclare_class_template into a separate function and using it in duplicate_decls as well. PR c++/65396 gcc/cp/ChangeLog: * cp-tree.h (merge_default_template_args): Declare. * decl.cc (merge_default_template_args): Define, factored out from redeclare_class_template. (duplicate_decls): Use it when merging member function template and free function declarations. * pt.cc (redeclare_class_template): Factor out default argument merging logic into merge_default_template_args. Improve location of a note when there's a template parameter kind mismatch. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/vt-34314.C: Adjust expected location of "redeclared here" note. * g++.dg/template/pr92440.C: Likewise. * g++.old-deja/g++.pt/redecl1.C: Adjust expected location of "redefinition of default argument" error. * g++.dg/template/defarg23.C: New test. * g++.dg/template/defarg23a.C: New test. Diff: --- gcc/cp/cp-tree.h | 1 + gcc/cp/decl.cc | 58 ++++++++++++++++++++++++++++- gcc/cp/pt.cc | 31 ++------------- gcc/testsuite/g++.dg/cpp0x/vt-34314.C | 12 +++--- gcc/testsuite/g++.dg/template/defarg23.C | 21 +++++++++++ gcc/testsuite/g++.dg/template/defarg23a.C | 24 ++++++++++++ gcc/testsuite/g++.dg/template/pr92440.C | 4 +- gcc/testsuite/g++.old-deja/g++.pt/redecl1.C | 12 +++--- 8 files changed, 121 insertions(+), 42 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index cf08e16e172..757711bc03a 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6787,6 +6787,7 @@ extern void note_iteration_stmt_body_end (bool); extern void determine_local_discriminator (tree); extern int decls_match (tree, tree, bool = true); extern bool maybe_version_functions (tree, tree, bool); +extern bool merge_default_template_args (tree, tree, bool); extern tree duplicate_decls (tree, tree, bool hiding = false, bool was_hidden = false); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index de41b4de5ed..48763c44518 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -1470,6 +1470,43 @@ duplicate_function_template_decls (tree newdecl, tree olddecl) return false; } +/* OLD_PARMS is the innermost set of template parameters for some template + declaration, and NEW_PARMS is the corresponding set of template parameters + for a redeclaration of that template. Merge the default arguments within + these two sets of parameters. CLASS_P is true iff the template in + question is a class template. */ + +bool +merge_default_template_args (tree new_parms, tree old_parms, bool class_p) +{ + gcc_checking_assert (TREE_VEC_LENGTH (new_parms) + == TREE_VEC_LENGTH (old_parms)); + for (int i = 0; i < TREE_VEC_LENGTH (new_parms); i++) + { + tree new_parm = TREE_VALUE (TREE_VEC_ELT (new_parms, i)); + tree old_parm = TREE_VALUE (TREE_VEC_ELT (old_parms, i)); + tree& new_default = TREE_PURPOSE (TREE_VEC_ELT (new_parms, i)); + tree& old_default = TREE_PURPOSE (TREE_VEC_ELT (old_parms, i)); + if (new_default != NULL_TREE && old_default != NULL_TREE) + { + auto_diagnostic_group d; + error ("redefinition of default argument for %q+#D", new_parm); + inform (DECL_SOURCE_LOCATION (old_parm), + "original definition appeared here"); + return false; + } + else if (new_default != NULL_TREE) + /* Update the previous template parameters (which are the ones + that will really count) with the new default value. */ + old_default = new_default; + else if (class_p && old_default != NULL_TREE) + /* Update the new parameters, too; they'll be used as the + parameters for any members. */ + new_default = old_default; + } + return true; +} + /* If NEWDECL is a redeclaration of OLDDECL, merge the declarations. If the redeclaration is invalid, a diagnostic is issued, and the error_mark_node is returned. Otherwise, OLDDECL is returned. @@ -1990,7 +2027,21 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) template shall be specified on the initial declaration of the member function within the class template. */ || CLASSTYPE_TEMPLATE_INFO (CP_DECL_CONTEXT (olddecl)))) - check_redeclaration_no_default_args (newdecl); + { + check_redeclaration_no_default_args (newdecl); + + if (DECL_TEMPLATE_INFO (olddecl) + && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (olddecl))) + { + tree new_parms = DECL_TEMPLATE_INFO (newdecl) + ? DECL_INNERMOST_TEMPLATE_PARMS (DECL_TI_TEMPLATE (newdecl)) + : INNERMOST_TEMPLATE_PARMS (current_template_parms); + tree old_parms + = DECL_INNERMOST_TEMPLATE_PARMS (DECL_TI_TEMPLATE (olddecl)); + merge_default_template_args (new_parms, old_parms, + /*class_p=*/false); + } + } else { tree t1 = FUNCTION_FIRST_USER_PARMTYPE (olddecl); @@ -2235,6 +2286,11 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden) translation unit." */ check_no_redeclaration_friend_default_args (old_result, new_result); + + tree new_parms = DECL_INNERMOST_TEMPLATE_PARMS (newdecl); + tree old_parms = DECL_INNERMOST_TEMPLATE_PARMS (olddecl); + merge_default_template_args (new_parms, old_parms, + /*class_p=*/false); } if (!DECL_UNIQUE_FRIEND_P (old_result)) DECL_UNIQUE_FRIEND_P (new_result) = false; diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index d47483dd4f2..c93676ed8d2 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -6274,8 +6274,6 @@ redeclare_class_template (tree type, tree parms, tree cons) { tree tmpl_parm; tree parm; - tree tmpl_default; - tree parm_default; if (TREE_VEC_ELT (tmpl_parms, i) == error_mark_node || TREE_VEC_ELT (parms, i) == error_mark_node) @@ -6286,8 +6284,6 @@ redeclare_class_template (tree type, tree parms, tree cons) return false; parm = TREE_VALUE (TREE_VEC_ELT (parms, i)); - tmpl_default = TREE_PURPOSE (TREE_VEC_ELT (tmpl_parms, i)); - parm_default = TREE_PURPOSE (TREE_VEC_ELT (parms, i)); /* TMPL_PARM and PARM can be either TYPE_DECL, PARM_DECL, or TEMPLATE_DECL. */ @@ -6303,7 +6299,7 @@ redeclare_class_template (tree type, tree parms, tree cons) { auto_diagnostic_group d; error ("template parameter %q+#D", tmpl_parm); - inform (input_location, "redeclared here as %q#D", parm); + inform (DECL_SOURCE_LOCATION (parm), "redeclared here as %q#D", parm); return false; } @@ -6321,28 +6317,6 @@ redeclare_class_template (tree type, tree parms, tree cons) return false; } - if (tmpl_default != NULL_TREE && parm_default != NULL_TREE) - { - /* We have in [temp.param]: - - A template-parameter may not be given default arguments - by two different declarations in the same scope. */ - auto_diagnostic_group d; - error_at (input_location, "redefinition of default argument for %q#D", parm); - inform (DECL_SOURCE_LOCATION (tmpl_parm), - "original definition appeared here"); - return false; - } - - if (parm_default != NULL_TREE) - /* Update the previous template parameters (which are the ones - that will really count) with the new default value. */ - TREE_PURPOSE (TREE_VEC_ELT (tmpl_parms, i)) = parm_default; - else if (tmpl_default != NULL_TREE) - /* Update the new parameters, too; they'll be used as the - parameters for any members. */ - TREE_PURPOSE (TREE_VEC_ELT (parms, i)) = tmpl_default; - /* Give each template template parm in this redeclaration a DECL_CONTEXT of the template for which they are a parameter. */ if (TREE_CODE (parm) == TEMPLATE_DECL) @@ -6352,6 +6326,9 @@ redeclare_class_template (tree type, tree parms, tree cons) } } + if (!merge_default_template_args (parms, tmpl_parms, /*class_p=*/true)) + return false; + tree ci = get_constraints (tmpl); tree req1 = ci ? CI_TEMPLATE_REQS (ci) : NULL_TREE; tree req2 = cons ? CI_TEMPLATE_REQS (cons) : NULL_TREE; diff --git a/gcc/testsuite/g++.dg/cpp0x/vt-34314.C b/gcc/testsuite/g++.dg/cpp0x/vt-34314.C index b37cac53223..704a975cc95 100644 --- a/gcc/testsuite/g++.dg/cpp0x/vt-34314.C +++ b/gcc/testsuite/g++.dg/cpp0x/vt-34314.C @@ -3,8 +3,8 @@ template // { dg-error "template parameter" } struct call; -template -struct call // { dg-message "note: redeclared here" } +template // { dg-message "note: redeclared here" } +struct call { template struct result; @@ -20,8 +20,8 @@ struct call // { dg-message "note: redeclared here" } template // { dg-error "template parameter" } struct call2; -template -struct call2 // { dg-message "note: redeclared here" } +template // { dg-message "note: redeclared here" } +struct call2 { template struct result; @@ -36,8 +36,8 @@ struct call2 // { dg-message "note: redeclared here" } template class... TT> // { dg-error "template parameter" } struct call3; -template class TT> -struct call3 // { dg-message "note: redeclared here" } +template class TT> // { dg-message "note: redeclared here" } +struct call3 { template struct result; diff --git a/gcc/testsuite/g++.dg/template/defarg23.C b/gcc/testsuite/g++.dg/template/defarg23.C new file mode 100644 index 00000000000..443d02656cc --- /dev/null +++ b/gcc/testsuite/g++.dg/template/defarg23.C @@ -0,0 +1,21 @@ +// PR c++/65396 +// { dg-do compile { target c++11 } } + +template void f(); +template void f(); + +template void g(); // { dg-message "original definition" } +template void g(); // { dg-error "redefinition of default" } + +template void h(); +template +void h() { + static_assert(__is_same(T, char), ""); + static_assert(__is_same(U, bool), ""); +} + +int main() { + f(); + g(); + h(); +} diff --git a/gcc/testsuite/g++.dg/template/defarg23a.C b/gcc/testsuite/g++.dg/template/defarg23a.C new file mode 100644 index 00000000000..3de0306112e --- /dev/null +++ b/gcc/testsuite/g++.dg/template/defarg23a.C @@ -0,0 +1,24 @@ +// PR c++/65396 +// { dg-do compile { target c++11 } } +// Like defarg23.C, but for member functions. + +struct A { + template void f(); + template void g(); // { dg-message "original definition" } + template void h(); +}; + +template void A::f() { } +template void A::g() { } // { dg-error "redefinition of default" } +template +void A::h() { + static_assert(__is_same(T, char), ""); + static_assert(__is_same(U, bool), ""); +} + +int main() { + A a; + a.f(); + a.g(); + a.h(); +} diff --git a/gcc/testsuite/g++.dg/template/pr92440.C b/gcc/testsuite/g++.dg/template/pr92440.C index 20db5f10586..f1e9281ab86 100644 --- a/gcc/testsuite/g++.dg/template/pr92440.C +++ b/gcc/testsuite/g++.dg/template/pr92440.C @@ -3,8 +3,8 @@ template // { dg-error "template parameter" } struct S { - template - friend struct S; // { dg-message "note: redeclared here as" } + template // { dg-message "note: redeclared here as" } + friend struct S; }; S<0> s; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/redecl1.C b/gcc/testsuite/g++.old-deja/g++.pt/redecl1.C index 48517f5d1d3..7596513acc0 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/redecl1.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/redecl1.C @@ -9,14 +9,14 @@ struct S1 {}; // { dg-error "redeclared" } used 1 template parameter template // { dg-message "original definition" } struct S2; -template -struct S2; // { dg-error "redefinition of default" } +template // { dg-error "redefinition of default" } +struct S2; template // { dg-error "template parameter" } struct S3; -template -struct S3; // { dg-message "note: redeclared here" } +template // { dg-message "note: redeclared here" } +struct S3; -template