c++: merge default targs for function templates [PR65396]
Commit Message
We currently merge default template arguments for class templates, but
not for function templates. This patch fixes this by splitting out the
argument merging logic in redeclare_class_template into a separate
function and using it in duplicate_decls as well.
Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
trunk?
PR c++/65396
gcc/cp/ChangeLog:
* cp-tree.h (merge_default_template_args): Declare.
* decl.cc (merge_default_template_args): Define, split out from
redeclare_class_template.
(duplicate_decls): Use it when merging member function template
and free function declarations.
* pt.cc (redeclare_class_template): Split 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.
---
gcc/cp/cp-tree.h | 1 +
gcc/cp/decl.cc | 60 ++++++++++++++++++++-
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, 123 insertions(+), 42 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/template/defarg23.C
create mode 100644 gcc/testsuite/g++.dg/template/defarg23a.C
Comments
On 3/3/22 16:06, Patrick Palka wrote:
> We currently merge default template arguments for class templates, but
> not for function templates. This patch fixes this by splitting out the
> argument merging logic in redeclare_class_template into a separate
> function and using it in duplicate_decls as well.
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for
> trunk?
>
> PR c++/65396
>
> gcc/cp/ChangeLog:
>
> * cp-tree.h (merge_default_template_args): Declare.
> * decl.cc (merge_default_template_args): Define, split out from
> redeclare_class_template.
> (duplicate_decls): Use it when merging member function template
> and free function declarations.
> * pt.cc (redeclare_class_template): Split 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.
> ---
> gcc/cp/cp-tree.h | 1 +
> gcc/cp/decl.cc | 60 ++++++++++++++++++++-
> 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, 123 insertions(+), 42 deletions(-)
> create mode 100644 gcc/testsuite/g++.dg/template/defarg23.C
> create mode 100644 gcc/testsuite/g++.dg/template/defarg23a.C
>
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index 8a44218611f..ea53e2d0ef2 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -6783,6 +6783,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 23c06655bde..a0bce56c121 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,23 @@ 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)))
> + {
> + /* NEWDECL doesn't have its own TEMPLATE_INFO, so we need to
> + use current_template_parms. */
> + gcc_checking_assert (!DECL_TEMPLATE_INFO (newdecl));
I think let's try to use DECL_TEMPLATE_INFO if it's set, and only fall
back to current_template_parms if it isn't. OK with that change.
> + tree new_parms
> + = 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 +2288,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 18a21572ce3..d94d4538faa 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<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 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<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 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<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 20db5f10586..f1e9281ab86 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 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 <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;
@@ -6783,6 +6783,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);
@@ -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,23 @@ 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)))
+ {
+ /* NEWDECL doesn't have its own TEMPLATE_INFO, so we need to
+ use current_template_parms. */
+ gcc_checking_assert (!DECL_TEMPLATE_INFO (newdecl));
+ tree new_parms
+ = 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 +2288,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;
@@ -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;
@@ -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;
new file mode 100644
@@ -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();
+}
new file mode 100644
@@ -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();
+}
@@ -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;
@@ -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;