summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Trieu <rtrieu@google.com>2019-05-01 23:33:49 +0000
committerRichard Trieu <rtrieu@google.com>2019-05-01 23:33:49 +0000
commitc9884fd36d9a452fad1edc440dbc2835340e1602 (patch)
tree563a1ffb2df7a3bfb26d3da86e7cb6d93388dd42
parentb1e9fc11aabd9b342d59b9449936426731e0d023 (diff)
Consume unexpected "template" keywords after "using"
The parser was dealing with unexpected "template" keywords after "using" keywords too late and putting the parser into the wrong state, which could lead to a crash down the line. This change allows the parser to consume the bad "template" keywords earlier, and continue parsing as if "template" was never there to begin with for better error recovery. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359740 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td2
-rw-r--r--lib/Parse/ParseDeclCXX.cpp14
-rw-r--r--test/Parser/using-template.cpp52
3 files changed, 68 insertions, 0 deletions
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 3003d0a8d3..4bd29b629d 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -683,6 +683,8 @@ def err_id_after_template_in_nested_name_spec : Error<
"expected template name after 'template' keyword in nested name specifier">;
def err_unexpected_template_in_unqualified_id : Error<
"'template' keyword not permitted here">;
+def err_unexpected_template_after_using : Error<
+ "'template' keyword not permitted after 'using' keyword">;
def err_two_right_angle_brackets_need_space : Error<
"a space is required between consecutive right angle brackets (use '> >')">;
def err_right_angle_bracket_equal_needs_space : Error<
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 7d2fcbd3e1..c4fe23c60c 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -474,6 +474,13 @@ Parser::ParseUsingDirectiveOrDeclaration(DeclaratorContext Context,
return nullptr;
}
+ // Consume unexpected 'template' keywords.
+ while (Tok.is(tok::kw_template)) {
+ SourceLocation TemplateLoc = ConsumeToken();
+ Diag(TemplateLoc, diag::err_unexpected_template_after_using)
+ << FixItHint::CreateRemoval(TemplateLoc);
+ }
+
// 'using namespace' means this is a using-directive.
if (Tok.is(tok::kw_namespace)) {
// Template parameters are always an error here.
@@ -2542,6 +2549,13 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// Eat 'using'.
SourceLocation UsingLoc = ConsumeToken();
+ // Consume unexpected 'template' keywords.
+ while (Tok.is(tok::kw_template)) {
+ SourceLocation TemplateLoc = ConsumeToken();
+ Diag(TemplateLoc, diag::err_unexpected_template_after_using)
+ << FixItHint::CreateRemoval(TemplateLoc);
+ }
+
if (Tok.is(tok::kw_namespace)) {
Diag(UsingLoc, diag::err_using_namespace_in_class);
SkipUntil(tok::semi, StopBeforeMatch);
diff --git a/test/Parser/using-template.cpp b/test/Parser/using-template.cpp
new file mode 100644
index 0000000000..686873d60b
--- /dev/null
+++ b/test/Parser/using-template.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 %s -verify
+
+namespace N1 {
+template <typename... Ts>
+struct Foo {
+ template <typename T>
+ struct Bar {
+ static constexpr bool is_present = false;
+ };
+};
+
+template <typename T, typename... Ts>
+struct Foo<T, Ts...> : public Foo<Ts...> {
+ using template Foo<Ts...>::Bar;
+ // expected-error@-1 {{'template' keyword not permitted after 'using' keyword}}
+};
+}
+
+namespace N2 {
+namespace foo {
+ using I = int;
+}
+using template namespace foo;
+// expected-error@-1 {{'template' keyword not permitted after 'using' keyword}}
+using template template namespace foo;
+// expected-error@-1 2{{'template' keyword not permitted after 'using' keyword}}
+I i;
+}
+
+namespace N3 {
+namespace foo {
+ using I = int;
+}
+using template foo::I;
+// expected-error@-1 {{'template' keyword not permitted after 'using' keyword}}
+I i;
+}
+
+namespace N4 {
+template <typename T>
+class A {};
+
+template <typename T>
+using B = A<T>;
+B<int> b;
+
+using template <typename T> C = A<T>;
+// expected-error@-1 {{'template' keyword not permitted after 'using' keyword}}
+// expected-error@-2 {{expected unqualified-id}}
+C<int> c;
+// expected-error@-1 {{no template named 'C'}}
+}