diff options
author | Chris Lattner <sabre@nondot.org> | 2010-02-28 18:18:36 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2010-02-28 18:18:36 +0000 |
commit | b3a4e432c90be98c6d918087750397e86d030368 (patch) | |
tree | 169e560fd0cef319e42fae5e336abdc8e2d707cd /lib/Parse/ParseDeclCXX.cpp | |
parent | 0378bf0840335c6d56b2f1b51079522054f7da4f (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.cpp | 41 |
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; } } } |