aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse/ParseDecl.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-12-01 17:42:47 +0000
committerDouglas Gregor <dgregor@apple.com>2010-12-01 17:42:47 +0000
commita61b3e7443056f8d05b24ca4cbea90fe66235d6b (patch)
tree5ed483b461473fc0d663356e107a19343e5b9f3b /lib/Parse/ParseDecl.cpp
parentd11617f6e0622bbf843d6f8d60c441f844e46e9a (diff)
After parsing a ':' in an enum-specifier within class context,
disambiguate between an expression (for a bit-field width) and a type (for a fixed underlying type). Since the disambiguation can be expensive (due to tentative parsing), we perform a simplistic disambiguation based on one-token lookahead before going into the full-blown tentative parsing. Based on a patch by Daniel Wallin. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@120582 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseDecl.cpp')
-rw-r--r--lib/Parse/ParseDecl.cpp54
1 files changed, 50 insertions, 4 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index db02c78351..f1fb7b29a1 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1921,7 +1921,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, RBraceLoc);
}
-
/// ParseEnumSpecifier
/// enum-specifier: [C99 6.7.2.2]
/// 'enum' identifier[opt] '{' enumerator-list '}'
@@ -2014,10 +2013,57 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
TypeResult BaseType;
+ // Parse the fixed underlying type.
if (getLang().CPlusPlus0x && Tok.is(tok::colon)) {
- ConsumeToken();
- SourceRange Range;
- BaseType = ParseTypeName(&Range);
+ bool PossibleBitfield = false;
+ if (getCurScope()->getFlags() & Scope::ClassScope) {
+ // If we're in class scope, this can either be an enum declaration with
+ // an underlying type, or a declaration of a bitfield member. We try to
+ // use a simple disambiguation scheme first to catch the common cases
+ // (integer literal, sizeof); if it's still ambiguous, we then consider
+ // anything that's a simple-type-specifier followed by '(' as an
+ // expression. This suffices because function types are not valid
+ // underlying types anyway.
+ TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind());
+ // If the next token starts an expression, we know we're parsing a
+ // bit-field. This is the common case.
+ if (TPR == TPResult::True())
+ PossibleBitfield = true;
+ // If the next token starts a type-specifier-seq, it may be either a
+ // a fixed underlying type or the start of a function-style cast in C++;
+ // lookahead one more token to see if it's obvious that we have a
+ // fixed underlying type.
+ else if (TPR == TPResult::False() &&
+ GetLookAheadToken(2).getKind() == tok::semi) {
+ // Consume the ':'.
+ ConsumeToken();
+ } else {
+ // We have the start of a type-specifier-seq, so we have to perform
+ // tentative parsing to determine whether we have an expression or a
+ // type.
+ TentativeParsingAction TPA(*this);
+
+ // Consume the ':'.
+ ConsumeToken();
+
+ if (isCXXDeclarationSpecifier() != TPResult::True()) {
+ // We'll parse this as a bitfield later.
+ PossibleBitfield = true;
+ TPA.Revert();
+ } else {
+ // We have a type-specifier-seq.
+ TPA.Commit();
+ }
+ }
+ } else {
+ // Consume the ':'.
+ ConsumeToken();
+ }
+
+ if (!PossibleBitfield) {
+ SourceRange Range;
+ BaseType = ParseTypeName(&Range);
+ }
}
// There are three options here. If we have 'enum foo;', then this is a