diff options
author | Serge Pavlov <sepavloff@gmail.com> | 2014-07-14 16:42:20 +0000 |
---|---|---|
committer | Serge Pavlov <sepavloff@gmail.com> | 2014-07-14 16:42:20 +0000 |
commit | a88f27897a2f638e14398422669155effd3a2ee2 (patch) | |
tree | 54d577983d9ed4dbd35cf04fe0cf41a2e4cb4141 /clang/lib | |
parent | b51d464f1ea70eba6f04bdfe8b6d1103fe865cc8 (diff) | |
download | bcm5719-llvm-a88f27897a2f638e14398422669155effd3a2ee2.tar.gz bcm5719-llvm-a88f27897a2f638e14398422669155effd3a2ee2.zip |
Improve error recovery around colon.
Recognize additional cases, when '::' is mistyped as ':'.
This is a fix to RP18587 - colons have too much protection in member-declarations.
Differential Revision: http://reviews.llvm.org/D3653
llvm-svn: 212957
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 24 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 31 |
2 files changed, 31 insertions, 24 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 09f78e5a755..89f4fc9fb92 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2715,24 +2715,23 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // typedef-name case tok::kw_decltype: case tok::identifier: { + // This identifier can only be a typedef name if we haven't already seen + // a type-specifier. Without this check we misparse: + // typedef int X; struct Y { short X; }; as 'short int'. + if (DS.hasTypeSpecifier()) + goto DoneWithDeclSpec; + // In C++, check to see if this is a scope specifier like foo::bar::, if // so handle it as such. This is important for ctor parsing. if (getLangOpts().CPlusPlus) { if (TryAnnotateCXXScopeToken(EnteringContext)) { - if (!DS.hasTypeSpecifier()) - DS.SetTypeSpecError(); + DS.SetTypeSpecError(); goto DoneWithDeclSpec; } if (!Tok.is(tok::identifier)) continue; } - // This identifier can only be a typedef name if we haven't already seen - // a type-specifier. Without this check we misparse: - // typedef int X; struct Y { short X; }; as 'short int'. - if (DS.hasTypeSpecifier()) - goto DoneWithDeclSpec; - // Check for need to substitute AltiVec keyword tokens. if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) break; @@ -4529,7 +4528,9 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // Member pointers get special handling, since there's no place for the // scope spec in the generic path below. if (getLangOpts().CPlusPlus && - (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) || + (Tok.is(tok::coloncolon) || + (Tok.is(tok::identifier) && + (NextToken().is(tok::coloncolon) || NextToken().is(tok::less))) || Tok.is(tok::annot_cxxscope))) { bool EnteringContext = D.getContext() == Declarator::FileContext || D.getContext() == Declarator::MemberContext; @@ -4722,6 +4723,11 @@ void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR inside a class, in + // this context it is a bitfield. + ColonProtectionRAIIObject X(*this, + D.getContext() == Declarator::MemberContext); + // ParseDeclaratorInternal might already have parsed the scope. if (D.getCXXScopeSpec().isEmpty()) { bool EnteringContext = D.getContext() == Declarator::FileContext || diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index cd2e3971884..6200363b3bc 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1239,7 +1239,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Parse the (optional) nested-name-specifier. CXXScopeSpec &SS = DS.getTypeSpecScope(); if (getLangOpts().CPlusPlus) { - // "FOO : BAR" is not a potential typo for "FOO::BAR". + // "FOO : BAR" is not a potential typo for "FOO::BAR". In this context it + // is a base-specifier-list. ColonProtectionRAIIObject X(*this); if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) @@ -1926,14 +1927,8 @@ void Parser::ParseCXXMemberDeclaratorBeforeInitializer( // declarator pure-specifier[opt] // declarator brace-or-equal-initializer[opt] // identifier[opt] ':' constant-expression - if (Tok.isNot(tok::colon)) { - // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it - // is a bitfield. - // FIXME: This should only apply when parsing the id-expression (see - // PR18587). - ColonProtectionRAIIObject X(*this); + if (Tok.isNot(tok::colon)) ParseDeclarator(DeclaratorInfo); - } if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) { BitfieldSize = ParseConstantExpression(); @@ -2015,6 +2010,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } + // Turn on colon protection early, while parsing declspec, although there is + // nothing to protect there. It prevents from false errors if error recovery + // incorrectly determines where the declspec ends, as in the example: + // struct A { enum class B { C }; }; + // const int C = 4; + // struct D { A::B : C; }; + ColonProtectionRAIIObject X(*this); + // Access declarations. bool MalformedTypeSpec = false; if (!TemplateInfo.Kind && @@ -2128,13 +2131,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (MalformedTypeSpec) DS.SetTypeSpecError(); - { - // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it - // is a bitfield. - ColonProtectionRAIIObject X(*this); - ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, - &CommonLateParsedAttrs); - } + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, + &CommonLateParsedAttrs); + + // Turn off colon protection that was set for declspec. + X.restore(); // If we had a free-standing type definition with a missing semicolon, we // may get this far before the problem becomes obvious. |