diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -179,6 +179,13 @@ CompilerInstance(const CompilerInstance &) = delete; void operator=(const CompilerInstance &) = delete; public: + struct EntryStruct { + Optional FE; + bool IsSystemFile; + bool IsTopLevelModuleMap; + }; + llvm::StringMap> SortedFiles; + explicit CompilerInstance( std::shared_ptr PCHContainerOps = std::make_shared(), diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1129,6 +1129,226 @@ return LangOpts.CPlusPlus ? Language::CXX : Language::C; } +class Translator { + CompilerInstance &A; + const CompilerInstance &B; + + llvm::StringSet<> TranslatedModules; + +public: + Translator(CompilerInstance &A, const CompilerInstance &B) : A(A), B(B) {} + + template Optional translate(const Optional &BO) { + if (!BO) + return None; + return translate(*BO); + } + + template const T *translate(const T *BP) { + if (!BP) + return nullptr; + return &translate(*BP); + } + + template T *translate(T *BP) { + if (!BP) + return nullptr; + return &translate(*BP); + } + + template llvm::PointerUnion translate(llvm::PointerUnion BPU) { + if (!BPU) + return nullptr; + if (BPU.template is()) + return translate(BPU.template get()); + return translate(BPU.template get()); + } + + template + SmallVector translate(const SmallVector &BV) { + SmallVector AV; + AV.reserve(BV.size()); + for (const T &Entry : BV) + AV.push_back(translate(Entry)); + return AV; + } + + template + llvm::SmallSetVector translate(const llvm::SmallSetVector& BSSV) { + llvm::SmallSetVector ASSV; + for (const auto &Entry : BSSV) + ASSV.insert(translate(Entry)); + return ASSV; + } + + const FileEntry &translate(const FileEntry &BFE) { + return **A.getFileManager().getFile(BFE.getName()); + } + + FileEntryRef translate(FileEntryRef BFE) { + return *A.getFileManager().getOptionalFileRef(BFE.getName()); + } + + const DirectoryEntry &translate(const DirectoryEntry &BDE) { + return **A.getFileManager().getDirectory(BDE.getName()); + } + + SourceLocation translate(SourceLocation BLoc) { + auto &ASM = A.getSourceManager(); + auto &BSM = B.getSourceManager(); + + auto BFileID = BSM.getFileID(BLoc); + auto BFileCharacteristic = BSM.getFileCharacteristic(BLoc); + auto *AFileEntry = translate(BSM.getFileEntryForID(BFileID)); + auto AFileID = ASM.getOrCreateFileID(AFileEntry, BFileCharacteristic); + + auto AOffset = BSM.getFileOffset(BLoc); + + return ASM.getComposedLoc(AFileID, AOffset); + } + + Module::Header translate(const Module::Header &BHeader) { + return Module::Header{BHeader.NameAsWritten, + BHeader.PathRelativeToRootModuleDirectory, + translate(BHeader.Entry)}; + } + + std::vector translate(Module::submodule_iterator Begin, + Module::submodule_iterator End) { + std::vector ASubModules; + for (auto It = Begin; It != End; ++It) + ASubModules.push_back(translate(*It)); + return ASubModules; + } + + Module::UnresolvedHeaderDirective + translate(const Module::UnresolvedHeaderDirective &BD) { + return {BD.Kind, // + translate(BD.FileNameLoc), + BD.FileName, + BD.IsUmbrella, + BD.HasBuiltinHeader, + BD.Size, + BD.ModTime}; + } + + Module::ExportDecl translate(const Module::ExportDecl &BED) { + return {translate(BED.getPointer()), BED.getInt()}; + } + + ModuleId translate(const ModuleId &BId) { + ModuleId Res; + for (const auto &Element : BId) + Res.push_back({Element.first, translate(Element.second)}); + return Res; + } + + Module::UnresolvedExportDecl + translate(const Module::UnresolvedExportDecl &BUED) { + return {translate(BUED.ExportLoc), translate(BUED.Id), BUED.Wildcard}; + } + + Module::LinkLibrary translate(const Module::LinkLibrary &X) { + return X; + } + + Module::UnresolvedConflict translate(const Module::UnresolvedConflict &X) { + return {translate(X.Id), X.Message}; + } + + Module::Conflict translate(const Module::Conflict &X) { + return {translate(X.Other), X.Message}; + } + + Module &translate(const Module &BMod) { + return translate(const_cast(BMod)); + } + + Module &translate(Module &BMod) { + auto &AModMap = A.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + auto &BHS = B.getPreprocessor().getHeaderSearchInfo(); + + auto [AMod, New] = AModMap.findOrCreateModule( + BMod.Name, translate(BMod.Parent), + BMod.IsFramework, BMod.IsExplicit); + + if (!TranslatedModules.insert(BMod.Name).second) + return *AMod; + + // Even if instance A already knows about module, it might not know + // information that's figured during compile of the module (e.g. imports). + if (!New) { + // llvm::errs() << "translating existing module " << BMod.Name << "\n"; + } + + AMod->Kind = BMod.Kind; + AMod->Directory = translate(BMod.Directory); + AMod->PresumedModuleMapFile = BMod.PresumedModuleMapFile; + AMod->DefinitionLoc = translate(AMod->DefinitionLoc); + AMod->Umbrella = translate(BMod.Umbrella); + AMod->UmbrellaAsWritten = BMod.UmbrellaAsWritten; + AMod->UmbrellaRelativeToRootModuleDirectory = BMod.UmbrellaRelativeToRootModuleDirectory; + AMod->ExportAsModule = BMod.ExportAsModule; + + for (Module *BSubMod : BMod.submodules()) + translate(BSubMod); + + for (const FileEntry *BTopHeader : BMod.getTopHeaders(B.getFileManager())) + AMod->addTopHeader(translate(BTopHeader)); + + // TODO: Propagate VisibilityID to other data structures. + + for (auto Kind : {Module::HK_Normal, Module::HK_Textual, Module::HK_Private, + Module::HK_PrivateTextual, Module::HK_Excluded}) { + for (const auto &BH : BMod.Headers[Kind]) { + const auto &AH = translate(BH); + AModMap.addHeader(AMod, AH, ModuleMap::headerKindToRole(Kind), + BHS.getFileInfo(BH.Entry).isModuleHeader); + } + } + + AMod->UnresolvedHeaders = translate(BMod.UnresolvedHeaders); + AMod->MissingHeaders = translate(BMod.MissingHeaders); + AMod->Requirements = BMod.Requirements; + AMod->ShadowingModule = translate(BMod.ShadowingModule); + AMod->IsUnimportable = BMod.IsUnimportable; + AMod->HasIncompatibleModuleFile = BMod.HasIncompatibleModuleFile; + AMod->IsAvailable = BMod.IsAvailable; + AMod->IsFromModuleFile = BMod.IsFromModuleFile; + AMod->IsFramework = BMod.IsFramework; + AMod->IsExplicit = BMod.IsExplicit; + AMod->IsSystem = BMod.IsSystem; + AMod->IsExternC = BMod.IsExternC; + AMod->IsInferred = BMod.IsInferred; + AMod->InferSubmodules = BMod.InferSubmodules; + AMod->InferExplicitSubmodules = BMod.InferExplicitSubmodules; + AMod->InferExportWildcard = BMod.InferExportWildcard; + AMod->ConfigMacrosExhaustive = BMod.ConfigMacrosExhaustive; + AMod->NoUndeclaredIncludes = BMod.NoUndeclaredIncludes; + AMod->ModuleMapIsPrivate = BMod.ModuleMapIsPrivate; + AMod->NameVisibility = BMod.NameVisibility; + AMod->InferredSubmoduleLoc = translate(BMod.InferredSubmoduleLoc); + AMod->Imports = translate(BMod.Imports); + AMod->Exports = translate(BMod.Exports); + AMod->UnresolvedExports = translate(BMod.UnresolvedExports); + AMod->DirectUses = translate(BMod.DirectUses); + AMod->UnresolvedDirectUses = translate(BMod.UnresolvedDirectUses); + AMod->UndeclaredUses = translate(BMod.UndeclaredUses); + AMod->LinkLibraries = translate(BMod.LinkLibraries); + AMod->UseExportAsModuleLinkName = BMod.UseExportAsModuleLinkName; + AMod->ConfigMacros = BMod.ConfigMacros; + AMod->UnresolvedConflicts = BMod.UnresolvedConflicts; + AMod->Conflicts = BMod.Conflicts; + + return *AMod; + } + + Module *translateModule(StringRef BName) { + return translate( + B.getPreprocessor().getHeaderSearchInfo().lookupModule(BName)); + } +}; + /// Compile a module file for the given module, using the options /// provided by the importing compiler instance. Returns true if the module /// was built without errors. @@ -1254,6 +1474,48 @@ [&]() { GenerateModuleFromModuleMapAction Action; Instance.ExecuteAction(Action); + + Translator T(ImportingInstance, Instance); + T.translateModule(ModuleName); + // llvm::errs() << "translated " << ModuleName << "\n"; + + std::set AffectingModuleMaps; + std::set SkippedModuleMaps; + + auto &SortedFiles = ImportingInstance.SortedFiles[ModuleName]; + for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) { + // Get this source location entry. + const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I); + + // We only care about file entries that were not overridden. + if (!SLoc->isFile()) + continue; + const SrcMgr::FileInfo &File = SLoc->getFile(); + const SrcMgr::ContentCache *Cache = &File.getContentCache(); + if (!Cache->OrigEntry) + continue; + + if (isModuleMap(File.getFileCharacteristic()) && + !isSystem(File.getFileCharacteristic()) && + !AffectingModuleMaps.empty() && + AffectingModuleMaps.find(Cache->OrigEntry) == + AffectingModuleMaps.end()) { + SkippedModuleMaps.insert(Cache->OrigEntry); + // Do not emit modulemaps that do not affect current module. + continue; + } + + CompilerInstance::EntryStruct Entry{ + T.translate(Cache->OrigEntry), + isSystem(File.getFileCharacteristic()), + isModuleMap(File.getFileCharacteristic()) && + File.getIncludeLoc().isInvalid()}; + + if (Entry.IsSystemFile) + SortedFiles.push_back(Entry); + else + SortedFiles.push_front(Entry); + } }, DesiredStackSize); @@ -1370,11 +1632,16 @@ if (OutOfDate) ModuleLoadCapabilities |= ASTReader::ARR_OutOfDate; + llvm::errs() << "readASTAfterCompileModule " << Module << " " << Module->getFullModuleName() << " " << Module->Imports.size() << "\n"; + // Try to read the module file, now that we've compiled it. ASTReader::ASTReadResult ReadResult = ImportingInstance.getASTReader()->ReadAST( ModuleFileName, serialization::MK_ImplicitModule, ImportLoc, ModuleLoadCapabilities); + + llvm::errs() << "readASTAfterCompileModule " << Module << " " << Module->getFullModuleName() << " " << Module->Imports.size() << "\n"; + if (ReadResult == ASTReader::Success) return true; @@ -1799,6 +2066,8 @@ Module *M = HS.lookupModule(ModuleName, ImportLoc, true, !IsInclusionDirective); + assert(M && "no module in findOrCompileModuleAndReadAST"); + // Select the source and filename for loading the named module. std::string ModuleFilename; ModuleSource Source = @@ -1938,7 +2207,7 @@ // Try to compile and then read the AST. if (!compileModuleAndReadAST(*this, ImportLoc, ModuleNameLoc, M, - ModuleFilename)) { + ModuleFilename)) { // assert(getDiagnostics().hasErrorOccurred() && "undiagnosed error in compileModuleAndReadAST"); if (getPreprocessorOpts().FailedModules) diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -424,6 +424,7 @@ MD.ClangModuleMapFile = std::string(Path); } + if (MDC.ScanInstance.SortedFiles.find(M->getFullModuleName()) == MDC.ScanInstance.SortedFiles.end()) { serialization::ModuleFile *MF = MDC.ScanInstance.getASTReader()->getModuleManager().lookup( M->getASTFile()); @@ -452,12 +453,32 @@ return; MD.ModuleMapFileDeps.emplace_back(FE->getName()); }); + } else { + for (const auto &E : MDC.ScanInstance.SortedFiles[M->getFullModuleName()]) { + if (E.FE->getName().endswith("__inferred_module.map")) { + MDC.addFileDep(MD, ModuleMap->getName()); + continue; + } + MDC.addFileDep(MD, E.FE->getName()); + } + if (M->NoUndeclaredIncludes) { + for (const auto &E : MDC.ScanInstance.SortedFiles[M->getFullModuleName()]) { + if (E.FE->getName().endswith("__inferred_module.map")) + continue; + // The top-level modulemap of this module will be the input file. We + // don't need to specify it as a module map. + if (E.FE == ModuleMap) + continue; + MD.ModuleMapFileDeps.push_back(E.FE->getName().str()); + } + } + } CompilerInvocation CI = MDC.makeInvocationForModuleBuildWithoutOutputs( MD, [&](CompilerInvocation &BuildInvocation) { - if (MDC.OptimizeArgs) - optimizeHeaderSearchOpts(BuildInvocation.getHeaderSearchOpts(), - *MDC.ScanInstance.getASTReader(), *MF); +// if (MDC.OptimizeArgs) +// optimizeHeaderSearchOpts(BuildInvocation.getHeaderSearchOpts(), +// *MDC.ScanInstance.getASTReader(), *MF); }); MDC.associateWithContextHash(CI, MD);