From: Richard Smith Date: Thu, 29 Jun 2017 02:19:42 +0000 (+0000) Subject: Track the set of module maps read while building a .pcm file and reload those when... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2d7d5c241bce687a4c7018a023efb7b22769ca9d;p=clang Track the set of module maps read while building a .pcm file and reload those when preprocessing from that .pcm file. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@306628 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 5e01f64167..e658af742e 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -80,9 +80,19 @@ namespace SrcMgr { /// system_header is seen or in various other cases. /// enum CharacteristicKind { - C_User, C_System, C_ExternCSystem + C_User, C_System, C_ExternCSystem, C_User_ModuleMap, C_System_ModuleMap }; + /// Determine whether a file / directory characteristic is for system code. + inline bool isSystem(CharacteristicKind CK) { + return CK != C_User && CK != C_User_ModuleMap; + } + + /// Determine whether a file characteristic is for a module map. + inline bool isModuleMap(CharacteristicKind CK) { + return CK == C_User_ModuleMap || CK == C_System_ModuleMap; + } + /// \brief One instance of this struct is kept for every file loaded or used. /// /// This object owns the MemoryBuffer object. @@ -251,12 +261,14 @@ namespace SrcMgr { /// preprocessing of this \#include, including this SLocEntry. /// /// Zero means the preprocessor didn't provide such info for this SLocEntry. - unsigned NumCreatedFIDs; + unsigned NumCreatedFIDs : 31; + + /// \brief Whether this FileInfo has any \#line directives. + unsigned HasLineDirectives : 1; - /// \brief Contains the ContentCache* and the bits indicating the - /// characteristic of the file and whether it has \#line info, all - /// bitmangled together. - uintptr_t Data; + /// \brief The content cache and the characteristic of the file. + llvm::PointerIntPair + ContentAndKind; friend class clang::SourceManager; friend class clang::ASTWriter; @@ -269,10 +281,9 @@ namespace SrcMgr { FileInfo X; X.IncludeLoc = IL.getRawEncoding(); X.NumCreatedFIDs = 0; - X.Data = (uintptr_t)Con; - assert((X.Data & 7) == 0 &&"ContentCache pointer insufficiently aligned"); - assert((unsigned)FileCharacter < 4 && "invalid file character"); - X.Data |= (unsigned)FileCharacter; + X.HasLineDirectives = false; + X.ContentAndKind.setPointer(Con); + X.ContentAndKind.setInt(FileCharacter); return X; } @@ -280,22 +291,22 @@ namespace SrcMgr { return SourceLocation::getFromRawEncoding(IncludeLoc); } - const ContentCache* getContentCache() const { - return reinterpret_cast(Data & ~uintptr_t(7)); + const ContentCache *getContentCache() const { + return ContentAndKind.getPointer(); } /// \brief Return whether this is a system header or not. CharacteristicKind getFileCharacteristic() const { - return (CharacteristicKind)(Data & 3); + return ContentAndKind.getInt(); } /// \brief Return true if this FileID has \#line directives in it. - bool hasLineDirectives() const { return (Data & 4) != 0; } + bool hasLineDirectives() const { return HasLineDirectives; } /// \brief Set the flag that indicates that this FileID has /// line table entries associated with it. void setHasLineDirectives() { - Data |= 4; + HasLineDirectives = true; } }; @@ -407,6 +418,8 @@ namespace SrcMgr { }; public: + SLocEntry() : Offset(), IsExpansion(), File() {} + unsigned getOffset() const { return Offset; } bool isExpansion() const { return IsExpansion; } @@ -789,9 +802,8 @@ public: FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, int LoadedID = 0, unsigned LoadedOffset = 0) { - const SrcMgr::ContentCache * - IR = getOrCreateContentCache(SourceFile, - /*isSystemFile=*/FileCharacter != SrcMgr::C_User); + const SrcMgr::ContentCache *IR = + getOrCreateContentCache(SourceFile, isSystem(FileCharacter)); assert(IR && "getOrCreateContentCache() cannot return NULL"); return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset); } @@ -1360,7 +1372,7 @@ public: /// \brief Returns if a SourceLocation is in a system header. bool isInSystemHeader(SourceLocation Loc) const { - return getFileCharacteristic(Loc) != SrcMgr::C_User; + return isSystem(getFileCharacteristic(Loc)); } /// \brief Returns if a SourceLocation is in an "extern C" system header. diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h index ee17dcbb8b..1b7f80c87f 100644 --- a/include/clang/Lex/HeaderSearch.h +++ b/include/clang/Lex/HeaderSearch.h @@ -47,7 +47,7 @@ struct HeaderFileInfo { /// whether it is C++ clean or not. This can be set by the include paths or /// by \#pragma gcc system_header. This is an instance of /// SrcMgr::CharacteristicKind. - unsigned DirInfo : 2; + unsigned DirInfo : 3; /// \brief Whether this header file info was supplied by an external source, /// and has not changed since. diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 737f6fb3d4..9b94aadd76 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -1146,6 +1146,7 @@ private: time_t StoredTime; bool Overridden; bool Transient; + bool TopLevelModuleMap; }; /// \brief Reads the stored information about an input file. @@ -2249,6 +2250,12 @@ public: llvm::function_ref Visitor); + /// Visit all the top-level module maps loaded when building the given module + /// file. + void visitTopLevelModuleMaps(serialization::ModuleFile &MF, + llvm::function_ref< + void(const FileEntry *)> Visitor); + bool isProcessingUpdateRecords() { return ProcessingUpdateRecords; } }; diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index e5da2ae4f2..3b5335478d 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -825,8 +825,11 @@ bool CompilerInstance::InitializeSourceManager( const FrontendInputFile &Input, DiagnosticsEngine &Diags, FileManager &FileMgr, SourceManager &SourceMgr, HeaderSearch *HS, DependencyOutputOptions &DepOpts, const FrontendOptions &Opts) { - SrcMgr::CharacteristicKind - Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; + SrcMgr::CharacteristicKind Kind = + Input.getKind().getFormat() == InputKind::ModuleMap + ? Input.isSystem() ? SrcMgr::C_System_ModuleMap + : SrcMgr::C_User_ModuleMap + : Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; if (Input.isBuffer()) { SourceMgr.setMainFileID(SourceMgr.createFileID( diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp index bd14c53e4d..561eb9c4a3 100644 --- a/lib/Frontend/DependencyFile.cpp +++ b/lib/Frontend/DependencyFile.cpp @@ -55,8 +55,8 @@ struct DepCollectorPPCallbacks : public PPCallbacks { llvm::sys::path::remove_leading_dotslash(FE->getName()); DepCollector.maybeAddDependency(Filename, /*FromModule*/false, - FileType != SrcMgr::C_User, - /*IsModuleFile*/false, /*IsMissing*/false); + isSystem(FileType), + /*IsModuleFile*/false, /*IsMissing*/false); } void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, @@ -265,7 +265,7 @@ bool DFGImpl::FileMatchesDepCriteria(const char *Filename, if (IncludeSystemHeaders) return true; - return FileType == SrcMgr::C_User; + return !isSystem(FileType); } void DFGImpl::FileChanged(SourceLocation Loc, diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index f81a06b318..eed8631bdb 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -200,12 +200,12 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, /// /// \param CI The compiler instance. /// \param InputFile Populated with the filename from the line marker. -/// \param AddLineNote If \c true, add a line note corresponding to this line -/// directive. Only use this if the directive will not actually be -/// visited by the preprocessor. +/// \param IsModuleMap If \c true, add a line note corresponding to this line +/// directive. (We need to do this because the directive will not be +/// visited by the preprocessor.) static SourceLocation ReadOriginalFileName(CompilerInstance &CI, std::string &InputFile, - bool AddLineNote = false) { + bool IsModuleMap = false) { auto &SourceMgr = CI.getSourceManager(); auto MainFileID = SourceMgr.getMainFileID(); @@ -231,7 +231,7 @@ static SourceLocation ReadOriginalFileName(CompilerInstance &CI, unsigned LineNo; SourceLocation LineNoLoc = T.getLocation(); - if (AddLineNote) { + if (IsModuleMap) { llvm::SmallString<16> Buffer; if (Lexer::getSpelling(LineNoLoc, Buffer, SourceMgr, CI.getLangOpts()) .getAsInteger(10, LineNo)) @@ -250,10 +250,10 @@ static SourceLocation ReadOriginalFileName(CompilerInstance &CI, return SourceLocation(); InputFile = Literal.GetString().str(); - if (AddLineNote) + if (IsModuleMap) CI.getSourceManager().AddLineNote( LineNoLoc, LineNo, SourceMgr.getLineTableFilenameID(InputFile), false, - false, SrcMgr::C_User); + false, SrcMgr::C_User_ModuleMap); return T.getLocation(); } @@ -403,7 +403,7 @@ static bool loadModuleMapForModuleBuild(CompilerInstance &CI, bool IsSystem, Offset = 0; if (IsPreprocessed) { SourceLocation EndOfLineMarker = - ReadOriginalFileName(CI, PresumedModuleMapFile, /*AddLineNote*/true); + ReadOriginalFileName(CI, PresumedModuleMapFile, /*IsModuleMap*/ true); if (EndOfLineMarker.isValid()) Offset = CI.getSourceManager().getDecomposedLoc(EndOfLineMarker).second; } @@ -547,21 +547,29 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.getPreprocessorOpts() = AST->getPreprocessorOpts(); CI.getLangOpts() = AST->getLangOpts(); - // Preload all the module files loaded transitively by the AST unit. - if (auto ASTReader = AST->getASTReader()) { - auto &MM = ASTReader->getModuleManager(); - for (ModuleFile &MF : MM) - if (&MF != &MM.getPrimaryModule()) - CI.getFrontendOpts().ModuleFiles.push_back(MF.FileName); - } - // FIXME: Preload module maps loaded by the AST unit. - // Set the shared objects, these are reset when we finish processing the // file, otherwise the CompilerInstance will happily destroy them. CI.setFileManager(&AST->getFileManager()); CI.createSourceManager(CI.getFileManager()); CI.getSourceManager().initializeForReplay(AST->getSourceManager()); + // Preload all the module files loaded transitively by the AST unit. Also + // load all module map files that were parsed as part of building the AST + // unit. + if (auto ASTReader = AST->getASTReader()) { + auto &MM = ASTReader->getModuleManager(); + auto &PrimaryModule = MM.getPrimaryModule(); + + for (ModuleFile &MF : MM) + if (&MF != &PrimaryModule) + CI.getFrontendOpts().ModuleFiles.push_back(MF.FileName); + + ASTReader->visitTopLevelModuleMaps(PrimaryModule, + [&](const FileEntry *FE) { + CI.getFrontendOpts().ModuleMapFiles.push_back(FE->getName()); + }); + } + // Set up the input file for replay purposes. auto Kind = AST->getInputKind(); if (Kind.getFormat() == InputKind::ModuleMap) { diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index 018d59e5e8..40f78ce25c 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -2710,7 +2710,8 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem, // If the module map file wasn't already entered, do so now. if (ID.isInvalid()) { - auto FileCharacter = IsSystem ? SrcMgr::C_System : SrcMgr::C_User; + auto FileCharacter = + IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap; ID = SourceMgr.createFileID(File, ExternModuleLoc, FileCharacter); } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 7c9ff09125..fab7539aaa 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -1398,8 +1398,7 @@ bool ASTReader::ReadSLocEntry(int ID) { } const SrcMgr::ContentCache *ContentCache - = SourceMgr.getOrCreateContentCache(File, - /*isSystemFile=*/FileCharacter != SrcMgr::C_User); + = SourceMgr.getOrCreateContentCache(File, isSystem(FileCharacter)); if (OverriddenBuffer && !ContentCache->BufferOverridden && ContentCache->ContentsEntry == ContentCache->OrigEntry && !ContentCache->getRawBuffer()) { @@ -1697,9 +1696,9 @@ HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d, HeaderFileInfo HFI; unsigned Flags = *d++; // FIXME: Refactor with mergeHeaderFileInfo in HeaderSearch.cpp. - HFI.isImport |= (Flags >> 4) & 0x01; - HFI.isPragmaOnce |= (Flags >> 3) & 0x01; - HFI.DirInfo = (Flags >> 1) & 0x03; + HFI.isImport |= (Flags >> 5) & 0x01; + HFI.isPragmaOnce |= (Flags >> 4) & 0x01; + HFI.DirInfo = (Flags >> 1) & 0x07; HFI.IndexHeaderMapHeader = Flags & 0x01; // FIXME: Find a better way to handle this. Maybe just store a // "has been included" flag? @@ -2029,6 +2028,7 @@ ASTReader::readInputFileInfo(ModuleFile &F, unsigned ID) { R.StoredTime = static_cast(Record[2]); R.Overridden = static_cast(Record[3]); R.Transient = static_cast(Record[4]); + R.TopLevelModuleMap = static_cast(Record[5]); R.Filename = Blob; ResolveImportedPath(F, R.Filename); return R; @@ -8909,6 +8909,19 @@ void ASTReader::visitInputFiles(serialization::ModuleFile &MF, } } +void ASTReader::visitTopLevelModuleMaps( + serialization::ModuleFile &MF, + llvm::function_ref Visitor) { + unsigned NumInputs = MF.InputFilesLoaded.size(); + for (unsigned I = 0; I < NumInputs; ++I) { + InputFileInfo IFI = readInputFileInfo(MF, I + 1); + if (IFI.TopLevelModuleMap) + // FIXME: This unnecessarily re-reads the InputFileInfo. + if (auto *FE = getInputFile(MF, I + 1).getFile()) + Visitor(FE); + } +} + std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) { // If we know the owning module, use it. if (Module *M = D->getImportedOwningModule()) diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 1c0db14ced..c6129d326c 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1692,6 +1692,7 @@ namespace { bool IsSystemFile; bool IsTransient; bool BufferOverridden; + bool IsTopLevelModuleMap; }; } // end anonymous namespace @@ -1710,6 +1711,7 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, 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::Fixed, 1)); // Module map IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name unsigned IFAbbrevCode = Stream.EmitAbbrev(std::move(IFAbbrev)); @@ -1724,7 +1726,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, // We only care about file entries that were not overridden. if (!SLoc->isFile()) continue; - const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache(); + const SrcMgr::FileInfo &File = SLoc->getFile(); + const SrcMgr::ContentCache *Cache = File.getContentCache(); if (!Cache->OrigEntry) continue; @@ -1733,6 +1736,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, Entry.IsSystemFile = Cache->IsSystemFile; Entry.IsTransient = Cache->IsTransient; Entry.BufferOverridden = Cache->BufferOverridden; + Entry.IsTopLevelModuleMap = isModuleMap(File.getFileCharacteristic()) && + File.getIncludeLoc().isInvalid(); if (Cache->IsSystemFile) SortedFiles.push_back(Entry); else @@ -1763,7 +1768,8 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, (uint64_t)Entry.File->getSize(), (uint64_t)getTimestampForOutput(Entry.File), Entry.BufferOverridden, - Entry.IsTransient}; + Entry.IsTransient, + Entry.IsTopLevelModuleMap}; EmitRecordWithPath(IFAbbrevCode, Record, Entry.File->getName()); } @@ -1798,7 +1804,7 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_FILE_ENTRY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Characteristic Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives // FileEntry fields. Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Input File ID @@ -1817,7 +1823,7 @@ static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) { Abbrev->Add(BitCodeAbbrevOp(SM_SLOC_BUFFER_ENTRY)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Characteristic Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob return Stream.EmitAbbrev(std::move(Abbrev)); @@ -1925,8 +1931,8 @@ namespace { endian::Writer LE(Out); uint64_t Start = Out.tell(); (void)Start; - unsigned char Flags = (Data.HFI.isImport << 4) - | (Data.HFI.isPragmaOnce << 3) + unsigned char Flags = (Data.HFI.isImport << 5) + | (Data.HFI.isPragmaOnce << 4) | (Data.HFI.DirInfo << 1) | Data.HFI.IndexHeaderMapHeader; LE.write(Flags); diff --git a/test/Modules/Inputs/preprocess-decluse/a.h b/test/Modules/Inputs/preprocess-decluse/a.h new file mode 100644 index 0000000000..17ab46c848 --- /dev/null +++ b/test/Modules/Inputs/preprocess-decluse/a.h @@ -0,0 +1 @@ +// a.h diff --git a/test/Modules/Inputs/preprocess-decluse/a.modulemap b/test/Modules/Inputs/preprocess-decluse/a.modulemap new file mode 100644 index 0000000000..47105fe363 --- /dev/null +++ b/test/Modules/Inputs/preprocess-decluse/a.modulemap @@ -0,0 +1 @@ +module A { textual header "a.h" } diff --git a/test/Modules/Inputs/preprocess-decluse/b.h b/test/Modules/Inputs/preprocess-decluse/b.h new file mode 100644 index 0000000000..2243de1baf --- /dev/null +++ b/test/Modules/Inputs/preprocess-decluse/b.h @@ -0,0 +1 @@ +#include "a.h" diff --git a/test/Modules/Inputs/preprocess-decluse/b.modulemap b/test/Modules/Inputs/preprocess-decluse/b.modulemap new file mode 100644 index 0000000000..bd0bdf0e2e --- /dev/null +++ b/test/Modules/Inputs/preprocess-decluse/b.modulemap @@ -0,0 +1 @@ +module B { header "b.h" use A } diff --git a/test/Modules/Inputs/preprocess-decluse/main.modulemap b/test/Modules/Inputs/preprocess-decluse/main.modulemap new file mode 100644 index 0000000000..0392c846ce --- /dev/null +++ b/test/Modules/Inputs/preprocess-decluse/main.modulemap @@ -0,0 +1 @@ +module Main { use B } diff --git a/test/Modules/preprocess-decluse.cpp b/test/Modules/preprocess-decluse.cpp new file mode 100644 index 0000000000..5c87e0ddda --- /dev/null +++ b/test/Modules/preprocess-decluse.cpp @@ -0,0 +1,18 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fmodules-strict-decluse -I%S/Inputs/preprocess-decluse \ +// RUN: -fmodule-name=B -emit-module -o %t/b.pcm \ +// RUN: -fmodule-map-file=%S/Inputs/preprocess-decluse/a.modulemap \ +// RUN: -x c++-module-map %S/Inputs/preprocess-decluse/b.modulemap +// RUN: %clang_cc1 -fmodules -fmodules-strict-decluse -I%S/Inputs/preprocess-decluse \ +// RUN: -fmodule-map-file=%S/Inputs/preprocess-decluse/main.modulemap \ +// RUN: -fmodule-file=%t/b.pcm -fmodule-name=Main %s -verify +// RUN: %clang_cc1 -fmodules -fmodules-strict-decluse -I%S/Inputs/preprocess-decluse \ +// RUN: -fmodule-map-file=%S/Inputs/preprocess-decluse/main.modulemap \ +// RUN: -fmodule-file=%t/b.pcm -fmodule-name=Main %s \ +// RUN: -E -frewrite-imports -o %t/rewrite.ii +// RUN: %clang_cc1 -fmodules -fmodules-strict-decluse -I%S/Inputs/preprocess-decluse \ +// RUN: -fmodule-map-file=%S/Inputs/preprocess-decluse/main.modulemap \ +// RUN: -fmodule-name=Main %t/rewrite.ii -verify + +// expected-no-diagnostics +#include "b.h"