From c91211a5d28d0d6c3323a6a838b046d7c1fb020e Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 18 Sep 2025 16:54:54 -0700 Subject: [PATCH] Serialize explicit module dependencies in swift module files For clients, such as the debugger, who do not have access the full output of the dependency scanner, it is a huger performance and correctness improvement if each explicitly built Swift module not just serialized all its Clang .pcm dependencies (via the serialized Clang compiler invocation) but also its direct Swift module dependencies. This patch changes the Swift module format to store the absolute path or cas cache key for each dependency in the INPUT block, and makes sure the deserialization makes these available to the ESML. rdar://150969755 --- include/swift/AST/ASTContext.h | 5 +++- include/swift/AST/Module.h | 7 +++++ include/swift/AST/SearchPathOptions.h | 2 +- include/swift/Basic/LangOptions.h | 3 ++ .../swift/Frontend/ModuleInterfaceLoader.h | 11 +++++--- .../Serialization/SerializedModuleLoader.h | 6 ++-- lib/AST/ASTContext.cpp | 18 ++++++++++-- lib/DependencyScan/ScanDependencies.cpp | 1 - lib/Frontend/Frontend.cpp | 2 +- lib/Frontend/ModuleInterfaceLoader.cpp | 16 ++++++++--- lib/Serialization/ModuleFile.cpp | 4 +++ lib/Serialization/ModuleFileSharedCore.cpp | 27 ++++++++++++------ lib/Serialization/ModuleFileSharedCore.h | 28 +++++++++---------- lib/Serialization/ModuleFormat.h | 17 +++++++---- lib/Serialization/Serialization.cpp | 21 +++++++++++--- lib/Serialization/SerializedModuleLoader.cpp | 24 ++++++++-------- .../optional_transitive_dep_load_fail.swift | 2 +- test/Serialization/Inputs/a.swift | 1 + test/Serialization/external_macros.swift | 8 +++--- test/Serialization/module-dependencies.swift | 9 ++++++ 20 files changed, 149 insertions(+), 63 deletions(-) create mode 100644 test/Serialization/Inputs/a.swift create mode 100644 test/Serialization/module-dependencies.swift diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index dfcaadeac7533..cc99b57120491 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -1074,6 +1074,9 @@ class ASTContext final { /// Does any proper bookkeeping to keep all module loaders up to date as well. void addSearchPath(StringRef searchPath, bool isFramework, bool isSystem); + /// Adds the path to the explicitly built module \c name. + void addExplicitModulePath(StringRef name, std::string path); + /// Adds a module loader to this AST context. /// /// \param loader The new module loader, which will be added after any @@ -1087,7 +1090,7 @@ class ASTContext final { /// interface. void addModuleLoader(std::unique_ptr loader, bool isClang = false, bool isDWARF = false, - bool IsInterface = false); + bool IsInterface = false, bool IsExplicit = false); /// Add a module interface checker to use for this AST context. void addModuleInterfaceChecker(std::unique_ptr checker); diff --git a/include/swift/AST/Module.h b/include/swift/AST/Module.h index 39091dcd3ad78..70774ef3bdaa7 100644 --- a/include/swift/AST/Module.h +++ b/include/swift/AST/Module.h @@ -858,6 +858,13 @@ class ModuleDecl /// returns true. bool isSubmoduleOf(const ModuleDecl *M) const; +private: + std::string CacheKey; + +public: + void setCacheKey(const std::string &key) { CacheKey = key; } + StringRef getCacheKey() const { return CacheKey; } + bool isResilient() const { return getResilienceStrategy() != ResilienceStrategy::Default; } diff --git a/include/swift/AST/SearchPathOptions.h b/include/swift/AST/SearchPathOptions.h index f8101fe93db68..f6fd586b2f5ec 100644 --- a/include/swift/AST/SearchPathOptions.h +++ b/include/swift/AST/SearchPathOptions.h @@ -45,7 +45,7 @@ enum class ModuleLoadingMode { PreferInterface, PreferSerialized, OnlyInterface, - OnlySerialized + OnlySerialized, }; /// A single module search path that can come from different sources, e.g. diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 3e89fc1062711..8c4eb2475fbc5 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -459,6 +459,9 @@ namespace swift { bool EnableDeserializationSafety = ::getenv("SWIFT_ENABLE_DESERIALIZATION_SAFETY"); + /// Disable injecting deserializes module paths into the explict module map. + bool DisableDeserializationOfExplicitPaths = false; + /// Attempt to recover for imported modules with broken modularization /// in an unsafe way. Currently applies only to xrefs where the target /// decl moved to a different module that is already loaded. diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index c1cbdb7ed7d85..a5fadd951074b 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -152,8 +152,9 @@ class ExplicitSwiftModuleLoader: public SerializedModuleLoaderBase { std::unique_ptr *moduleBuffer, std::unique_ptr *moduleDocBuffer, std::unique_ptr *moduleSourceInfoBuffer, - bool isCanImportLookup, bool isTestableDependencyLookup, - bool &isFramework, bool &isSystemModule) override; + std::string *cacheKey, bool isCanImportLookup, + bool isTestableDependencyLookup, bool &isFramework, + bool &isSystemModule) override; std::error_code findModuleFilesInDirectory( ImportPath::Element ModuleID, const SerializedModuleBaseName &BaseName, @@ -181,6 +182,7 @@ class ExplicitSwiftModuleLoader: public SerializedModuleLoaderBase { const llvm::StringMap &ExplicitSwiftModuleInputs, bool IgnoreSwiftSourceInfoFile); + void addExplicitModulePath(StringRef name, std::string path) override; /// Append visible module names to \p names. Note that names are possibly /// duplicated, and not guaranteed to be ordered in any way. void collectVisibleTopLevelModuleNames( @@ -201,8 +203,9 @@ class ExplicitCASModuleLoader : public SerializedModuleLoaderBase { std::unique_ptr *moduleBuffer, std::unique_ptr *moduleDocBuffer, std::unique_ptr *moduleSourceInfoBuffer, - bool isCanImportLookup, bool isTestableDependencyLookup, - bool &isFramework, bool &isSystemModule) override; + std::string *cacheKey, bool isCanImportLookup, + bool isTestableDependencyLookup, bool &isFramework, + bool &isSystemModule) override; std::error_code findModuleFilesInDirectory( ImportPath::Element ModuleID, const SerializedModuleBaseName &BaseName, diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index c137370177bdf..5e1231640c8a3 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -103,8 +103,8 @@ class SerializedModuleLoaderBase : public ModuleLoader { std::unique_ptr *moduleBuffer, std::unique_ptr *moduleDocBuffer, std::unique_ptr *moduleSourceInfoBuffer, - bool isCanImportLookup, bool isTestableDependencyLookup, - bool &isFramework, bool &isSystemModule); + std::string *CacheKey, bool isCanImportLookup, + bool isTestableDependencyLookup, bool &isFramework, bool &isSystemModule); /// Attempts to search the provided directory for a loadable serialized /// .swiftmodule with the provided `ModuleFilename`. Subclasses must @@ -268,6 +268,8 @@ class SerializedModuleLoaderBase : public ModuleLoader { /// A textual reason why the compiler rejected a binary module load /// attempt with a given status, to be used for diagnostic output. static std::optional invalidModuleReason(serialization::Status status); + + virtual void addExplicitModulePath(StringRef name, std::string path) {}; }; /// Imports serialized Swift modules into an ASTContext. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 0acc541f5eff9..91765c5271b33 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -19,8 +19,8 @@ #include "ClangTypeConverter.h" #include "ForeignRepresentationInfo.h" #include "SubstitutionMapStorage.h" -#include "swift/AST/ASTContextGlobalCache.h" #include "swift/ABI/MetadataValues.h" +#include "swift/AST/ASTContextGlobalCache.h" #include "swift/AST/AvailabilityContextStorage.h" #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/ConcreteDeclRef.h" @@ -67,6 +67,8 @@ #include "swift/Basic/Statistic.h" #include "swift/Basic/StringExtras.h" #include "swift/ClangImporter/ClangModule.h" +#include "swift/Frontend/ModuleInterfaceLoader.h" +#include "swift/Serialization/SerializedModuleLoader.h" #include "swift/Strings.h" #include "swift/Subsystems.h" #include "swift/SymbolGraphGen/SymbolGraphOptions.h" @@ -445,6 +447,9 @@ struct ASTContext::Implementation { /// Singleton used to cache the import graph. swift::namelookup::ImportCache TheImportCache; + /// The module loader used to load explicit Swift modules. + SerializedModuleLoaderBase *TheExplicitSwiftModuleLoader = nullptr; + /// The module loader used to load Clang modules. ClangModuleLoader *TheClangModuleLoader = nullptr; @@ -2159,14 +2164,23 @@ void ASTContext::addSearchPath(StringRef searchPath, bool isFramework, clangLoader->addSearchPath(searchPath, isFramework, isSystem); } +void ASTContext::addExplicitModulePath(StringRef name, std::string path) { + if (getImpl().TheExplicitSwiftModuleLoader) + getImpl().TheExplicitSwiftModuleLoader->addExplicitModulePath(name, path); +} + void ASTContext::addModuleLoader(std::unique_ptr loader, - bool IsClang, bool IsDwarf, bool IsInterface) { + bool IsClang, bool IsDwarf, bool IsInterface, + bool IsExplicit) { if (IsClang && !IsDwarf && !getImpl().TheClangModuleLoader) getImpl().TheClangModuleLoader = static_cast(loader.get()); if (IsClang && IsDwarf && !getImpl().TheDWARFModuleLoader) getImpl().TheDWARFModuleLoader = static_cast(loader.get()); + if (IsExplicit && !getImpl().TheExplicitSwiftModuleLoader) + getImpl().TheExplicitSwiftModuleLoader = + static_cast(loader.get()); getImpl().ModuleLoaders.push_back(std::move(loader)); } diff --git a/lib/DependencyScan/ScanDependencies.cpp b/lib/DependencyScan/ScanDependencies.cpp index 934076ae9961f..ad22f0cbb089b 100644 --- a/lib/DependencyScan/ScanDependencies.cpp +++ b/lib/DependencyScan/ScanDependencies.cpp @@ -1497,7 +1497,6 @@ bool swift::dependencies::scanDependencies(CompilerInstance &CI) { ctx.Allocate(); ModuleDependenciesCache cache(CI.getMainModule()->getNameStr().str(), CI.getInvocation().getModuleScanningHash()); - if (service->setupCachingDependencyScanningService(CI)) return true; diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 89e0e7238ffeb..7e196020dfe4c 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -870,7 +870,7 @@ bool CompilerInstance::setUpModuleLoaders() { // Install an explicit module loader if it was created earlier. if (ESML) { this->DefaultSerializedLoader = ESML.get(); - Context->addModuleLoader(std::move(ESML)); + Context->addModuleLoader(std::move(ESML), false, false, false, true); } if (!ExplicitModuleBuild) { diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index ec3a53d8ec57f..1f5343d664380 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -2304,8 +2304,8 @@ bool ExplicitSwiftModuleLoader::findModule( std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool IsCanImportLookup, bool isTestableDependencyLookup, - bool &IsFramework, bool &IsSystemModule) { + std::string *cacheKey, bool IsCanImportLookup, + bool isTestableDependencyLookup, bool &IsFramework, bool &IsSystemModule) { // Find a module with an actual, physical name on disk, in case // -module-alias is used (otherwise same). // @@ -2473,6 +2473,12 @@ ExplicitSwiftModuleLoader::create(ASTContext &ctx, return result; } +void ExplicitSwiftModuleLoader::addExplicitModulePath(StringRef name, + std::string path) { + ExplicitSwiftModuleInputInfo entry(path, {}, {}, {}); + Impl.ExplicitModuleMap.try_emplace(name, std::move(entry)); +} + struct ExplicitCASModuleLoader::Implementation { ASTContext &Ctx; llvm::BumpPtrAllocator Allocator; @@ -2660,8 +2666,8 @@ bool ExplicitCASModuleLoader::findModule( std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool IsCanImportLookup, bool IsTestableDependencyLookup, - bool &IsFramework, bool &IsSystemModule) { + std::string *CacheKey, bool IsCanImportLookup, + bool IsTestableDependencyLookup, bool &IsFramework, bool &IsSystemModule) { // Find a module with an actual, physical name on disk, in case // -module-alias is used (otherwise same). // @@ -2681,6 +2687,8 @@ bool ExplicitCASModuleLoader::findModule( // Set IsFramework bit according to the moduleInfo IsFramework = moduleInfo.isFramework; IsSystemModule = moduleInfo.isSystem; + if (CacheKey && moduleInfo.moduleCacheKey) + *CacheKey = *moduleInfo.moduleCacheKey; // Fallback check for module cache key passed on command-line as module path. std::string moduleCASID = moduleInfo.moduleCacheKey diff --git a/lib/Serialization/ModuleFile.cpp b/lib/Serialization/ModuleFile.cpp index e08c44ec0cd0f..2f8a847cf5bbb 100644 --- a/lib/Serialization/ModuleFile.cpp +++ b/lib/Serialization/ModuleFile.cpp @@ -210,6 +210,10 @@ ModuleFile::loadDependenciesForFileContext(const FileUnit *file, auto importPath = builder.copyTo(ctx); auto modulePath = importPath.getModulePath(dependency.isScoped()); auto accessPath = importPath.getAccessPath(dependency.isScoped()); + if (!getContext().LangOpts.DisableDeserializationOfExplicitPaths && + !dependency.Core.BinaryModulePath.empty()) + ctx.addExplicitModulePath(modulePath.front().Item.str(), + dependency.Core.BinaryModulePath.str()); auto module = getModule(modulePath, /*allowLoading*/true); if (!module || module->failedToLoad()) { diff --git a/lib/Serialization/ModuleFileSharedCore.cpp b/lib/Serialization/ModuleFileSharedCore.cpp index 98dca3cfdf402..77ca9daa48c90 100644 --- a/lib/Serialization/ModuleFileSharedCore.cpp +++ b/lib/Serialization/ModuleFileSharedCore.cpp @@ -1561,9 +1561,9 @@ ModuleFileSharedCore::ModuleFileSharedCore( unsigned rawImportControl; bool scoped; bool hasSPI; - input_block::ImportedModuleLayout::readRecord(scratch, - rawImportControl, - scoped, hasSPI); + bool hasPath; + input_block::ImportedModuleLayout::readRecord( + scratch, rawImportControl, scoped, hasSPI, hasPath); auto importKind = getActualImportControl(rawImportControl); if (!importKind) { // We don't know how to import this dependency. @@ -1580,14 +1580,25 @@ ModuleFileSharedCore::ModuleFileSharedCore( unsigned recordID = fatalIfUnexpected( cursor.readRecord(entry.ID, scratch, &spiBlob)); assert(recordID == input_block::IMPORTED_MODULE_SPIS); - input_block::ImportedModuleLayoutSPI::readRecord(scratch); - (void) recordID; - } else { - spiBlob = StringRef(); + input_block::ImportedModuleSPILayout::readRecord(scratch); + (void)recordID; + } + + StringRef pathBlob; + if (hasPath) { + scratch.clear(); + + llvm::BitstreamEntry entry = + fatalIfUnexpected(cursor.advance(AF_DontPopBlockAtEnd)); + unsigned recordID = fatalIfUnexpected( + cursor.readRecord(entry.ID, scratch, &pathBlob)); + assert(recordID == input_block::IMPORTED_MODULE_PATH); + input_block::ImportedModulePathLayout::readRecord(scratch); + (void)recordID; } Dependencies.push_back( - {blobData, spiBlob, importKind.value(), scoped}); + {blobData, spiBlob, pathBlob, importKind.value(), scoped}); break; } case input_block::LINK_LIBRARY: { diff --git a/lib/Serialization/ModuleFileSharedCore.h b/lib/Serialization/ModuleFileSharedCore.h index ca0a132e82bb0..32c213d8ac853 100644 --- a/lib/Serialization/ModuleFileSharedCore.h +++ b/lib/Serialization/ModuleFileSharedCore.h @@ -123,6 +123,7 @@ class ModuleFileSharedCore { public: const StringRef RawPath; const StringRef RawSPIs; + const StringRef BinaryModulePath; private: using ImportFilterKind = ModuleDecl::ImportFilterKind; @@ -137,27 +138,26 @@ class ModuleFileSharedCore { return static_cast(1 << RawImportControl); } - Dependency(StringRef path, StringRef spiGroups, bool isHeader, - ImportFilterKind importControl, bool isScoped) - : RawPath(path), - RawSPIs(spiGroups), + Dependency(StringRef path, StringRef spiGroups, StringRef binaryModulePath, + bool isHeader, ImportFilterKind importControl, bool isScoped) + : RawPath(path), RawSPIs(spiGroups), BinaryModulePath(binaryModulePath), RawImportControl(rawControlFromKind(importControl)), - IsHeader(isHeader), - IsScoped(isScoped) { + IsHeader(isHeader), IsScoped(isScoped) { assert(llvm::popcount(static_cast(importControl)) == 1 && "must be a particular filter option, not a bitset"); assert(getImportControl() == importControl && "not enough bits"); } public: - Dependency(StringRef path, StringRef spiGroups, - ImportFilterKind importControl, bool isScoped) - : Dependency(path, spiGroups, false, importControl, isScoped) {} - - static Dependency forHeader(StringRef headerPath, bool exported) { - auto importControl = - exported ? ImportFilterKind::Exported : ImportFilterKind::Default; - return Dependency(headerPath, StringRef(), true, importControl, false); + Dependency(StringRef path, StringRef spiGroups, StringRef binaryModulePath, + ImportFilterKind importControl, bool isScoped) + : Dependency(path, spiGroups, binaryModulePath, false, importControl, + isScoped) {} + + static Dependency forHeader(StringRef headerPath, bool exported) { + auto importControl = + exported ? ImportFilterKind::Exported : ImportFilterKind::Default; + return Dependency(headerPath, {}, {}, true, importControl, false); } bool isExported() const { diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index b2d9408be5655..fcd082d0c3b29 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 968; // @inout result convention +const uint16_t SWIFTMODULE_VERSION_MINOR = 969; // Module import paths /// A standard hash seed used for all string hashes in a serialized module. /// @@ -1131,6 +1131,7 @@ namespace input_block { DEPENDENCY_DIRECTORY, MODULE_INTERFACE_PATH, IMPORTED_MODULE_SPIS, + IMPORTED_MODULE_PATH, EXTERNAL_MACRO, }; @@ -1139,16 +1140,22 @@ namespace input_block { ImportControlField, // import kind BCFixed<1>, // scoped? BCFixed<1>, // has spis? - BCBlob // module name, with submodule path pieces separated by \0s. - // If the 'scoped' flag is set, the final path piece is an access - // path within the module. + BCFixed<1>, // has path? + BCBlob // module name, with submodule path pieces separated by \0s. If the + // 'scoped' flag is set, the final path piece is an access path + // within the module. >; - using ImportedModuleLayoutSPI = BCRecordLayout< + using ImportedModuleSPILayout = BCRecordLayout< IMPORTED_MODULE_SPIS, BCBlob // SPI names, separated by \0s >; + using ImportedModulePathLayout = BCRecordLayout< + IMPORTED_MODULE_PATH, + BCBlob // Module file path + >; + using ExternalMacroLayout = BCRecordLayout< EXTERNAL_MACRO, ImportControlField, // import kind diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 0ccab47c9e0d7..be73cfa600ddf 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -884,6 +884,7 @@ void Serializer::writeBlockInfoBlock() { BLOCK_RECORD(input_block, DEPENDENCY_DIRECTORY); BLOCK_RECORD(input_block, MODULE_INTERFACE_PATH); BLOCK_RECORD(input_block, IMPORTED_MODULE_SPIS); + BLOCK_RECORD(input_block, IMPORTED_MODULE_PATH); BLOCK_RECORD(input_block, EXTERNAL_MACRO); BLOCK(DECLS_AND_TYPES_BLOCK); @@ -1334,7 +1335,8 @@ static ImportSet getImportsAsSet(const ModuleDecl *M, void Serializer::writeInputBlock() { BCBlockRAII restoreBlock(Out, INPUT_BLOCK_ID, 4); input_block::ImportedModuleLayout importedModule(Out); - input_block::ImportedModuleLayoutSPI ImportedModuleSPI(Out); + input_block::ImportedModuleSPILayout ImportedModuleSPI(Out); + input_block::ImportedModulePathLayout ImportedModulePath(Out); input_block::LinkLibraryLayout LinkLibrary(Out); input_block::ImportedHeaderLayout ImportedHeader(Out); input_block::ImportedHeaderContentsLayout ImportedHeaderContents(Out); @@ -1510,9 +1512,17 @@ void Serializer::writeInputBlock() { llvm::SmallSetVector spis; M->lookupImportedSPIGroups(import.importedModule, spis); - importedModule.emit(ScratchRecord, - static_cast(stableImportControl), - !import.accessPath.empty(), !spis.empty(), importPath); + StringRef path; + if (Options.ExplicitModuleBuild && import.importedModule && + !import.importedModule->isNonSwiftModule()) { + path = import.importedModule->getCacheKey(); + if (path.empty()) + path = import.importedModule->getModuleLoadedFilename(); + } + + importedModule.emit( + ScratchRecord, static_cast(stableImportControl), + !import.accessPath.empty(), !spis.empty(), !path.empty(), importPath); if (!spis.empty()) { SmallString<64> out; @@ -1522,6 +1532,9 @@ void Serializer::writeInputBlock() { [&outStream] { outStream << StringRef("\0", 1); }); ImportedModuleSPI.emit(ScratchRecord, out); } + + if (!path.empty()) + ImportedModulePath.emit(ScratchRecord, path); } if (!Options.ModuleLinkName.empty()) diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index bcedbc8d0471e..31753a574d8e6 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -732,8 +732,8 @@ bool SerializedModuleLoaderBase::findModule( std::unique_ptr *moduleBuffer, std::unique_ptr *moduleDocBuffer, std::unique_ptr *moduleSourceInfoBuffer, - bool isCanImportLookup, bool isTestableDependencyLookup, - bool &isFramework, bool &isSystemModule) { + std::string *cacheKey, bool isCanImportLookup, + bool isTestableDependencyLookup, bool &isFramework, bool &isSystemModule) { // Find a module with an actual, physical name on disk, in case // -module-alias is used (otherwise same). // @@ -1508,12 +1508,13 @@ bool SerializedModuleLoaderBase::canImportModule( bool isSystemModule = false; auto mID = path[0]; - auto found = findModule( - mID, /*moduleInterfacePath=*/nullptr, &moduleInterfaceSourcePath, - &moduleInputBuffer, - /*moduleDocBuffer=*/nullptr, /*moduleSourceInfoBuffer=*/nullptr, - /*isCanImportLookup=*/true, isTestableDependencyLookup, - isFramework, isSystemModule); + auto found = + findModule(mID, /*moduleInterfacePath=*/nullptr, + &moduleInterfaceSourcePath, &moduleInputBuffer, + /*moduleDocBuffer=*/nullptr, + /*moduleSourceInfoBuffer=*/nullptr, /*cacheKey=*/nullptr, + /*isCanImportLookup=*/true, isTestableDependencyLookup, + isFramework, isSystemModule); // If we cannot find the module, don't continue. if (!found) return false; @@ -1597,6 +1598,7 @@ SerializedModuleLoaderBase::loadModule(SourceLoc importLoc, bool isFramework = false; bool isSystemModule = false; + std::string cacheKey; llvm::SmallString<256> moduleInterfacePath; llvm::SmallString<256> moduleInterfaceSourcePath; std::unique_ptr moduleInputBuffer; @@ -1606,10 +1608,9 @@ SerializedModuleLoaderBase::loadModule(SourceLoc importLoc, // Look on disk. if (!findModule(moduleID, &moduleInterfacePath, &moduleInterfaceSourcePath, &moduleInputBuffer, &moduleDocInputBuffer, - &moduleSourceInfoInputBuffer, + &moduleSourceInfoInputBuffer, &cacheKey, /*isCanImportLookup=*/false, - /*isTestableDependencyLookup=*/false, - isFramework, + /*isTestableDependencyLookup=*/false, isFramework, isSystemModule)) { return nullptr; } @@ -1635,6 +1636,7 @@ SerializedModuleLoaderBase::loadModule(SourceLoc importLoc, } M->setHasResolvedImports(); }); + M->setCacheKey(cacheKey); if (dependencyTracker && file) { auto DepPath = file->getFilename(); diff --git a/test/ScanDependencies/optional_transitive_dep_load_fail.swift b/test/ScanDependencies/optional_transitive_dep_load_fail.swift index 6b5ccbb2df19a..698ae416944e9 100644 --- a/test/ScanDependencies/optional_transitive_dep_load_fail.swift +++ b/test/ScanDependencies/optional_transitive_dep_load_fail.swift @@ -37,7 +37,7 @@ // Step 1: build Foo Swift module // RUN: %target-swift-frontend -emit-module %t/Foo.swift -emit-module-path %t/Foo.swiftmodule/%target-swiftmodule-name -module-name Foo -emit-module-interface-path %t/Foo.swiftmodule/%target-swiftinterface-name -enable-library-evolution -I %S/Inputs/CHeaders -I %S/Inputs/Swift -enable-testing -swift-version 5 -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -// Step 2: scan dependencies and ensure the transitive dependency on "A" is misssing +// Step 2: scan dependencies and ensure the transitive dependency on "A" is missing // RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -I %t -sdk %t -prebuilt-module-cache-path %t/clang-module-cache // RUN: %validate-json %t/deps.json | %FileCheck -check-prefix CHECK_SCAN %s // CHECK_SCAN-NOT: "swift": "A" diff --git a/test/Serialization/Inputs/a.swift b/test/Serialization/Inputs/a.swift new file mode 100644 index 0000000000000..2028afdf91aa9 --- /dev/null +++ b/test/Serialization/Inputs/a.swift @@ -0,0 +1 @@ +@_exported import B diff --git a/test/Serialization/external_macros.swift b/test/Serialization/external_macros.swift index a497e1cafa1db..27b1594aea762 100644 --- a/test/Serialization/external_macros.swift +++ b/test/Serialization/external_macros.swift @@ -12,15 +12,15 @@ // RUN: -swift-version 5 -external-plugin-path %t#%swift-plugin-server // RUN: llvm-bcanalyzer -dump %t/Test.swiftmodule | %FileCheck %s -// CHECK-COUNT-1: blob data = 'MacroOne' -// CHECK-COUNT-1: blob data = 'MacroTwo' +// CHECK-COUNT-1: blob data = 'MacroOne' +// CHECK-COUNT-1: blob data = 'MacroTwo' // RUN: %target-swift-frontend -emit-module %t/test2.swift -module-name Test2 -o %t/Test2.swiftmodule \ // RUN: -swift-version 5 -external-plugin-path %t#%swift-plugin-server -package-name Test // RUN: llvm-bcanalyzer -dump %t/Test2.swiftmodule | %FileCheck %s --check-prefix CHECK2 -// CHECK2-COUNT-1: blob data = 'MacroOne' -// CHECK2-COUNT-1: blob data = 'MacroTwo' +// CHECK2-COUNT-1: blob data = 'MacroOne' +// CHECK2-COUNT-1: blob data = 'MacroTwo' //--- macro-1.swift import SwiftSyntax diff --git a/test/Serialization/module-dependencies.swift b/test/Serialization/module-dependencies.swift new file mode 100644 index 0000000000000..cc1d0e7de29e6 --- /dev/null +++ b/test/Serialization/module-dependencies.swift @@ -0,0 +1,9 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir %t/a %t/b +// RUN: %target-swift-frontend -emit-module -o %t/b/B.swiftmodule %S/../Inputs/empty.swift -disable-implicit-swift-modules -parse-stdlib +//-no-serialize-debugging-options +// RUN: %target-swift-frontend -emit-module -o %t/a/A.swiftmodule %S/Inputs/a.swift -swift-module-file=B=%t/b/B.swiftmodule -disable-implicit-swift-modules -parse-stdlib + +// Not passing in path to b/B.swiftmodule -- it should be found in the INPUT block. +// RUN: %target-swift-frontend -emit-module -o %t/Library.swiftmodule %s -swift-module-file=A=%t/a/A.swiftmodule -disable-implicit-swift-modules -parse-stdlib +import A