diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 5006b00929cf676121dbb0cca369f90b2e025172..99392a09827432dd397a2bae035ee2062e14cced 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -122,7 +122,7 @@ namespace SrcMgr { /// \brief The number of lines in this ContentCache. /// /// This is only valid if SourceLineCache is non-null. - unsigned NumLines : 31; + unsigned NumLines; /// \brief Indicates whether the buffer itself was provided to override /// the actual file contents. @@ -135,12 +135,17 @@ namespace SrcMgr { /// file considered as a system one. unsigned IsSystemFile : 1; + /// \brief True if this file may be transient, that is, if it might not + /// exist at some later point in time when this content entry is used, + /// after serialization and deserialization. + unsigned IsTransient : 1; + ContentCache(const FileEntry *Ent = nullptr) : ContentCache(Ent, Ent) {} ContentCache(const FileEntry *Ent, const FileEntry *contentEnt) : Buffer(nullptr, false), OrigEntry(Ent), ContentsEntry(contentEnt), SourceLineCache(nullptr), NumLines(0), BufferOverridden(false), - IsSystemFile(false) {} + IsSystemFile(false), IsTransient(false) {} ~ContentCache(); @@ -149,7 +154,7 @@ namespace SrcMgr { /// is not transferred, so this is a logical error. ContentCache(const ContentCache &RHS) : Buffer(nullptr, false), SourceLineCache(nullptr), - BufferOverridden(false), IsSystemFile(false) { + BufferOverridden(false), IsSystemFile(false), IsTransient(false) { OrigEntry = RHS.OrigEntry; ContentsEntry = RHS.ContentsEntry; @@ -862,17 +867,13 @@ public: /// This should be called before parsing has begun. void disableFileContentsOverride(const FileEntry *File); - /// \brief Request that the contents of the given source file are written - /// to a created module file if they are used in this compilation. This - /// removes the requirement that the file still exist when the module is used - /// (but does not make the file visible to header search and the like when - /// the module is used). - void embedFileContentsInModule(const FileEntry *SourceFile); - - /// \brief Request that all files that are read during this compilation be - /// written to any created module file. - void setEmbedAllFileContentsInModule(bool Embed) { - FilesAreTransient = Embed; + /// \brief Specify that a file is transient. + void setFileIsTransient(const FileEntry *SourceFile); + + /// \brief Specify that all files that are read during this compilation are + /// transient. + void setAllFilesAreTransient(bool Transient) { + FilesAreTransient = Transient; } //===--------------------------------------------------------------------===// diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index eb613802e3bf3504b971d5ab9bc0e872c678cba7..588a6a978c2d33f60a1f126cf4f6ff948703f336 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -1058,6 +1058,7 @@ private: off_t StoredSize; time_t StoredTime; bool Overridden; + bool Transient; }; /// \brief Reads the stored information about an input file. diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index 8a523d26dec13718a28a8af886a0a953e2024417..137ff6e65871fc1e8d6782fb8d56a7f789f7dbe5 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -137,7 +137,7 @@ void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { // at the same time. Therefore, if DirName is already in the cache, // we don't need to recurse as its ancestors must also already be in // the cache. - if (NamedDirEnt.second) + if (NamedDirEnt.second && NamedDirEnt.second != NON_EXISTENT_DIR) return; // Add the virtual directory to the cache. diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 7abcba1fb73b9007b0ea5a2480e533ddd0b32fde..80a003fc932fa14556dff96114c4140bb189297b 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -439,7 +439,7 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt, } Entry->IsSystemFile = isSystemFile; - Entry->BufferOverridden = FilesAreTransient; + Entry->IsTransient = FilesAreTransient; return Entry; } @@ -674,11 +674,9 @@ void SourceManager::disableFileContentsOverride(const FileEntry *File) { OverriddenFilesInfo->OverriddenFilesWithBuffer.erase(File); } -void SourceManager::embedFileContentsInModule(const FileEntry *File) { - // We model an embedded file as a file whose buffer has been overridden - // by its contents as they are now. +void SourceManager::setFileIsTransient(const FileEntry *File) { const SrcMgr::ContentCache *CC = getOrCreateContentCache(File); - const_cast<SrcMgr::ContentCache *>(CC)->BufferOverridden = true; + const_cast<SrcMgr::ContentCache *>(CC)->IsTransient = true; } StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 4edb958441416420ca41816a54f4ebb1b2a74463..d6c88d20fc2acf5c323f9f25a481d2c8c122d9f3 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -277,6 +277,17 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, return false; } + // Set up embedding for any specified files. Do this before we load any + // source files, including the primary module map for the compilation. + for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) { + if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true)) + CI.getSourceManager().setFileIsTransient(FE); + else + CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F; + } + if (CI.getFrontendOpts().ModulesEmbedAllFiles) + CI.getSourceManager().setAllFilesAreTransient(true); + // Parse the module map file. HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); if (HS.loadModuleMapFile(ModuleMap, IsSystem)) @@ -292,16 +303,6 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, return false; } - // Set up embedding for any specified files. - for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) { - if (const auto *FE = CI.getFileManager().getFile(F, /*openFile*/true)) - CI.getSourceManager().embedFileContentsInModule(FE); - else - CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F; - } - if (CI.getFrontendOpts().ModulesEmbedAllFiles) - CI.getSourceManager().setEmbedAllFileContentsInModule(true); - // If we're being run from the command-line, the module build stack will not // have been filled in yet, so complete it now in order to allow us to detect // module cycles. diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index fa84b94b082a1b87d82bcaff36b5f93ee2031556..2defd38e27a6ff91503d229216b9496820fe4022 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -1259,7 +1259,8 @@ bool ASTReader::ReadSLocEntry(int ID) { = SourceMgr.getOrCreateContentCache(File, /*isSystemFile=*/FileCharacter != SrcMgr::C_User); if (OverriddenBuffer && !ContentCache->BufferOverridden && - ContentCache->ContentsEntry == ContentCache->OrigEntry) { + ContentCache->ContentsEntry == ContentCache->OrigEntry && + !ContentCache->getRawBuffer()) { unsigned Code = SLocEntryCursor.ReadCode(); Record.clear(); unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob); @@ -1890,19 +1891,14 @@ ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) { "invalid record type for input file"); (void)Result; - std::string Filename; - off_t StoredSize; - time_t StoredTime; - bool Overridden; - assert(Record[0] == ID && "Bogus stored ID or offset"); - StoredSize = static_cast<off_t>(Record[1]); - StoredTime = static_cast<time_t>(Record[2]); - Overridden = static_cast<bool>(Record[3]); - Filename = Blob; - ResolveImportedPath(F, Filename); - - InputFileInfo R = { std::move(Filename), StoredSize, StoredTime, Overridden }; + InputFileInfo R; + R.StoredSize = static_cast<off_t>(Record[1]); + R.StoredTime = static_cast<time_t>(Record[2]); + R.Overridden = static_cast<bool>(Record[3]); + R.Transient = static_cast<bool>(Record[4]); + R.Filename = Blob; + ResolveImportedPath(F, R.Filename); return R; } @@ -1927,11 +1923,10 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { off_t StoredSize = FI.StoredSize; time_t StoredTime = FI.StoredTime; bool Overridden = FI.Overridden; + bool Transient = FI.Transient; StringRef Filename = FI.Filename; - const FileEntry *File - = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime) - : FileMgr.getFile(Filename, /*OpenFile=*/false); + const FileEntry *File = FileMgr.getFile(Filename, /*OpenFile=*/false); // If we didn't find the file, resolve it relative to the // original directory from which this AST file was created. @@ -1946,9 +1941,8 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { // For an overridden file, create a virtual file with the stored // size/timestamp. - if (Overridden && File == nullptr) { + if ((Overridden || Transient) && File == nullptr) File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime); - } if (File == nullptr) { if (Complain) { @@ -1974,6 +1968,11 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { Error(diag::err_fe_pch_file_overridden, Filename); // After emitting the diagnostic, recover by disabling the override so // that the original file will be used. + // + // FIXME: This recovery is just as broken as the original state; there may + // be another precompiled module that's using the overridden contents, or + // we might be half way through parsing it. Instead, we should treat the + // overridden contents as belonging to a separate FileEntry. SM.disableFileContentsOverride(File); // The FileEntry is a virtual file entry with the size of the contents // that would override the original contents. Set it to the original's @@ -2024,8 +2023,10 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { IsOutOfDate = true; } + // FIXME: If the file is overridden and we've already opened it, + // issue an error (or split it into a separate FileEntry). - InputFile IF = InputFile(File, Overridden, IsOutOfDate); + InputFile IF = InputFile(File, Overridden || Transient, IsOutOfDate); // Note that we've loaded this input file. F.InputFilesLoaded[ID-1] = IF; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 0b257a4a1b07ad5df2cc0c3ad233ec5215dc8593..e6eb9be25e9ef2ed130e9bf733d51caa68807b51 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1485,6 +1485,7 @@ namespace { struct InputFileEntry { const FileEntry *File; bool IsSystemFile; + bool IsTransient; bool BufferOverridden; }; } @@ -1502,6 +1503,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden + IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Transient IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev); @@ -1523,6 +1525,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, InputFileEntry Entry; Entry.File = Cache->OrigEntry; Entry.IsSystemFile = Cache->IsSystemFile; + Entry.IsTransient = Cache->IsTransient; Entry.BufferOverridden = Cache->BufferOverridden; if (Cache->IsSystemFile) SortedFiles.push_back(Entry); @@ -1552,8 +1555,12 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, // Emit size/modification time for this file. // And whether this file was overridden. RecordData::value_type Record[] = { - INPUT_FILE, InputFileOffsets.size(), (uint64_t)Entry.File->getSize(), - (uint64_t)getTimestampForOutput(Entry.File), Entry.BufferOverridden}; + INPUT_FILE, + InputFileOffsets.size(), + (uint64_t)Entry.File->getSize(), + (uint64_t)getTimestampForOutput(Entry.File), + Entry.BufferOverridden, + Entry.IsTransient}; EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName()); } @@ -1902,7 +1909,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Stream.EmitRecordWithAbbrev(SLocFileAbbrv, Record); - if (Content->BufferOverridden) { + if (Content->BufferOverridden || Content->IsTransient) { RecordData::value_type Record[] = {SM_SLOC_BUFFER_BLOB}; const llvm::MemoryBuffer *Buffer = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager());