This patch fixes the above PR where it was reported that the C++
frontend does not reject the malformed class declaration

    struct X<5>;

Instead of rejecting it, the FE treats this declaration as if it were a
forward declaration of a template specialization, i.e. as if it were
written

    template<> struct X<5>;

First off, the FE should reject the declaration because it is malformed
(not 100% sure, though).  Second, since the user probably intended to
have written an explicit template instantiation (as in the PR), the FE
should suggest adding "template" before such a declaration, that is the
declaration

    struct X<5>; // error + suggest adding "template"

This patch does both these things along with adding error messages +
suggestions for

    struct X<5> { }; // error + suggest adding "template <>"

and

    template struct X<5> { }; // error + suggest replacing with "template <>"

Bootstrap and regtesting in progress.  Does this patch look OK for trunk?

gcc/cp/ChangeLog:

        PR c++/16160
        * parser.c (cp_parser_class_head): Identify and reject malformed
        template-id declarations and definitions.
---
 gcc/cp/parser.c                          | 53 +++++++++++++++++++++++---------
 gcc/testsuite/g++.dg/cpp0x/gen-attrs-9.C |  2 +-
 gcc/testsuite/g++.dg/ext/attrib9.C       |  2 +-
 gcc/testsuite/g++.dg/template/crash54.C  |  2 +-
 gcc/testsuite/g++.dg/template/error55.C  | 11 +++++++
 5 files changed, 53 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/template/error55.C

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 3290dfa..f6dc004 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -20264,6 +20264,34 @@ cp_parser_class_head (cp_parser* parser,
     }
   virt_specifiers = cp_parser_virt_specifier_seq_opt (parser);
 
+  /* Make sure a top-level template-id declaration or definition is preceded
+     by "template" or "template <>".  */
+  if (template_id_p
+      && at_namespace_scope_p ()
+      && parser->num_template_parameter_lists == 0
+      && !processing_explicit_instantiation)
+    {
+      if (cp_parser_next_token_starts_class_definition_p (parser))
+       {
+          error_at (type_start_token->location,
+                   "an explicit specialization must be preceded by "
+                   "%<template <>%>");
+         invalid_explicit_specialization_p = true;
+         /* Try to recover gracefully by taking the same action that would
+            have been taken by cp_parser_explicit_specialization.  */
+         ++parser->num_template_parameter_lists;
+         begin_specialization ();
+       }
+      else if (cp_parser_declares_only_class_p (parser))
+       {
+          error_at (type_start_token->location,
+                   "an explicit instantiation must be preceded by "
+                   "%<template%>");
+         type = error_mark_node;
+         goto out;
+       }
+    }
+
   /* If it's not a `:' or a `{' then we can't really be looking at a
      class-head, since a class-head only appears as part of a
      class-specifier.  We have to detect this situation before calling
@@ -20275,6 +20303,16 @@ cp_parser_class_head (cp_parser* parser,
       goto out;
     }
 
+  if (processing_explicit_instantiation)
+    {
+      error_at (type_start_token->location,
+               "an explicit instantiation may not have a definition");
+      inform (type_start_token->location,
+             "use %<template <>%> to define an explicit specialization");
+      type = error_mark_node;
+      goto out;
+    }
+
   /* At this point, we're going ahead with the class-specifier, even
      if some other problem occurs.  */
   cp_parser_commit_to_tentative_parse (parser);
@@ -20346,20 +20384,7 @@ cp_parser_class_head (cp_parser* parser,
          num_templates = 0;
        }
     }
-  /* An explicit-specialization must be preceded by "template <>".  If
-     it is not, try to recover gracefully.  */
-  if (at_namespace_scope_p ()
-      && parser->num_template_parameter_lists == 0
-      && template_id_p)
-    {
-      error_at (type_start_token->location,
-               "an explicit specialization must be preceded by %<template 
<>%>");
-      invalid_explicit_specialization_p = true;
-      /* Take the same action that would have been taken by
-        cp_parser_explicit_specialization.  */
-      ++parser->num_template_parameter_lists;
-      begin_specialization ();
-    }
+
   /* There must be no "return" statements between this point and the
      end of this function; set "type "to the correct return value and
      use "goto done;" to return.  */
diff --git a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-9.C 
b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-9.C
index 3dc51ee..4957ba1 100644
--- a/gcc/testsuite/g++.dg/cpp0x/gen-attrs-9.C
+++ b/gcc/testsuite/g++.dg/cpp0x/gen-attrs-9.C
@@ -9,4 +9,4 @@ enum [[gnu::unused]] e; // { dg-warning "already defined" }
 struct [[gnu::unused]] B *p;   //  { dg-warning "attributes" }
 
 template <class T> struct A { };
-struct [[gnu::unused]] A<int>; //  { dg-warning "attributes" }
+struct [[gnu::unused]] A<int> y;       //  { dg-warning "attributes" }
diff --git a/gcc/testsuite/g++.dg/ext/attrib9.C 
b/gcc/testsuite/g++.dg/ext/attrib9.C
index 6672f75..e8e158c 100644
--- a/gcc/testsuite/g++.dg/ext/attrib9.C
+++ b/gcc/testsuite/g++.dg/ext/attrib9.C
@@ -7,4 +7,4 @@ enum __attribute__((unused)) e; // { dg-warning "already 
defined" }
 struct __attribute((unused)) B *p;     //  { dg-warning "attributes" }
 
 template <class T> struct A { };
-struct __attribute((unused)) A<int>;   //  { dg-warning "attributes" }
+struct __attribute((unused)) A<int> y; //  { dg-warning "attributes" }
diff --git a/gcc/testsuite/g++.dg/template/crash54.C 
b/gcc/testsuite/g++.dg/template/crash54.C
index 26b4875..b1dbec0 100644
--- a/gcc/testsuite/g++.dg/template/crash54.C
+++ b/gcc/testsuite/g++.dg/template/crash54.C
@@ -2,4 +2,4 @@
 
 template<int> struct A;
 
-struct __attribute__((unused)) A<0<; // { dg-error "template 
argument|unqualified-id" }
+struct __attribute__((unused)) A<0<; // { dg-error "template argument|explicit 
instantiation" }
diff --git a/gcc/testsuite/g++.dg/template/error55.C 
b/gcc/testsuite/g++.dg/template/error55.C
new file mode 100644
index 0000000..e40b3a1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/error55.C
@@ -0,0 +1,11 @@
+// PR c++/16160
+
+template <int N> struct X { };
+template <int N> struct Y { };
+template <int N> struct Z { };
+
+struct X<2>; // { dg-error "explicit instantiation" }
+
+struct Y<2> { }; // { dg-error "explicit specialization" }
+
+template struct Z<2> { }; // { dg-error "may not have a definition" }
-- 
2.3.0.rc0

Reply via email to