Index: include/clang/Frontend/ASTUnit.h =================================================================== --- include/clang/Frontend/ASTUnit.h +++ include/clang/Frontend/ASTUnit.h @@ -547,6 +547,13 @@ return SourceRange(mapLocationToPreamble(R.getBegin()), mapLocationToPreamble(R.getEnd())); } + + std::chrono::steady_clock::time_point getPreambleCreationTimePoint() const + { + if (Preamble) + return Preamble->getCreationTimePoint(); + return std::chrono::steady_clock::time_point(); + } // Retrieve the diagnostics associated with this AST typedef StoredDiagnostic *stored_diag_iterator; Index: include/clang/Frontend/PrecompiledPreamble.h =================================================================== --- include/clang/Frontend/PrecompiledPreamble.h +++ include/clang/Frontend/PrecompiledPreamble.h @@ -93,7 +93,7 @@ /// MainFileBuffer) of the main file. bool CanReuse(const CompilerInvocation &Invocation, const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, - vfs::FileSystem *VFS) const; + IntrusiveRefCntPtr VFS) const; /// Changes options inside \p CI to use PCH from this preamble. Also remaps /// main file to \p MainFileBuffer and updates \p VFS to ensure the preamble @@ -106,6 +106,10 @@ IntrusiveRefCntPtr &VFS, llvm::MemoryBuffer *MainFileBuffer) const; + std::chrono::steady_clock::time_point getCreationTimePoint() const { + return CreationTimePoint; + } + private: PrecompiledPreamble(PCHStorage Storage, std::vector PreambleBytes, bool PreambleEndsAtStartOfLine, @@ -237,6 +241,7 @@ std::vector PreambleBytes; /// See PreambleBounds::PreambleEndsAtStartOfLine bool PreambleEndsAtStartOfLine; + std::chrono::steady_clock::time_point CreationTimePoint; }; /// A set of callbacks to gather useful information while building a preamble. Index: lib/Frontend/ASTUnit.cpp =================================================================== --- lib/Frontend/ASTUnit.cpp +++ lib/Frontend/ASTUnit.cpp @@ -1244,7 +1244,7 @@ if (Preamble) { if (Preamble->CanReuse(PreambleInvocationIn, MainFileBuffer.get(), Bounds, - VFS.get())) { + VFS)) { // Okay! We can re-use the precompiled preamble. // Set the state of the diagnostic object to mimic its state Index: lib/Frontend/PrecompiledPreamble.cpp =================================================================== --- lib/Frontend/PrecompiledPreamble.cpp +++ lib/Frontend/PrecompiledPreamble.cpp @@ -390,10 +390,10 @@ return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine); } -bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation, - const llvm::MemoryBuffer *MainFileBuffer, - PreambleBounds Bounds, - vfs::FileSystem *VFS) const { +bool PrecompiledPreamble::CanReuse( + const CompilerInvocation &Invocation, + const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, + IntrusiveRefCntPtr VFS) const { assert( Bounds.Size <= MainFileBuffer->getBufferSize() && @@ -434,11 +434,14 @@ Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime())); } + vfs::OverlayFileSystem OFS(VFS); + IntrusiveRefCntPtr IMFS( + new vfs::InMemoryFileSystem()); + OFS.pushOverlay(IMFS); for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { + IMFS->addFile(RB.first, 0, llvm::MemoryBuffer::getMemBuffer("")); vfs::Status Status; - if (!moveOnNoError(VFS->status(RB.first), Status)) - return false; - + assert(moveOnNoError(IMFS->status(RB.first), Status)); OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForMemoryBuffer(RB.second); } @@ -446,7 +449,7 @@ // Check whether anything has changed. for (const auto &F : FilesInPreamble) { vfs::Status Status; - if (!moveOnNoError(VFS->status(F.first()), Status)) { + if (!moveOnNoError(OFS.status(F.first()), Status)) { // If we can't stat the file, assume that something horrible happened. return false; } @@ -495,7 +498,8 @@ llvm::StringMap FilesInPreamble) : Storage(std::move(Storage)), FilesInPreamble(std::move(FilesInPreamble)), PreambleBytes(std::move(PreambleBytes)), - PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) { + PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine), + CreationTimePoint(std::chrono::steady_clock::now()){ assert(this->Storage.getKind() != PCHStorage::Kind::Empty); } Index: unittests/Frontend/PCHPreambleTest.cpp =================================================================== --- unittests/Frontend/PCHPreambleTest.cpp +++ unittests/Frontend/PCHPreambleTest.cpp @@ -124,6 +124,23 @@ } }; +TEST_F(PCHPreambleTest, ReparseDoesNotInvalidatePreambleDueToNotExistingUnsavedFile) { + std::string Header1 = "//./header1.h"; + std::string MainName = "//./main.cpp"; + AddFile(MainName, "#include \"//./header1.h\"\n" + "int main() { return ZERO; }"); + + std::unique_ptr AST(ParseAST(MainName)); + ASSERT_TRUE(AST.get()); + auto InitialPreambleCreationTimePoint = AST->getPreambleCreationTimePoint(); + ASSERT_NE(std::chrono::steady_clock::time_point(), InitialPreambleCreationTimePoint); + + RemapFile(Header1, "#define ZERO 0\n"); + ASSERT_TRUE(ReparseAST(AST)); + + ASSERT_EQ(InitialPreambleCreationTimePoint, AST->getPreambleCreationTimePoint()); +} + TEST_F(PCHPreambleTest, ReparseWithOverriddenFileDoesNotInvalidatePreamble) { std::string Header1 = "//./header1.h"; std::string Header2 = "//./header2.h";