summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2012-08-31 21:35:33 +0000
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>2012-08-31 21:35:33 +0000
commit3572e5ae42d63e5c91472ff011d86f468f3f1744 (patch)
tree1524695c56ed99a3ea06e58c582ae2814eb03a05
parentf228b1b9535997cd15a0fd5652a3d6182c4ea9e4 (diff)
downloadgcc-3572e5ae42d63e5c91472ff011d86f468f3f1744.tar.gz
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
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/decl.c34
-rw-r--r--gcc/cp/parser.c7
-rw-r--r--gcc/cp/pt.c60
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/parse/error50.C18
7 files changed, 103 insertions, 35 deletions
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 <paolo.carlini@oracle.com>
+ Jason Merrill <jason@redhat.com>
+
+ 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 <aaw@google.com>
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 <class T> struct S{};
- template <> struct S<int> { void f(); };
- void S<int>::f () {}
-
- is correct; there shouldn't be a `template <>' for the
- definition of `S<int>::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 <class T> struct S{};
+ template <> struct S<int> { void f(); };
+ void S<int>::f () {}
+
+ is correct; there shouldn't be a `template <>' for the
+ definition of `S<int>::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 <paolo.carlini@oracle.com>
+ Jason Merrill <jason@redhat.com>
+
+ PR c++/18747
+ * g++.dg/parse/error50.C: New.
+
2012-08-31 Jakub Jelinek <jakub@redhat.com>
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 <class T>
+struct B
+{
+ static T i;
+};
+
+template<> template <> int B<int>::i; // { dg-error "should be 1" }