[cfe-commits] r97403 - in /cfe/trunk: include/clang/Parse/Parser.h lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp test/Sema/declspec.c
Chris Lattner
sabre at nondot.org
Sun Feb 28 10:18:36 PST 2010
Author: lattner
Date: Sun Feb 28 12:18:36 2010
New Revision: 97403
URL: http://llvm.org/viewvc/llvm-project?rev=97403&view=rev
Log:
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
}
^
;
Modified:
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/test/Sema/declspec.c
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=97403&r1=97402&r2=97403&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Sun Feb 28 12:18:36 2010
@@ -329,7 +329,8 @@
/// replacing them with the non-context-sensitive keywords. This returns
/// true if the token was replaced.
bool TryAltiVecToken(DeclSpec &DS, SourceLocation Loc,
- const char *&PrevSpec, unsigned &DiagID, bool &isInvalid) {
+ const char *&PrevSpec, unsigned &DiagID,
+ bool &isInvalid) {
if (getLang().AltiVec) {
if (Tok.getIdentifierInfo() == Ident_vector) {
const Token nextToken = NextToken();
@@ -369,33 +370,31 @@
/// identifier token, replacing it with the non-context-sensitive __vector.
/// This returns true if the token was replaced.
bool TryAltiVecVectorToken() {
- if (getLang().AltiVec) {
- if (Tok.getIdentifierInfo() == Ident_vector) {
- const Token nextToken = NextToken();
- switch (nextToken.getKind()) {
- case tok::kw_short:
- case tok::kw_long:
- case tok::kw_signed:
- case tok::kw_unsigned:
- case tok::kw_void:
- case tok::kw_char:
- case tok::kw_int:
- case tok::kw_float:
- case tok::kw_double:
- case tok::kw_bool:
- case tok::kw___pixel:
- Tok.setKind(tok::kw___vector);
- return true;
- case tok::identifier:
- if (nextToken.getIdentifierInfo() == Ident_pixel) {
- Tok.setKind(tok::kw___vector);
- return true;
- }
- break;
- default:
- break;
- }
+ if (!getLang().AltiVec ||
+ Tok.getIdentifierInfo() != Ident_vector) return false;
+ const Token nextToken = NextToken();
+ switch (nextToken.getKind()) {
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_int:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_bool:
+ case tok::kw___pixel:
+ Tok.setKind(tok::kw___vector);
+ return true;
+ case tok::identifier:
+ if (nextToken.getIdentifierInfo() == Ident_pixel) {
+ Tok.setKind(tok::kw___vector);
+ return true;
}
+ break;
+ default:
+ break;
}
return false;
}
@@ -1181,6 +1180,11 @@
bool isDeclarationSpecifier();
bool isTypeSpecifierQualifier();
bool isTypeQualifier() const;
+
+ /// isKnownToBeTypeSpecifier - Return true if we know that the specified token
+ /// is definitely a type-specifier. Return false if it isn't part of a type
+ /// specifier or if we're not sure.
+ bool isKnownToBeTypeSpecifier(const Token &Tok) const;
/// isDeclarationStatement - Disambiguates between a declaration or an
/// expression statement, when parsing function bodies.
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=97403&r1=97402&r2=97403&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Sun Feb 28 12:18:36 2010
@@ -2019,6 +2019,47 @@
}
}
+/// isKnownToBeTypeSpecifier - Return true if we know that the specified token
+/// is definitely a type-specifier. Return false if it isn't part of a type
+/// specifier or if we're not sure.
+bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const {
+ switch (Tok.getKind()) {
+ default: return false;
+ // type-specifiers
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw__Complex:
+ case tok::kw__Imaginary:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_wchar_t:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_int:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_bool:
+ case tok::kw__Bool:
+ case tok::kw__Decimal32:
+ case tok::kw__Decimal64:
+ case tok::kw__Decimal128:
+ case tok::kw___vector:
+
+ // struct-or-union-specifier (C99) or class-specifier (C++)
+ case tok::kw_class:
+ case tok::kw_struct:
+ case tok::kw_union:
+ // enum-specifier
+ case tok::kw_enum:
+
+ // typedef-name
+ case tok::annot_typename:
+ return true;
+ }
+}
+
/// isTypeSpecifierQualifier - Return true if the current token could be the
/// start of a specifier-qualifier-list.
bool Parser::isTypeSpecifierQualifier() {
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=97403&r1=97402&r2=97403&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Sun Feb 28 12:18:36 2010
@@ -940,7 +940,9 @@
//
// 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 @@
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 @@
// ';' after the definition.
PP.EnterToken(Tok);
Tok.setKind(tok::semi);
- break;
}
}
}
Modified: cfe/trunk/test/Sema/declspec.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/declspec.c?rev=97403&r1=97402&r2=97403&view=diff
==============================================================================
--- cfe/trunk/test/Sema/declspec.c (original)
+++ cfe/trunk/test/Sema/declspec.c Sun Feb 28 12:18:36 2010
@@ -31,3 +31,8 @@
void test2() {}
+
+// PR6423
+struct test3s {
+} // expected-error {{expected ';' after struct}}
+typedef int test3g;
More information about the cfe-commits
mailing list