decl.c (redeclaration_error_message): Complain when redeclaring a friend function with default template arguments...
2007-03-28 Douglas Gregor <doug.gregor@gmail.com> * decl.c (redeclaration_error_message): Complain when redeclaring a friend function with default template arguments (C++0x mode only). * cp-tree.h (check_default_tmpl_args): Declare. * pt.c (check_default_tmpl_args): In C++0x mode, permit default template arguments in function templates. Add support for checking the default template arguments of friend templates. (push_template_decl_real): Fix call to check_default_tmpl_args. (type_unification_real): If a template parameter has not been deduced but provides a default template argument, substitute into that default template argument. * parser.c (cp_parser_init_declarator): When declaring (but not defining!) a function template in C++0x mode, check for default template arguments. 2007-03-28 Douglas Gregor <doug.gregor@gmail.com> * g++.dg/cpp0x/temp_default1.C: New. * g++.dg/cpp0x/temp_default3.C: New. * g++.dg/cpp0x/temp_default2.C: New. * g++.dg/cpp0x/temp_default4.C: New. From-SVN: r123300
This commit is contained in:
parent
e701c05c17
commit
9b7dd5e868
|
@ -1,3 +1,19 @@
|
|||
2007-03-28 Douglas Gregor <doug.gregor@gmail.com>
|
||||
|
||||
* decl.c (redeclaration_error_message): Complain when redeclaring
|
||||
a friend function with default template arguments (C++0x mode only).
|
||||
* cp-tree.h (check_default_tmpl_args): Declare.
|
||||
* pt.c (check_default_tmpl_args): In C++0x mode, permit default
|
||||
template arguments in function templates. Add support for checking
|
||||
the default template arguments of friend templates.
|
||||
(push_template_decl_real): Fix call to check_default_tmpl_args.
|
||||
(type_unification_real): If a template parameter has not been
|
||||
deduced but provides a default template argument, substitute into
|
||||
that default template argument.
|
||||
* parser.c (cp_parser_init_declarator): When declaring (but not
|
||||
defining!) a function template in C++0x mode, check for default
|
||||
template arguments.
|
||||
|
||||
2007-03-28 Douglas Gregor <doug.gregor@gmail.com>
|
||||
|
||||
PR c++/29993
|
||||
|
|
|
@ -4300,6 +4300,7 @@ extern tree check_explicit_specialization (tree, tree, int, int);
|
|||
extern tree process_template_parm (tree, tree, bool, bool);
|
||||
extern tree end_template_parm_list (tree);
|
||||
extern void end_template_decl (void);
|
||||
extern bool check_default_tmpl_args (tree, tree, int, int, int);
|
||||
extern tree push_template_decl (tree);
|
||||
extern tree push_template_decl_real (tree, bool);
|
||||
extern bool redeclare_class_template (tree, tree);
|
||||
|
|
|
@ -2148,6 +2148,19 @@ redeclaration_error_message (tree newdecl, tree olddecl)
|
|||
if (DECL_INITIAL (nt) && DECL_INITIAL (ot))
|
||||
return "redefinition of %q#D";
|
||||
|
||||
/* Core issue #226 (C++0x):
|
||||
|
||||
If a friend function template declaration specifies a
|
||||
default template-argument, that declaration shall be a
|
||||
definition and shall be the only declaration of the
|
||||
function template in the translation unit. */
|
||||
if (flag_cpp0x
|
||||
&& TREE_CODE (ot) == FUNCTION_DECL && DECL_FRIEND_P (ot)
|
||||
&& !check_default_tmpl_args (nt, DECL_TEMPLATE_PARMS (newdecl),
|
||||
/*is_primary=*/1, /*is_partial=*/0,
|
||||
/*is_friend_decl=*/2))
|
||||
return "redeclaration of friend %q#D may not have default template arguments";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
else if (TREE_CODE (newdecl) == VAR_DECL
|
||||
|
|
|
@ -11721,6 +11721,13 @@ cp_parser_init_declarator (cp_parser* parser,
|
|||
((is_parenthesized_init || !is_initialized)
|
||||
? 0 : LOOKUP_ONLYCONVERTING));
|
||||
}
|
||||
else if (flag_cpp0x && friend_p && decl && TREE_CODE (decl) == FUNCTION_DECL)
|
||||
/* Core issue #226 (C++0x only): A default template-argument
|
||||
shall not be specified in a friend class template
|
||||
declaration. */
|
||||
check_default_tmpl_args (decl, current_template_parms, /*is_primary=*/1,
|
||||
/*is_partial=*/0, /*is_friend_decl=*/1);
|
||||
|
||||
if (!friend_p && pushed_scope)
|
||||
pop_scope (pushed_scope);
|
||||
|
||||
|
|
121
gcc/cp/pt.c
121
gcc/cp/pt.c
|
@ -152,7 +152,6 @@ static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
|
|||
static bool check_specialization_scope (void);
|
||||
static tree process_partial_specialization (tree);
|
||||
static void set_current_access_from_decl (tree);
|
||||
static void check_default_tmpl_args (tree, tree, int, int);
|
||||
static tree get_template_base (tree, tree, tree, tree);
|
||||
static tree try_class_unification (tree, tree, tree, tree);
|
||||
static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
|
||||
|
@ -3377,14 +3376,24 @@ process_partial_specialization (tree decl)
|
|||
/* Check that a template declaration's use of default arguments is not
|
||||
invalid. Here, PARMS are the template parameters. IS_PRIMARY is
|
||||
nonzero if DECL is the thing declared by a primary template.
|
||||
IS_PARTIAL is nonzero if DECL is a partial specialization. */
|
||||
IS_PARTIAL is nonzero if DECL is a partial specialization.
|
||||
|
||||
|
||||
static void
|
||||
check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
|
||||
IS_FRIEND_DECL is nonzero if DECL is a friend function template
|
||||
declaration (but not a definition); 1 indicates a declaration, 2
|
||||
indicates a redeclaration. When IS_FRIEND_DECL=2, no errors are
|
||||
emitted for extraneous default arguments.
|
||||
|
||||
Returns TRUE if there were no errors found, FALSE otherwise. */
|
||||
|
||||
bool
|
||||
check_default_tmpl_args (tree decl, tree parms, int is_primary,
|
||||
int is_partial, int is_friend_decl)
|
||||
{
|
||||
const char *msg;
|
||||
int last_level_to_check;
|
||||
tree parm_level;
|
||||
bool no_errors = true;
|
||||
|
||||
/* [temp.param]
|
||||
|
||||
|
@ -3397,7 +3406,7 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
|
|||
/* You can't have a function template declaration in a local
|
||||
scope, nor you can you define a member of a class template in a
|
||||
local scope. */
|
||||
return;
|
||||
return true;
|
||||
|
||||
if (current_class_type
|
||||
&& !TYPE_BEING_DEFINED (current_class_type)
|
||||
|
@ -3417,40 +3426,49 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
|
|||
declared, so there's no need to do it again now. This function
|
||||
was defined in class scope, but we're processing it's body now
|
||||
that the class is complete. */
|
||||
return;
|
||||
return true;
|
||||
|
||||
/* [temp.param]
|
||||
|
||||
If a template-parameter has a default template-argument, all
|
||||
subsequent template-parameters shall have a default
|
||||
template-argument supplied. */
|
||||
for (parm_level = parms; parm_level; parm_level = TREE_CHAIN (parm_level))
|
||||
/* Core issue 226 (C++0x only): the following only applies to class
|
||||
templates. */
|
||||
if (!flag_cpp0x || TREE_CODE (decl) != FUNCTION_DECL)
|
||||
{
|
||||
tree inner_parms = TREE_VALUE (parm_level);
|
||||
int ntparms = TREE_VEC_LENGTH (inner_parms);
|
||||
int seen_def_arg_p = 0;
|
||||
int i;
|
||||
/* [temp.param]
|
||||
|
||||
for (i = 0; i < ntparms; ++i)
|
||||
{
|
||||
tree parm = TREE_VEC_ELT (inner_parms, i);
|
||||
If a template-parameter has a default template-argument, all
|
||||
subsequent template-parameters shall have a default
|
||||
template-argument supplied. */
|
||||
for (parm_level = parms; parm_level; parm_level = TREE_CHAIN (parm_level))
|
||||
{
|
||||
tree inner_parms = TREE_VALUE (parm_level);
|
||||
int ntparms = TREE_VEC_LENGTH (inner_parms);
|
||||
int seen_def_arg_p = 0;
|
||||
int i;
|
||||
|
||||
if (parm == error_mark_node)
|
||||
continue;
|
||||
for (i = 0; i < ntparms; ++i)
|
||||
{
|
||||
tree parm = TREE_VEC_ELT (inner_parms, i);
|
||||
|
||||
if (TREE_PURPOSE (parm))
|
||||
seen_def_arg_p = 1;
|
||||
else if (seen_def_arg_p)
|
||||
{
|
||||
error ("no default argument for %qD", TREE_VALUE (parm));
|
||||
/* For better subsequent error-recovery, we indicate that
|
||||
there should have been a default argument. */
|
||||
TREE_PURPOSE (parm) = error_mark_node;
|
||||
}
|
||||
}
|
||||
if (parm == error_mark_node)
|
||||
continue;
|
||||
|
||||
if (TREE_PURPOSE (parm))
|
||||
seen_def_arg_p = 1;
|
||||
else if (seen_def_arg_p)
|
||||
{
|
||||
error ("no default argument for %qD", TREE_VALUE (parm));
|
||||
/* For better subsequent error-recovery, we indicate that
|
||||
there should have been a default argument. */
|
||||
TREE_PURPOSE (parm) = error_mark_node;
|
||||
no_errors = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (TREE_CODE (decl) != TYPE_DECL || is_partial || !is_primary)
|
||||
if ((!flag_cpp0x && TREE_CODE (decl) != TYPE_DECL)
|
||||
|| is_partial
|
||||
|| !is_primary
|
||||
|| is_friend_decl)
|
||||
/* For an ordinary class template, default template arguments are
|
||||
allowed at the innermost level, e.g.:
|
||||
template <class T = int>
|
||||
|
@ -3461,8 +3479,8 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
|
|||
The template parameter list of a specialization shall not
|
||||
contain default template argument values.
|
||||
|
||||
So, for a partial specialization, or for a function template,
|
||||
we look at all of them. */
|
||||
So, for a partial specialization, or for a function template
|
||||
(in C++98/C++03), we look at all of them. */
|
||||
;
|
||||
else
|
||||
/* But, for a primary class template that is not a partial
|
||||
|
@ -3471,7 +3489,11 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
|
|||
parms = TREE_CHAIN (parms);
|
||||
|
||||
/* Figure out what error message to issue. */
|
||||
if (TREE_CODE (decl) == FUNCTION_DECL)
|
||||
if (is_friend_decl == 2)
|
||||
msg = "default template arguments may not be used in function template friend re-declaration";
|
||||
else if (is_friend_decl)
|
||||
msg = "default template arguments may not be used in function template friend declarations";
|
||||
else if (TREE_CODE (decl) == FUNCTION_DECL && !flag_cpp0x)
|
||||
msg = "default template arguments may not be used in function templates";
|
||||
else if (is_partial)
|
||||
msg = "default template arguments may not be used in partial specializations";
|
||||
|
@ -3510,6 +3532,10 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
|
|||
{
|
||||
if (msg)
|
||||
{
|
||||
no_errors = false;
|
||||
if (is_friend_decl == 2)
|
||||
return no_errors;
|
||||
|
||||
error (msg, decl);
|
||||
msg = 0;
|
||||
}
|
||||
|
@ -3525,6 +3551,8 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
|
|||
if (msg)
|
||||
msg = "default argument for template parameter for class enclosing %qD";
|
||||
}
|
||||
|
||||
return no_errors;
|
||||
}
|
||||
|
||||
/* Worker for push_template_decl_real, called via
|
||||
|
@ -3652,7 +3680,7 @@ push_template_decl_real (tree decl, bool is_friend)
|
|||
/* Check to see that the rules regarding the use of default
|
||||
arguments are not being violated. */
|
||||
check_default_tmpl_args (decl, current_template_parms,
|
||||
primary, is_partial);
|
||||
primary, is_partial, /*is_friend_decl=*/0);
|
||||
|
||||
/* Ensure that there are no parameter packs in the type of this
|
||||
declaration that have not been expanded. */
|
||||
|
@ -11346,6 +11374,27 @@ type_unification_real (tree tparms,
|
|||
&& !saw_undeduced++)
|
||||
goto again;
|
||||
|
||||
/* Core issue #226 (C++0x) [temp.deduct]:
|
||||
|
||||
If a template argument has not been deduced, its
|
||||
default template argument, if any, is used.
|
||||
|
||||
When we are not in C++0x mode (i.e., !flag_cpp0x),
|
||||
TREE_PURPOSE will either be NULL_TREE or ERROR_MARK_NODE,
|
||||
so we do not need to explicitly check flag_cpp0x here. */
|
||||
if (TREE_PURPOSE (TREE_VEC_ELT (tparms, i)))
|
||||
{
|
||||
tree arg = tsubst (TREE_PURPOSE (TREE_VEC_ELT (tparms, i)),
|
||||
targs, tf_none, NULL_TREE);
|
||||
if (arg == error_mark_node)
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
TREE_VEC_ELT (targs, i) = arg;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
2007-03-28 Douglas Gregor <doug.gregor@gmail.com>
|
||||
|
||||
* g++.dg/cpp0x/temp_default1.C: New.
|
||||
* g++.dg/cpp0x/temp_default3.C: New.
|
||||
* g++.dg/cpp0x/temp_default2.C: New.
|
||||
* g++.dg/cpp0x/temp_default4.C: New.
|
||||
|
||||
2007-03-28 Douglas Gregor <doug.gregor@gmail.com>
|
||||
|
||||
PR c++/29993
|
||||
* g++.dg/other/cv_func2.C: New.
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
// { dg-options "-std=c++0x" }
|
||||
|
||||
template<typename T, typename U>
|
||||
struct is_same
|
||||
{
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_same<T, T> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template<typename T = int> void f()
|
||||
{
|
||||
static_assert(is_same<T, int>::value,
|
||||
"T can only be instantiated with an int");
|
||||
}
|
||||
|
||||
template<typename T = int, typename U>
|
||||
void f(U)
|
||||
{
|
||||
static_assert(is_same<T, int>::value,
|
||||
"T can only be instantiated with an int");
|
||||
}
|
||||
|
||||
void g()
|
||||
{
|
||||
float pi = 3.14159;
|
||||
f();
|
||||
f(pi);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// { dg-options "-std=c++0x" }
|
||||
|
||||
template <class T, class U = double>
|
||||
void f(T t = 0, U u = 0);
|
||||
|
||||
void g()
|
||||
{
|
||||
f(1, 'c'); // f<int,char>(1,'c')
|
||||
f(1); // f<int,double>(1,0)
|
||||
f(); // { dg-error "no matching function" }
|
||||
f<int>(); // f<int,double>(0,0)
|
||||
f<int,char>(); // f<int,char>(0,0)
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// { dg-options "-std=c++0x" }
|
||||
|
||||
template<typename T, typename U = typename T::value_type>
|
||||
void f(T);
|
||||
|
||||
void f(...);
|
||||
|
||||
struct X {
|
||||
typedef int value_type;
|
||||
};
|
||||
|
||||
void g()
|
||||
{
|
||||
f(X()); // okay
|
||||
f(17); // okay?
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// { dg-options "-std=c++0x" }
|
||||
|
||||
class X {
|
||||
template<typename T = int> friend void f(X) { }
|
||||
template<typename T> friend void g(X); // { dg-error "previously declared here" }
|
||||
template<typename T = int> friend void h(X); // { dg-error "function template friend" }
|
||||
};
|
||||
|
||||
template<typename T = int> void g(X) // { dg-error "default template argument" }
|
||||
{
|
||||
}
|
Loading…
Reference in New Issue