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
next 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).