]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/18747 ("template<> int i;" accepted)
authorPaolo Carlini <paolo.carlini@oracle.com>
Fri, 31 Aug 2012 21:35:33 +0000 (21:35 +0000)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 31 Aug 2012 21:35:33 +0000 (17:35 -0400)
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.
.
Co-Authored-By: Jason Merrill <jason@redhat.com>
From-SVN: r190842

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/parse/error50.C [new file with mode: 0644]

index 5fb1b41c149162bd9b2cecc1c9a225d23217f609..c36ed8888ddd9b38f854e001af04bef506eb209d 100644 (file)
@@ -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
index 1b085bd16094d7994aa4d81b21021532eba14b9c..bd57b92c961939540cc5cd1c8bfefe79ea687f3b 100644 (file)
@@ -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);
index c909dea177580b67785c819a78e29112359114f7..8b94e26ac0ce67097b361bc25e8292274e9ca340 100644 (file)
@@ -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)
        {
index 091a96728ad17b02e6a6fbe51b5fe94c8ba944f6..60ba380cf745c292063a5457138d002b2d7cbb71 100644 (file)
@@ -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.  */
index 5ce6e8af87fc0ce79b37e4659841c60a94f893fb..4a3942715b868a7cfbe5bc5ba1b127a54b9ae4ff 100644 (file)
@@ -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
index 685c60dc460621b23d2642fc39a759725036e3b6..22fcd065e3c9b7dac15f8acb6c3e5ea8f81e9c07 100644 (file)
@@ -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 (file)
index 0000000..dbd8958
--- /dev/null
@@ -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" }