diff options
author | Douglas Gregor <doug.gregor@gmail.com> | 2007-03-28 14:05:29 +0000 |
---|---|---|
committer | Doug Gregor <dgregor@gcc.gnu.org> | 2007-03-28 14:05:29 +0000 |
commit | 9b7dd5e868e5c3978ea8c6cfef383c2846321ddf (patch) | |
tree | c72b508351bff91028912e57668dee64204baa72 | |
parent | e701c05c17884fb38917e613f42b000e57bacc57 (diff) | |
download | gcc-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/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 1 | ||||
-rw-r--r-- | gcc/cp/decl.c | 13 | ||||
-rw-r--r-- | gcc/cp/parser.c | 7 | ||||
-rw-r--r-- | gcc/cp/pt.c | 121 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/temp_default1.C | 32 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/temp_default2.C | 13 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/temp_default3.C | 16 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/temp_default4.C | 11 |
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" } +{ +} |