oontvoo updated this revision to Diff 254384. oontvoo added a comment. Update docs.
Note: The failure looks spurious ... They seemed to pass locally for me: One eg: [hi on] vyng@vyng:~/repo/llvm-project$ ./build/bin/llvm-lit -v ./clang/test/ClangScanDeps/modules-full.cpp llvm-lit: /usr/local/google/home/vyng/repo/llvm-project/llvm/utils/lit/lit/llvm/config.py:342: note: using clang: /usr/local/google/home/vyng/repo/llvm-project/build/bin/clang - Testing: 1 tests, 1 workers -- PASS: Clang :: ClangScanDeps/modules-full.cpp (1 of 1) Testing Time: 2.75s Expected Passes : 1 Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D75951/new/ https://reviews.llvm.org/D75951 Files: clang/include/clang/Lex/HeaderSearch.h clang/include/clang/Lex/Preprocessor.h clang/include/clang/Serialization/ASTBitCodes.h clang/include/clang/Serialization/ASTReader.h clang/include/clang/Serialization/ASTWriter.h clang/lib/Lex/HeaderSearch.cpp clang/lib/Lex/PPDirectives.cpp clang/lib/Lex/PPLexerChange.cpp clang/lib/Lex/Preprocessor.cpp clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTWriter.cpp clang/test/Modules/Inputs/dummy_pragma_once.h clang/test/Modules/Inputs/dummy_textual_header.h clang/test/Modules/Inputs/header_in_imported_module.h clang/test/Modules/Inputs/imported_module.cppm clang/test/Modules/Inputs/module.map clang/test/Modules/header-in-imported-module.c clang/test/Modules/import-pragma-once.c
Index: clang/test/Modules/import-pragma-once.c =================================================================== --- /dev/null +++ clang/test/Modules/import-pragma-once.c @@ -0,0 +1,8 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x c %s +// expected-no-diagnostics +#include "dummy_pragma_once.h" +#include "dummy_textual_header.h" + +void *p = &x; +void *q = &y; Index: clang/test/Modules/header-in-imported-module.c =================================================================== --- /dev/null +++ clang/test/Modules/header-in-imported-module.c @@ -0,0 +1,15 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: %clang -x c++ -fmodules -fmodules-ts --precompile -o %t/ModuleB39206.pcm %S/Inputs/imported_module.cppm +// RUN: %clang -x c++ -fmodules -fmodules-ts -c %t/ModuleB39206.pcm -o %t/ModuleB39206.o +// RUN: %clang -x c++ -fmodules -fmodules-ts -I%S/Inputs -fmodule-file=%t/ModuleB39206.pcm -c %s +// expected-no-diagnostics + +// Bug 39206 + +#include "header_in_imported_module.h" +module ModuleB39206; + +#ifndef ALL_GOOD +#error "missing macro in impl" +#endif Index: clang/test/Modules/Inputs/module.map =================================================================== --- clang/test/Modules/Inputs/module.map +++ clang/test/Modules/Inputs/module.map @@ -282,6 +282,11 @@ header "dummy.h" } +module dummy_pragma_once { + header "dummy_pragma_once.h" + textual header "dummy_textual_header.h" +} + module builtin { header "builtin.h" explicit module sub { Index: clang/test/Modules/Inputs/imported_module.cppm =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/imported_module.cppm @@ -0,0 +1,6 @@ +export module ModuleB39206; +#include "header_in_imported_module.h" + +#ifndef ALL_GOOD +#error "Missing macro in module decl" +#endif \ No newline at end of file Index: clang/test/Modules/Inputs/header_in_imported_module.h =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/header_in_imported_module.h @@ -0,0 +1,3 @@ +#pragma once + +#define ALL_GOOD Index: clang/test/Modules/Inputs/dummy_textual_header.h =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/dummy_textual_header.h @@ -0,0 +1,2 @@ +#pragma once +int y = 6; Index: clang/test/Modules/Inputs/dummy_pragma_once.h =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/dummy_pragma_once.h @@ -0,0 +1,3 @@ +#include "dummy_textual_header.h" + +int x = 5; Index: clang/lib/Serialization/ASTWriter.cpp =================================================================== --- clang/lib/Serialization/ASTWriter.cpp +++ clang/lib/Serialization/ASTWriter.cpp @@ -1621,7 +1621,7 @@ endian::Writer LE(Out, little); unsigned KeyLen = key.Filename.size() + 1 + 8 + 8; LE.write<uint16_t>(KeyLen); - unsigned DataLen = 1 + 2 + 4 + 4; + unsigned DataLen = 1 + 2 + 4 + 4 + 4; for (auto ModInfo : Data.KnownHeaders) if (Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule())) DataLen += 4; @@ -1678,6 +1678,9 @@ } LE.write<uint32_t>(Offset); + // Write this file UID. + LE.write<uint32_t>(Data.HFI.UID); + auto EmitModule = [&](Module *M, ModuleMap::ModuleHeaderRole Role) { if (uint32_t ModID = Writer.getLocalOrImportedSubmoduleID(M)) { uint32_t Value = (ModID << 2) | (unsigned)Role; @@ -1705,7 +1708,7 @@ /// Write the header search block for the list of files that /// /// \param HS The header search structure to save. -void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) { +void ASTWriter::WriteHeaderSearch(HeaderSearch &HS) { HeaderFileInfoTrait GeneratorTrait(*this); llvm::OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator; SmallVector<const char *, 4> SavedStrings; @@ -1783,8 +1786,7 @@ // changed since it was loaded. Also skip it if it's for a modular header // from a different module; in that case, we rely on the module(s) // containing the header to provide this information. - const HeaderFileInfo *HFI = - HS.getExistingFileInfo(File, /*WantExternal*/!Chain); + HeaderFileInfo *HFI = HS.getExistingFileInfo(File, /*WantExternal*/ !Chain); if (!HFI || (HFI->isModuleHeader && !HFI->isCompilingModuleHeader)) continue; @@ -1801,8 +1803,13 @@ HeaderFileInfoTrait::key_type Key = { Filename, File->getSize(), getTimestampForOutput(File) }; + // Set the UID for this HFI so that its importers could use it + // when serializing. + HFI->UID = UID; HeaderFileInfoTrait::data_type Data = { - *HFI, HS.getModuleMap().findAllModulesForHeader(File), {} + *HFI, + HS.getModuleMap().findAllModulesForHeader(File), + {}, }; Generator.insert(Key, Data, GeneratorTrait); ++NumHeaderSearchEntries; @@ -2636,6 +2643,25 @@ Stream.EmitRecord(SUBMODULE_IMPORTS, Record); } + // Emit the imported header's UIDs. + { + auto it = PP->Submodules.find(Mod); + if (it != PP->Submodules.end() && !it->second.IncludedFiles.empty()) { + RecordData Record; + for (unsigned UID : it->second.IncludedFiles) { + // Only save it if the header is actually import/pragma once. + // FIXME When we first see a header, it always goes into the mod's + // list of included, regardless of whether it was pragma-once or not. + // Maybe better to fix that earlier? + auto HFI = PP->getHeaderSearchInfo().FileInfo[UID]; + if (HFI.isImport || HFI.isPragmaOnce) { + Record.push_back(HFI.UID); + } + } + Stream.EmitRecord(SUBMODULE_IMPORTED_HEADERS, Record); + } + } + // Emit the exports. if (!Mod->Exports.empty()) { RecordData Record; @@ -4722,6 +4748,23 @@ if (WritingModule) WriteSubmodules(WritingModule); + // Write the imported headers, only for the precompiled header (ie, no + // modules) because the modules will have emitted their own imported headers. + if (!WritingModule && !PP.CurSubmoduleState->IncludedFiles.empty()) { + RecordData Record; + for (unsigned UID : PP.CurSubmoduleState->IncludedFiles) { + // Only save it if the header is actually import/pragma once. + // FIXME When we first see a header, it always goes into the + // list of included, regardless of whether it was pragma-once or not. + // Maybe better to fix that earlier? + auto HFI = PP.getHeaderSearchInfo().FileInfo[UID]; + if (HFI.isImport || HFI.isPragmaOnce) { + Record.push_back(HFI.UID); + } + } + Stream.EmitRecord(PP_IMPORTED_HEADERS, Record); + } + // We need to have information about submodules to correctly deserialize // decls from OpenCLExtensionDecls block WriteOpenCLExtensionDecls(SemaRef); Index: clang/lib/Serialization/ASTReader.cpp =================================================================== --- clang/lib/Serialization/ASTReader.cpp +++ clang/lib/Serialization/ASTReader.cpp @@ -1898,6 +1898,10 @@ HFI.Framework = HS->getUniqueFrameworkName(FrameworkName); } + // Read the file old UID + HFI.OldUID = endian::readNext<uint32_t, little, unaligned>(d); + HFI.UIDSet = true; + assert((End - d) % 4 == 0 && "Wrong data length in HeaderFileInfo deserialization"); while (d != End) { @@ -3081,6 +3085,7 @@ case HEADER_SEARCH_TABLE: case IMPORTED_MODULES: case MACRO_OFFSET: + case PP_IMPORTED_HEADERS: break; default: continue; @@ -3530,6 +3535,12 @@ break; } + case PP_IMPORTED_HEADERS: { + for (unsigned Idx = 0; Idx < Record.size(); ++Idx) { + PendingImportedHeaders.insert(Record[Idx]); + } + break; + } case DECL_UPDATE_OFFSETS: if (Record.size() % 2 != 0) { Error("invalid DECL_UPDATE_OFFSETS block in AST file"); @@ -5620,6 +5631,11 @@ } break; + case SUBMODULE_IMPORTED_HEADERS: + for (unsigned Idx = 0; Idx < Record.size(); ++Idx) { + PendingImportedHeadersForModuleFiles[&F].insert(Record[Idx]); + } + break; case SUBMODULE_EXPORTS: for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) { UnresolvedModuleRef Unresolved; @@ -6171,6 +6187,8 @@ return HeaderFileInfo(); } +void ASTReader::ResolvePendings() { resolvePendingImportedHeaders(); } + void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { using DiagState = DiagnosticsEngine::DiagState; SmallVector<DiagState *, 32> DiagStates; @@ -9292,6 +9310,97 @@ for (auto *ND : PendingMergedDefinitionsToDeduplicate) getContext().deduplicateMergedDefinitonsFor(ND); PendingMergedDefinitionsToDeduplicate.clear(); + + // Have to be done last because we need the modules + // and other PP info. + { + // First, Map ModuleFile* to Module* for more convenient lookup. + const auto &Iter = PendingImportedHeadersForModuleFiles.begin(); + for (unsigned I = 0; I < PendingImportedHeadersForModuleFiles.size(); ++I) { + ModuleFile *ModFile = Iter[I].first; + auto &HeaderUIDs = Iter[I].second; + Module *Mod = PP.getHeaderSearchInfo().lookupModule(ModFile->ModuleName); + + PendingImportedHeadersForModules.insert({Mod, {std::move(HeaderUIDs)}}); + } + PendingImportedHeadersForModuleFiles.clear(); + resolvePendingImportedHeaders(); + } +} + +void ASTReader::resolvePendingImportedHeaders() { + if (PP.getHeaderSearchInfo().FileInfo.empty()) { + return; + } + + if (!PendingImportedHeadersForModules.empty() || + !PendingImportedHeaders.empty()) { + + // These HFIs were deserialized and assigned their "old" + // UID. + HeaderSearch &HS = PP.getHeaderSearchInfo(); + // TODO: maybe only do this update, if it's out of date + std::map<unsigned, unsigned> OldToNewUIDMapping; + for (unsigned Idx = 0; Idx < HS.FileInfo.size(); ++Idx) { + if (!HS.FileInfo[Idx].UIDSet) { + continue; + } + OldToNewUIDMapping[HS.FileInfo[Idx].OldUID] = Idx; + } + + if (OldToNewUIDMapping.empty()) + return; + + const auto &Iter = PendingImportedHeadersForModules.begin(); + bool Unresolved = false; + for (unsigned I = 0; I < PendingImportedHeadersForModules.size(); ++I) { + auto &HeaderUIDs = Iter[I].second; + Module *M = Iter[I].first; + + Preprocessor::SubmoduleState &SubState = PP.Submodules[M]; + for (auto OldUIDItr = HeaderUIDs.begin(); + OldUIDItr != HeaderUIDs.end();) { + auto IdxIt = OldToNewUIDMapping.find(*OldUIDItr); + if (IdxIt == OldToNewUIDMapping.end()) { + Unresolved = true; + ++OldUIDItr; + continue; + } + OldUIDItr = HeaderUIDs.erase(OldUIDItr); + SubState.IncludedFiles.insert(IdxIt->second); + } + } + if (!Unresolved) + PendingImportedHeadersForModules.clear(); + + if (!PendingImportedHeaders.empty()) { + std::set<unsigned> Remaining; + for (auto OldUIDItr = PendingImportedHeaders.begin(); + OldUIDItr != PendingImportedHeaders.end();) { + auto IdxIt = OldToNewUIDMapping.find(*OldUIDItr); + if (IdxIt == OldToNewUIDMapping.end()) { + Unresolved = true; + ++OldUIDItr; + continue; + } + OldUIDItr = PendingImportedHeaders.erase(OldUIDItr); + PP.CurSubmoduleState->IncludedFiles.insert(IdxIt->second); + } + } + } +} + +void ASTReader::ImportPendingIncludedFiles(Module *FromMod, Module *ToMod) { + auto Iter = PendingImportedHeadersForModules.find(FromMod); + if (Iter == PendingImportedHeadersForModules.end() || Iter->second.empty()) + return; + + auto &TargetUIDVector = ToMod == nullptr + ? PendingImportedHeaders + : PendingImportedHeadersForModules[ToMod]; + for (unsigned UID : Iter->second) { + TargetUIDVector.insert(UID); + } } void ASTReader::diagnoseOdrViolations() { Index: clang/lib/Lex/Preprocessor.cpp =================================================================== --- clang/lib/Lex/Preprocessor.cpp +++ clang/lib/Lex/Preprocessor.cpp @@ -554,8 +554,9 @@ // Tell the header info that the main file was entered. If the file is later // #imported, it won't be re-entered. - if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID)) - HeaderInfo.IncrementIncludeCount(FE); + if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID)) { + HeaderInfo.MarkAsIncluded(*this, FE); + } } // Preprocess Predefines to populate the initial preprocessor state. Index: clang/lib/Lex/PPLexerChange.cpp =================================================================== --- clang/lib/Lex/PPLexerChange.cpp +++ clang/lib/Lex/PPLexerChange.cpp @@ -642,10 +642,13 @@ void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc, bool ForPragma) { if (!getLangOpts().ModulesLocalVisibility) { - // Just track that we entered this submodule. + // Just track that we entered this submodule (and track the imports) BuildingSubmoduleStack.push_back( BuildingSubmoduleInfo(M, ImportLoc, ForPragma, CurSubmoduleState, PendingModuleMacroNames.size())); + auto R = Submodules.insert(std::make_pair(M, SubmoduleState())); + auto &State = R.first->second; + CurSubmoduleState = &State; if (Callbacks) Callbacks->EnteredSubmodule(M, ImportLoc, ForPragma); return; @@ -731,6 +734,7 @@ if (!needModuleMacros() || (!getLangOpts().ModulesLocalVisibility && LeavingMod->getTopLevelModuleName() != getLangOpts().CurrentModule)) { + CurSubmoduleState = Info.OuterSubmoduleState; // If we don't need module macros, or this is not a module for which we // are tracking macro visibility, don't build any, and preserve the list // of pending names for the surrounding submodule. Index: clang/lib/Lex/PPDirectives.cpp =================================================================== --- clang/lib/Lex/PPDirectives.cpp +++ clang/lib/Lex/PPDirectives.cpp @@ -2013,6 +2013,14 @@ if (Imported) { Action = Import; + Module *ImportedMod = (Imported); + // If we're auto importing this module, also import the hdrs. + for (auto UID : Submodules[ImportedMod].IncludedFiles) { + setIncludeVisible(UID); + } + // Also import the pendings. + getHeaderSearchInfo().ImportPendingIncludedFiles(ImportedMod, + getCurrentModule()); } else if (Imported.isMissingExpected()) { // We failed to find a submodule that we assumed would exist (because it // was in the directory of an umbrella header, for instance), but no Index: clang/lib/Lex/HeaderSearch.cpp =================================================================== --- clang/lib/Lex/HeaderSearch.cpp +++ clang/lib/Lex/HeaderSearch.cpp @@ -1156,16 +1156,22 @@ if (HFI.Framework.empty()) HFI.Framework = OtherHFI.Framework; + + HFI.UID = OtherHFI.UID; + HFI.UIDSet = OtherHFI.UIDSet; + HFI.OldUID = OtherHFI.OldUID; } /// getFileInfo - Return the HeaderFileInfo structure for the specified /// FileEntry. HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) { - if (FE->getUID() >= FileInfo.size()) + if (FE->getUID() >= FileInfo.size()) { FileInfo.resize(FE->getUID() + 1); + } HeaderFileInfo *HFI = &FileInfo[FE->getUID()]; - // FIXME: Use a generation count to check whether this is really up to date. + HFI->UID = FE->getUID(); + if (ExternalSource && !HFI->Resolved) { HFI->Resolved = true; auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE); @@ -1182,9 +1188,8 @@ return *HFI; } -const HeaderFileInfo * -HeaderSearch::getExistingFileInfo(const FileEntry *FE, - bool WantExternal) const { +HeaderFileInfo *HeaderSearch::getExistingFileInfo(const FileEntry *FE, + bool WantExternal) const { // If we have an external source, ensure we have the latest information. // FIXME: Use a generation count to check whether this is really up to date. HeaderFileInfo *HFI; @@ -1196,6 +1201,8 @@ } HFI = &FileInfo[FE->getUID()]; + HFI->UID = FE->getUID(); + if (!WantExternal && (!HFI->IsValid || HFI->External)) return nullptr; if (!HFI->Resolved) { @@ -1245,68 +1252,58 @@ HFI.isCompilingModuleHeader |= isCompilingModuleHeader; } +void HeaderSearch::MarkAsIncluded(Preprocessor &PP, const FileEntry *File) { + HeaderFileInfo HFI = getFileInfo(File); + ++HFI.NumIncludes; + PP.setIncludeVisible(HFI.UID); +} + bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, const FileEntry *File, bool isImport, bool ModulesEnabled, Module *M) { ++NumIncluded; // Count # of attempted #includes. + // Make sure everything is up to date. + ModMap.resolveHeaderDirectives(File); + + const bool SeenBefore = + getExistingFileInfo(File, /*WantExernal=*/true) != nullptr; + // Get information about this file. HeaderFileInfo &FileInfo = getFileInfo(File); - // FIXME: this is a workaround for the lack of proper modules-aware support - // for #import / #pragma once - auto TryEnterImported = [&]() -> bool { - if (!ModulesEnabled) - return false; - // Ensure FileInfo bits are up to date. - ModMap.resolveHeaderDirectives(File); - // Modules with builtins are special; multiple modules use builtins as - // modular headers, example: - // - // module stddef { header "stddef.h" export * } - // - // After module map parsing, this expands to: - // - // module stddef { - // header "/path_to_builtin_dirs/stddef.h" - // textual "stddef.h" - // } - // - // It's common that libc++ and system modules will both define such - // submodules. Make sure cached results for a builtin header won't - // prevent other builtin modules to potentially enter the builtin header. - // Note that builtins are header guarded and the decision to actually - // enter them is postponed to the controlling macros logic below. - bool TryEnterHdr = false; - if (FileInfo.isCompilingModuleHeader && FileInfo.isModuleHeader) - TryEnterHdr = File->getDir() == ModMap.getBuiltinDir() && - ModuleMap::isBuiltinHeader( - llvm::sys::path::filename(File->getName())); - - // Textual headers can be #imported from different modules. Since ObjC - // headers find in the wild might rely only on #import and do not contain - // controlling macros, be conservative and only try to enter textual headers - // if such macro is present. - if (!FileInfo.isModuleHeader && - FileInfo.getControllingMacro(ExternalLookup)) - TryEnterHdr = true; - return TryEnterHdr; - }; + // Resolve any pendings before we do calculations. + if (ExternalSource) { + ExternalSource->ResolvePendings(); + } - // If this is a #import directive, check that we have not already imported - // this header. if (isImport) { // If this has already been imported, don't import it again. FileInfo.isImport = true; + } - // Has this already been #import'ed or #include'd? - if (FileInfo.NumIncludes && !TryEnterImported()) + if (!SeenBefore || FileInfo.NumIncludes == 0 || FileInfo.isPragmaOnce || + FileInfo.isImport) { + if (PP.isIncludeVisible(FileInfo.UID)) { return false; - } else { - // Otherwise, if this is a #include of a file that was previously #import'd - // or if this is the second #include of a #pragma once file, ignore it. - if (FileInfo.isImport && !TryEnterImported()) + } else if (FileInfo.isModuleHeader && FileInfo.isCompilingModuleHeader && + PP.isIncludeVisibleFromOuterModule(FileInfo.UID)) { return false; + } else { + // Mark as 'included'. + PP.setIncludeVisible(FileInfo.UID); + + // FIXME: This is kind of hack to handle textual-header in ObjC + // Textual headers can be #imported from different modules. + // ObjC headers rely only on #import and do not contain + // controlling macros. Hence we won't enter the header if + // macro is absent. + if (isImport && FileInfo.NumIncludes && + (FileInfo.isModuleHeader || + !FileInfo.getControllingMacro(ExternalLookup))) { + return false; + } + } } // Next, check to see if the file is wrapped with #ifndef guards. If so, and @@ -1325,7 +1322,6 @@ // Increment the number of times this file has been included. ++FileInfo.NumIncludes; - return true; } Index: clang/include/clang/Serialization/ASTWriter.h =================================================================== --- clang/include/clang/Serialization/ASTWriter.h +++ clang/include/clang/Serialization/ASTWriter.h @@ -463,7 +463,7 @@ void WriteSourceManagerBlock(SourceManager &SourceMgr, const Preprocessor &PP); void WritePreprocessor(const Preprocessor &PP, bool IsModule); - void WriteHeaderSearch(const HeaderSearch &HS); + void WriteHeaderSearch(HeaderSearch &HS); void WritePreprocessorDetail(PreprocessingRecord &PPRec); void WriteSubmodules(Module *WritingModule); Index: clang/include/clang/Serialization/ASTReader.h =================================================================== --- clang/include/clang/Serialization/ASTReader.h +++ clang/include/clang/Serialization/ASTReader.h @@ -736,6 +736,16 @@ /// IDs have not yet been deserialized to the global IDs of those macros. PendingMacroIDsMap PendingMacroIDs; + /// Mapping from ModuleFile to a list of its imported headers' (old) UID. + /// These UIDs are yet to be mapped to their corresponding HeaderFileInfo + llvm::MapVector<ModuleFile *, std::set<unsigned>> + PendingImportedHeadersForModuleFiles; + llvm::MapVector<Module *, std::set<unsigned>> + PendingImportedHeadersForModules; + + /// List of a PCH imported headers' (old)UID. + std::set<unsigned> PendingImportedHeaders; + using GlobalPreprocessedEntityMapType = ContinuousRangeMap<unsigned, ModuleFile *, 4>; @@ -1416,6 +1426,8 @@ void PassInterestingDeclsToConsumer(); void PassInterestingDeclToConsumer(Decl *D); + void resolvePendingImportedHeaders(); + void finishPendingActions(); void diagnoseOdrViolations(); @@ -1722,6 +1734,12 @@ /// Read the header file information for the given file entry. HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE) override; + /// Resolve as many pending 'included' headers as possible. + void ResolvePendings() override; + + /// Import pending included headers from FromMod to ToMod. + void ImportPendingIncludedFiles(Module *FromMod, Module *ToMod) override; + void ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag); /// Returns the number of source locations found in the chain. Index: clang/include/clang/Serialization/ASTBitCodes.h =================================================================== --- clang/include/clang/Serialization/ASTBitCodes.h +++ clang/include/clang/Serialization/ASTBitCodes.h @@ -654,6 +654,9 @@ /// Record code for the Decls to be checked for deferred diags. DECLS_TO_CHECK_FOR_DEFERRED_DIAGS = 64, + + /// List of imported headers' UID for a PCH + PP_IMPORTED_HEADERS = 65, }; /// Record types used within a source manager block. @@ -784,6 +787,9 @@ /// Specifies the name of the module that will eventually /// re-export the entities in this module. SUBMODULE_EXPORT_AS = 17, + + // Specifies the headers' UID imported by this submodule. + SUBMODULE_IMPORTED_HEADERS = 18, }; /// Record types used within a comments block. Index: clang/include/clang/Lex/Preprocessor.h =================================================================== --- clang/include/clang/Lex/Preprocessor.h +++ clang/include/clang/Lex/Preprocessor.h @@ -51,6 +51,7 @@ #include <cstdint> #include <map> #include <memory> +#include <set> #include <string> #include <utility> #include <vector> @@ -128,6 +129,8 @@ class Preprocessor { friend class VAOptDefinitionContext; friend class VariadicMacroScopeGuard; + friend class ASTWriter; + friend class ASTReader; llvm::unique_function<void(const clang::Token &)> OnToken; std::shared_ptr<PreprocessorOptions> PPOpts; @@ -743,6 +746,9 @@ /// The set of modules that are visible within the submodule. VisibleModuleSet VisibleModules; + /// The set of the included headers' UID for the submodule. + std::set<unsigned> IncludedFiles; + // FIXME: CounterValue? // FIXME: PragmaPushMacroInfo? }; @@ -1038,6 +1044,24 @@ OnToken = std::move(F); } + void setIncludeVisible(unsigned UID) { + CurSubmoduleState->IncludedFiles.insert(UID); + } + + bool isIncludeVisibleFromOuterModule(unsigned UID) { + if (BuildingSubmoduleStack.empty()) + return false; + + auto OuterState = BuildingSubmoduleStack.back().OuterSubmoduleState; + return OuterState->IncludedFiles.find(UID) != + OuterState->IncludedFiles.end(); + } + + bool isIncludeVisible(unsigned UID) { + return CurSubmoduleState->IncludedFiles.find(UID) != + CurSubmoduleState->IncludedFiles.end(); + } + bool isMacroDefined(StringRef Id) { return isMacroDefined(&Identifiers.get(Id)); } Index: clang/include/clang/Lex/HeaderSearch.h =================================================================== --- clang/include/clang/Lex/HeaderSearch.h +++ clang/include/clang/Lex/HeaderSearch.h @@ -110,10 +110,17 @@ /// of the framework. StringRef Framework; + /// The file UID used during [de]serialization. + unsigned UIDSet = false; // DO not serialize this. + unsigned OldUID = 0; + + // CurrentUid + unsigned UID = 0; + HeaderFileInfo() : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User), External(false), isModuleHeader(false), isCompilingModuleHeader(false), - Resolved(false), IndexHeaderMapHeader(false), IsValid(false) {} + Resolved(false), IndexHeaderMapHeader(false), IsValid(false) {} /// Retrieve the controlling macro for this header file, if /// any. @@ -140,6 +147,12 @@ /// \c External bit set. If the file entry is not known, return a /// default-constructed \c HeaderFileInfo. virtual HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE) = 0; + + /// Resolve any pending imported headers. + virtual void ResolvePendings() = 0; + + /// Add the set of pending imported from FromMod to ToMod. + virtual void ImportPendingIncludedFiles(Module *FromMod, Module *ToMod) = 0; }; /// This structure is used to record entries in our framework cache. @@ -157,6 +170,8 @@ /// by a \#include or \#include_next, (sub-)framework lookup, etc. class HeaderSearch { friend class DirectoryLookup; + friend class ASTReader; + friend class ASTWriter; /// Header-search options used to initialize this header search. std::shared_ptr<HeaderSearchOptions> HSOpts; @@ -350,6 +365,12 @@ ExternalSource = ES; } + void ImportPendingIncludedFiles(Module *FromMod, Module *ToMod) { + if (ExternalSource) { + ExternalSource->ImportPendingIncludedFiles(FromMod, ToMod); + } + } + /// Set the target information for the header search, if not /// already known. void setTarget(const TargetInfo &Target); @@ -449,11 +470,9 @@ ModuleMap::ModuleHeaderRole Role, bool isCompilingModuleHeader); - /// Increment the count for the number of times the specified - /// FileEntry has been entered. - void IncrementIncludeCount(const FileEntry *File) { - ++getFileInfo(File).NumIncludes; - } + /// Mark this file as included for the current so if it is + /// later imported, it won't be re-entered. + void MarkAsIncluded(Preprocessor &PP, const FileEntry *File); /// Mark the specified file as having a controlling macro. /// @@ -664,8 +683,8 @@ /// if it has ever been filled in. /// \param WantExternal Whether the caller wants purely-external header file /// info (where \p External is true). - const HeaderFileInfo *getExistingFileInfo(const FileEntry *FE, - bool WantExternal = true) const; + HeaderFileInfo *getExistingFileInfo(const FileEntry *FE, + bool WantExternal = true) const; // Used by external tools using search_dir_iterator = std::vector<DirectoryLookup>::const_iterator;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits