Fixed a crash on replaying Preamble's PP conditional stack.

Summary:
The crash occurs when the first token after a preamble is a macro
expansion.
Fixed by moving replayPreambleConditionalStack from Parser into
Preprocessor. It is now called right after the predefines file is
processed.

Reviewers: erikjv, bkramer, klimek, yvvan

Reviewed By: bkramer

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D36872

llvm-svn: 311330
This commit is contained in:
Ilya Biryukov 2017-08-21 12:03:08 +00:00
parent 7bc77e87c8
commit f315000613
6 changed files with 38 additions and 7 deletions

View File

@ -1049,10 +1049,6 @@ public:
/// which implicitly adds the builtin defines etc.
void EnterMainSourceFile();
/// \brief After parser warm-up, initialize the conditional stack from
/// the preamble.
void replayPreambleConditionalStack();
/// \brief Inform the preprocessor callbacks that processing is complete.
void EndSourceFile();
@ -2026,6 +2022,10 @@ public:
}
private:
/// \brief After processing predefined file, initialize the conditional stack from
/// the preamble.
void replayPreambleConditionalStack();
// Macro handling.
void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef);
void HandleUndefDirective();

View File

@ -458,10 +458,16 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
SourceMgr.setNumCreatedFIDsForFileID(CurPPLexer->getFileID(), NumFIDs);
}
bool ExitedFromPredefinesFile = false;
FileID ExitedFID;
if (Callbacks && !isEndOfMacro && CurPPLexer)
if (!isEndOfMacro && CurPPLexer) {
ExitedFID = CurPPLexer->getFileID();
assert(PredefinesFileID.isValid() &&
"HandleEndOfFile is called before PredefinesFileId is set");
ExitedFromPredefinesFile = (PredefinesFileID == ExitedFID);
}
if (LeavingSubmodule) {
// We're done with this submodule.
Module *M = LeaveSubmodule(/*ForPragma*/false);
@ -489,6 +495,11 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
PPCallbacks::ExitFile, FileType, ExitedFID);
}
// Restore conditional stack from the preamble right after exiting from the
// predefines file.
if (ExitedFromPredefinesFile)
replayPreambleConditionalStack();
// Client should lex another token unless we generated an EOM.
return LeavingSubmodule;
}

View File

@ -540,6 +540,8 @@ void Preprocessor::EnterMainSourceFile() {
void Preprocessor::replayPreambleConditionalStack() {
// Restore the conditional stack from the preamble, if there is one.
if (PreambleConditionalStack.isReplaying()) {
assert(CurPPLexer &&
"CurPPLexer is null when calling replayPreambleConditionalStack.");
CurPPLexer->setConditionalLevels(PreambleConditionalStack.getStack());
PreambleConditionalStack.doneReplaying();
}

View File

@ -516,8 +516,6 @@ void Parser::Initialize() {
// Prime the lexer look-ahead.
ConsumeToken();
PP.replayPreambleConditionalStack();
}
void Parser::LateTemplateParserCleanupCallback(void *P) {

View File

@ -0,0 +1,12 @@
#ifndef HEADER_GUARD
#define FOO int aba;
FOO
#endif
// 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 "libclang: crash detected" \
// RUN: --implicit-check-not "error:"
// CHECK: macro expansion=FOO:3:9 Extent=[4:1 - 4:4]
// CHECK: VarDecl=aba:4:1 (Definition) Extent=[4:1 - 4:4]

View File

@ -0,0 +1,8 @@
// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source local %s 2>&1 \
// RUN: | FileCheck %s --implicit-check-not "error:"
#ifndef FOO_H
#define FOO_H
void foo();
#endif