aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse/ParseDeclCXX.cpp
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2010-02-28 18:18:36 +0000
committerChris Lattner <sabre@nondot.org>2010-02-28 18:18:36 +0000
commitb3a4e432c90be98c6d918087750397e86d030368 (patch)
tree169e560fd0cef319e42fae5e336abdc8e2d707cd /lib/Parse/ParseDeclCXX.cpp
parent0378bf0840335c6d56b2f1b51079522054f7da4f (diff)
Implement PR6423 by using one token of lookahead to disambiguate
an *almost* always incorrect case. This only does the lookahead in the insanely unlikely case, so it shouldn't impact performance. On this testcase: struct foo { } typedef int x; Before: t.c:3:9: error: cannot combine with previous 'struct' declaration specifier typedef int x; ^ After: t.c:2:2: error: expected ';' after struct } ^ ; git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97403 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseDeclCXX.cpp')
-rw-r--r--lib/Parse/ParseDeclCXX.cpp41
1 files changed, 32 insertions, 9 deletions
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index cb0e5a7f87..bccfc6ad62 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -940,7 +940,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
//
// This switch enumerates the valid "follow" set for definition.
if (TUK == Action::TUK_Definition) {
+ bool ExpectedSemi = true;
switch (Tok.getKind()) {
+ default: break;
case tok::semi: // struct foo {...} ;
case tok::star: // struct foo {...} * P;
case tok::amp: // struct foo {...} & R = ...
@@ -951,24 +953,46 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
case tok::annot_template_id: // struct foo {...} a<int> ::b;
case tok::l_paren: // struct foo {...} ( x);
case tok::comma: // __builtin_offsetof(struct foo{...} ,
+ ExpectedSemi = false;
+ break;
+ // Type qualifiers
+ case tok::kw_const: // struct foo {...} const x;
+ case tok::kw_volatile: // struct foo {...} volatile x;
+ case tok::kw_restrict: // struct foo {...} restrict x;
+ case tok::kw_inline: // struct foo {...} inline foo() {};
// Storage-class specifiers
case tok::kw_static: // struct foo {...} static x;
case tok::kw_extern: // struct foo {...} extern x;
case tok::kw_typedef: // struct foo {...} typedef x;
case tok::kw_register: // struct foo {...} register x;
case tok::kw_auto: // struct foo {...} auto x;
- // Type qualifiers
- case tok::kw_const: // struct foo {...} const x;
- case tok::kw_volatile: // struct foo {...} volatile x;
- case tok::kw_restrict: // struct foo {...} restrict x;
- case tok::kw_inline: // struct foo {...} inline foo() {};
+ // As shown above, type qualifiers and storage class specifiers absolutely
+ // can occur after class specifiers according to the grammar. However,
+ // almost noone actually writes code like this. If we see one of these,
+ // it is much more likely that someone missed a semi colon and the
+ // type/storage class specifier we're seeing is part of the *next*
+ // intended declaration, as in:
+ //
+ // struct foo { ... }
+ // typedef int X;
+ //
+ // We'd really like to emit a missing semicolon error instead of emitting
+ // an error on the 'int' saying that you can't have two type specifiers in
+ // the same declaration of X. Because of this, we look ahead past this
+ // token to see if it's a type specifier. If so, we know the code is
+ // otherwise invalid, so we can produce the expected semi error.
+ if (!isKnownToBeTypeSpecifier(NextToken()))
+ ExpectedSemi = false;
break;
case tok::r_brace: // struct bar { struct foo {...} }
// Missing ';' at end of struct is accepted as an extension in C mode.
- if (!getLang().CPlusPlus) break;
- // FALL THROUGH.
- default:
+ if (!getLang().CPlusPlus)
+ ExpectedSemi = false;
+ break;
+ }
+
+ if (ExpectedSemi) {
ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
TagType == DeclSpec::TST_class ? "class"
: TagType == DeclSpec::TST_struct? "struct" : "union");
@@ -977,7 +1001,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// ';' after the definition.
PP.EnterToken(Tok);
Tok.setKind(tok::semi);
- break;
}
}
}