aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <doug.gregor@gmail.com>2007-03-28 14:05:29 +0000
committerDoug Gregor <dgregor@gcc.gnu.org>2007-03-28 14:05:29 +0000
commit9b7dd5e868e5c3978ea8c6cfef383c2846321ddf (patch)
treec72b508351bff91028912e57668dee64204baa72
parente701c05c17884fb38917e613f42b000e57bacc57 (diff)
downloadgcc-9b7dd5e868e5c3978ea8c6cfef383c2846321ddf.zip
gcc-9b7dd5e868e5c3978ea8c6cfef383c2846321ddf.tar.gz
gcc-9b7dd5e868e5c3978ea8c6cfef383c2846321ddf.tar.bz2
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
-rw-r--r--gcc/cp/ChangeLog16
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/decl.c13
-rw-r--r--gcc/cp/parser.c7
-rw-r--r--gcc/cp/pt.c121
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/temp_default1.C32
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/temp_default2.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/temp_default3.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/temp_default4.C11
10 files changed, 200 insertions, 36 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 7541770..2a63629 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 18f2cfb..95945b3 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index f107bee..ce1c54f 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index ec90726..da573cb 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index da3cd23..1e6c044 100644
--- a/gcc/cp/pt.c
+++ b/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;
-
- /* [temp.param]
+ return true;
- 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;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 442ea61..b59cc0a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default1.C b/gcc/testsuite/g++.dg/cpp0x/temp_default1.C
new file mode 100644
index 0000000..dfa2cfb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/temp_default1.C
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default2.C b/gcc/testsuite/g++.dg/cpp0x/temp_default2.C
new file mode 100644
index 0000000..f7f2228
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/temp_default2.C
@@ -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)
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default3.C b/gcc/testsuite/g++.dg/cpp0x/temp_default3.C
new file mode 100644
index 0000000..f71fe0f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/temp_default3.C
@@ -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?
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default4.C b/gcc/testsuite/g++.dg/cpp0x/temp_default4.C
new file mode 100644
index 0000000..f1e254c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/temp_default4.C
@@ -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" }
+{
+}