forked from OSchip/llvm-project
[preamble] Also record the "skipping" state of the preprocessor
When a preamble ends in a conditional preprocessor block that is being skipped, the preprocessor needs to continue skipping that block when the preamble is used. This fixes PR34570. llvm-svn: 317308
This commit is contained in:
parent
8c825db25e
commit
4d1eb2d5cb
|
@ -286,6 +286,23 @@ class Preprocessor {
|
|||
/// This is used when loading a precompiled preamble.
|
||||
std::pair<int, bool> SkipMainFilePreamble;
|
||||
|
||||
public:
|
||||
struct PreambleSkipInfo {
|
||||
PreambleSkipInfo(SourceLocation HashTokenLoc, SourceLocation IfTokenLoc,
|
||||
bool FoundNonSkipPortion, bool FoundElse,
|
||||
SourceLocation ElseLoc)
|
||||
: HashTokenLoc(HashTokenLoc), IfTokenLoc(IfTokenLoc),
|
||||
FoundNonSkipPortion(FoundNonSkipPortion), FoundElse(FoundElse),
|
||||
ElseLoc(ElseLoc) {}
|
||||
|
||||
SourceLocation HashTokenLoc;
|
||||
SourceLocation IfTokenLoc;
|
||||
bool FoundNonSkipPortion;
|
||||
bool FoundElse;
|
||||
SourceLocation ElseLoc;
|
||||
};
|
||||
|
||||
private:
|
||||
class PreambleConditionalStackStore {
|
||||
enum State {
|
||||
Off = 0,
|
||||
|
@ -319,6 +336,12 @@ class Preprocessor {
|
|||
|
||||
bool hasRecordedPreamble() const { return !ConditionalStack.empty(); }
|
||||
|
||||
bool reachedEOFWhileSkipping() const { return SkipInfo.hasValue(); }
|
||||
|
||||
void clearSkipInfo() { SkipInfo.reset(); }
|
||||
|
||||
llvm::Optional<PreambleSkipInfo> SkipInfo;
|
||||
|
||||
private:
|
||||
SmallVector<PPConditionalInfo, 4> ConditionalStack;
|
||||
State ConditionalStackState;
|
||||
|
@ -1839,7 +1862,7 @@ private:
|
|||
/// \p FoundElse is false, then \#else directives are ok, if not, then we have
|
||||
/// already seen one so a \#else directive is a duplicate. When this returns,
|
||||
/// the caller can lex the first valid token.
|
||||
void SkipExcludedConditionalBlock(const Token &HashToken,
|
||||
void SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
|
||||
SourceLocation IfTokenLoc,
|
||||
bool FoundNonSkipPortion, bool FoundElse,
|
||||
SourceLocation ElseLoc = SourceLocation());
|
||||
|
@ -2019,9 +2042,15 @@ public:
|
|||
PreambleConditionalStack.setStack(s);
|
||||
}
|
||||
|
||||
void setReplayablePreambleConditionalStack(ArrayRef<PPConditionalInfo> s) {
|
||||
void setReplayablePreambleConditionalStack(ArrayRef<PPConditionalInfo> s,
|
||||
llvm::Optional<PreambleSkipInfo> SkipInfo) {
|
||||
PreambleConditionalStack.startReplaying();
|
||||
PreambleConditionalStack.setStack(s);
|
||||
PreambleConditionalStack.SkipInfo = SkipInfo;
|
||||
}
|
||||
|
||||
llvm::Optional<PreambleSkipInfo> getPreambleSkipInfo() const {
|
||||
return PreambleConditionalStack.SkipInfo;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -350,7 +350,7 @@ void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) {
|
|||
/// If ElseOk is true, then \#else directives are ok, if not, then we have
|
||||
/// already seen one so a \#else directive is a duplicate. When this returns,
|
||||
/// the caller can lex the first valid token.
|
||||
void Preprocessor::SkipExcludedConditionalBlock(const Token &HashToken,
|
||||
void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc,
|
||||
SourceLocation IfTokenLoc,
|
||||
bool FoundNonSkipPortion,
|
||||
bool FoundElse,
|
||||
|
@ -358,7 +358,10 @@ void Preprocessor::SkipExcludedConditionalBlock(const Token &HashToken,
|
|||
++NumSkipped;
|
||||
assert(!CurTokenLexer && CurPPLexer && "Lexing a macro, not a file?");
|
||||
|
||||
CurPPLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/false,
|
||||
if (PreambleConditionalStack.reachedEOFWhileSkipping())
|
||||
PreambleConditionalStack.clearSkipInfo();
|
||||
else
|
||||
CurPPLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/ false,
|
||||
FoundNonSkipPortion, FoundElse);
|
||||
|
||||
if (CurPTHLexer) {
|
||||
|
@ -385,6 +388,9 @@ void Preprocessor::SkipExcludedConditionalBlock(const Token &HashToken,
|
|||
// We don't emit errors for unterminated conditionals here,
|
||||
// Lexer::LexEndOfFile can do that propertly.
|
||||
// Just return and let the caller lex after this #include.
|
||||
if (PreambleConditionalStack.isRecording())
|
||||
PreambleConditionalStack.SkipInfo.emplace(
|
||||
HashTokenLoc, IfTokenLoc, FoundNonSkipPortion, FoundElse, ElseLoc);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -554,7 +560,7 @@ void Preprocessor::SkipExcludedConditionalBlock(const Token &HashToken,
|
|||
|
||||
if (Callbacks)
|
||||
Callbacks->SourceRangeSkipped(
|
||||
SourceRange(HashToken.getLocation(), CurPPLexer->getSourceLocation()),
|
||||
SourceRange(HashTokenLoc, CurPPLexer->getSourceLocation()),
|
||||
Tok.getLocation());
|
||||
}
|
||||
|
||||
|
@ -2676,7 +2682,8 @@ void Preprocessor::HandleIfdefDirective(Token &Result,
|
|||
if (MacroNameTok.is(tok::eod)) {
|
||||
// Skip code until we get to #endif. This helps with recovery by not
|
||||
// emitting an error when the #endif is reached.
|
||||
SkipExcludedConditionalBlock(HashToken, DirectiveTok.getLocation(),
|
||||
SkipExcludedConditionalBlock(HashToken.getLocation(),
|
||||
DirectiveTok.getLocation(),
|
||||
/*Foundnonskip*/ false, /*FoundElse*/ false);
|
||||
return;
|
||||
}
|
||||
|
@ -2725,7 +2732,8 @@ void Preprocessor::HandleIfdefDirective(Token &Result,
|
|||
/*foundelse*/false);
|
||||
} else {
|
||||
// No, skip the contents of this block.
|
||||
SkipExcludedConditionalBlock(HashToken, DirectiveTok.getLocation(),
|
||||
SkipExcludedConditionalBlock(HashToken.getLocation(),
|
||||
DirectiveTok.getLocation(),
|
||||
/*Foundnonskip*/ false,
|
||||
/*FoundElse*/ false);
|
||||
}
|
||||
|
@ -2772,7 +2780,7 @@ void Preprocessor::HandleIfDirective(Token &IfToken,
|
|||
/*foundnonskip*/true, /*foundelse*/false);
|
||||
} else {
|
||||
// No, skip the contents of this block.
|
||||
SkipExcludedConditionalBlock(HashToken, IfToken.getLocation(),
|
||||
SkipExcludedConditionalBlock(HashToken.getLocation(), IfToken.getLocation(),
|
||||
/*Foundnonskip*/ false,
|
||||
/*FoundElse*/ false);
|
||||
}
|
||||
|
@ -2837,7 +2845,8 @@ void Preprocessor::HandleElseDirective(Token &Result, const Token &HashToken) {
|
|||
}
|
||||
|
||||
// Finally, skip the rest of the contents of this block.
|
||||
SkipExcludedConditionalBlock(HashToken, CI.IfLoc, /*Foundnonskip*/ true,
|
||||
SkipExcludedConditionalBlock(HashToken.getLocation(), CI.IfLoc,
|
||||
/*Foundnonskip*/ true,
|
||||
/*FoundElse*/ true, Result.getLocation());
|
||||
}
|
||||
|
||||
|
@ -2881,7 +2890,7 @@ void Preprocessor::HandleElifDirective(Token &ElifToken,
|
|||
}
|
||||
|
||||
// Finally, skip the rest of the contents of this block.
|
||||
SkipExcludedConditionalBlock(HashToken, CI.IfLoc, /*Foundnonskip*/ true,
|
||||
/*FoundElse*/ CI.FoundElse,
|
||||
ElifToken.getLocation());
|
||||
SkipExcludedConditionalBlock(
|
||||
HashToken.getLocation(), CI.IfLoc, /*Foundnonskip*/ true,
|
||||
/*FoundElse*/ CI.FoundElse, ElifToken.getLocation());
|
||||
}
|
||||
|
|
|
@ -550,6 +550,13 @@ void Preprocessor::replayPreambleConditionalStack() {
|
|||
"CurPPLexer is null when calling replayPreambleConditionalStack.");
|
||||
CurPPLexer->setConditionalLevels(PreambleConditionalStack.getStack());
|
||||
PreambleConditionalStack.doneReplaying();
|
||||
if (PreambleConditionalStack.reachedEOFWhileSkipping())
|
||||
SkipExcludedConditionalBlock(
|
||||
PreambleConditionalStack.SkipInfo->HashTokenLoc,
|
||||
PreambleConditionalStack.SkipInfo->IfTokenLoc,
|
||||
PreambleConditionalStack.SkipInfo->FoundNonSkipPortion,
|
||||
PreambleConditionalStack.SkipInfo->FoundElse,
|
||||
PreambleConditionalStack.SkipInfo->ElseLoc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2995,8 +2995,20 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
|
|||
|
||||
case PP_CONDITIONAL_STACK:
|
||||
if (!Record.empty()) {
|
||||
unsigned Idx = 0, End = Record.size() - 1;
|
||||
bool ReachedEOFWhileSkipping = Record[Idx++];
|
||||
llvm::Optional<Preprocessor::PreambleSkipInfo> SkipInfo;
|
||||
if (ReachedEOFWhileSkipping) {
|
||||
SourceLocation HashToken = ReadSourceLocation(F, Record, Idx);
|
||||
SourceLocation IfTokenLoc = ReadSourceLocation(F, Record, Idx);
|
||||
bool FoundNonSkipPortion = Record[Idx++];
|
||||
bool FoundElse = Record[Idx++];
|
||||
SourceLocation ElseLoc = ReadSourceLocation(F, Record, Idx);
|
||||
SkipInfo.emplace(HashToken, IfTokenLoc, FoundNonSkipPortion,
|
||||
FoundElse, ElseLoc);
|
||||
}
|
||||
SmallVector<PPConditionalInfo, 4> ConditionalStack;
|
||||
for (unsigned Idx = 0, N = Record.size() - 1; Idx < N; /* in loop */) {
|
||||
while (Idx < End) {
|
||||
auto Loc = ReadSourceLocation(F, Record, Idx);
|
||||
bool WasSkipping = Record[Idx++];
|
||||
bool FoundNonSkip = Record[Idx++];
|
||||
|
@ -3004,7 +3016,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
|
|||
ConditionalStack.push_back(
|
||||
{Loc, WasSkipping, FoundNonSkip, FoundElse});
|
||||
}
|
||||
PP.setReplayablePreambleConditionalStack(ConditionalStack);
|
||||
PP.setReplayablePreambleConditionalStack(ConditionalStack, SkipInfo);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -2407,6 +2407,17 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
|
|||
|
||||
if (PP.isRecordingPreamble() && PP.hasRecordedPreamble()) {
|
||||
assert(!IsModule);
|
||||
auto SkipInfo = PP.getPreambleSkipInfo();
|
||||
if (SkipInfo.hasValue()) {
|
||||
Record.push_back(true);
|
||||
AddSourceLocation(SkipInfo->HashTokenLoc, Record);
|
||||
AddSourceLocation(SkipInfo->IfTokenLoc, Record);
|
||||
Record.push_back(SkipInfo->FoundNonSkipPortion);
|
||||
Record.push_back(SkipInfo->FoundElse);
|
||||
AddSourceLocation(SkipInfo->ElseLoc, Record);
|
||||
} else {
|
||||
Record.push_back(false);
|
||||
}
|
||||
for (const auto &Cond : PP.getPreambleConditionalStack()) {
|
||||
AddSourceLocation(Cond.IfLoc, Record);
|
||||
Record.push_back(Cond.WasSkipping);
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
// RUN: | FileCheck %s --implicit-check-not "error:"
|
||||
#ifdef FOO_H
|
||||
|
||||
void foo();
|
||||
void foo() {}
|
||||
|
||||
#endif
|
||||
|
||||
int foo() { return 0; }
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 \
|
||||
// RUN: local -std=c++14 %s 2>&1 \
|
||||
// RUN: | FileCheck %s --implicit-check-not "error:"
|
||||
|
||||
#ifdef MYCPLUSPLUS
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef MYCPLUSPLUS
|
||||
}
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue