summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Verbruggen <erikjv@me.com>2017-11-03 09:40:07 +0000
committerErik Verbruggen <erikjv@me.com>2017-11-03 09:40:07 +0000
commit16962ce7c214f12f7362c41bfbe79689bc07ea2f (patch)
treede4b9d348928f65c509e85d952e95b9d4eb8e130
parent324e0a9695a1682b11e60f5c22024243fa2246d3 (diff)
[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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317308 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Lex/Preprocessor.h33
-rw-r--r--lib/Lex/PPDirectives.cpp31
-rw-r--r--lib/Lex/Preprocessor.cpp7
-rw-r--r--lib/Serialization/ASTReader.cpp16
-rw-r--r--lib/Serialization/ASTWriter.cpp11
-rw-r--r--test/Index/preamble-conditionals-inverted.cpp4
-rw-r--r--test/Index/preamble-conditionals-skipping.cpp16
7 files changed, 102 insertions, 16 deletions
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index 4f211a3eb6..5e847effdc 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -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:
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index f9a97505bf..ca3e70fd10 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -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,8 +358,11 @@ void Preprocessor::SkipExcludedConditionalBlock(const Token &HashToken,
++NumSkipped;
assert(!CurTokenLexer && CurPPLexer && "Lexing a macro, not a file?");
- CurPPLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/false,
- FoundNonSkipPortion, FoundElse);
+ if (PreambleConditionalStack.reachedEOFWhileSkipping())
+ PreambleConditionalStack.clearSkipInfo();
+ else
+ CurPPLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/ false,
+ FoundNonSkipPortion, FoundElse);
if (CurPTHLexer) {
PTHSkipExcludedConditionalBlock();
@@ -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());
}
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 65df6a57f1..d80899de8f 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -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);
}
}
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 5a3423a3ec..dacdac6658 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -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;
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index dec8d8f7d7..3834314109 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -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);
diff --git a/test/Index/preamble-conditionals-inverted.cpp b/test/Index/preamble-conditionals-inverted.cpp
index 1d67ccb61a..f5cf1205e3 100644
--- a/test/Index/preamble-conditionals-inverted.cpp
+++ b/test/Index/preamble-conditionals-inverted.cpp
@@ -3,6 +3,8 @@
// RUN: | FileCheck %s --implicit-check-not "error:"
#ifdef FOO_H
-void foo();
+void foo() {}
#endif
+
+int foo() { return 0; }
diff --git a/test/Index/preamble-conditionals-skipping.cpp b/test/Index/preamble-conditionals-skipping.cpp
new file mode 100644
index 0000000000..fa5764cd5d
--- /dev/null
+++ b/test/Index/preamble-conditionals-skipping.cpp
@@ -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;
+}