From 3572e5ae42d63e5c91472ff011d86f468f3f1744 Mon Sep 17 00:00:00 2001 From: jason Date: Fri, 31 Aug 2012 21:35:33 +0000 Subject: [PATCH] PR c++/18747 * pt.c (check_template_variable): New. (num_template_headers_for_class): Split out... * decl.c (grokdeclarator): ...from here. (start_decl): Remove redundant diagnostic. * cp-tree.h: Declare them * parser.c (cp_parser_single_declaration): Call check_template_variable. . git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@190842 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 11 +++++++ gcc/cp/cp-tree.h | 2 ++ gcc/cp/decl.c | 34 +------------------- gcc/cp/parser.c | 7 +++-- gcc/cp/pt.c | 60 ++++++++++++++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 6 ++++ gcc/testsuite/g++.dg/parse/error50.C | 18 +++++++++++ 7 files changed, 103 insertions(+), 35 deletions(-) create mode 100644 gcc/testsuite/g++.dg/parse/error50.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5fb1b41c149..c36ed8888dd 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2012-08-31 Paolo Carlini + Jason Merrill + + PR c++/18747 + * pt.c (check_template_variable): New. + (num_template_headers_for_class): Split out... + * decl.c (grokdeclarator): ...from here. + (start_decl): Remove redundant diagnostic. + * cp-tree.h: Declare them + * parser.c (cp_parser_single_declaration): Call check_template_variable. + 2012-08-31 Ollie Wild PR c++/54197 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 1b085bd1609..bd57b92c961 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5316,6 +5316,8 @@ extern void end_specialization (void); extern void begin_explicit_instantiation (void); extern void end_explicit_instantiation (void); extern tree check_explicit_specialization (tree, tree, int, int); +extern int num_template_headers_for_class (tree); +extern void check_template_variable (tree); extern tree make_auto (void); extern tree do_auto_deduction (tree, tree, tree); extern tree type_uses_auto (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index c909dea1775..8b94e26ac0c 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -4461,11 +4461,6 @@ start_decl (const cp_declarator *declarator, context, DECL_NAME (decl)); DECL_CONTEXT (decl) = DECL_CONTEXT (field); } - if (processing_specialization - && template_class_depth (context) == 0 - && CLASSTYPE_TEMPLATE_SPECIALIZATION (context)) - error ("template header not allowed in member definition " - "of explicitly specialized class"); /* Static data member are tricky; an in-class initialization still doesn't provide a definition, so the in-class declaration will have DECL_EXTERNAL set, but will have an @@ -9564,36 +9559,9 @@ grokdeclarator (const cp_declarator *declarator, && declarator->u.id.qualifying_scope && MAYBE_CLASS_TYPE_P (declarator->u.id.qualifying_scope)) { - tree t; - ctype = declarator->u.id.qualifying_scope; ctype = TYPE_MAIN_VARIANT (ctype); - t = ctype; - while (t != NULL_TREE && CLASS_TYPE_P (t)) - { - /* You're supposed to have one `template <...>' for every - template class, but you don't need one for a full - specialization. For example: - - template struct S{}; - template <> struct S { void f(); }; - void S::f () {} - - is correct; there shouldn't be a `template <>' for the - definition of `S::f'. */ - if (CLASSTYPE_TEMPLATE_SPECIALIZATION (t) - && !any_dependent_template_arguments_p (CLASSTYPE_TI_ARGS (t))) - /* T is an explicit (not partial) specialization. All - containing classes must therefore also be explicitly - specialized. */ - break; - if ((CLASSTYPE_USE_TEMPLATE (t) || CLASSTYPE_IS_TEMPLATE (t)) - && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t))) - template_count += 1; - - t = TYPE_MAIN_DECL (t); - t = DECL_CONTEXT (t); - } + template_count = num_template_headers_for_class (ctype); if (ctype == current_class_type) { diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 091a96728ad..60ba380cf74 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -21310,8 +21310,8 @@ cp_parser_perform_template_parameter_access_checks (VEC (deferred_access_check,g } /* Parse a `decl-specifier-seq [opt] init-declarator [opt] ;' or - `function-definition' sequence. MEMBER_P is true, this declaration - appears in a class scope. + `function-definition' sequence that follows a template header. + If MEMBER_P is true, this declaration appears in a class scope. Returns the DECL for the declared entity. If FRIEND_P is non-NULL, *FRIEND_P is set to TRUE iff the declaration is a friend. */ @@ -21431,6 +21431,9 @@ cp_parser_single_declaration (cp_parser* parser, "explicit template specialization cannot have a storage class"); decl = error_mark_node; } + + if (decl && TREE_CODE (decl) == VAR_DECL) + check_template_variable (decl); } /* Look for a trailing `;' after the declaration. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 5ce6e8af87f..4a3942715b8 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2208,6 +2208,66 @@ copy_default_args_to_explicit_spec (tree decl) TREE_TYPE (decl) = new_type; } +/* Return the number of template headers we expect to see for a definition + or specialization of CTYPE or one of its non-template members. */ + +int +num_template_headers_for_class (tree ctype) +{ + int template_count = 0; + tree t = ctype; + while (t != NULL_TREE && CLASS_TYPE_P (t)) + { + /* You're supposed to have one `template <...>' for every + template class, but you don't need one for a full + specialization. For example: + + template struct S{}; + template <> struct S { void f(); }; + void S::f () {} + + is correct; there shouldn't be a `template <>' for the + definition of `S::f'. */ + if (CLASSTYPE_TEMPLATE_SPECIALIZATION (t) + && !any_dependent_template_arguments_p (CLASSTYPE_TI_ARGS (t))) + /* T is an explicit (not partial) specialization. All + containing classes must therefore also be explicitly + specialized. */ + break; + if ((CLASSTYPE_USE_TEMPLATE (t) || CLASSTYPE_IS_TEMPLATE (t)) + && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t))) + template_count += 1; + + t = TYPE_MAIN_DECL (t); + t = DECL_CONTEXT (t); + } + + return template_count; +} + +/* Do a simple sanity check on the template headers that precede the + variable declaration DECL. */ + +void +check_template_variable (tree decl) +{ + tree ctx = CP_DECL_CONTEXT (decl); + int wanted = num_template_headers_for_class (ctx); + if (!TYPE_P (ctx) || !CLASSTYPE_TEMPLATE_INFO (ctx)) + permerror (DECL_SOURCE_LOCATION (decl), + "%qD is not a static data member of a class template", decl); + else if (template_header_count > wanted) + { + pedwarn (DECL_SOURCE_LOCATION (decl), 0, + "too many template headers for %D (should be %d)", + decl, wanted); + if (CLASSTYPE_TEMPLATE_SPECIALIZATION (ctx)) + inform (DECL_SOURCE_LOCATION (decl), + "members of an explicitly specialized class are defined " + "without a template header"); + } +} + /* Check to see if the function just declared, as indicated in DECLARATOR, and in DECL, is a specialization of a function template. We may also discover that the declaration is an explicit diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 685c60dc460..22fcd065e3c 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2012-08-31 Paolo Carlini + Jason Merrill + + PR c++/18747 + * g++.dg/parse/error50.C: New. + 2012-08-31 Jakub Jelinek PR c/54428 diff --git a/gcc/testsuite/g++.dg/parse/error50.C b/gcc/testsuite/g++.dg/parse/error50.C new file mode 100644 index 00000000000..dbd8958c360 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/error50.C @@ -0,0 +1,18 @@ +// PR c++/18747 + +template<> int i; // { dg-error "template" } + +struct A +{ + static int i; +}; + +template<> int A::i; // { dg-error "template" } + +template +struct B +{ + static T i; +}; + +template<> template <> int B::i; // { dg-error "should be 1" } -- 2.11.4.GIT