Index: include/clang/Lex/Preprocessor.h =================================================================== --- include/clang/Lex/Preprocessor.h +++ include/clang/Lex/Preprocessor.h @@ -96,6 +96,17 @@ /// know anything about preprocessor-level issues like the \#include stack, /// token expansion, etc. class Preprocessor { +public: + struct PreambleSkipInfo { + bool ReachedEOFWhileSkipping; + SourceLocation HashToken; + SourceLocation IfTokenLoc; + bool FoundNonSkipPortion; + bool FoundElse; + SourceLocation ElseLoc; + }; + +private: friend class VariadicMacroScopeGuard; std::shared_ptr PPOpts; DiagnosticsEngine *Diags; @@ -292,7 +303,9 @@ }; public: - PreambleConditionalStackStore() : ConditionalStackState(Off) {} + PreambleConditionalStackStore() : ConditionalStackState(Off) { + SkipInfo.ReachedEOFWhileSkipping = false; + } void startRecording() { ConditionalStackState = Recording; } void startReplaying() { ConditionalStackState = Replaying; } @@ -317,6 +330,12 @@ bool hasRecordedPreamble() const { return !ConditionalStack.empty(); } + PreambleSkipInfo SkipInfo; + + bool reachedEOFWhileSkipping() const { + return SkipInfo.ReachedEOFWhileSkipping; + } + private: SmallVector ConditionalStack; State ConditionalStackState; @@ -1837,7 +1856,7 @@ /// \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 HashToken, SourceLocation IfTokenLoc, bool FoundNonSkipPortion, bool FoundElse, SourceLocation ElseLoc = SourceLocation()); @@ -2017,9 +2036,15 @@ PreambleConditionalStack.setStack(s); } - void setReplayablePreambleConditionalStack(ArrayRef s) { + void setReplayablePreambleConditionalStack(ArrayRef s, + const PreambleSkipInfo &SkipInfo) { PreambleConditionalStack.startReplaying(); PreambleConditionalStack.setStack(s); + PreambleConditionalStack.SkipInfo = SkipInfo; + } + + const PreambleSkipInfo &getPreambleSkipInfo() const { + return PreambleConditionalStack.SkipInfo; } private: Index: lib/Lex/PPDirectives.cpp =================================================================== --- lib/Lex/PPDirectives.cpp +++ lib/Lex/PPDirectives.cpp @@ -350,7 +350,7 @@ /// 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 HashToken, SourceLocation IfTokenLoc, bool FoundNonSkipPortion, bool FoundElse, @@ -358,8 +358,11 @@ ++NumSkipped; assert(!CurTokenLexer && CurPPLexer && "Lexing a macro, not a file?"); - CurPPLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/false, - FoundNonSkipPortion, FoundElse); + if (PreambleConditionalStack.reachedEOFWhileSkipping()) + PreambleConditionalStack.SkipInfo.ReachedEOFWhileSkipping = false; + else + CurPPLexer->pushConditionalLevel(IfTokenLoc, /*isSkipping*/ false, + FoundNonSkipPortion, FoundElse); if (CurPTHLexer) { PTHSkipExcludedConditionalBlock(); @@ -385,6 +388,10 @@ // 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 = {true, HashToken, + IfTokenLoc, FoundNonSkipPortion, + FoundElse, ElseLoc}; break; } @@ -554,7 +561,7 @@ if (Callbacks) Callbacks->SourceRangeSkipped( - SourceRange(HashToken.getLocation(), CurPPLexer->getSourceLocation()), + SourceRange(HashToken, CurPPLexer->getSourceLocation()), Tok.getLocation()); } @@ -2623,7 +2630,8 @@ 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; } @@ -2672,7 +2680,8 @@ /*foundelse*/false); } else { // No, skip the contents of this block. - SkipExcludedConditionalBlock(HashToken, DirectiveTok.getLocation(), + SkipExcludedConditionalBlock(HashToken.getLocation(), + DirectiveTok.getLocation(), /*Foundnonskip*/ false, /*FoundElse*/ false); } @@ -2719,7 +2728,7 @@ /*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); } @@ -2784,7 +2793,8 @@ } // 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()); } @@ -2828,7 +2838,7 @@ } // 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()); } Index: lib/Lex/Preprocessor.cpp =================================================================== --- lib/Lex/Preprocessor.cpp +++ lib/Lex/Preprocessor.cpp @@ -544,6 +544,13 @@ "CurPPLexer is null when calling replayPreambleConditionalStack."); CurPPLexer->setConditionalLevels(PreambleConditionalStack.getStack()); PreambleConditionalStack.doneReplaying(); + if (PreambleConditionalStack.reachedEOFWhileSkipping()) + SkipExcludedConditionalBlock( + PreambleConditionalStack.SkipInfo.HashToken, + PreambleConditionalStack.SkipInfo.IfTokenLoc, + PreambleConditionalStack.SkipInfo.FoundNonSkipPortion, + PreambleConditionalStack.SkipInfo.FoundElse, + PreambleConditionalStack.SkipInfo.ElseLoc); } } Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -2995,8 +2995,16 @@ case PP_CONDITIONAL_STACK: if (!Record.empty()) { + unsigned Idx = 0, End = Record.size() - 1; + Preprocessor::PreambleSkipInfo SkipInfo; + SkipInfo.ReachedEOFWhileSkipping = Record[Idx++]; + SkipInfo.HashToken = ReadSourceLocation(F, Record, Idx); + SkipInfo.IfTokenLoc = ReadSourceLocation(F, Record, Idx); + SkipInfo.FoundNonSkipPortion = Record[Idx++]; + SkipInfo.FoundElse = Record[Idx++]; + SkipInfo.ElseLoc = ReadSourceLocation(F, Record, Idx); SmallVector 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 +3012,7 @@ ConditionalStack.push_back( {Loc, WasSkipping, FoundNonSkip, FoundElse}); } - PP.setReplayablePreambleConditionalStack(ConditionalStack); + PP.setReplayablePreambleConditionalStack(ConditionalStack, SkipInfo); } break; Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -2407,6 +2407,13 @@ if (PP.isRecordingPreamble() && PP.hasRecordedPreamble()) { assert(!IsModule); + const Preprocessor::PreambleSkipInfo &SkipInfo = PP.getPreambleSkipInfo(); + Record.push_back(SkipInfo.ReachedEOFWhileSkipping); + AddSourceLocation(SkipInfo.HashToken, Record); + AddSourceLocation(SkipInfo.IfTokenLoc, Record); + Record.push_back(SkipInfo.FoundNonSkipPortion); + Record.push_back(SkipInfo.FoundElse); + AddSourceLocation(SkipInfo.ElseLoc, Record); for (const auto &Cond : PP.getPreambleConditionalStack()) { AddSourceLocation(Cond.IfLoc, Record); Record.push_back(Cond.WasSkipping); Index: test/Index/preamble-conditionals-inverted.cpp =================================================================== --- test/Index/preamble-conditionals-inverted.cpp +++ 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; } Index: test/Index/preamble-conditionals-skipping.cpp =================================================================== --- /dev/null +++ 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; +}