diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index dc11457bdc837..3739d7465eaf1 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -20,6 +20,7 @@ #include "swift/AST/Import.h" #include "swift/AST/LinkLibrary.h" +#include "swift/Basic/Assertions.h" #include "swift/Basic/CXXStdlibKind.h" #include "swift/Basic/LLVM.h" #include "swift/Serialization/Validation.h" @@ -212,6 +213,11 @@ class ModuleDependencyInfoStorageBase { /// The macro dependencies. std::map macroDependencies; + /// A list of Clang modules that are visible to this Swift module. This + /// includes both direct Clang modules as well as transitive Clang + /// module dependencies when they are exported + llvm::StringSet<> visibleClangModules; + /// ModuleDependencyInfo is finalized (with all transitive dependencies /// and inputs). bool finalized; @@ -816,7 +822,17 @@ class ModuleDependencyInfo { cast(storage.get())->CASFileSystemRootID = rootID; else - llvm_unreachable("Unexpected type"); + llvm_unreachable("Unexpected module dependency kind"); + } + + llvm::StringSet<> &getVisibleClangModules() const { + return storage->visibleClangModules; + } + + void + addVisibleClangModules(const std::vector &moduleNames) const { + storage->visibleClangModules.insert(moduleNames.begin(), + moduleNames.end()); } /// Whether explicit input paths of all the module dependencies @@ -1057,6 +1073,9 @@ class ModuleDependenciesCache { /// Query all cross-import overlay dependencies llvm::ArrayRef getCrossImportOverlayDependencies(const ModuleDependencyID &moduleID) const; + /// Query all visible Clang modules for a given Swift dependency + llvm::StringSet<>& + getVisibleClangModules(ModuleDependencyID moduleID) const; /// Look for module dependencies for a module with the given ID /// @@ -1087,9 +1106,9 @@ class ModuleDependenciesCache { void recordDependency(StringRef moduleName, ModuleDependencyInfo dependencies); - /// Record dependencies for the given module collection. - void recordDependencies(ModuleDependencyVector moduleDependencies, - DiagnosticEngine &diags); + /// Record dependencies for the given collection of Clang modules. + void recordClangDependencies(ModuleDependencyVector moduleDependencies, + DiagnosticEngine &diags); /// Update stored dependencies for the given module. void updateDependency(ModuleDependencyID moduleID, @@ -1122,6 +1141,10 @@ class ModuleDependenciesCache { void setCrossImportOverlayDependencies(ModuleDependencyID moduleID, const ArrayRef dependencyIDs); + /// Add to this module's set of visible Clang modules + void + addVisibleClangModules(ModuleDependencyID moduleID, + const std::vector &moduleNames); StringRef getMainModuleName() const { return mainScanModuleName; } diff --git a/include/swift/DependencyScan/ModuleDependencyScanner.h b/include/swift/DependencyScan/ModuleDependencyScanner.h index 6d64b53c68876..6bc8a4ddc3c59 100644 --- a/include/swift/DependencyScan/ModuleDependencyScanner.h +++ b/include/swift/DependencyScan/ModuleDependencyScanner.h @@ -40,7 +40,7 @@ class ModuleDependencyScanningWorker { private: /// Retrieve the module dependencies for the Clang module with the given name. - ModuleDependencyVector scanFilesystemForClangModuleDependency( + ClangModuleScannerQueryResult scanFilesystemForClangModuleDependency( Identifier moduleName, const llvm::DenseSet &alreadySeenModules); @@ -72,6 +72,7 @@ class ModuleDependencyScanningWorker { ModuleDependencyIDSetVector &headerClangModuleDependencies, std::vector &headerFileInputs, std::vector &bridgingHeaderCommandLine, + std::vector &visibleClangModules, std::optional &includeTreeID); diff --git a/include/swift/Serialization/ScanningLoaders.h b/include/swift/Serialization/ScanningLoaders.h index 2ae4a5d01576f..f80c80c0fe4cf 100644 --- a/include/swift/Serialization/ScanningLoaders.h +++ b/include/swift/Serialization/ScanningLoaders.h @@ -40,6 +40,18 @@ struct SwiftModuleScannerQueryResult { std::vector incompatibleCandidates; }; +/// Result of looking up a Clang module on the current filesystem +/// search paths. +struct ClangModuleScannerQueryResult { + ClangModuleScannerQueryResult(const ModuleDependencyVector &dependencyModuleGraph, + const std::vector &visibleModuleIdentifiers) + : foundDependencyModuleGraph(dependencyModuleGraph), + visibleModuleIdentifiers(visibleModuleIdentifiers) {} + + ModuleDependencyVector foundDependencyModuleGraph; + std::vector visibleModuleIdentifiers; +}; + /// A module "loader" that looks for .swiftinterface and .swiftmodule files /// for the purpose of determining dependencies, but does not attempt to /// load the module files. diff --git a/lib/AST/ModuleDependencies.cpp b/lib/AST/ModuleDependencies.cpp index e473a0734dcbe..ae2ba45e722af 100644 --- a/lib/AST/ModuleDependencies.cpp +++ b/lib/AST/ModuleDependencies.cpp @@ -778,65 +778,62 @@ void ModuleDependenciesCache::recordDependency( map.insert({moduleName, dependency}); } -void ModuleDependenciesCache::recordDependencies( +void ModuleDependenciesCache::recordClangDependencies( ModuleDependencyVector dependencies, DiagnosticEngine &diags) { for (const auto &dep : dependencies) { + ASSERT(dep.first.Kind == ModuleDependencyKind::Clang); + auto newClangModuleDetails = dep.second.getAsClangModule(); if (hasDependency(dep.first)) { - if (dep.first.Kind == ModuleDependencyKind::Clang) { - auto priorClangModuleDetails = - findKnownDependency(dep.first).getAsClangModule(); - auto newClangModuleDetails = dep.second.getAsClangModule(); - auto priorContextHash = priorClangModuleDetails->contextHash; - auto newContextHash = newClangModuleDetails->contextHash; - if (priorContextHash != newContextHash) { - // This situation means that within the same scanning action, Clang - // Dependency Scanner has produced two different variants of the same - // module. This is not supposed to happen, but we are currently - // hunting down the rare cases where it does, seemingly due to - // differences in Clang Scanner direct by-name queries and transitive - // header lookup queries. - // - // Emit a failure diagnostic here that is hopefully more actionable - // for the time being. - diags.diagnose(SourceLoc(), diag::dependency_scan_unexpected_variant, - dep.first.ModuleName); - diags.diagnose( - SourceLoc(), - diag::dependency_scan_unexpected_variant_context_hash_note, - priorContextHash, newContextHash); - diags.diagnose( - SourceLoc(), - diag::dependency_scan_unexpected_variant_module_map_note, - priorClangModuleDetails->moduleMapFile, - newClangModuleDetails->moduleMapFile); - - auto diagnoseExtraCommandLineFlags = - [&diags](const ClangModuleDependencyStorage *checkModuleDetails, - const ClangModuleDependencyStorage *baseModuleDetails, - bool isNewlyDiscovered) -> void { - std::unordered_set baseCommandLineSet( - baseModuleDetails->buildCommandLine.begin(), - baseModuleDetails->buildCommandLine.end()); - for (const auto &checkArg : checkModuleDetails->buildCommandLine) - if (baseCommandLineSet.find(checkArg) == baseCommandLineSet.end()) - diags.diagnose( - SourceLoc(), - diag::dependency_scan_unexpected_variant_extra_arg_note, - isNewlyDiscovered, checkArg); - }; - diagnoseExtraCommandLineFlags(priorClangModuleDetails, - newClangModuleDetails, true); - diagnoseExtraCommandLineFlags(newClangModuleDetails, - priorClangModuleDetails, false); - } + auto priorClangModuleDetails = + findKnownDependency(dep.first).getAsClangModule(); + DEBUG_ASSERT(priorClangModuleDetails && newClangModuleDetails); + auto priorContextHash = priorClangModuleDetails->contextHash; + auto newContextHash = newClangModuleDetails->contextHash; + if (priorContextHash != newContextHash) { + // This situation means that within the same scanning action, Clang + // Dependency Scanner has produced two different variants of the same + // module. This is not supposed to happen, but we are currently + // hunting down the rare cases where it does, seemingly due to + // differences in Clang Scanner direct by-name queries and transitive + // header lookup queries. + // + // Emit a failure diagnostic here that is hopefully more actionable + // for the time being. + diags.diagnose(SourceLoc(), diag::dependency_scan_unexpected_variant, + dep.first.ModuleName); + diags.diagnose( + SourceLoc(), + diag::dependency_scan_unexpected_variant_context_hash_note, + priorContextHash, newContextHash); + diags.diagnose( + SourceLoc(), + diag::dependency_scan_unexpected_variant_module_map_note, + priorClangModuleDetails->moduleMapFile, + newClangModuleDetails->moduleMapFile); + + auto diagnoseExtraCommandLineFlags = + [&diags](const ClangModuleDependencyStorage *checkModuleDetails, + const ClangModuleDependencyStorage *baseModuleDetails, + bool isNewlyDiscovered) -> void { + std::unordered_set baseCommandLineSet( + baseModuleDetails->buildCommandLine.begin(), + baseModuleDetails->buildCommandLine.end()); + for (const auto &checkArg : checkModuleDetails->buildCommandLine) + if (baseCommandLineSet.find(checkArg) == baseCommandLineSet.end()) + diags.diagnose( + SourceLoc(), + diag::dependency_scan_unexpected_variant_extra_arg_note, + isNewlyDiscovered, checkArg); + }; + diagnoseExtraCommandLineFlags(priorClangModuleDetails, + newClangModuleDetails, true); + diagnoseExtraCommandLineFlags(newClangModuleDetails, + priorClangModuleDetails, false); } - } else + } else { recordDependency(dep.first.ModuleName, dep.second); - - if (dep.first.Kind == ModuleDependencyKind::Clang) { - auto clangModuleDetails = dep.second.getAsClangModule(); addSeenClangModule(clang::tooling::dependencies::ModuleID{ - dep.first.ModuleName, clangModuleDetails->contextHash}); + dep.first.ModuleName, newClangModuleDetails->contextHash}); } } } @@ -918,6 +915,24 @@ ModuleDependenciesCache::setCrossImportOverlayDependencies(ModuleDependencyID mo updateDependency(moduleID, updatedDependencyInfo); } +void +ModuleDependenciesCache::addVisibleClangModules(ModuleDependencyID moduleID, + const std::vector &moduleNames) { + if (moduleNames.empty()) + return; + auto dependencyInfo = findKnownDependency(moduleID); + auto updatedDependencyInfo = dependencyInfo; + updatedDependencyInfo.addVisibleClangModules(moduleNames); + updateDependency(moduleID, updatedDependencyInfo); +} + +llvm::StringSet<> &ModuleDependenciesCache::getVisibleClangModules(ModuleDependencyID moduleID) const { + ASSERT(moduleID.Kind == ModuleDependencyKind::SwiftSource || + moduleID.Kind == ModuleDependencyKind::SwiftInterface || + moduleID.Kind == ModuleDependencyKind::SwiftBinary); + return findKnownDependency(moduleID).getVisibleClangModules(); +} + ModuleDependencyIDSetVector ModuleDependenciesCache::getAllDependencies(const ModuleDependencyID &moduleID) const { const auto &moduleInfo = findKnownDependency(moduleID); diff --git a/lib/DependencyScan/ModuleDependencyScanner.cpp b/lib/DependencyScan/ModuleDependencyScanner.cpp index cccfc249694bb..3617a73294e18 100644 --- a/lib/DependencyScan/ModuleDependencyScanner.cpp +++ b/lib/DependencyScan/ModuleDependencyScanner.cpp @@ -305,7 +305,7 @@ ModuleDependencyScanningWorker::scanFilesystemForSwiftModuleDependency( isTestableImport); } -ModuleDependencyVector +ClangModuleScannerQueryResult ModuleDependencyScanningWorker::scanFilesystemForClangModuleDependency( Identifier moduleName, const llvm::DenseSet @@ -332,13 +332,15 @@ ModuleDependencyScanningWorker::scanFilesystemForClangModuleDependency( "' not found") == std::string::npos) workerASTContext->Diags.diagnose( SourceLoc(), diag::clang_dependency_scan_error, errorStr); - return {}; + return ClangModuleScannerQueryResult({}, {}); } - return ClangImporter::bridgeClangModuleDependencies( - *workerASTContext, clangScanningTool, *clangModuleDependencies, - lookupModuleOutput, - [&](StringRef path) { return remapPath(PrefixMapper, path); }); + return ClangModuleScannerQueryResult( + ClangImporter::bridgeClangModuleDependencies( + *workerASTContext, clangScanningTool, + clangModuleDependencies->ModuleGraph, lookupModuleOutput, + [&](StringRef path) { return remapPath(PrefixMapper, path); }), + clangModuleDependencies->VisibleModules); } bool ModuleDependencyScanningWorker::scanHeaderDependenciesOfSwiftModule( @@ -349,6 +351,7 @@ bool ModuleDependencyScanningWorker::scanHeaderDependenciesOfSwiftModule( ModuleDependencyIDSetVector &headerClangModuleDependencies, std::vector &headerFileInputs, std::vector &bridgingHeaderCommandLine, + std::vector &visibleClangModules, std::optional &includeTreeID) { // Scan the specified textual header file and collect its dependencies auto scanHeaderDependencies = [&]() @@ -374,7 +377,8 @@ bool ModuleDependencyScanningWorker::scanHeaderDependenciesOfSwiftModule( auto bridgedDeps = ClangImporter::bridgeClangModuleDependencies( ctx, clangScanningTool, dependencies->ModuleGraph, lookupModuleOutput, [this](StringRef path) { return remapPath(PrefixMapper, path); }); - cache.recordDependencies(bridgedDeps, ctx.Diags); + cache.recordClangDependencies(bridgedDeps, ctx.Diags); + visibleClangModules = dependencies->VisibleModules; llvm::copy(dependencies->FileDeps, std::back_inserter(headerFileInputs)); auto bridgedDependencyIDs = @@ -605,25 +609,6 @@ ModuleDependencyScanner::ModuleDependencyScanner( DependencyTracker, CAS, ActionCache, PrefixMapper.get(), Diagnostics)); } -/// Find all of the imported Clang modules starting with the given module name. -static void findAllImportedClangModules(StringRef moduleName, - const ModuleDependenciesCache &cache, - std::vector &allModules, - llvm::StringSet<> &knownModules) { - if (!knownModules.insert(moduleName).second) - return; - allModules.push_back(moduleName.str()); - auto moduleID = - ModuleDependencyID{moduleName.str(), ModuleDependencyKind::Clang}; - auto optionalDependencies = cache.findDependency(moduleID); - if (!optionalDependencies.has_value()) - return; - - for (const auto &dep : cache.getClangDependencies(moduleID)) - findAllImportedClangModules(dep.ModuleName, cache, allModules, - knownModules); -} - static std::set collectBinarySwiftDeps(const ModuleDependenciesCache &cache) { std::set binarySwiftModuleDepIDs; @@ -1072,7 +1057,7 @@ void ModuleDependencyScanner::resolveAllClangModuleDependencies( continue; } else { // We need to query the Clang dependency scanner for this module's - // unresolved imports + // non-Swift imports llvm::StringSet<> resolvedImportIdentifiers; for (const auto &resolvedDep : moduleDependencyInfo.getImportedSwiftDependencies()) @@ -1110,47 +1095,25 @@ void ModuleDependencyScanner::resolveAllClangModuleDependencies( } } - // Prepare the module lookup result collection - llvm::StringMap> moduleLookupResult; - for (const auto &unresolvedIdentifier : unresolvedImportIdentifiers) - moduleLookupResult.insert( - std::make_pair(unresolvedIdentifier.getKey(), std::nullopt)); - - // We need a copy of the shared already-seen module set, which will be shared - // amongst all the workers. In `recordDependencies`, each worker will - // contribute its results back to the shared set for future lookups. + // Module lookup result collection + llvm::StringMap moduleLookupResult; const llvm::DenseSet - seenClangModules = cache.getAlreadySeenClangModules(); - std::mutex cacheAccessLock; - auto scanForClangModuleDependency = - [this, &cache, &moduleLookupResult, &cacheAccessLock, - &seenClangModules](Identifier moduleIdentifier) { - auto moduleName = moduleIdentifier.str(); - { - std::lock_guard guard(cacheAccessLock); - if (cache.hasDependency(moduleName, ModuleDependencyKind::Clang)) - return; - } - - auto moduleDependencies = withDependencyScanningWorker( - [&seenClangModules, - moduleIdentifier](ModuleDependencyScanningWorker *ScanningWorker) { - return ScanningWorker->scanFilesystemForClangModuleDependency( - moduleIdentifier, seenClangModules); - }); - - // Update the `moduleLookupResult` and cache all discovered dependencies - // so that subsequent queries do not have to call into the scanner - // if looking for a module that was discovered as a transitive - // dependency in this scan. - { - std::lock_guard guard(cacheAccessLock); - moduleLookupResult.insert_or_assign(moduleName, moduleDependencies); - if (!moduleDependencies.empty()) - cache.recordDependencies(moduleDependencies, - IssueReporter.Diagnostics); - } - }; + seenClangModules = cache.getAlreadySeenClangModules(); + std::mutex resultAccessLock; + auto scanForClangModuleDependency = [this, &moduleLookupResult, + &resultAccessLock, &seenClangModules]( + Identifier moduleIdentifier) { + auto scanResult = withDependencyScanningWorker( + [&seenClangModules, + moduleIdentifier](ModuleDependencyScanningWorker *ScanningWorker) { + return ScanningWorker->scanFilesystemForClangModuleDependency( + moduleIdentifier, seenClangModules); + }); + { + std::lock_guard guard(resultAccessLock); + moduleLookupResult.insert_or_assign(moduleIdentifier.str(), scanResult); + } + }; // Enque asynchronous lookup tasks for (const auto &unresolvedIdentifier : unresolvedImportIdentifiers) @@ -1168,30 +1131,37 @@ void ModuleDependencyScanner::resolveAllClangModuleDependencies( std::vector failedToResolveImports; ModuleDependencyIDSetVector importedClangDependencies; auto recordResolvedClangModuleImport = - [&moduleLookupResult, &importedClangDependencies, + [this, &moduleLookupResult, &importedClangDependencies, &cache, &allDiscoveredClangModules, moduleID, &failedToResolveImports]( const ScannerImportStatementInfo &moduleImport, bool optionalImport) { - auto lookupResult = moduleLookupResult[moduleImport.importIdentifier]; - // The imported module was found in the cache - if (lookupResult == std::nullopt) { - importedClangDependencies.insert( - {moduleImport.importIdentifier, ModuleDependencyKind::Clang}); - } else { - // Cache discovered module dependencies. - if (!lookupResult.value().empty()) { - importedClangDependencies.insert( - {moduleImport.importIdentifier, ModuleDependencyKind::Clang}); + ASSERT(moduleLookupResult.contains(moduleImport.importIdentifier)); + const auto &lookupResult = + moduleLookupResult.at(moduleImport.importIdentifier); + // Cache discovered module dependencies. + if (!lookupResult.foundDependencyModuleGraph.empty() || + !lookupResult.visibleModuleIdentifiers.empty()) { + if (!lookupResult.foundDependencyModuleGraph.empty()) { + cache.recordClangDependencies(lookupResult.foundDependencyModuleGraph, + IssueReporter.Diagnostics); // Add the full transitive dependency set - for (const auto &dep : lookupResult.value()) + for (const auto &dep : lookupResult.foundDependencyModuleGraph) allDiscoveredClangModules.insert(dep.first); - } else if (!optionalImport) { - // Otherwise, we failed to resolve this dependency. We will try - // again using the cache after all other imports have been - // resolved. If that fails too, a scanning failure will be - // diagnosed. - failedToResolveImports.push_back(moduleImport); } + + importedClangDependencies.insert( + {moduleImport.importIdentifier, ModuleDependencyKind::Clang}); + + // Add visible Clang modules for this query to the depending + // Swift module + cache.addVisibleClangModules(moduleID, + lookupResult.visibleModuleIdentifiers); + } else if (!optionalImport) { + // Otherwise, we failed to resolve this dependency. We will try + // again using the cache after all other imports have been + // resolved. If that fails too, a scanning failure will be + // diagnosed. + failedToResolveImports.push_back(moduleImport); } }; @@ -1458,14 +1428,16 @@ void ModuleDependencyScanner::resolveHeaderDependenciesForModule( std::vector headerFileInputs; std::optional includeTreeID; std::vector bridgingHeaderCommandLine; + std::vector visibleClangModules; auto headerScan = ScanningWorker->scanHeaderDependenciesOfSwiftModule( *ScanningWorker->workerASTContext, moduleID, headerPath, sourceBufferRef, cache, headerClangModuleDependencies, - headerFileInputs, bridgingHeaderCommandLine, includeTreeID); + headerFileInputs, bridgingHeaderCommandLine, visibleClangModules, + includeTreeID); if (!headerScan) { // Record direct header Clang dependencies - cache.setHeaderClangDependencies( - moduleID, headerClangModuleDependencies.getArrayRef()); + moduleDependencyInfo.setHeaderClangDependencies( + headerClangModuleDependencies.getArrayRef()); // Record include Tree ID if (includeTreeID) moduleDependencyInfo.addBridgingHeaderIncludeTree(*includeTreeID); @@ -1474,6 +1446,8 @@ void ModuleDependencyScanner::resolveHeaderDependenciesForModule( moduleDependencyInfo.updateBridgingHeaderCommandLine( bridgingHeaderCommandLine); moduleDependencyInfo.setHeaderSourceFiles(headerFileInputs); + // Update the set of visible Clang modules + moduleDependencyInfo.addVisibleClangModules(visibleClangModules); // Update the dependency in the cache cache.updateDependency(moduleID, moduleDependencyInfo); } else { @@ -1481,8 +1455,6 @@ void ModuleDependencyScanner::resolveHeaderDependenciesForModule( } return true; }); - cache.setHeaderClangDependencies(moduleID, - headerClangModuleDependencies.getArrayRef()); } void ModuleDependencyScanner::resolveSwiftOverlayDependenciesForModule( @@ -1490,17 +1462,10 @@ void ModuleDependencyScanner::resolveSwiftOverlayDependenciesForModule( ModuleDependencyIDSetVector &swiftOverlayDependencies) { PrettyStackTraceStringAction trace( "Resolving Swift Overlay dependencies of module", moduleID.ModuleName); - std::vector allClangDependencies; - llvm::StringSet<> knownModules; - - // Find all of the discovered Clang modules that this module depends on. - for (const auto &dep : cache.getClangDependencies(moduleID)) - findAllImportedClangModules(dep.ModuleName, cache, allClangDependencies, - knownModules); - + auto visibleClangDependencies = cache.getVisibleClangModules(moduleID); llvm::StringMap swiftOverlayLookupResult; std::mutex lookupResultLock; - + // A scanning task to query a Swift module by-name. If the module already // exists in the cache, do nothing and return. auto scanForSwiftDependency = [this, &cache, &lookupResultLock, @@ -1527,9 +1492,9 @@ void ModuleDependencyScanner::resolveSwiftOverlayDependenciesForModule( }; // Enque asynchronous lookup tasks - for (const auto &clangDep : allClangDependencies) + for (const auto &clangDep : visibleClangDependencies) ScanningThreadPool.async(scanForSwiftDependency, - getModuleImportIdentifier(clangDep)); + getModuleImportIdentifier(clangDep.getKey())); ScanningThreadPool.wait(); // Aggregate both previously-cached and freshly-scanned module results @@ -1556,8 +1521,8 @@ void ModuleDependencyScanner::resolveSwiftOverlayDependenciesForModule( lookupResult.incompatibleCandidates, cache, std::nullopt); } }; - for (const auto &clangDep : allClangDependencies) - recordResult(clangDep); + for (const auto &clangDep : visibleClangDependencies) + recordResult(clangDep.getKey().str()); // C++ Interop requires additional handling bool lookupCxxStdLibOverlay = ScanCompilerInvocation.getLangOptions().EnableCXXInterop; @@ -1578,7 +1543,8 @@ void ModuleDependencyScanner::resolveSwiftOverlayDependenciesForModule( } if (lookupCxxStdLibOverlay) { - for (const auto &clangDepName : allClangDependencies) { + for (const auto &clangDepNameEntry : visibleClangDependencies) { + auto clangDepName = clangDepNameEntry.getKey().str(); // If this Clang module is a part of the C++ stdlib, and we haven't // loaded the overlay for it so far, it is a split libc++ module (e.g. // std_vector). Load the CxxStdlib overlay explicitly. @@ -1756,11 +1722,12 @@ llvm::Error ModuleDependencyScanner::performBridgingHeaderChaining( [&](ModuleDependencyScanningWorker *ScanningWorker) -> llvm::Error { std::vector headerFileInputs; std::vector bridgingHeaderCommandLine; + std::vector visibleClangModules; if (ScanningWorker->scanHeaderDependenciesOfSwiftModule( *ScanningWorker->workerASTContext, rootModuleID, /*headerPath=*/std::nullopt, sourceBuffer->getMemBufferRef(), cache, headerClangModuleDependencies, headerFileInputs, - bridgingHeaderCommandLine, includeTreeID)) + bridgingHeaderCommandLine, visibleClangModules, includeTreeID)) return llvm::createStringError( "failed to scan generated bridging header " + outputPath); @@ -1977,12 +1944,13 @@ ModuleDependencyScanner::attemptToFindResolvingSerializedSearchPath( binaryDepID, swiftResult.foundDependencyInfo->getModuleDefiningPath()); - ModuleDependencyVector clangResult = + ClangModuleScannerQueryResult clangResult = ScanningWorker->scanFilesystemForClangModuleDependency( importIdentifier, {}); - if (!clangResult.empty()) - return std::make_pair( - binaryDepID, clangResult[0].second.getModuleDefiningPath()); + if (!clangResult.foundDependencyModuleGraph.empty()) + return std::make_pair(binaryDepID, + clangResult.foundDependencyModuleGraph[0] + .second.getModuleDefiningPath()); return std::nullopt; }); if (result) diff --git a/lib/DependencyScan/ScanDependencies.cpp b/lib/DependencyScan/ScanDependencies.cpp index d901187cf157c..e78151de2eb71 100644 --- a/lib/DependencyScan/ScanDependencies.cpp +++ b/lib/DependencyScan/ScanDependencies.cpp @@ -1226,8 +1226,16 @@ static bool diagnoseCycle(const CompilerInstance &instance, while (!openSet.empty()) { auto lastOpen = openSet.back(); auto beforeSize = openSet.size(); + +#ifndef NDEBUG + if (!cache.findDependency(lastOpen)) { + llvm::dbgs() << "Missing Dependency Info during cycle diagnosis\n"; + llvm::dbgs() << "mainID: " << mainId.ModuleName << "\n"; + llvm::dbgs() << "lastOpen: " << lastOpen.ModuleName << "\n"; + } +#endif assert(cache.findDependency(lastOpen).has_value() && - "Missing dependency info during cycle diagnosis."); + "Missing dependency info during cycle diagnosis"); for (const auto &depId : cache.getAllDependencies(lastOpen)) { if (closeSet.count(depId)) continue; diff --git a/test/ScanDependencies/module_deps_swift_overlay_only_visible.swift b/test/ScanDependencies/module_deps_swift_overlay_only_visible.swift new file mode 100644 index 0000000000000..eff4edf747f5a --- /dev/null +++ b/test/ScanDependencies/module_deps_swift_overlay_only_visible.swift @@ -0,0 +1,72 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/clang-module-cache) +// RUN: %empty-directory(%t/swiftDeps) +// RUN: %empty-directory(%t/clangDeps) +// RUN: split-file %s %t + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %t/client.swift -o %t/deps.json -I %t/swiftDeps -I %t/clangDeps +// RUN: %validate-json %t/deps.json | %FileCheck %s + +// Ensure Swift module 'E' has a Swift overlay dependency on +// 'G', because Clang module 'G' is a visible dependency of Clang module 'E' +// +// CHECK-LABEL: "modulePath": "{{.*}}E-{{.*}}.swiftmodule" +// CHECK: "swiftOverlayDependencies": [ +// CHECK-NEXT: { +// CHECK-NEXT: "swift": "G" +// CHECK-NEXT: } +// CHECK-NEXT: ] + +// Ensure Swift module 'A' does not have a Swift overlay dependency on +// 'G', because although 'A' depends on Clang module 'G', it does not export it +// and therefore it is not visible +// +// CHECK: "modulePath": "{{.*}}A-{{.*}}.swiftmodule" +// CHECK-NOT: "swiftOverlayDependencies": [ + +//--- swiftDeps/A.swiftinterface +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name A -enable-library-evolution +@_exported import A +public func overlayFuncA() {} + +//--- swiftDeps/E.swiftinterface +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name E -enable-library-evolution +@_exported import E +public func overlayFuncE() {} + +//--- swiftDeps/G.swiftinterface +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name G -enable-library-evolution +@_exported import G +public func overlayFuncG() {} + +//--- clangDeps/module.modulemap +module A { + header "A.h" + // No export * +} +module E { + header "E.h" + export * +} +module G { + header "G.h" + export * +} + +//--- clangDeps/A.h +#include "G.h" +void funcA(void); + +//--- clangDeps/E.h +#include "G.h" +void funcE(void); + +//--- clangDeps/G.h +void funcG(void); + +//--- client.swift +import A +import E diff --git a/test/ScanDependencies/module_deps_swift_overlay_only_visible_cached.swift b/test/ScanDependencies/module_deps_swift_overlay_only_visible_cached.swift new file mode 100644 index 0000000000000..aefe39de769f0 --- /dev/null +++ b/test/ScanDependencies/module_deps_swift_overlay_only_visible_cached.swift @@ -0,0 +1,78 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/clang-module-cache) +// RUN: %empty-directory(%t/swiftDeps) +// RUN: %empty-directory(%t/clangDeps) +// RUN: split-file %s %t + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %t/client.swift -o %t/deps.json -I %t/swiftDeps -I %t/clangDeps +// RUN: %validate-json %t/deps.json | %FileCheck %s + +// Ensure Swift module 'E' has a Swift overlay dependency on +// 'G', because Clang module 'G' is a visible dependency of Clang module 'E' +// +// CHECK-LABEL: "modulePath": "{{.*}}E-{{.*}}.swiftmodule" +// CHECK: "swiftOverlayDependencies": [ +// CHECK-NEXT: { +// CHECK-DAG: "swift": "G" +// CHECK-DAG: "swift": "Y" +// CHECK: } + +// Ensure Swift module 'G' has a Swift overlay dependency on +// 'Y', because Clang module 'Y' is a visible dependency of Clang module 'X' +// +// CHECK-LABEL: "modulePath": "{{.*}}G-{{.*}}.swiftmodule" + +//--- swiftDeps/E.swiftinterface +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name E -enable-library-evolution +@_exported import E +public func overlayFuncE() {} + +//--- swiftDeps/G.swiftinterface +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name G -enable-library-evolution +@_exported import G +import X +public func overlayFuncG() {} + +//--- swiftDeps/Y.swiftinterface +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name Y -enable-library-evolution +@_exported import Y +public func overlayFuncX() {} + +//--- clangDeps/module.modulemap +module E { + header "E.h" + export * +} +module G { + header "G.h" + export * +} +module X { + header "X.h" + export * +} +module Y { + header "Y.h" + export * +} + +//--- clangDeps/E.h +#include "G.h"; +#include "X.h"; +void funcE(void); + +//--- clangDeps/G.h +void funcG(void); + +//--- clangDeps/X.h +#include "Y.h"; +void funcX(void); + +//--- clangDeps/Y.h +void funcY(void); + +//--- client.swift +import E