public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Patrick Palka <patrick@parcs.ath.cx>
To: gcc-patches@gcc.gnu.org
Cc: jason@redhat.com,	Patrick Palka <patrick@parcs.ath.cx>
Subject: [PATCH] Fix PR c++/16160
Date: Wed, 14 Jan 2015 05:30:00 -0000	[thread overview]
Message-ID: <1421207682-14372-1-git-send-email-patrick@parcs.ath.cx> (raw)

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	other threads:[~2015-01-14  3:55 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-01-14  5:30 Patrick Palka [this message]
2015-01-14 13:27 ` Jason Merrill
2015-01-14 13:34   ` Patrick Palka
2015-01-14 13:49     ` Patrick Palka
2015-01-14 18:23 ` Patrick Palka
2015-01-14 21:34   ` Jason Merrill
2015-01-14 22:20     ` Patrick Palka
2015-01-15  1:19       ` Jason Merrill

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1421207682-14372-1-git-send-email-patrick@parcs.ath.cx \
    --to=patrick@parcs.ath.cx \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jason@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).