Commit 9b7dd5e8 by Douglas Gregor Committed by Doug Gregor

decl.c (redeclaration_error_message): Complain when redeclaring a friend…

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
parent e701c05c
2007-03-28 Douglas Gregor <doug.gregor@gmail.com> 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 PR c++/29993
* decl.c (grokdeclarator): Deal with cv-qualified function type * decl.c (grokdeclarator): Deal with cv-qualified function type
typedefs in the same way for member and non-member functions. typedefs in the same way for member and non-member functions.
......
...@@ -4300,6 +4300,7 @@ extern tree check_explicit_specialization (tree, tree, int, int); ...@@ -4300,6 +4300,7 @@ extern tree check_explicit_specialization (tree, tree, int, int);
extern tree process_template_parm (tree, tree, bool, bool); extern tree process_template_parm (tree, tree, bool, bool);
extern tree end_template_parm_list (tree); extern tree end_template_parm_list (tree);
extern void end_template_decl (void); 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 (tree);
extern tree push_template_decl_real (tree, bool); extern tree push_template_decl_real (tree, bool);
extern bool redeclare_class_template (tree, tree); extern bool redeclare_class_template (tree, tree);
......
...@@ -2148,6 +2148,19 @@ redeclaration_error_message (tree newdecl, tree olddecl) ...@@ -2148,6 +2148,19 @@ redeclaration_error_message (tree newdecl, tree olddecl)
if (DECL_INITIAL (nt) && DECL_INITIAL (ot)) if (DECL_INITIAL (nt) && DECL_INITIAL (ot))
return "redefinition of %q#D"; 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; return NULL;
} }
else if (TREE_CODE (newdecl) == VAR_DECL else if (TREE_CODE (newdecl) == VAR_DECL
......
...@@ -11721,6 +11721,13 @@ cp_parser_init_declarator (cp_parser* parser, ...@@ -11721,6 +11721,13 @@ cp_parser_init_declarator (cp_parser* parser,
((is_parenthesized_init || !is_initialized) ((is_parenthesized_init || !is_initialized)
? 0 : LOOKUP_ONLYCONVERTING)); ? 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) if (!friend_p && pushed_scope)
pop_scope (pushed_scope); pop_scope (pushed_scope);
......
...@@ -152,7 +152,6 @@ static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree); ...@@ -152,7 +152,6 @@ static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
static bool check_specialization_scope (void); static bool check_specialization_scope (void);
static tree process_partial_specialization (tree); static tree process_partial_specialization (tree);
static void set_current_access_from_decl (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 get_template_base (tree, tree, tree, tree);
static tree try_class_unification (tree, tree, tree, tree); static tree try_class_unification (tree, tree, tree, tree);
static int coerce_template_template_parms (tree, tree, tsubst_flags_t, static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
...@@ -3377,14 +3376,24 @@ process_partial_specialization (tree decl) ...@@ -3377,14 +3376,24 @@ process_partial_specialization (tree decl)
/* Check that a template declaration's use of default arguments is not /* Check that a template declaration's use of default arguments is not
invalid. Here, PARMS are the template parameters. IS_PRIMARY is invalid. Here, PARMS are the template parameters. IS_PRIMARY is
nonzero if DECL is the thing declared by a primary template. 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; const char *msg;
int last_level_to_check; int last_level_to_check;
tree parm_level; tree parm_level;
bool no_errors = true;
/* [temp.param] /* [temp.param]
...@@ -3397,7 +3406,7 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial) ...@@ -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 /* 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 scope, nor you can you define a member of a class template in a
local scope. */ local scope. */
return; return true;
if (current_class_type if (current_class_type
&& !TYPE_BEING_DEFINED (current_class_type) && !TYPE_BEING_DEFINED (current_class_type)
...@@ -3417,8 +3426,12 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial) ...@@ -3417,8 +3426,12 @@ 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 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 was defined in class scope, but we're processing it's body now
that the class is complete. */ that the class is complete. */
return; return true;
/* Core issue 226 (C++0x only): the following only applies to class
templates. */
if (!flag_cpp0x || TREE_CODE (decl) != FUNCTION_DECL)
{
/* [temp.param] /* [temp.param]
If a template-parameter has a default template-argument, all If a template-parameter has a default template-argument, all
...@@ -3446,11 +3459,16 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial) ...@@ -3446,11 +3459,16 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
/* For better subsequent error-recovery, we indicate that /* For better subsequent error-recovery, we indicate that
there should have been a default argument. */ there should have been a default argument. */
TREE_PURPOSE (parm) = error_mark_node; 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 /* For an ordinary class template, default template arguments are
allowed at the innermost level, e.g.: allowed at the innermost level, e.g.:
template <class T = int> template <class T = int>
...@@ -3461,8 +3479,8 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial) ...@@ -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 The template parameter list of a specialization shall not
contain default template argument values. contain default template argument values.
So, for a partial specialization, or for a function template, So, for a partial specialization, or for a function template
we look at all of them. */ (in C++98/C++03), we look at all of them. */
; ;
else else
/* But, for a primary class template that is not a partial /* 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) ...@@ -3471,7 +3489,11 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
parms = TREE_CHAIN (parms); parms = TREE_CHAIN (parms);
/* Figure out what error message to issue. */ /* 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"; msg = "default template arguments may not be used in function templates";
else if (is_partial) else if (is_partial)
msg = "default template arguments may not be used in partial specializations"; 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) ...@@ -3510,6 +3532,10 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
{ {
if (msg) if (msg)
{ {
no_errors = false;
if (is_friend_decl == 2)
return no_errors;
error (msg, decl); error (msg, decl);
msg = 0; msg = 0;
} }
...@@ -3525,6 +3551,8 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial) ...@@ -3525,6 +3551,8 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, int is_partial)
if (msg) if (msg)
msg = "default argument for template parameter for class enclosing %qD"; msg = "default argument for template parameter for class enclosing %qD";
} }
return no_errors;
} }
/* Worker for push_template_decl_real, called via /* Worker for push_template_decl_real, called via
...@@ -3652,7 +3680,7 @@ push_template_decl_real (tree decl, bool is_friend) ...@@ -3652,7 +3680,7 @@ push_template_decl_real (tree decl, bool is_friend)
/* Check to see that the rules regarding the use of default /* Check to see that the rules regarding the use of default
arguments are not being violated. */ arguments are not being violated. */
check_default_tmpl_args (decl, current_template_parms, 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 /* Ensure that there are no parameter packs in the type of this
declaration that have not been expanded. */ declaration that have not been expanded. */
...@@ -11346,6 +11374,27 @@ type_unification_real (tree tparms, ...@@ -11346,6 +11374,27 @@ type_unification_real (tree tparms,
&& !saw_undeduced++) && !saw_undeduced++)
goto again; 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; return 2;
} }
......
2007-03-28 Douglas Gregor <doug.gregor@gmail.com> 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 PR c++/29993
* g++.dg/other/cv_func2.C: New. * g++.dg/other/cv_func2.C: New.
// { 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);
}
// { 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)
}
// { 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?
}
// { 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" }
{
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment