+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
 
 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);
 
                               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
       && 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)
        {
 
 }
 
 /* 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.  */
                  "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.  */
 
   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
 
+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
 
--- /dev/null
+// 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" }