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:
Douglas Gregor 2007-03-28 14:05:29 +00:00 committed by Doug Gregor
parent e701c05c17
commit 9b7dd5e868
10 changed files with 200 additions and 36 deletions

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;
}

View File

@ -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.

View File

@ -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);
}

View File

@ -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)
}

View File

@ -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?
}

View File

@ -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" }
{
}