diff options
author | Patrick Palka <ppalka@redhat.com> | 2022-03-09 08:42:19 -0500 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2022-03-09 08:42:19 -0500 |
commit | fe548eb8436f3906e6a3c6e3e8707d24e60ec0fa (patch) | |
tree | d155334d863e95a715b555679753ac37c91d8f04 | |
parent | 4470e813b0b46d2e579b9e3d69a41a7192709c50 (diff) | |
download | gcc-fe548eb8436f3906e6a3c6e3e8707d24e60ec0fa.zip gcc-fe548eb8436f3906e6a3c6e3e8707d24e60ec0fa.tar.gz gcc-fe548eb8436f3906e6a3c6e3e8707d24e60ec0fa.tar.bz2 |
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.
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/decl.cc | 58 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 31 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/vt-34314.C | 12 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/defarg23.C | 21 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/defarg23a.C | 24 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/template/pr92440.C | 4 | ||||
-rw-r--r-- | 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 cf08e16..757711b 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 de41b4d..48763c4 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 d47483d..c93676e 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 b37cac5..704a975 100644 --- a/gcc/testsuite/g++.dg/cpp0x/vt-34314.C +++ b/gcc/testsuite/g++.dg/cpp0x/vt-34314.C @@ -3,8 +3,8 @@ template<typename Fun, typename... Args> // { dg-error "template parameter" } struct call; -template<typename Fun, typename Arg0> -struct call // { dg-message "note: redeclared here" } +template<typename Fun, typename Arg0> // { dg-message "note: redeclared here" } +struct call { template<typename Sig> struct result; @@ -20,8 +20,8 @@ struct call // { dg-message "note: redeclared here" } template<typename Fun, int... N> // { dg-error "template parameter" } struct call2; -template<typename Fun, int N> -struct call2 // { dg-message "note: redeclared here" } +template<typename Fun, int N> // { dg-message "note: redeclared here" } +struct call2 { template<typename Sig> struct result; @@ -36,8 +36,8 @@ struct call2 // { dg-message "note: redeclared here" } template<typename Fun, template<typename> class... TT> // { dg-error "template parameter" } struct call3; -template<typename Fun, template<typename> class TT> -struct call3 // { dg-message "note: redeclared here" } +template<typename Fun, template<typename> class TT> // { dg-message "note: redeclared here" } +struct call3 { template<typename Sig> 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 0000000..443d026 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/defarg23.C @@ -0,0 +1,21 @@ +// PR c++/65396 +// { dg-do compile { target c++11 } } + +template<class T> void f(); +template<class T=int> void f(); + +template<class T=int> void g(); // { dg-message "original definition" } +template<class T=int> void g(); // { dg-error "redefinition of default" } + +template<class T, class U=bool> void h(); +template<class T=char, class U> +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 0000000..3de0306 --- /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<class T> void f(); + template<class T=int> void g(); // { dg-message "original definition" } + template<class T=char, class U> void h(); +}; + +template<class T=int> void A::f() { } +template<class T=int> void A::g() { } // { dg-error "redefinition of default" } +template<class T, class U=bool> +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 20db5f1..f1e9281 100644 --- a/gcc/testsuite/g++.dg/template/pr92440.C +++ b/gcc/testsuite/g++.dg/template/pr92440.C @@ -3,8 +3,8 @@ template <int T> // { dg-error "template parameter" } struct S { - template <class U> - friend struct S; // { dg-message "note: redeclared here as" } + template <class U> // { 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 48517f5d..7596513 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 <class T = int> // { dg-message "original definition" } struct S2; -template <class T = int> -struct S2; // { dg-error "redefinition of default" } +template <class T = int> // { dg-error "redefinition of default" } +struct S2; template <class T> // { dg-error "template parameter" } struct S3; -template <int I> -struct S3; // { dg-message "note: redeclared here" } +template <int I> // { dg-message "note: redeclared here" } +struct S3; -template <template <class T> class C> -struct S3; // { dg-message "note: redeclared here" } +template <template <class T> class C> // { dg-message "note: redeclared here" } +struct S3; |