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.
This commit is contained in:
parent
4470e813b0
commit
fe548eb843
8 changed files with 121 additions and 42 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
31
gcc/cp/pt.cc
31
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
21
gcc/testsuite/g++.dg/template/defarg23.C
Normal file
21
gcc/testsuite/g++.dg/template/defarg23.C
Normal file
|
@ -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();
|
||||
}
|
24
gcc/testsuite/g++.dg/template/defarg23a.C
Normal file
24
gcc/testsuite/g++.dg/template/defarg23a.C
Normal file
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue