diff options
author | Alex Lorenz <arphaman@gmail.com> | 2017-04-11 15:01:53 +0000 |
---|---|---|
committer | Alex Lorenz <arphaman@gmail.com> | 2017-04-11 15:01:53 +0000 |
commit | f127821140b107f35aad84b4b214d12bfa19ba8b (patch) | |
tree | 7b15d5c81ea6f83fc60d3db07eb6f0797493c46e /clang/lib | |
parent | 59a2d7b9093617aff6b6f147ba267bc788aa08b7 (diff) | |
download | bcm5719-llvm-f127821140b107f35aad84b4b214d12bfa19ba8b.tar.gz bcm5719-llvm-f127821140b107f35aad84b4b214d12bfa19ba8b.zip |
[Parser][ObjC++] Improve diagnostics and recovery when C++ keywords are used
as identifiers in Objective-C++
This commit improves the 'expected identifier' errors that are presented when a
C++ keyword is used as an identifier in Objective-C++ by mentioning that this is
a C++ keyword in the diagnostic message. It also improves the error recovery:
the parser will now treat the C++ keywords as identifiers to prevent unrelated
parsing errors.
rdar://20626062
Differential Revision: https://reviews.llvm.org/D26503
llvm-svn: 299950
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Basic/IdentifierTable.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Parse/ParseObjc.cpp | 75 | ||||
-rw-r--r-- | clang/lib/Parse/Parser.cpp | 15 |
4 files changed, 68 insertions, 52 deletions
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 5caa8a6fb21..74c85376c7d 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -244,7 +244,7 @@ static KeywordStatus getTokenKwStatus(const LangOptions &LangOpts, /// \brief Returns true if the identifier represents a keyword in the /// specified language. -bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) { +bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) const { switch (getTokenKwStatus(LangOpts, getTokenID())) { case KS_Enabled: case KS_Extension: @@ -254,6 +254,19 @@ bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) { } } +/// \brief Returns true if the identifier represents a C++ keyword in the +/// specified language. +bool IdentifierInfo::isCPlusPlusKeyword(const LangOptions &LangOpts) const { + if (!LangOpts.CPlusPlus || !isKeyword(LangOpts)) + return false; + // This is a C++ keyword if this identifier is not a keyword when checked + // using LangOptions without C++ support. + LangOptions LangOptsNoCPP = LangOpts; + LangOptsNoCPP.CPlusPlus = false; + LangOptsNoCPP.CPlusPlus11 = false; + return !isKeyword(LangOptsNoCPP); +} + tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { // We use a perfect hash function here involving the length of the keyword, // the first and third character. For preprocessor ID's there are no diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 85ac71f296c..1465d21ac5e 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5580,6 +5580,21 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (Tok.is(tok::l_square)) return ParseMisplacedBracketDeclarator(D); if (D.getContext() == Declarator::MemberContext) { + // Objective-C++: Detect C++ keywords and try to prevent further errors by + // treating these keyword as valid member names. + if (getLangOpts().ObjC1 && getLangOpts().CPlusPlus && + Tok.getIdentifierInfo() && + Tok.getIdentifierInfo()->isCPlusPlusKeyword(getLangOpts())) { + Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()), + diag::err_expected_member_name_or_semi_objcxx_keyword) + << Tok.getIdentifierInfo() + << (D.getDeclSpec().isEmpty() ? SourceRange() + : D.getDeclSpec().getSourceRange()); + D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + D.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); + goto PastIdentifier; + } Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()), diag::err_expected_member_name_or_semi) << (D.getDeclSpec().isEmpty() ? SourceRange() diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 9a677d1b40e..77e63efc065 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -137,8 +137,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { while (1) { MaybeSkipAttributes(tok::objc_class); - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected) << tok::identifier; + if (expectIdentifier()) { SkipUntil(tok::semi); return Actions.ConvertDeclToDeclGroup(nullptr); } @@ -229,11 +228,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, MaybeSkipAttributes(tok::objc_interface); - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected) - << tok::identifier; // missing class or category name. - return nullptr; - } + if (expectIdentifier()) + return nullptr; // missing class or category name. // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); @@ -319,11 +315,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, return nullptr; } - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected) - << tok::identifier; // missing super class name. - return nullptr; - } + if (expectIdentifier()) + return nullptr; // missing super class name. superClassId = Tok.getIdentifierInfo(); superClassLoc = ConsumeToken(); @@ -1438,12 +1431,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, cutOffParsing(); return nullptr; } - - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected) - << tok::identifier; // missing argument name. - break; - } + + if (expectIdentifier()) + break; // missing argument name. ArgInfo.Name = Tok.getIdentifierInfo(); ArgInfo.NameLoc = Tok.getLocation(); @@ -1552,8 +1542,7 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols, return true; } - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected) << tok::identifier; + if (expectIdentifier()) { SkipUntil(tok::greater, StopAtSemi); return true; } @@ -2035,10 +2024,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, MaybeSkipAttributes(tok::objc_protocol); - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected) << tok::identifier; // missing protocol name. - return nullptr; - } + if (expectIdentifier()) + return nullptr; // missing protocol name. // Save the protocol name, then consume it. IdentifierInfo *protocolName = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); @@ -2058,8 +2045,7 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, // Parse the list of forward declarations. while (1) { ConsumeToken(); // the ',' - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected) << tok::identifier; + if (expectIdentifier()) { SkipUntil(tok::semi); return nullptr; } @@ -2126,11 +2112,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { MaybeSkipAttributes(tok::objc_implementation); - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected) - << tok::identifier; // missing class or category name. - return nullptr; - } + if (expectIdentifier()) + return nullptr; // missing class or category name. // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); // consume class or category name @@ -2200,11 +2183,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) { IdentifierInfo *superClassId = nullptr; if (TryConsumeToken(tok::colon)) { // We have a super class - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected) - << tok::identifier; // missing super class name. - return nullptr; - } + if (expectIdentifier()) + return nullptr; // missing super class name. superClassId = Tok.getIdentifierInfo(); superClassLoc = ConsumeToken(); // Consume super class name } @@ -2304,16 +2284,12 @@ Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) && "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias"); ConsumeToken(); // consume compatibility_alias - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected) << tok::identifier; + if (expectIdentifier()) return nullptr; - } IdentifierInfo *aliasId = Tok.getIdentifierInfo(); SourceLocation aliasLoc = ConsumeToken(); // consume alias-name - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected) << tok::identifier; + if (expectIdentifier()) return nullptr; - } IdentifierInfo *classId = Tok.getIdentifierInfo(); SourceLocation classLoc = ConsumeToken(); // consume class-name; ExpectAndConsume(tok::semi, diag::err_expected_after, "@compatibility_alias"); @@ -2361,11 +2337,9 @@ Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { cutOffParsing(); return nullptr; } - - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected) << tok::identifier; + + if (expectIdentifier()) break; - } propertyIvar = Tok.getIdentifierInfo(); propertyIvarLoc = ConsumeToken(); // consume ivar-name } @@ -2423,9 +2397,8 @@ Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { cutOffParsing(); return nullptr; } - - if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_expected) << tok::identifier; + + if (expectIdentifier()) { SkipUntil(tok::semi); return nullptr; } @@ -3561,8 +3534,8 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - if (Tok.isNot(tok::identifier)) - return ExprError(Diag(Tok, diag::err_expected) << tok::identifier); + if (expectIdentifier()) + return ExprError(); IdentifierInfo *protocolId = Tok.getIdentifierInfo(); SourceLocation ProtoIdLoc = ConsumeToken(); diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 81a4580e271..aa8ed91d382 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -211,6 +211,21 @@ void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) { << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc)); } +bool Parser::expectIdentifier() { + if (Tok.is(tok::identifier)) + return false; + if (const auto *II = Tok.getIdentifierInfo()) { + if (II->isCPlusPlusKeyword(getLangOpts())) { + Diag(Tok, diag::err_expected_token_instead_of_objcxx_keyword) + << tok::identifier << Tok.getIdentifierInfo(); + // Objective-C++: Recover by treating this keyword as a valid identifier. + return false; + } + } + Diag(Tok, diag::err_expected) << tok::identifier; + return true; +} + //===----------------------------------------------------------------------===// // Error recovery. //===----------------------------------------------------------------------===// |