Author: erikjv Date: Fri Nov 3 02:40:07 2017 New Revision: 317308 URL: http://llvm.org/viewvc/llvm-project?rev=317308&view=rev Log: [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. Added: cfe/trunk/test/Index/preamble-conditionals-skipping.cpp Modified: cfe/trunk/include/clang/Lex/Preprocessor.h cfe/trunk/lib/Lex/PPDirectives.cpp cfe/trunk/lib/Lex/Preprocessor.cpp cfe/trunk/lib/Serialization/ASTReader.cpp cfe/trunk/lib/Serialization/ASTWriter.cpp cfe/trunk/test/Index/preamble-conditionals-inverted.cpp Modified: cfe/trunk/include/clang/Lex/Preprocessor.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=317308&r1=317307&r2=317308&view=diff ============================================================================== --- cfe/trunk/include/clang/Lex/Preprocessor.h (original) +++ cfe/trunk/include/clang/Lex/Preprocessor.h Fri Nov 3 02:40:07 2017 @@ -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: Modified: cfe/trunk/lib/Lex/PPDirectives.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=317308&r1=317307&r2=317308&view=diff ============================================================================== --- cfe/trunk/lib/Lex/PPDirectives.cpp (original) +++ cfe/trunk/lib/Lex/PPDirectives.cpp Fri Nov 3 02:40:07 2017 @@ -350,7 +350,7 @@ void Preprocessor::CheckEndOfDirective(c /// 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::SkipExcludedCondition ++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::SkipExcludedCondition // 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::SkipExcludedCondition if (Callbacks) Callbacks->SourceRangeSkipped( - SourceRange(HashToken.getLocation(), CurPPLexer->getSourceLocation()), + SourceRange(HashTokenLoc, CurPPLexer->getSourceLocation()), Tok.getLocation()); } @@ -2676,7 +2682,8 @@ void Preprocessor::HandleIfdefDirective( 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( /*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(Tok /*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(T } // 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(T } // 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()); } Modified: cfe/trunk/lib/Lex/Preprocessor.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Preprocessor.cpp?rev=317308&r1=317307&r2=317308&view=diff ============================================================================== --- cfe/trunk/lib/Lex/Preprocessor.cpp (original) +++ cfe/trunk/lib/Lex/Preprocessor.cpp Fri Nov 3 02:40:07 2017 @@ -550,6 +550,13 @@ void Preprocessor::replayPreambleConditi "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); } } Modified: cfe/trunk/lib/Serialization/ASTReader.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=317308&r1=317307&r2=317308&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReader.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReader.cpp Fri Nov 3 02:40:07 2017 @@ -2995,8 +2995,20 @@ ASTReader::ReadASTBlock(ModuleFile &F, u 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, u ConditionalStack.push_back( {Loc, WasSkipping, FoundNonSkip, FoundElse}); } - PP.setReplayablePreambleConditionalStack(ConditionalStack); + PP.setReplayablePreambleConditionalStack(ConditionalStack, SkipInfo); } break; Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=317308&r1=317307&r2=317308&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Fri Nov 3 02:40:07 2017 @@ -2407,6 +2407,17 @@ void ASTWriter::WritePreprocessor(const 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); Modified: cfe/trunk/test/Index/preamble-conditionals-inverted.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/preamble-conditionals-inverted.cpp?rev=317308&r1=317307&r2=317308&view=diff ============================================================================== --- cfe/trunk/test/Index/preamble-conditionals-inverted.cpp (original) +++ cfe/trunk/test/Index/preamble-conditionals-inverted.cpp Fri Nov 3 02:40:07 2017 @@ -3,6 +3,8 @@ // RUN: | FileCheck %s --implicit-check-not "error:" #ifdef FOO_H -void foo(); +void foo() {} #endif + +int foo() { return 0; } Added: cfe/trunk/test/Index/preamble-conditionals-skipping.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/preamble-conditionals-skipping.cpp?rev=317308&view=auto ============================================================================== --- cfe/trunk/test/Index/preamble-conditionals-skipping.cpp (added) +++ cfe/trunk/test/Index/preamble-conditionals-skipping.cpp Fri Nov 3 02:40:07 2017 @@ -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; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits