diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-12-01 17:42:47 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-12-01 17:42:47 +0000 |
commit | a61b3e7443056f8d05b24ca4cbea90fe66235d6b (patch) | |
tree | 5ed483b461473fc0d663356e107a19343e5b9f3b /lib/Parse/ParseDecl.cpp | |
parent | d11617f6e0622bbf843d6f8d60c441f844e46e9a (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.cpp | 54 |
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 |