Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit a0d5dbf

Browse files
committed
[Parser] Update CachedTokens while parsing ObjectiveC template argument list
Consider the following ObjC++ snippet: -- @protocol PA; @protocol PB; @Class NSArray<ObjectType>; typedef int some_t; id<PA> FA(NSArray<id<PB>> *h, some_t group); -- This would hit an assertion in the parser after generating an annotation token while trying to update the token cache: Assertion failed: (CachedTokens[CachedLexPos-1].getLastLoc() == Tok.getAnnotationEndLoc() && "The annotation should be until the most recent cached token") ... 7 clang::Preprocessor::AnnotatePreviousCachedTokens(clang::Token const&) + 494 8 clang::Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool, bool, clang::CXXScopeSpec&, bool) + 1163 9 clang::Parser::TryAnnotateTypeOrScopeToken(bool, bool) + 361 10 clang::Parser::isCXXDeclarationSpecifier(clang::Parser::TPResult, bool*) + 598 ... The cached preprocessor token in this case is: greatergreater '>>' Loc=<testcase.mm:7:24> while the annotation ("NSArray<id<PB>>") ends at "testcase.mm:7:25", hence the assertion. Properly update the CachedTokens during template parsing to contain two greater tokens instead of a greatergreater. Differential Revision: http://reviews.llvm.org/D15173 rdar://problem/23494277 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@259311 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent e9cc0aa commit a0d5dbf

File tree

4 files changed

+57
-0
lines changed

4 files changed

+57
-0
lines changed

include/clang/Lex/Preprocessor.h

+11
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,17 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
11851185
return CachedTokens[CachedLexPos-1].getLastLoc();
11861186
}
11871187

1188+
/// \brief Whether \p Tok is the most recent token (`CachedLexPos - 1`) in
1189+
/// CachedTokens.
1190+
bool IsPreviousCachedToken(const Token &Tok) const;
1191+
1192+
/// \brief Replace token in `CachedLexPos - 1` in CachedTokens by the tokens
1193+
/// in \p NewToks.
1194+
///
1195+
/// Useful when a token needs to be split in smaller ones and CachedTokens
1196+
/// most recent token must to be updated to reflect that.
1197+
void ReplacePreviousCachedToken(ArrayRef<Token> NewToks);
1198+
11881199
/// \brief Replace the last token with an annotation token.
11891200
///
11901201
/// Like AnnotateCachedTokens(), this routine replaces an

lib/Lex/PPCaching.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,29 @@ void Preprocessor::AnnotatePreviousCachedTokens(const Token &Tok) {
116116
}
117117
}
118118
}
119+
120+
bool Preprocessor::IsPreviousCachedToken(const Token &Tok) const {
121+
// There's currently no cached token...
122+
if (!CachedLexPos)
123+
return false;
124+
125+
const Token LastCachedTok = CachedTokens[CachedLexPos - 1];
126+
if (LastCachedTok.getKind() != Tok.getKind())
127+
return false;
128+
129+
int RelOffset = 0;
130+
if ((!getSourceManager().isInSameSLocAddrSpace(
131+
Tok.getLocation(), getLastCachedTokenLocation(), &RelOffset)) ||
132+
RelOffset)
133+
return false;
134+
135+
return true;
136+
}
137+
138+
void Preprocessor::ReplacePreviousCachedToken(ArrayRef<Token> NewToks) {
139+
assert(CachedLexPos != 0 && "Expected to have some cached tokens");
140+
CachedTokens.insert(CachedTokens.begin() + CachedLexPos - 1, NewToks.begin(),
141+
NewToks.end());
142+
CachedTokens.erase(CachedTokens.begin() + CachedLexPos - 1 + NewToks.size());
143+
CachedLexPos += NewToks.size() - 1;
144+
}

lib/Parse/ParseTemplate.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,7 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
831831
}
832832

833833
// Strip the initial '>' from the token.
834+
Token PrevTok = Tok;
834835
if (RemainingToken == tok::equal && Next.is(tok::equal) &&
835836
areTokensAdjacent(Tok, Next)) {
836837
// Join two adjacent '=' tokens into one, for cases like:
@@ -847,6 +848,17 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
847848
PP.getSourceManager(),
848849
getLangOpts()));
849850

851+
// The advance from '>>' to '>' in a ObjectiveC template argument list needs
852+
// to be properly reflected in the token cache to allow correct interaction
853+
// between annotation and backtracking.
854+
if (ObjCGenericList && PrevTok.getKind() == tok::greatergreater &&
855+
RemainingToken == tok::greater && PP.IsPreviousCachedToken(PrevTok)) {
856+
PrevTok.setKind(RemainingToken);
857+
PrevTok.setLength(1);
858+
Token NewToks[] = {PrevTok, Tok};
859+
PP.ReplacePreviousCachedToken(NewToks);
860+
}
861+
850862
if (!ConsumeLastToken) {
851863
// Since we're not supposed to consume the '>' token, we need to push
852864
// this token and revert the current token back to the '>'.

test/Parser/objcxx11-protocol-in-template.mm

+8
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,11 @@ @protocol P @end
88

99
vector<id<P>> v;
1010
vector<vector<id<P>>> v2;
11+
12+
@protocol PA;
13+
@protocol PB;
14+
15+
@class NSArray<ObjectType>;
16+
typedef int some_t;
17+
18+
id<PA> FA(NSArray<id<PB>> *h, some_t group);

0 commit comments

Comments
 (0)