From cd2890a26c57071e1c5204afb276734dd096f941 Mon Sep 17 00:00:00 2001 From: Steven Wu Date: Wed, 28 Feb 2024 16:35:22 -0800 Subject: [PATCH 1/6] [ScanDependency] Move binary module validation into scanner Improve swift dependency scanner by validating and selecting dependency module into scanner. This provides benefits that: * Build system does not need to schedule interface compilation task if the candidate module is picked, it can just use the candidate module directly. * There is no need for forwarding module in the explicit module build. Since the build system is coordinating the build, there is no need for the forwarding module in the module cache to avoid duplicated work, * This also correctly supports all the module loading modes in the dependency scanner. This is achieved by only adding validate and up-to-date binary module as the candidate module for swift interface module dependency. This allows caching build to construct the correct dependency in the CAS. If there is a candidate module for the interface module, dependency scanner will return a binary module dependency in the dependency graph. The legacy behavior is mostly preserved with a hidden frontend flag `-no-scanner-module-validation`, while the scanner output is mostly interchangeable with new scanner behavior with `prefer-interface` module loading mode except the candidate module will not be returned. rdar://123711823 (cherry picked from commit 0e12f2042e920d0f015fe21838b118e4eb7189ce) --- include/swift/AST/ModuleDependencies.h | 6 + include/swift/AST/SearchPathOptions.h | 19 ++- include/swift/Option/FrontendOptions.td | 6 + .../Serialization/SerializedModuleLoader.h | 10 +- lib/AST/ModuleDependencies.cpp | 7 + .../ModuleDependencyScanner.cpp | 3 +- lib/DependencyScan/ScanDependencies.cpp | 139 ++++++++---------- lib/Frontend/CompilerInvocation.cpp | 28 +++- lib/Frontend/Frontend.cpp | 21 +-- lib/Frontend/ModuleInterfaceLoader.cpp | 44 ++++-- lib/Serialization/ScanningLoaders.cpp | 13 +- lib/Serialization/SerializedModuleLoader.cpp | 6 +- test/CAS/Xcc_args.swift | 5 +- test/CAS/cached_diagnostics.swift | 4 +- test/CAS/cross_import.swift | 2 +- test/CAS/index-store.swift | 2 +- test/CAS/module_deps.swift | 6 +- test/CAS/module_deps_include_tree.swift | 6 +- test/CAS/module_hash.swift | 4 +- test/CAS/plugin_cas.swift | 4 +- test/Frontend/module-alias-scan-deps.swift | 4 +- .../clang-args-transitive-availability.swift | 2 +- .../clang-session-transitive.swift | 2 +- .../extension-transitive-availability.swift | 2 +- .../infer-arch-from-file.swift | 2 +- .../FilterClangSearchPaths.swift | 2 +- test/ScanDependencies/ObjCStrict.swift | 2 +- test/ScanDependencies/batch_module_scan.swift | 2 +- test/ScanDependencies/bin_mod_import.swift | 4 +- .../blocklist-path-pass-down.swift | 2 +- .../bridging_header_dep_module_map.swift | 2 +- .../can_import_placeholder.swift | 4 +- test/ScanDependencies/clang-target.swift | 2 +- .../clang_auxiliary_module_framework.swift | 4 +- .../compiled_swift_modules.swift | 22 ++- test/ScanDependencies/direct_cc1_scan.swift | 4 +- .../eliminate_unused_vfs.swift | 2 +- .../explicit-swift-dependencies.swift | 2 +- .../header_deps_of_binary.swift | 2 +- .../include-sdk-in-command.swift | 2 +- ...module_deps_binary_dep_swift_overlay.swift | 2 +- .../module_deps_cache_reuse.swift | 4 +- .../module_deps_cross_import_overlay.swift | 4 +- ...module_deps_different_paths_no_reuse.swift | 4 +- .../module_deps_external.swift | 4 +- test/ScanDependencies/module_framework.swift | 4 +- test/ScanDependencies/module_load_mode.swift | 21 +++ .../no_cross_import_module_for_self.swift | 2 +- .../no_main_module_cross_import.swift | 2 +- test/ScanDependencies/package_interface.swift | 8 +- test/ScanDependencies/preserve_used_vfs.swift | 2 +- .../private_interface_candidate_module.swift | 2 +- .../separate_bridging_header_deps.swift | 2 +- test/ScanDependencies/testable-import.swift | 6 +- 54 files changed, 282 insertions(+), 190 deletions(-) create mode 100644 test/ScanDependencies/module_load_mode.swift diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index a20807d09c081..c3d6bae702397 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -1097,6 +1097,12 @@ class ModuleDependenciesCache { std::optional findDependency(StringRef moduleName) const; + /// Look for known existing dependencies. + /// + /// \returns the cached result. + const ModuleDependencyInfo & + findKnownDependency(const ModuleDependencyID &moduleID) const; + /// Record dependencies for the given module. void recordDependency(StringRef moduleName, ModuleDependencyInfo dependencies); diff --git a/include/swift/AST/SearchPathOptions.h b/include/swift/AST/SearchPathOptions.h index 14ed706c67a95..dd7debcce1351 100644 --- a/include/swift/AST/SearchPathOptions.h +++ b/include/swift/AST/SearchPathOptions.h @@ -38,6 +38,15 @@ enum class ModuleSearchPathKind { RuntimeLibrary, }; +/// Specifies how to load modules when both a module interface and serialized +/// AST are present, or whether to disallow one format or the other altogether. +enum class ModuleLoadingMode { + PreferInterface, + PreferSerialized, + OnlyInterface, + OnlySerialized +}; + /// A single module search path that can come from different sources, e.g. /// framework search paths, import search path etc. class ModuleSearchPath : public llvm::RefCountedBase { @@ -499,6 +508,12 @@ class SearchPathOptions { /// original form. PathObfuscator DeserializedPathRecoverer; + /// Specify the module loading behavior of the compilation. + ModuleLoadingMode ModuleLoadMode = ModuleLoadingMode::PreferSerialized; + + /// Legacy scanner search behavior. + bool NoScannerModuleValidation = false; + /// Return all module search paths that (non-recursively) contain a file whose /// name is in \p Filenames. SmallVector @@ -546,7 +561,9 @@ class SearchPathOptions { RuntimeResourcePath, hash_combine_range(RuntimeLibraryImportPaths.begin(), RuntimeLibraryImportPaths.end()), - DisableModulesValidateSystemDependencies); + DisableModulesValidateSystemDependencies, + NoScannerModuleValidation, + ModuleLoadMode); } /// Return a hash code of any components from these options that should diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index f30e8b1ede5a1..27098b7cd1a37 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -1337,4 +1337,10 @@ def disable_strict_concurrency_region_based_isolation : Flag<["-"], HelpText<"Disable region based isolation when running with strict concurrency enabled. Only enabled with asserts">, Flags<[HelpHidden]>; +def no_scanner_module_validation: Flag<["-"], "no-scanner-module-validation">, + HelpText<"Do not validate binary modules in scanner and delegate the validation to swift-frontend">; +def module_load_mode: Separate<["-"], "module-load-mode">, + MetaVarName<"only-interface|prefer-interface|prefer-serialized|only-serialized">, + HelpText<"Module loading mode">; + } // end let Flags = [FrontendOption, NoDriverOption, HelpHidden] diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index a51f85d918c8c..5b08a71f9e783 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -16,6 +16,7 @@ #include "swift/AST/FileUnit.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" +#include "swift/AST/SearchPathOptions.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrefixMapper.h" #include "llvm/TargetParser/Triple.h" @@ -28,15 +29,6 @@ namespace file_types { enum ID : uint8_t; } -/// Specifies how to load modules when both a module interface and serialized -/// AST are present, or whether to disallow one format or the other altogether. -enum class ModuleLoadingMode { - PreferInterface, - PreferSerialized, - OnlyInterface, - OnlySerialized -}; - /// How a dependency should be loaded. /// /// \sa getTransitiveLoadingBehavior diff --git a/lib/AST/ModuleDependencies.cpp b/lib/AST/ModuleDependencies.cpp index 0a26a5bac8848..0210d0a8084fa 100644 --- a/lib/AST/ModuleDependencies.cpp +++ b/lib/AST/ModuleDependencies.cpp @@ -739,6 +739,13 @@ ModuleDependenciesCache::findDependency(StringRef moduleName) const { return std::nullopt; } +const ModuleDependencyInfo &ModuleDependenciesCache::findKnownDependency( + const ModuleDependencyID &moduleID) const { + auto dep = findDependency(moduleID); + assert(dep && "dependency unknown"); + return **dep; +} + bool ModuleDependenciesCache::hasDependency(const ModuleDependencyID &moduleID) const { return hasDependency(moduleID.ModuleName, moduleID.Kind); } diff --git a/lib/DependencyScan/ModuleDependencyScanner.cpp b/lib/DependencyScan/ModuleDependencyScanner.cpp index 9c953020f8481..402e6cf651142 100644 --- a/lib/DependencyScan/ModuleDependencyScanner.cpp +++ b/lib/DependencyScan/ModuleDependencyScanner.cpp @@ -185,7 +185,8 @@ ModuleDependencyScanningWorker::ModuleDependencyScanningWorker( ScanASTContext, *static_cast( ScanASTContext.getModuleInterfaceChecker()), - &DependencyTracker, ModuleLoadingMode::OnlyInterface); + &DependencyTracker, + ScanCompilerInvocation.getSearchPathOptions().ModuleLoadMode); } ModuleDependencyVector diff --git a/lib/DependencyScan/ScanDependencies.cpp b/lib/DependencyScan/ScanDependencies.cpp index 841c4d12b257e..f8f6c3c0f082e 100644 --- a/lib/DependencyScan/ScanDependencies.cpp +++ b/lib/DependencyScan/ScanDependencies.cpp @@ -192,7 +192,7 @@ updateModuleCacheKey(ModuleDependencyInfo &depInfo, } static llvm::Error resolveExplicitModuleInputs( - ModuleDependencyID moduleID, const ModuleDependencyInfo &resolvingDepInfo, + ModuleDependencyID moduleID, const std::set &dependencies, ModuleDependenciesCache &cache, CompilerInstance &instance, std::optional> bridgingHeaderDeps) { @@ -200,6 +200,7 @@ static llvm::Error resolveExplicitModuleInputs( if (moduleID.Kind == ModuleDependencyKind::SwiftPlaceholder) return llvm::Error::success(); + auto &resolvingDepInfo = cache.findKnownDependency(moduleID); // If the dependency is already finalized, nothing needs to be done. if (resolvingDepInfo.isFinalized()) return llvm::Error::success(); @@ -242,13 +243,10 @@ static llvm::Error resolveExplicitModuleInputs( std::vector commandLine = resolvingDepInfo.getCommandline(); for (const auto &depModuleID : dependencies) { - const auto optionalDepInfo = - cache.findDependency(depModuleID); - assert(optionalDepInfo.has_value()); - const auto depInfo = optionalDepInfo.value(); + const auto &depInfo = cache.findKnownDependency(depModuleID); switch (depModuleID.Kind) { case swift::ModuleDependencyKind::SwiftInterface: { - auto interfaceDepDetails = depInfo->getAsSwiftInterfaceModule(); + auto interfaceDepDetails = depInfo.getAsSwiftInterfaceModule(); assert(interfaceDepDetails && "Expected Swift Interface dependency."); auto &path = interfaceDepDetails->moduleCacheKey.empty() ? interfaceDepDetails->moduleOutputPath @@ -257,7 +255,7 @@ static llvm::Error resolveExplicitModuleInputs( path); } break; case swift::ModuleDependencyKind::SwiftBinary: { - auto binaryDepDetails = depInfo->getAsSwiftBinaryModule(); + auto binaryDepDetails = depInfo.getAsSwiftBinaryModule(); assert(binaryDepDetails && "Expected Swift Binary Module dependency."); auto &path = binaryDepDetails->moduleCacheKey.empty() ? binaryDepDetails->compiledModulePath @@ -269,24 +267,23 @@ static llvm::Error resolveExplicitModuleInputs( // order to resolve the header's own header include directives. for (const auto &bridgingHeaderDepName : binaryDepDetails->headerModuleDependencies) { - auto optionalBridgingHeaderDepModuleInfo = cache.findDependency( + auto optionalBridgingHeaderDepModuleInfo = cache.findKnownDependency( {bridgingHeaderDepName, ModuleDependencyKind::Clang}); - assert(optionalDepInfo.has_value()); const auto bridgingHeaderDepModuleDetails = - optionalBridgingHeaderDepModuleInfo.value()->getAsClangModule(); + optionalBridgingHeaderDepModuleInfo.getAsClangModule(); commandLine.push_back( "-fmodule-map-file=" + remapPath(bridgingHeaderDepModuleDetails->moduleMapFile)); } } break; case swift::ModuleDependencyKind::SwiftPlaceholder: { - auto placeholderDetails = depInfo->getAsPlaceholderDependencyModule(); + auto placeholderDetails = depInfo.getAsPlaceholderDependencyModule(); assert(placeholderDetails && "Expected Swift Placeholder dependency."); commandLine.push_back("-swift-module-file=" + depModuleID.ModuleName + "=" + placeholderDetails->compiledModulePath); } break; case swift::ModuleDependencyKind::Clang: { - auto clangDepDetails = depInfo->getAsClangModule(); + auto clangDepDetails = depInfo.getAsClangModule(); assert(clangDepDetails && "Expected Clang Module dependency."); if (!resolvingDepInfo.isClangModule()) { commandLine.push_back("-Xcc"); @@ -303,13 +300,13 @@ static llvm::Error resolveExplicitModuleInputs( } // Only need to merge the CASFS from clang importer. - if (auto ID = depInfo->getCASFSRootID()) + if (auto ID = depInfo.getCASFSRootID()) rootIDs.push_back(*ID); - if (auto ID = depInfo->getClangIncludeTree()) + if (auto ID = depInfo.getClangIncludeTree()) includeTrees.push_back(*ID); } break; case swift::ModuleDependencyKind::SwiftSource: { - if (auto E = addBridgingHeaderDeps(*depInfo)) + if (auto E = addBridgingHeaderDeps(depInfo)) return E; break; } @@ -390,9 +387,8 @@ static llvm::Error resolveExplicitModuleInputs( std::vector newCommandLine = dependencyInfoCopy.getBridgingHeaderCommandline(); for (auto bridgingDep : *bridgingHeaderDeps) { - auto dep = cache.findDependency(bridgingDep); - assert(dep && "unknown clang dependency"); - auto *clangDep = (*dep)->getAsClangModule(); + auto &dep = cache.findKnownDependency(bridgingDep); + auto *clangDep = dep.getAsClangModule(); assert(clangDep && "wrong module dependency kind"); if (!clangDep->moduleCacheKey.empty()) { newCommandLine.push_back("-Xcc"); @@ -406,19 +402,11 @@ static llvm::Error resolveExplicitModuleInputs( dependencyInfoCopy.updateBridgingHeaderCommandLine(newCommandLine); } - if (resolvingDepInfo.isClangModule() || - resolvingDepInfo.isSwiftInterfaceModule()) { - // Compute and update module cache key. - auto Key = updateModuleCacheKey(dependencyInfoCopy, cache, CAS); - if (!Key) - return Key.takeError(); - } - - // For binary module, we need to make sure the lookup key is setup here in - // action cache. We just use the CASID of the binary module itself as key. - if (auto *binaryDep = dependencyInfoCopy.getAsSwiftBinaryModule()) { - auto Ref = - CASFS.getObjectRefForFileContent(binaryDep->compiledModulePath); + // Compute and update module cache key. + auto setupBinaryCacheKey = [&](StringRef path) -> llvm::Error { + // For binary module, we need to make sure the lookup key is setup here in + // action cache. We just use the CASID of the binary module itself as key. + auto Ref = CASFS.getObjectRefForFileContent(path); if (!Ref) return llvm::errorCodeToError(Ref.getError()); assert(*Ref && "Binary module should be loaded into CASFS already"); @@ -432,18 +420,36 @@ static llvm::Error resolveExplicitModuleInputs( if (auto E = instance.getActionCache().put(CAS.getID(**Ref), CAS.getID(*Result))) return E; + return llvm::Error::success(); + }; + + if (resolvingDepInfo.isClangModule() || + resolvingDepInfo.isSwiftInterfaceModule()) { + auto Key = updateModuleCacheKey(dependencyInfoCopy, cache, CAS); + if (!Key) + return Key.takeError(); + } else if (auto *binaryDep = dependencyInfoCopy.getAsSwiftBinaryModule()) { + if (auto E = setupBinaryCacheKey(binaryDep->compiledModulePath)) + return E; } } + dependencyInfoCopy.setIsFinalized(true); cache.updateDependency(moduleID, dependencyInfoCopy); return llvm::Error::success(); } -static llvm::Error pruneUnusedVFSOverlays( - ModuleDependencyID moduleID, const ModuleDependencyInfo &resolvingDepInfo, - const std::set &dependencies, - ModuleDependenciesCache &cache, CompilerInstance &instance) { +static llvm::Error +pruneUnusedVFSOverlays(ModuleDependencyID moduleID, + const std::set &dependencies, + ModuleDependenciesCache &cache, + CompilerInstance &instance) { + // Pruning of unused VFS overlay options for Clang dependencies + // is performed by the Clang dependency scanner. + if (moduleID.Kind == ModuleDependencyKind::Clang) + return llvm::Error::success(); + auto isVFSOverlayFlag = [](StringRef arg) { return arg == "-ivfsoverlay" || arg == "-vfsoverlay"; }; @@ -451,11 +457,7 @@ static llvm::Error pruneUnusedVFSOverlays( return arg == "-Xcc"; }; - // Pruning of unused VFS overlay options for Clang dependencies - // is performed by the Clang dependency scanner. - if (!resolvingDepInfo.isSwiftModule()) - return llvm::Error::success(); - + auto &resolvingDepInfo = cache.findKnownDependency(moduleID); // If this Swift dependency contains any VFS overlay paths, // then attempt to prune the ones not used by any of the Clang dependencies. if (!llvm::any_of(resolvingDepInfo.getCommandline(), @@ -469,10 +471,8 @@ static llvm::Error pruneUnusedVFSOverlays( // pruned by the Clang dependency scanner. llvm::StringSet<> usedVFSOverlayPaths; for (const auto &depModuleID : dependencies) { - const auto optionalDepInfo = cache.findDependency(depModuleID); - assert(optionalDepInfo.has_value()); - const auto depInfo = optionalDepInfo.value(); - if (auto clangDepDetails = depInfo->getAsClangModule()) { + const auto &depInfo = cache.findKnownDependency(depModuleID); + if (auto clangDepDetails = depInfo.getAsClangModule()) { const auto &depCommandLine = clangDepDetails->buildCommandLine; // true if the previous argument was the dash-option of an option pair bool getNext = false; @@ -1158,24 +1158,17 @@ generateFullDependencyGraph(const CompilerInstance &instance, for (size_t i = 0; i < allModules.size(); ++i) { const auto &module = allModules[i]; - // Grab the completed module dependencies. - auto moduleDepsQuery = cache.findDependency(module); - if (!moduleDepsQuery) { - llvm::report_fatal_error(Twine("Module Dependency Cache missing module") + - module.ModuleName); - } - - auto moduleDeps = *moduleDepsQuery; + auto &moduleDeps = cache.findKnownDependency(module); // Collect all the required pieces to build a ModuleInfo - auto swiftPlaceholderDeps = moduleDeps->getAsPlaceholderDependencyModule(); - auto swiftTextualDeps = moduleDeps->getAsSwiftInterfaceModule(); - auto swiftSourceDeps = moduleDeps->getAsSwiftSourceModule(); - auto swiftBinaryDeps = moduleDeps->getAsSwiftBinaryModule(); - auto clangDeps = moduleDeps->getAsClangModule(); + auto swiftPlaceholderDeps = moduleDeps.getAsPlaceholderDependencyModule(); + auto swiftTextualDeps = moduleDeps.getAsSwiftInterfaceModule(); + auto swiftSourceDeps = moduleDeps.getAsSwiftSourceModule(); + auto swiftBinaryDeps = moduleDeps.getAsSwiftBinaryModule(); + auto clangDeps = moduleDeps.getAsClangModule(); // ModulePath const char *modulePathSuffix = - moduleDeps->isSwiftModule() ? ".swiftmodule" : ".pcm"; + moduleDeps.isSwiftModule() ? ".swiftmodule" : ".pcm"; std::string modulePath; if (swiftTextualDeps) modulePath = swiftTextualDeps->moduleOutputPath; @@ -1196,10 +1189,8 @@ generateFullDependencyGraph(const CompilerInstance &instance, sourceFiles = clangDeps->fileDependencies; } - auto optionalDepInfo = cache.findDependency(module); - assert(optionalDepInfo.has_value() && "Missing dependency info during graph generation diagnosis."); - auto depInfo = optionalDepInfo.value(); - auto directDependencies = depInfo->getDirectModuleDependencies(); + auto &depInfo = cache.findKnownDependency(module); + auto directDependencies = depInfo.getDirectModuleDependencies(); // Generate a swiftscan_clang_details_t object based on the dependency kind auto getModuleDetails = [&]() -> swiftscan_module_details_t { @@ -1208,9 +1199,12 @@ generateFullDependencyGraph(const CompilerInstance &instance, swiftscan_string_ref_t moduleInterfacePath = create_clone(swiftTextualDeps->swiftInterfaceFile.c_str()); swiftscan_string_ref_t bridgingHeaderPath = - swiftTextualDeps->textualModuleDetails.bridgingHeaderFile.has_value() + swiftTextualDeps->textualModuleDetails.bridgingHeaderFile + .has_value() ? create_clone( - swiftTextualDeps->textualModuleDetails.bridgingHeaderFile.value().c_str()) + swiftTextualDeps->textualModuleDetails.bridgingHeaderFile + .value() + .c_str()) : create_null(); details->kind = SWIFTSCAN_DEPENDENCY_INFO_SWIFT_TEXTUAL; // Create an overlay dependencies set according to the output format @@ -1414,12 +1408,12 @@ computeTransitiveClosureOfExplicitDependencies( } static std::set computeBridgingHeaderTransitiveDependencies( - const ModuleDependencyInfo *dep, + const ModuleDependencyInfo &dep, const std::unordered_map> &transitiveClosures, const ModuleDependenciesCache &cache) { std::set result; - auto *sourceDep = dep->getAsSwiftSourceModule(); + auto *sourceDep = dep.getAsSwiftSourceModule(); if (!sourceDep) return result; @@ -1871,22 +1865,19 @@ static void resolveDependencyCommandLineArguments( // For main module or binary modules, no command-line to resolve. // For Clang modules, their dependencies are resolved by the clang Scanner // itself for us. - auto optionalDeps = cache.findDependency(modID); - assert(optionalDeps.has_value()); - auto deps = optionalDeps.value(); + auto &deps = cache.findKnownDependency(modID); std::optional> bridgingHeaderDeps; if (modID.Kind == ModuleDependencyKind::SwiftSource) bridgingHeaderDeps = computeBridgingHeaderTransitiveDependencies( deps, moduleTransitiveClosures, cache); - if (auto E = - resolveExplicitModuleInputs(modID, *deps, dependencyClosure, cache, - instance, bridgingHeaderDeps)) + if (auto E = resolveExplicitModuleInputs(modID, dependencyClosure, cache, + instance, bridgingHeaderDeps)) instance.getDiags().diagnose(SourceLoc(), diag::error_cas, toString(std::move(E))); - if (auto E = pruneUnusedVFSOverlays(modID, *deps, dependencyClosure, - cache, instance)) + if (auto E = + pruneUnusedVFSOverlays(modID, dependencyClosure, cache, instance)) instance.getDiags().diagnose(SourceLoc(), diag::error_cas, toString(std::move(E))); } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index b28976fb8dc17..3f990a386ee2c 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1884,8 +1884,7 @@ static bool validateSwiftModuleFileArgumentAndAdd(const std::string &swiftModule return false; } -static bool ParseSearchPathArgs(SearchPathOptions &Opts, - ArgList &Args, +static bool ParseSearchPathArgs(SearchPathOptions &Opts, ArgList &Args, DiagnosticEngine &Diags, StringRef workingDirectory) { using namespace options; @@ -2020,6 +2019,31 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts, for (StringRef Opt : Args.getAllArgValues(OPT_scanner_prefix_map)) { Opts.ScannerPrefixMapper.push_back(Opt.str()); } + + Opts.NoScannerModuleValidation |= + Args.hasArg(OPT_no_scanner_module_validation); + + std::optional forceModuleLoadingMode; + if (auto *A = Args.getLastArg(OPT_module_load_mode)) + forceModuleLoadingMode = A->getValue(); + else if (auto Env = llvm::sys::Process::GetEnv("SWIFT_FORCE_MODULE_LOADING")) + forceModuleLoadingMode = Env; + if (forceModuleLoadingMode) { + if (*forceModuleLoadingMode == "prefer-interface" || + *forceModuleLoadingMode == "prefer-parseable") + Opts.ModuleLoadMode = ModuleLoadingMode::PreferInterface; + else if (*forceModuleLoadingMode == "prefer-serialized") + Opts.ModuleLoadMode = ModuleLoadingMode::PreferSerialized; + else if (*forceModuleLoadingMode == "only-interface" || + *forceModuleLoadingMode == "only-parseable") + Opts.ModuleLoadMode = ModuleLoadingMode::OnlyInterface; + else if (*forceModuleLoadingMode == "only-serialized") + Opts.ModuleLoadMode = ModuleLoadingMode::OnlySerialized; + else + Diags.diagnose(SourceLoc(), diag::unknown_forced_module_loading_mode, + *forceModuleLoadingMode); + } + // Opts.RuntimeIncludePath is set by calls to // setRuntimeIncludePath() or setMainExecutablePath(). // Opts.RuntimeImportPath is set by calls to diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 099b4e161f98d..94d76433bd9f6 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -709,26 +709,7 @@ bool CompilerInstance::setUpModuleLoaders() { enableLibraryEvolution, getDependencyTracker())); } - auto MLM = ModuleLoadingMode::PreferSerialized; - if (auto forceModuleLoadingMode = - llvm::sys::Process::GetEnv("SWIFT_FORCE_MODULE_LOADING")) { - if (*forceModuleLoadingMode == "prefer-interface" || - *forceModuleLoadingMode == "prefer-parseable") - MLM = ModuleLoadingMode::PreferInterface; - else if (*forceModuleLoadingMode == "prefer-serialized") - MLM = ModuleLoadingMode::PreferSerialized; - else if (*forceModuleLoadingMode == "only-interface" || - *forceModuleLoadingMode == "only-parseable") - MLM = ModuleLoadingMode::OnlyInterface; - else if (*forceModuleLoadingMode == "only-serialized") - MLM = ModuleLoadingMode::OnlySerialized; - else { - Diagnostics.diagnose(SourceLoc(), - diag::unknown_forced_module_loading_mode, - *forceModuleLoadingMode); - return true; - } - } + auto MLM = Invocation.getSearchPathOptions().ModuleLoadMode; auto IgnoreSourceInfoFile = Invocation.getFrontendOptions().IgnoreSwiftSourceInfo; if (Invocation.getLangOptions().EnableMemoryBufferImporter) { diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 04e93b05f1a13..d065f3837d1f6 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1372,7 +1372,8 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory( } std::vector -ModuleInterfaceCheckerImpl::getCompiledModuleCandidatesForInterface(StringRef moduleName, StringRef interfacePath) { +ModuleInterfaceCheckerImpl::getCompiledModuleCandidatesForInterface( + StringRef moduleName, StringRef interfacePath) { // Derive .swiftmodule path from the .swiftinterface path. auto interfaceExt = file_types::getExtension(file_types::TY_SwiftModuleInterfaceFile); auto newExt = file_types::getExtension(file_types::TY_SwiftModuleFile); @@ -1392,17 +1393,32 @@ ModuleInterfaceCheckerImpl::getCompiledModuleCandidatesForInterface(StringRef mo ModuleInterfaceLoaderImpl Impl(Ctx, modulePath, interfacePath, moduleName, CacheDir, PrebuiltCacheDir, BackupInterfaceDir, - SourceLoc(), Opts, - RequiresOSSAModules, - nullptr, - ModuleLoadingMode::PreferSerialized); + SourceLoc(), Opts, RequiresOSSAModules, + nullptr, Ctx.SearchPathOpts.ModuleLoadMode); std::vector results; - auto pair = Impl.getCompiledModuleCandidates(); - // Add compiled module candidates only when they are non-empty. - if (!pair.first.empty()) - results.push_back(pair.first); - if (!pair.second.empty()) - results.push_back(pair.second); + std::string adjacentMod, prebuiltMod; + std::tie(adjacentMod, prebuiltMod) = Impl.getCompiledModuleCandidates(); + + auto validateModule = [&](StringRef modulePath) { + // Legacy behavior do not validate module. + if (Ctx.SearchPathOpts.NoScannerModuleValidation) + return true; + + // If we picked the other module already, no need to validate this one since + // it should not be used anyway. + if (!results.empty()) + return false; + SmallVector deps; + std::unique_ptr moduleBuffer; + return Impl.upToDateChecker.swiftModuleIsUpToDate( + modulePath, Impl.rebuildInfo, deps, moduleBuffer); + }; + + // Add compiled module candidates only when they are non-empty and up-to-date. + if (!adjacentMod.empty() && validateModule(adjacentMod)) + results.push_back(adjacentMod); + if (!prebuiltMod.empty() && validateModule(prebuiltMod)) + results.push_back(prebuiltMod); return results; } @@ -1862,6 +1878,12 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( genericSubInvocation.getSearchPathOptions().PluginSearchOpts = searchPathOpts.PluginSearchOpts; + // Get module loading behavior options. + genericSubInvocation.getSearchPathOptions().NoScannerModuleValidation = + searchPathOpts.NoScannerModuleValidation; + genericSubInvocation.getSearchPathOptions().ModuleLoadMode = + searchPathOpts.ModuleLoadMode; + auto &subClangImporterOpts = genericSubInvocation.getClangImporterOptions(); // Respect the detailed-record preprocessor setting of the parent context. // This, and the "raw" clang module format it implicitly enables, are diff --git a/lib/Serialization/ScanningLoaders.cpp b/lib/Serialization/ScanningLoaders.cpp index a9dd8a9daba67..3cf6dec7769cb 100644 --- a/lib/Serialization/ScanningLoaders.cpp +++ b/lib/Serialization/ScanningLoaders.cpp @@ -152,8 +152,19 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath, std::string InPath = moduleInterfacePath.str(); auto compiledCandidates = getCompiledCandidates(Ctx, realModuleName.str(), InPath); - std::vector Args(BaseArgs.begin(), BaseArgs.end()); + if (!compiledCandidates.empty() && + !Ctx.SearchPathOpts.NoScannerModuleValidation) { + assert(compiledCandidates.size() == 1 && + "Should only have 1 candidate module"); + auto BinaryDep = scanModuleFile(compiledCandidates[0], isFramework); + if (!BinaryDep) + return BinaryDep.getError(); + + Result = *BinaryDep; + return std::error_code(); + } + std::vector Args(BaseArgs.begin(), BaseArgs.end()); // Add explicit Swift dependency compilation flags Args.push_back("-explicit-interface-module-build"); Args.push_back("-disable-implicit-swift-modules"); diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 3fca53c35caa7..a99e3b8539600 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -25,6 +25,7 @@ #include "swift/Basic/Version.h" #include "swift/Frontend/ModuleInterfaceLoader.h" #include "swift/Option/Options.h" +#include "swift/Serialization/Validation.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/ArgList.h" @@ -403,13 +404,16 @@ SerializedModuleLoaderBase::getImportsOfModule( llvm::StringSet<> importedModuleNames; std::string importedHeader = ""; - // Load the module file without validation. std::shared_ptr loadedModuleFile; serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load( "", "", std::move(moduleBuf.get()), nullptr, nullptr, isFramework, isRequiredOSSAModules, SDKName, recoverer, loadedModuleFile); + // If failed to load, just ignore and return do not found. + if (loadInfo.status != serialization::Status::Valid) + return std::make_error_code(std::errc::no_such_file_or_directory); + for (const auto &dependency : loadedModuleFile->getDependencies()) { if (dependency.isHeader()) { assert(importedHeader.empty() && diff --git a/test/CAS/Xcc_args.swift b/test/CAS/Xcc_args.swift index 0ffbe0ace877d..498635f0a7fc5 100644 --- a/test/CAS/Xcc_args.swift +++ b/test/CAS/Xcc_args.swift @@ -5,14 +5,11 @@ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \ // RUN: %t/test.swift -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas -Xcc -D_VERSION=1 \ // RUN: -Xcc -fmodule-map-file=%t/include/module.modulemap -Xcc -ivfsoverlay -Xcc %t/empty.yaml \ -// RUN: -Xcc -I%t/empty.hmap +// RUN: -Xcc -I%t/empty.hmap -module-load-mode prefer-serialized // RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:SwiftShims > %t/shims.cmd // RUN: %swift_frontend_plain @%t/shims.cmd -// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json Swift > %t/swift.cmd -// RUN: %swift_frontend_plain @%t/swift.cmd - // RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:_Macro > %t/Macro.cmd // RUN: %swift_frontend_plain @%t/Macro.cmd diff --git a/test/CAS/cached_diagnostics.swift b/test/CAS/cached_diagnostics.swift index 3bb71963b33b7..8ac6bd000da2e 100644 --- a/test/CAS/cached_diagnostics.swift +++ b/test/CAS/cached_diagnostics.swift @@ -5,12 +5,10 @@ // RUN: %target-swift-frontend -scan-dependencies -module-name Test -O -import-objc-header %S/Inputs/objc.h \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \ -// RUN: %s -o %t/deps.json -cache-compile-job -cas-path %t/cas +// RUN: %s -o %t/deps.json -cache-compile-job -cas-path %t/cas -module-load-mode prefer-serialized // RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:SwiftShims > %t/shim.cmd // RUN: %swift_frontend_plain @%t/shim.cmd -// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json Swift > %t/swift.cmd -// RUN: %swift_frontend_plain @%t/swift.cmd // RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json bridgingHeader | tail -n +2 > %t/header.cmd // RUN: %target-swift-frontend @%t/header.cmd -disable-implicit-swift-modules %S/Inputs/objc.h -O -o %t/objc.pch 2>&1 | %FileCheck %s -check-prefix CHECK-BRIDGE diff --git a/test/CAS/cross_import.swift b/test/CAS/cross_import.swift index 9e34140953536..9abba2673f00a 100644 --- a/test/CAS/cross_import.swift +++ b/test/CAS/cross_import.swift @@ -15,7 +15,7 @@ // RUN: %target-swift-frontend -scan-dependencies -module-name Test -module-cache-path %t/clang-module-cache %t/main.swift \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ -// RUN: -o %t/deps.json -I %t -cache-compile-job -cas-path %t/cas -swift-version 5 -enable-cross-import-overlays +// RUN: -o %t/deps.json -I %t -cache-compile-job -cas-path %t/cas -swift-version 5 -enable-cross-import-overlays -module-load-mode prefer-interface // RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json A > %t/A.cmd // RUN: %swift_frontend_plain @%t/A.cmd diff --git a/test/CAS/index-store.swift b/test/CAS/index-store.swift index 5e39880edef21..421fa3e105ad7 100644 --- a/test/CAS/index-store.swift +++ b/test/CAS/index-store.swift @@ -7,7 +7,7 @@ // RUN: -emit-module-interface-path %t/A.swiftinterface \ // RUN: -o %t/A.swiftmodule -// RUN: %target-swift-frontend -scan-dependencies -module-name Test -O -module-cache-path %t/clang-module-cache \ +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-name Test -O -module-cache-path %t/clang-module-cache \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ // RUN: %t/test.swift -I %t -o %t/deps.json -cache-compile-job -cas-path %t/cas diff --git a/test/CAS/module_deps.swift b/test/CAS/module_deps.swift index be04d1236b09d..fd2957394c6df 100644 --- a/test/CAS/module_deps.swift +++ b/test/CAS/module_deps.swift @@ -4,7 +4,7 @@ // RUN: mkdir -p %t/clang-module-cache // RUN: mkdir -p %t/cas -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -cache-compile-job -cas-path %t/cas -no-clang-include-tree +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -cache-compile-job -cas-path %t/cas -no-clang-include-tree // Check the contents of the JSON output // RUN: %validate-json %t/deps.json &>/dev/null // RUN: %FileCheck -check-prefix CHECK -check-prefix CHECK_NO_CLANG_TARGET %s < %t/deps.json @@ -15,12 +15,12 @@ // Check the make-style dependencies file // RUN: %FileCheck %s -check-prefix CHECK-MAKE-DEPS < %t/deps.d -// RUN: %target-swift-frontend -scan-dependencies -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -cache-compile-job -cas-path %t/cas -no-clang-include-tree +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -cache-compile-job -cas-path %t/cas -no-clang-include-tree // RUN: %validate-json %t/deps.json &>/dev/null // RUN: %FileCheck -check-prefix CHECK -check-prefix CHECK_NO_CLANG_TARGET %s < %t/deps.json // Ensure that scanning with `-clang-target` makes sure that Swift modules' respective PCM-dependency-build-argument sets do not contain target triples. -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps_clang_target.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -clang-target %target-cpu-apple-macosx10.14 -cache-compile-job -cas-path %t/cas -no-clang-include-tree +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps_clang_target.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -clang-target %target-cpu-apple-macosx10.14 -cache-compile-job -cas-path %t/cas -no-clang-include-tree // Check the contents of the JSON output // RUN: %validate-json %t/deps_clang_target.json &>/dev/null // RUN: %FileCheck -check-prefix CHECK_CLANG_TARGET %s < %t/deps_clang_target.json diff --git a/test/CAS/module_deps_include_tree.swift b/test/CAS/module_deps_include_tree.swift index b20c3e3a1f580..9800c30080cf5 100644 --- a/test/CAS/module_deps_include_tree.swift +++ b/test/CAS/module_deps_include_tree.swift @@ -4,7 +4,7 @@ // RUN: mkdir -p %t/clang-module-cache // RUN: mkdir -p %t/cas -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -cache-compile-job -cas-path %t/cas +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -cache-compile-job -cas-path %t/cas // Check the contents of the JSON output // RUN: %validate-json %t/deps.json &>/dev/null // RUN: %FileCheck -check-prefix CHECK -check-prefix CHECK_NO_CLANG_TARGET %s < %t/deps.json @@ -15,12 +15,12 @@ // Check the make-style dependencies file // RUN: %FileCheck %s -check-prefix CHECK-MAKE-DEPS < %t/deps.d -// RUN: %target-swift-frontend -scan-dependencies -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -cache-compile-job -cas-path %t/cas +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -cache-compile-job -cas-path %t/cas // RUN: %validate-json %t/deps.json &>/dev/null // RUN: %FileCheck -check-prefix CHECK -check-prefix CHECK_NO_CLANG_TARGET %s < %t/deps.json // Ensure that scanning with `-clang-target` makes sure that Swift modules' respective PCM-dependency-build-argument sets do not contain target triples. -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps_clang_target.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -clang-target %target-cpu-apple-macosx10.14 -cache-compile-job -cas-path %t/cas +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps_clang_target.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h -swift-version 4 -clang-target %target-cpu-apple-macosx10.14 -cache-compile-job -cas-path %t/cas // Check the contents of the JSON output // RUN: %validate-json %t/deps_clang_target.json &>/dev/null // RUN: %FileCheck -check-prefix CHECK_CLANG_TARGET %s < %t/deps_clang_target.json diff --git a/test/CAS/module_hash.swift b/test/CAS/module_hash.swift index 2a8e0c250b9bd..4272bb24cb88f 100644 --- a/test/CAS/module_hash.swift +++ b/test/CAS/module_hash.swift @@ -1,9 +1,9 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -module-name Test +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -module-name Test -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps_cache.json -module-name Test \ +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps_cache.json -module-name Test \ // RUN: -cache-compile-job -cas-path %t/cas // RUN: %{python} %S/Inputs/SwiftDepsExtractor.py %t/deps.json Swift modulePath > %t/path1 diff --git a/test/CAS/plugin_cas.swift b/test/CAS/plugin_cas.swift index 9a689b755e04b..a31f66b071f6f 100644 --- a/test/CAS/plugin_cas.swift +++ b/test/CAS/plugin_cas.swift @@ -4,7 +4,7 @@ // RUN: mkdir -p %t/clang-module-cache // RUN: mkdir -p %t/cas -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s \ +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s \ // RUN: -o %t/deps.json -I %S/../ScanDependencies/Inputs/CHeaders -I %S/../ScanDependencies/Inputs/Swift \ // RUN: -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h \ // RUN: -swift-version 4 -cache-compile-job \ @@ -23,7 +23,7 @@ // RUN: %FileCheck %s -check-prefix CHECK-MAKE-DEPS < %t/deps.d // Ensure that scanning with `-clang-target` makes sure that Swift modules' respective PCM-dependency-build-argument sets do not contain target triples. -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s \ +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s \ // RUN: -o %t/deps_clang_target.json -I %S/../ScanDependencies/Inputs/CHeaders \ // RUN: -I %S/../ScanDependencies/Inputs/Swift -import-objc-header %S/../ScanDependencies/Inputs/CHeaders/Bridging.h \ // RUN: -swift-version 4 -clang-target %target-cpu-apple-macosx10.14 -cache-compile-job \ diff --git a/test/Frontend/module-alias-scan-deps.swift b/test/Frontend/module-alias-scan-deps.swift index bf313ed52f280..a22c74411b0af 100644 --- a/test/Frontend/module-alias-scan-deps.swift +++ b/test/Frontend/module-alias-scan-deps.swift @@ -11,7 +11,7 @@ // RUN: test -f %t/AppleLogging.swiftmodule /// Scanned dependencies should contain real name AppleLogging -// RUN: %target-swift-frontend -scan-dependencies %t/FileLib.swift -module-alias XLogging=AppleLogging -I %t > %t/scandump.output +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface %t/FileLib.swift -module-alias XLogging=AppleLogging -I %t > %t/scandump.output // RUN: %validate-json %t/scandump.output | %FileCheck %s -check-prefix=CHECK-REAL-NAME // CHECK-REAL-NAME-NOT: "swiftPrebuiltExternal": "XLogging" // CHECK-REAL-NAME-NOT: "compiledModulePath":{{.*}}XLogging.swiftmodule", @@ -24,7 +24,7 @@ // RUN: test -f %t/AppleLoggingIF.swiftinterface /// Scanned dependencies should contain real name AppleLoggingIF -// RUN: %target-swift-frontend -scan-dependencies %t/FileLib.swift -module-alias XLogging=AppleLoggingIF -I %t > %t/scandumpIF.output +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface %t/FileLib.swift -module-alias XLogging=AppleLoggingIF -I %t > %t/scandumpIF.output // RUN: %validate-json %t/scandumpIF.output | %FileCheck %s -check-prefix=CHECK-REAL-NAME-IF // CHECK-REAL-NAME-IF-NOT: "swift": "XLogging" // CHECK-REAL-NAME-IF-NOT: "moduleInterfacePath":{{.*}}XLogging.swiftinterface diff --git a/test/ModuleInterface/clang-args-transitive-availability.swift b/test/ModuleInterface/clang-args-transitive-availability.swift index bdfb692fd3cee..dfc4df497cb38 100644 --- a/test/ModuleInterface/clang-args-transitive-availability.swift +++ b/test/ModuleInterface/clang-args-transitive-availability.swift @@ -5,7 +5,7 @@ // received the TANGERINE macro // RUN: %target-swift-frontend -typecheck -strict-implicit-module-context %s -I %S/Inputs/macro-only-module -Xcc -DTANGERINE=1 -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -// RUN: %target-swift-frontend -scan-dependencies -strict-implicit-module-context %s -o %t/deps.json -I %S/Inputs/macro-only-module -Xcc -DTANGERINE=1 -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -strict-implicit-module-context %s -o %t/deps.json -I %S/Inputs/macro-only-module -Xcc -DTANGERINE=1 -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import // RUN: %validate-json %t/deps.json &>/dev/null // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ModuleInterface/clang-session-transitive.swift b/test/ModuleInterface/clang-session-transitive.swift index ae6ef6e6ef4df..8bf1cd8314245 100644 --- a/test/ModuleInterface/clang-session-transitive.swift +++ b/test/ModuleInterface/clang-session-transitive.swift @@ -4,7 +4,7 @@ // RUN: %target-build-swift -module-name TestModule -module-link-name TestModule %S/Inputs/TestModule.swift -enable-library-evolution -emit-module-interface -o %t/TestModule.swiftmodule -swift-version 5 -Xfrontend -disable-implicit-concurrency-module-import -Xfrontend -disable-implicit-string-processing-module-import -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -I%t -validate-clang-modules-once -clang-build-session-file %t/Build.session -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import +// RUN: %target-swift-frontend -scan-dependencies -no-scanner-module-validation %s -o %t/deps.json -I%t -validate-clang-modules-once -clang-build-session-file %t/Build.session -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import // RUN: %validate-json %t/deps.json &>/dev/null // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ModuleInterface/extension-transitive-availability.swift b/test/ModuleInterface/extension-transitive-availability.swift index 318986238f24a..a677fc4d6292c 100644 --- a/test/ModuleInterface/extension-transitive-availability.swift +++ b/test/ModuleInterface/extension-transitive-availability.swift @@ -3,7 +3,7 @@ // RUN: %target-swift-emit-module-interface(%t/ExtensionAvailable.swiftinterface) %S/Inputs/extension-available.swift -module-name ExtensionAvailable -I%t -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -I%t -application-extension -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import +// RUN: %target-swift-frontend -scan-dependencies -no-scanner-module-validation %s -o %t/deps.json -I%t -application-extension -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import // RUN: %validate-json %t/deps.json &>/dev/null // RUN: %FileCheck %s < %t/deps.json diff --git a/test/ModuleInterface/infer-arch-from-file.swift b/test/ModuleInterface/infer-arch-from-file.swift index ab1e409401a13..f75771843269c 100644 --- a/test/ModuleInterface/infer-arch-from-file.swift +++ b/test/ModuleInterface/infer-arch-from-file.swift @@ -5,7 +5,7 @@ import arm64 -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -I %t -target arm64-apple-macos11.0 +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface %s -o %t/deps.json -I %t -target arm64-apple-macos11.0 // RUN: %validate-json %t/deps.json | %FileCheck %s // CHECK-NOT: arm64e-apple-macos11.0 diff --git a/test/ScanDependencies/FilterClangSearchPaths.swift b/test/ScanDependencies/FilterClangSearchPaths.swift index e8fdf399e224a..45563dd4c8506 100644 --- a/test/ScanDependencies/FilterClangSearchPaths.swift +++ b/test/ScanDependencies/FilterClangSearchPaths.swift @@ -1,7 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %empty-directory(%t/clang-module-cache) -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -Xcc -fobjc-disable-direct-methods-for-testing -Xcc -I -Xcc /tmp/foo -Xcc -I/tmp/bar +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -Xcc -fobjc-disable-direct-methods-for-testing -Xcc -I -Xcc /tmp/foo -Xcc -I/tmp/bar // Check the contents of the JSON output // RUN: %validate-json %t/deps.json | %FileCheck %s diff --git a/test/ScanDependencies/ObjCStrict.swift b/test/ScanDependencies/ObjCStrict.swift index 5ba108d5fabed..c5764b7c7a1f1 100644 --- a/test/ScanDependencies/ObjCStrict.swift +++ b/test/ScanDependencies/ObjCStrict.swift @@ -1,7 +1,7 @@ // RUN: %empty-directory(%t) // RUN: %empty-directory(%t/clang-module-cache) -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -Xcc -fobjc-disable-direct-methods-for-testing +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -Xcc -fobjc-disable-direct-methods-for-testing // Check the contents of the JSON output // RUN: %validate-json %t/deps.json | %FileCheck %s diff --git a/test/ScanDependencies/batch_module_scan.swift b/test/ScanDependencies/batch_module_scan.swift index e276fda317883..6c4714e5612bc 100644 --- a/test/ScanDependencies/batch_module_scan.swift +++ b/test/ScanDependencies/batch_module_scan.swift @@ -14,7 +14,7 @@ // RUN: echo "\"output\": \"%/t/outputs/F.pcm.json\"" >> %/t/inputs/input.json // RUN: echo "}]" >> %/t/inputs/input.json -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -batch-scan-input-file %/t/inputs/input.json +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -batch-scan-input-file %/t/inputs/input.json // Check the contents of the JSON output // RUN: %validate-json %t/outputs/F.pcm.json | %FileCheck %s -check-prefix=CHECK-PCM diff --git a/test/ScanDependencies/bin_mod_import.swift b/test/ScanDependencies/bin_mod_import.swift index bf4ad63e4673f..79a04013891e8 100644 --- a/test/ScanDependencies/bin_mod_import.swift +++ b/test/ScanDependencies/bin_mod_import.swift @@ -7,11 +7,11 @@ import EWrapper // Step 1: Build a swift interface into a binary module // RUN: %target-swift-frontend -compile-module-from-interface %S/Inputs/Swift/EWrapper.swiftinterface -o %t/EWrapper.swiftmodule -I %t // Step 3: scan dependency should give us the binary module and a textual swift dependency from it -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -I %t +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface %s -o %t/deps.json -I %t // RUN: %validate-json %t/deps.json | %FileCheck %s // Step 4: Ensure that round-trip serialization does not affect result -// RUN: %target-swift-frontend -scan-dependencies -test-dependency-scan-cache-serialization %s -o %t/deps.json -I %t +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -test-dependency-scan-cache-serialization %s -o %t/deps.json -I %t // RUN: %validate-json %t/deps.json | %FileCheck %s // CHECK: "modulePath": "{{.*}}EWrapper.swiftmodule" diff --git a/test/ScanDependencies/blocklist-path-pass-down.swift b/test/ScanDependencies/blocklist-path-pass-down.swift index 0136ddf9cefe7..bd7c40efb128c 100644 --- a/test/ScanDependencies/blocklist-path-pass-down.swift +++ b/test/ScanDependencies/blocklist-path-pass-down.swift @@ -14,7 +14,7 @@ // Run the scan -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -F %t/Frameworks/ -sdk %t -blocklist-file %t/blocklist.yml +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface %s -o %t/deps.json -F %t/Frameworks/ -sdk %t -blocklist-file %t/blocklist.yml // RUN: %validate-json %t/deps.json | %FileCheck %s import E diff --git a/test/ScanDependencies/bridging_header_dep_module_map.swift b/test/ScanDependencies/bridging_header_dep_module_map.swift index ac17bfba27eb8..7c14b3e40afd9 100644 --- a/test/ScanDependencies/bridging_header_dep_module_map.swift +++ b/test/ScanDependencies/bridging_header_dep_module_map.swift @@ -20,7 +20,7 @@ // - Scan main module and ensure that the "FooClient" recipe includes the modulemap for Foo's briding header's module dependencies // but not other dependencies -// RUN: %target-swift-frontend -scan-dependencies %t/bridging_header_dep_module_map.swift -I %t/FooModuleDir -I %t/TestSwiftInterfaces -I %t/TestCHeaders -I %S/Inputs/CHeaders -o %t/deps.json +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface %t/bridging_header_dep_module_map.swift -I %t/FooModuleDir -I %t/TestSwiftInterfaces -I %t/TestCHeaders -I %S/Inputs/CHeaders -o %t/deps.json // RUN: %validate-json %t/deps.json | %FileCheck %s // Given the following dependency graph: diff --git a/test/ScanDependencies/can_import_placeholder.swift b/test/ScanDependencies/can_import_placeholder.swift index c7400bccc4611..9a42e2b9a04a2 100644 --- a/test/ScanDependencies/can_import_placeholder.swift +++ b/test/ScanDependencies/can_import_placeholder.swift @@ -10,11 +10,11 @@ // RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // RUN: %validate-json %t/deps.json | %FileCheck %s // Ensure that round-trip serialization does not affect result -// RUN: %target-swift-frontend -scan-dependencies -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // RUN: %validate-json %t/deps.json | %FileCheck %s // REQUIRES: executable_test diff --git a/test/ScanDependencies/clang-target.swift b/test/ScanDependencies/clang-target.swift index 5bfaf3601b8cd..3c0170b80a251 100644 --- a/test/ScanDependencies/clang-target.swift +++ b/test/ScanDependencies/clang-target.swift @@ -12,7 +12,7 @@ // With -clang-target, we build one X.pcm // RUN: find %t.module-cache -name "X-*.pcm" | count 1 -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t.module-cache %s -o %t.deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -target %target-cpu-apple-macosx10.14 -clang-target %target-cpu-apple-macosx10.14 +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t.module-cache %s -o %t.deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -target %target-cpu-apple-macosx10.14 -clang-target %target-cpu-apple-macosx10.14 // RUN: %validate-json %t.deps.json | %FileCheck %s diff --git a/test/ScanDependencies/clang_auxiliary_module_framework.swift b/test/ScanDependencies/clang_auxiliary_module_framework.swift index 0c3448ce00c71..5154fdd85e5cb 100644 --- a/test/ScanDependencies/clang_auxiliary_module_framework.swift +++ b/test/ScanDependencies/clang_auxiliary_module_framework.swift @@ -1,11 +1,11 @@ // REQUIRES: OS=macosx // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -F %S/Inputs/Frameworks -verify +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -F %S/Inputs/Frameworks -verify // Check the contents of the JSON output // RUN: %validate-json %t/deps.json | %FileCheck %s // Ensure that round-trip serialization does not affect result -// RUN: %target-swift-frontend -scan-dependencies -test-dependency-scan-cache-serialization %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -F %S/Inputs/Frameworks -verify +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -test-dependency-scan-cache-serialization %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -F %S/Inputs/Frameworks -verify // RUN: %validate-json %t/deps.json | %FileCheck %s import WithAuxClangModule diff --git a/test/ScanDependencies/compiled_swift_modules.swift b/test/ScanDependencies/compiled_swift_modules.swift index d4bb2864dd23f..4ccda3f788fc1 100644 --- a/test/ScanDependencies/compiled_swift_modules.swift +++ b/test/ScanDependencies/compiled_swift_modules.swift @@ -8,32 +8,46 @@ import Foo // HAS_COMPILED: "compiledModuleCandidates": [ // HAS_COMPILED-NEXT: "{{.*}}Foo.swiftmodule{{.*}}.swiftmodule" +// HAS_BINARY: "swiftPrebuiltExternal": "Foo" + // HAS_NO_COMPILED-NOT: "{{.*}}Foo.swiftmodule{{.*}}.swiftmodule" // Step 1: build swift interface and swift module side by side // 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 // Step 2: scan dependency should give us the binary module adjacent to the interface file. -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -I %t -emit-dependencies -emit-dependencies-path %t/deps.d +// RUN: %target-swift-frontend -scan-dependencies -no-scanner-module-validation %s -o %t/deps.json -I %t -emit-dependencies -emit-dependencies-path %t/deps.d // RUN: %validate-json %t/deps.json | %FileCheck %s -check-prefix=HAS_COMPILED +/// Check scanner picked binary dependency if not requesting raw scan output. +// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -I %t -emit-dependencies -emit-dependencies-path %t/deps.d +// RUN: %validate-json %t/deps.json | %FileCheck %s -check-prefix=HAS_BINARY + // Step 3: remove the adjacent module. // RUN: rm %t/Foo.swiftmodule/%target-swiftmodule-name // Step 4: scan dependency should give us the interface file. -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -I %t -emit-dependencies -emit-dependencies-path %t/deps.d +// RUN: %target-swift-frontend -scan-dependencies -no-scanner-module-validation %s -o %t/deps.json -I %t -emit-dependencies -emit-dependencies-path %t/deps.d // RUN: %validate-json %t/deps.json | %FileCheck %s -check-prefix=HAS_NO_COMPILED // Step 4: build prebuilt module cache using the interface. // RUN: %target-swift-frontend -compile-module-from-interface -o %t/ResourceDir/%target-sdk-name/prebuilt-modules/Foo.swiftmodule/%target-swiftmodule-name -module-name Foo -disable-interface-lock %t/Foo.swiftmodule/%target-swiftinterface-name // Step 5: scan dependency now should give us the prebuilt module cache -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -I %t -emit-dependencies -emit-dependencies-path %t/deps.d -sdk %t -prebuilt-module-cache-path %t/ResourceDir/%target-sdk-name/prebuilt-modules +// RUN: %target-swift-frontend -scan-dependencies -no-scanner-module-validation %s -o %t/deps.json -I %t -emit-dependencies -emit-dependencies-path %t/deps.d -sdk %t -prebuilt-module-cache-path %t/ResourceDir/%target-sdk-name/prebuilt-modules // RUN: %validate-json %t/deps.json | %FileCheck %s -check-prefix=HAS_COMPILED +/// Check scanner picked binary dependency if not requesting raw scan output. +// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -I %t -emit-dependencies -emit-dependencies-path %t/deps.d -sdk %t -prebuilt-module-cache-path %t/ResourceDir/%target-sdk-name/prebuilt-modules +// RUN: %validate-json %t/deps.json | %FileCheck %s -check-prefix=HAS_BINARY + // Step 6: update the interface file from where the prebuilt module cache was built. // RUN: touch %t/Foo.swiftmodule/%target-swiftinterface-name // Step 7: scan dependency should give us the prebuilt module file even though it's out-of-date. -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -I %t -emit-dependencies -emit-dependencies-path %t/deps.d -sdk %t -prebuilt-module-cache-path %t/ResourceDir/%target-sdk-name/prebuilt-modules +// RUN: %target-swift-frontend -scan-dependencies -no-scanner-module-validation %s -o %t/deps.json -I %t -emit-dependencies -emit-dependencies-path %t/deps.d -sdk %t -prebuilt-module-cache-path %t/ResourceDir/%target-sdk-name/prebuilt-modules // RUN: %validate-json %t/deps.json | %FileCheck %s -check-prefix=HAS_COMPILED + +// Step 8: The new scanner behavior should not give use prebuilt module file because it is out-of-date. +// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -I %t -emit-dependencies -emit-dependencies-path %t/deps.d -sdk %t -prebuilt-module-cache-path %t/ResourceDir/%target-sdk-name/prebuilt-modules +// RUN: %validate-json %t/deps.json | %FileCheck %s -check-prefix=HAS_NO_COMPILED diff --git a/test/ScanDependencies/direct_cc1_scan.swift b/test/ScanDependencies/direct_cc1_scan.swift index 996fdec35832b..5888db7a9bd2f 100644 --- a/test/ScanDependencies/direct_cc1_scan.swift +++ b/test/ScanDependencies/direct_cc1_scan.swift @@ -7,13 +7,13 @@ // RUN: -emit-module-interface-path %t/A.swiftinterface \ // RUN: -o %t/A.swiftmodule -// RUN: %target-swift-frontend -scan-dependencies -o %t/deps.json -I %t \ +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -o %t/deps.json -I %t \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ // RUN: %t/test.swift -module-name Test -swift-version 5 // RUN: %{python} %S/../CAS/Inputs/BuildCommandExtractor.py %t/deps.json A | %FileCheck %s --check-prefix CHECK-NO-DIRECT-CC1 // RUN: %{python} %S/../CAS/Inputs/BuildCommandExtractor.py %t/deps.json Test | %FileCheck %s --allow-empty --check-prefix CHECK-NO-DIRECT-CC1 -// RUN: %target-swift-frontend -scan-dependencies -o %t/deps2.json -I %t \ +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -o %t/deps2.json -I %t \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ // RUN: -g -file-compilation-dir %t -Xcc -ferror-limit=1 \ // RUN: %t/test.swift -module-name Test -swift-version 5 -experimental-clang-importer-direct-cc1-scan diff --git a/test/ScanDependencies/eliminate_unused_vfs.swift b/test/ScanDependencies/eliminate_unused_vfs.swift index 7e5b88cff8ec2..dc2a9909595ec 100644 --- a/test/ScanDependencies/eliminate_unused_vfs.swift +++ b/test/ScanDependencies/eliminate_unused_vfs.swift @@ -6,7 +6,7 @@ // RUN: sed -e "s|OUT_DIR|%t/redirects|g" -e "s|IN_DIR|%S/Inputs/CHeaders|g" %t/overlay_template.yaml > %t/overlay.yaml -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/module-cache %t/test.swift -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -Xcc -ivfsoverlay -Xcc %t/overlay.yaml +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/module-cache %t/test.swift -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -Xcc -ivfsoverlay -Xcc %t/overlay.yaml // RUN: %validate-json %t/deps.json | %FileCheck %s //--- overlay_template.yaml diff --git a/test/ScanDependencies/explicit-swift-dependencies.swift b/test/ScanDependencies/explicit-swift-dependencies.swift index 746bf7f8416bf..e5a281caec5a0 100644 --- a/test/ScanDependencies/explicit-swift-dependencies.swift +++ b/test/ScanDependencies/explicit-swift-dependencies.swift @@ -1,7 +1,7 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // Check the contents of the JSON output // RUN: %validate-json %t/deps.json | %FileCheck %s diff --git a/test/ScanDependencies/header_deps_of_binary.swift b/test/ScanDependencies/header_deps_of_binary.swift index 20b43c3343925..d1c6e2b830ca8 100644 --- a/test/ScanDependencies/header_deps_of_binary.swift +++ b/test/ScanDependencies/header_deps_of_binary.swift @@ -23,7 +23,7 @@ // RUN: %target-swift-frontend -emit-module -emit-module-path %t/SwiftModules/Foo.swiftmodule %t/foo.swift -module-name Foo -import-objc-header %t/PCH/foo.pch -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -disable-implicit-swift-modules -explicit-swift-module-map-file %t/map.json // - Scan main module and ensure that the header dependencies point to .h and not .pch file -// RUN: %target-swift-frontend -scan-dependencies %t/header_deps_of_binary.swift -I %t/SwiftModules -I %S/Inputs/Swift -I %S/Inputs/CHeaders -o %t/deps.json +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface %t/header_deps_of_binary.swift -I %t/SwiftModules -I %S/Inputs/Swift -I %S/Inputs/CHeaders -o %t/deps.json // RUN: %validate-json %t/deps.json | %FileCheck %s // CHECK: "swift": "FooClient" diff --git a/test/ScanDependencies/include-sdk-in-command.swift b/test/ScanDependencies/include-sdk-in-command.swift index 1f1d96e1ec7bf..84512632a0b25 100644 --- a/test/ScanDependencies/include-sdk-in-command.swift +++ b/test/ScanDependencies/include-sdk-in-command.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -sdk %t/mysecretsdk.sdk +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface %s -o %t/deps.json -sdk %t/mysecretsdk.sdk // Check the contents of the JSON output // RUN: %validate-json %t/deps.json | %FileCheck %s diff --git a/test/ScanDependencies/module_deps_binary_dep_swift_overlay.swift b/test/ScanDependencies/module_deps_binary_dep_swift_overlay.swift index 75c70287c7cb1..8814a95ecfb3b 100644 --- a/test/ScanDependencies/module_deps_binary_dep_swift_overlay.swift +++ b/test/ScanDependencies/module_deps_binary_dep_swift_overlay.swift @@ -8,7 +8,7 @@ // RUN: %target-swift-frontend -emit-module -emit-module-path %t/DependencyModules/BinaryModuleDep.swiftmodule -module-cache-path %t/clang-module-cache %t/BinaryModuleDepSource.swift -module-name BinaryModuleDep -I %S/Inputs/CHeaders -I %S/Inputs/Swift // Scan the client and ensure both the Client and BinaryModuleDep modules have a Swift overlay dependency on 'F' as imported by 'ClangModuleWithOverlayedDep' -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -I %t/DependencyModules +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -I %t/DependencyModules // Check the contents of the JSON output // RUN: %validate-json %t/deps.json | %FileCheck %s diff --git a/test/ScanDependencies/module_deps_cache_reuse.swift b/test/ScanDependencies/module_deps_cache_reuse.swift index 4012e5d406597..51718ede38662 100644 --- a/test/ScanDependencies/module_deps_cache_reuse.swift +++ b/test/ScanDependencies/module_deps_cache_reuse.swift @@ -2,10 +2,10 @@ // RUN: mkdir -p %t/clang-module-cache // Run the scanner once, emitting the serialized scanner cache -// RUN: %target-swift-frontend -scan-dependencies -Rdependency-scan-cache -serialize-dependency-scan-cache -dependency-scan-cache-path %t/cache.moddepcache -module-cache-path %t/clang-module-cache %s -o %t/deps_initial.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 2>&1 | %FileCheck %s -check-prefix CHECK-REMARK-SAVE +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -Rdependency-scan-cache -serialize-dependency-scan-cache -dependency-scan-cache-path %t/cache.moddepcache -module-cache-path %t/clang-module-cache %s -o %t/deps_initial.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 2>&1 | %FileCheck %s -check-prefix CHECK-REMARK-SAVE // Run the scanner again, but now re-using previously-serialized cache -// RUN: %target-swift-frontend -scan-dependencies -Rdependency-scan-cache -load-dependency-scan-cache -dependency-scan-cache-path %t/cache.moddepcache -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 2>&1 | %FileCheck %s -check-prefix CHECK-REMARK-LOAD +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -Rdependency-scan-cache -load-dependency-scan-cache -dependency-scan-cache-path %t/cache.moddepcache -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 2>&1 | %FileCheck %s -check-prefix CHECK-REMARK-LOAD // Check the contents of the JSON output // RUN: %validate-json %t/deps.json &>/dev/null diff --git a/test/ScanDependencies/module_deps_cross_import_overlay.swift b/test/ScanDependencies/module_deps_cross_import_overlay.swift index b7a047a3b7461..c5a663ca9a551 100644 --- a/test/ScanDependencies/module_deps_cross_import_overlay.swift +++ b/test/ScanDependencies/module_deps_cross_import_overlay.swift @@ -1,11 +1,11 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -I %S/Inputs/CHeaders/ExtraCModules -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -module-name CrossImportTestModule +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -I %S/Inputs/CHeaders/ExtraCModules -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -module-name CrossImportTestModule // Check the contents of the JSON output // RUN: %validate-json %t/deps.json | %FileCheck %s // Ensure that round-trip serialization does not affect result -// RUN: %target-swift-frontend -scan-dependencies -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -I %S/Inputs/CHeaders/ExtraCModules -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -module-name CrossImportTestModule +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -I %S/Inputs/CHeaders/ExtraCModules -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -module-name CrossImportTestModule // RUN: %validate-json %t/deps.json | %FileCheck %s // REQUIRES: executable_test diff --git a/test/ScanDependencies/module_deps_different_paths_no_reuse.swift b/test/ScanDependencies/module_deps_different_paths_no_reuse.swift index 9844160fe9e61..0afa3bab97918 100644 --- a/test/ScanDependencies/module_deps_different_paths_no_reuse.swift +++ b/test/ScanDependencies/module_deps_different_paths_no_reuse.swift @@ -4,12 +4,12 @@ // This test ensures that subsequent invocations of the dependency scanner that re-use previous cache state do not re-use cache entries that contain modules found outside of the current scanner invocation's search paths. // Run the scanner once, emitting the serialized scanner cache, with one set of search paths -// RUN: %target-swift-frontend -scan-dependencies -serialize-dependency-scan-cache -dependency-scan-cache-path %t/cache.moddepcache -module-cache-path %t/clang-module-cache %s -o %t/deps_initial.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -serialize-dependency-scan-cache -dependency-scan-cache-path %t/cache.moddepcache -module-cache-path %t/clang-module-cache %s -o %t/deps_initial.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // RUN: %validate-json %t/deps_initial.json &>/dev/null // RUN: %FileCheck -input-file %t/deps_initial.json %s -check-prefix CHECK-INITIAL-SCAN // Run the scanner again, but now re-using previously-serialized cache and using a different search path for Swift modules -// RUN: %target-swift-frontend -scan-dependencies -load-dependency-scan-cache -dependency-scan-cache-path %t/cache.moddepcache -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/SwiftDifferent -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -load-dependency-scan-cache -dependency-scan-cache-path %t/cache.moddepcache -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/SwiftDifferent -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // RUN: %validate-json %t/deps.json &>/dev/null // RUN: %FileCheck -input-file %t/deps.json %s -check-prefix CHECK-DIFFERENT diff --git a/test/ScanDependencies/module_deps_external.swift b/test/ScanDependencies/module_deps_external.swift index 515d7a33edcb7..37a61b6b349e4 100644 --- a/test/ScanDependencies/module_deps_external.swift +++ b/test/ScanDependencies/module_deps_external.swift @@ -10,7 +10,7 @@ // RUN: echo "\"isFramework\": false" >> %/t/inputs/map.json // RUN: echo "}]" >> %/t/inputs/map.json -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // Check the contents of the JSON output // RUN: %validate-json %t/deps.json | %FileCheck %s @@ -28,7 +28,7 @@ // RUN: %target-run %t/main %t/deps.json // Ensure that round-trip serialization does not affect result -// RUN: %target-swift-frontend -scan-dependencies -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -placeholder-dependency-module-map-file %t/inputs/map.json -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 // RUN: %validate-json %t/deps.json | %FileCheck %s // REQUIRES: executable_test diff --git a/test/ScanDependencies/module_framework.swift b/test/ScanDependencies/module_framework.swift index 296ac57759690..2789c058fe21d 100644 --- a/test/ScanDependencies/module_framework.swift +++ b/test/ScanDependencies/module_framework.swift @@ -1,11 +1,11 @@ // REQUIRES: OS=macosx // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -F %S/Inputs/Frameworks +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -F %S/Inputs/Frameworks // Check the contents of the JSON output // RUN: %validate-json %t/deps.json | %FileCheck %s // Ensure that round-trip serialization does not affect result -// RUN: %target-swift-frontend -scan-dependencies -test-dependency-scan-cache-serialization %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -F %S/Inputs/Frameworks +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -test-dependency-scan-cache-serialization %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -F %S/Inputs/Frameworks // RUN: %validate-json %t/deps.json | %FileCheck %s import ScannerTestKit diff --git a/test/ScanDependencies/module_load_mode.swift b/test/ScanDependencies/module_load_mode.swift new file mode 100644 index 0000000000000..29ab5996dc185 --- /dev/null +++ b/test/ScanDependencies/module_load_mode.swift @@ -0,0 +1,21 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// 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 -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib + +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode only-serialized \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ +// RUN: %t/main.swift -I %t -o - | %FileCheck %s --check-prefix=SERIALIZED + +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode only-interface \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ +// RUN: %t/main.swift -I %t -o - | %FileCheck %s --check-prefix=INTERFACE + +// SERIALIZED: "swiftPrebuiltExternal": "Foo" +// INTERFACE: "swift": "Foo" + +//--- main.swift +import Foo + +//--- Foo.swift +public func foo() {} diff --git a/test/ScanDependencies/no_cross_import_module_for_self.swift b/test/ScanDependencies/no_cross_import_module_for_self.swift index 4d34d97e1692c..042baf7ace9f6 100644 --- a/test/ScanDependencies/no_cross_import_module_for_self.swift +++ b/test/ScanDependencies/no_cross_import_module_for_self.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/CHeaders/ExtraCModules -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -swift-version 4 -module-name _cross_import_E +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/CHeaders/ExtraCModules -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -swift-version 4 -module-name _cross_import_E // Check the contents of the JSON output // RUN: %validate-json %t/deps.json | %FileCheck %s diff --git a/test/ScanDependencies/no_main_module_cross_import.swift b/test/ScanDependencies/no_main_module_cross_import.swift index a111f9737fe0c..4aa299a9d4ee5 100644 --- a/test/ScanDependencies/no_main_module_cross_import.swift +++ b/test/ScanDependencies/no_main_module_cross_import.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/CHeaders/ExtraCModules -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -swift-version 4 -module-name SubE +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/CHeaders/ExtraCModules -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -swift-version 4 -module-name SubE // Check the contents of the JSON output // RUN: %validate-json %t/deps.json | %FileCheck %s diff --git a/test/ScanDependencies/package_interface.swift b/test/ScanDependencies/package_interface.swift index 4688fa3575698..0d0f0b079cb8c 100644 --- a/test/ScanDependencies/package_interface.swift +++ b/test/ScanDependencies/package_interface.swift @@ -9,21 +9,21 @@ // RUN: -emit-private-module-interface-path %t/Bar.private.swiftinterface \ // RUN: -emit-package-module-interface-path %t/Bar.package.swiftinterface -// RUN: %target-swift-frontend -scan-dependencies -o %t/deps.json -I %t -experimental-package-interface-load \ +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -o %t/deps.json -I %t -experimental-package-interface-load \ // RUN: %t/Client.swift -module-name Client -package-name barpkg -swift-version 5 // RUN: %FileCheck %s --input-file=%t/deps.json --check-prefix CHECK --check-prefix CHECK-PACKAGE /// When package name doesn't match or not used, it should find private interface. -// RUN: %target-swift-frontend -scan-dependencies -o %t/deps2.json -I %t -experimental-package-interface-load \ +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -o %t/deps2.json -I %t -experimental-package-interface-load \ // RUN: %t/Client.swift -module-name Client -package-name foopkg -swift-version 5 // RUN: %FileCheck %s --input-file=%t/deps2.json --check-prefix CHECK --check-prefix CHECK-PRIVATE -// RUN: %target-swift-frontend -scan-dependencies -o %t/deps3.json -I %t -experimental-package-interface-load \ +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -o %t/deps3.json -I %t -experimental-package-interface-load \ // RUN: %t/Client.swift -module-name Client -swift-version 5 // RUN: %FileCheck %s --input-file=%t/deps3.json --check-prefix CHECK --check-prefix CHECK-PRIVATE /// If -experimental-package-interface-load is not used but in the same package, it should find the binary module -// RUN: %target-swift-frontend -scan-dependencies -I %t \ +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -I %t \ // RUN: %t/Client.swift -module-name Client -package-name barpkg -swift-version 5 | \ // RUN: %FileCheck %s --check-prefix CHECK-BINARY diff --git a/test/ScanDependencies/preserve_used_vfs.swift b/test/ScanDependencies/preserve_used_vfs.swift index 6efbe236b2a9f..d7348931bf4ec 100644 --- a/test/ScanDependencies/preserve_used_vfs.swift +++ b/test/ScanDependencies/preserve_used_vfs.swift @@ -6,7 +6,7 @@ // RUN: sed -e "s|OUT_DIR|%t/redirects|g" -e "s|IN_DIR|%S/Inputs/CHeaders|g" %t/overlay_template.yaml > %t/overlay.yaml -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/module-cache %t/test.swift -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -Xcc -ivfsoverlay -Xcc %t/overlay.yaml +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/module-cache %t/test.swift -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -Xcc -ivfsoverlay -Xcc %t/overlay.yaml // RUN: %validate-json %t/deps.json | %FileCheck %s //--- redirects/RedirectedF.h diff --git a/test/ScanDependencies/private_interface_candidate_module.swift b/test/ScanDependencies/private_interface_candidate_module.swift index bf6752ee14555..41d9dd9013718 100644 --- a/test/ScanDependencies/private_interface_candidate_module.swift +++ b/test/ScanDependencies/private_interface_candidate_module.swift @@ -15,7 +15,7 @@ // RUN: %target-swift-frontend -emit-module -emit-module-path %t/Frameworks/E.framework/Modules/E.swiftmodule/%module-target-triple.swiftmodule -module-cache-path %t.module-cache %t/foo.swift -module-name E // Run the scan -// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -F %t/Frameworks/ -sdk %t +// RUN: %target-swift-frontend -scan-dependencies -no-scanner-module-validation %s -o %t/deps.json -F %t/Frameworks/ -sdk %t // RUN: %validate-json %t/deps.json | %FileCheck %s import E diff --git a/test/ScanDependencies/separate_bridging_header_deps.swift b/test/ScanDependencies/separate_bridging_header_deps.swift index 69e5de969112b..f9c9ed02bc758 100644 --- a/test/ScanDependencies/separate_bridging_header_deps.swift +++ b/test/ScanDependencies/separate_bridging_header_deps.swift @@ -1,7 +1,7 @@ // RUN: %empty-directory(%t) // RUN: mkdir -p %t/clang-module-cache -// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 5 // RUN: %validate-json %t/deps.json | %FileCheck %s import E diff --git a/test/ScanDependencies/testable-import.swift b/test/ScanDependencies/testable-import.swift index d2323cf9e3bf8..d6e57bd9c66c7 100644 --- a/test/ScanDependencies/testable-import.swift +++ b/test/ScanDependencies/testable-import.swift @@ -16,14 +16,14 @@ // RUN: -emit-module-interface-path %t/A.swiftinterface -enable-library-evolution -I %t -enable-testing \ // RUN: %t/A.swift -// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/test1.swift \ +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-name Test %t/test1.swift \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -enable-testing \ // RUN: -o %t/deps1.json -I %t -swift-version 5 // RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps1.json Test directDependencies | %FileCheck %s --check-prefix TEST1 // TEST1-DAG: "swiftPrebuiltExternal": "B" // TEST1-DAG: "swift": "C" -// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/test2.swift \ +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-name Test %t/test2.swift \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -enable-testing \ // RUN: -o %t/deps2.json -I %t -swift-version 5 // RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps2.json Test directDependencies | %FileCheck %s --check-prefix TEST2 @@ -36,7 +36,7 @@ // TEST2-A-DAG: "swift": "C" /// An indirect @testable import is still interface deps. -// RUN: %target-swift-frontend -scan-dependencies -module-name Test %t/test3.swift \ +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-name Test %t/test3.swift \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -enable-testing \ // RUN: -o %t/deps3.json -I %t -swift-version 5 // RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps3.json Test directDependencies | %FileCheck %s --check-prefix TEST3 From 69ee86f29c23ae645ec23962d844dbe342ab306c Mon Sep 17 00:00:00 2001 From: Steven Wu Date: Thu, 4 Apr 2024 14:16:21 -0700 Subject: [PATCH 2/6] [DependencyScanning] Handle testable dependencies correctly Teach scanner to pick and choose binary modules correctly based on if it is testable import or not. Some situations that scanner need to be careful when testable is involved: * When it is a regular import, it should not import binary modules that are built with -enable-testing, it should prefer interfaces if that is available. * When testable import, it should only load binary module and it should make sure the internal imports from binary modules are actually required for testable import to work. If a testable import only find a regular binary module, dependency scanner currently will just preceed with such module and leave the diagnostics to swift-frontend, because the alternative (failed to find module) can be confusing to users. rdar://125914165 (cherry picked from commit d4c90d6eeb4a2abbb86a19e8c808f8ba6928b488) --- include/swift/AST/DiagnosticsSema.def | 3 + include/swift/Serialization/ScanningLoaders.h | 3 +- .../Serialization/SerializedModuleLoader.h | 15 ++- lib/Serialization/ScanningLoaders.cpp | 23 +++-- lib/Serialization/SerializedModuleLoader.cpp | 96 ++++++++++--------- .../testable-dependencies.swift | 78 +++++++++++++++ 6 files changed, 154 insertions(+), 64 deletions(-) create mode 100644 test/ScanDependencies/testable-dependencies.swift diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 2905dcdd2d2ed..94006af84f9e5 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -1193,6 +1193,9 @@ REMARK(module_api_import_aliases,none, "%select{, which reexports definition from %2|}3", (const Decl *, ModuleDecl *, ModuleDecl *, bool)) +REMARK(skip_module_invalid,none,"skip invalid swiftmodule: %0", (StringRef)) +REMARK(skip_module_testable,none,"skip swiftmodule built with '-enable-testing': %0", (StringRef)) + REMARK(macro_loaded,none, "loaded macro implementation module %0 from " "%select{shared library '%2'|executable '%2'|" diff --git a/include/swift/Serialization/ScanningLoaders.h b/include/swift/Serialization/ScanningLoaders.h index 12698ce2af8ce..d3419e1269233 100644 --- a/include/swift/Serialization/ScanningLoaders.h +++ b/include/swift/Serialization/ScanningLoaders.h @@ -34,7 +34,8 @@ class SwiftModuleScanner : public SerializedModuleLoaderBase { /// Scan the given interface file to determine dependencies. llvm::ErrorOr - scanInterfaceFile(Twine moduleInterfacePath, bool isFramework); + scanInterfaceFile(Twine moduleInterfacePath, bool isFramework, + bool isTestableImport); InterfaceSubContextDelegate &astDelegate; diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index 5b08a71f9e783..fd13631f17342 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -24,6 +24,7 @@ namespace swift { class ModuleFile; class PathObfuscator; +class ModuleFileSharedCore; enum class ModuleLoadingBehavior; namespace file_types { enum ID : uint8_t; @@ -162,22 +163,18 @@ class SerializedModuleLoaderBase : public ModuleLoader { } /// Scan the given serialized module file to determine dependencies. - llvm::ErrorOr scanModuleFile(Twine modulePath, bool isFramework); + llvm::ErrorOr + scanModuleFile(Twine modulePath, bool isFramework, bool isTestableImport); struct BinaryModuleImports { llvm::StringSet<> moduleImports; std::string headerImport; }; - static llvm::ErrorOr - getImportsOfModule(Twine modulePath, + static BinaryModuleImports + getImportsOfModule(const ModuleFileSharedCore &loadedModule, ModuleLoadingBehavior transitiveBehavior, - bool isFramework, - bool isRequiredOSSAModules, - StringRef SDKName, - StringRef packageName, - llvm::vfs::FileSystem *fileSystem, - PathObfuscator &recoverer); + StringRef packageName); /// Load the module file into a buffer and also collect its module name. static std::unique_ptr diff --git a/lib/Serialization/ScanningLoaders.cpp b/lib/Serialization/ScanningLoaders.cpp index 3cf6dec7769cb..0bb53171a8c37 100644 --- a/lib/Serialization/ScanningLoaders.cpp +++ b/lib/Serialization/ScanningLoaders.cpp @@ -33,6 +33,7 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/VirtualFileSystem.h" #include +#include using namespace swift; @@ -55,7 +56,8 @@ std::error_code SwiftModuleScanner::findModuleFilesInDirectory( if (LoadMode == ModuleLoadingMode::OnlySerialized || !InPath) { if (fs.exists(ModPath)) { // The module file will be loaded directly. - auto dependencies = scanModuleFile(ModPath, IsFramework); + auto dependencies = + scanModuleFile(ModPath, IsFramework, isTestableDependencyLookup); if (dependencies) { this->dependencies = std::move(dependencies.get()); return std::error_code(); @@ -66,7 +68,8 @@ std::error_code SwiftModuleScanner::findModuleFilesInDirectory( } assert(InPath); - auto dependencies = scanInterfaceFile(*InPath, IsFramework); + auto dependencies = + scanInterfaceFile(*InPath, IsFramework, isTestableDependencyLookup); if (dependencies) { this->dependencies = std::move(dependencies.get()); return std::error_code(); @@ -133,7 +136,7 @@ static std::vector getCompiledCandidates(ASTContext &ctx, llvm::ErrorOr SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath, - bool isFramework) { + bool isFramework, bool isTestableImport) { // Create a module filename. // FIXME: Query the module interface loader to determine an appropriate // name for the module, which includes an appropriate hash. @@ -156,12 +159,16 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath, !Ctx.SearchPathOpts.NoScannerModuleValidation) { assert(compiledCandidates.size() == 1 && "Should only have 1 candidate module"); - auto BinaryDep = scanModuleFile(compiledCandidates[0], isFramework); - if (!BinaryDep) - return BinaryDep.getError(); + auto BinaryDep = scanModuleFile(compiledCandidates[0], isFramework, + isTestableImport); + if (BinaryDep) { + Result = *BinaryDep; + return std::error_code(); + } - Result = *BinaryDep; - return std::error_code(); + // If return no such file, just fallback to use interface. + if (BinaryDep.getError() != std::errc::no_such_file_or_directory) + return BinaryDep.getError(); } std::vector Args(BaseArgs.begin(), BaseArgs.end()); diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index a99e3b8539600..d63c8c1a4082e 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -392,29 +392,13 @@ std::error_code SerializedModuleLoaderBase::openModuleFile( return std::error_code(); } -llvm::ErrorOr +SerializedModuleLoaderBase::BinaryModuleImports SerializedModuleLoaderBase::getImportsOfModule( - Twine modulePath, ModuleLoadingBehavior transitiveBehavior, - bool isFramework, bool isRequiredOSSAModules, StringRef SDKName, - StringRef packageName, llvm::vfs::FileSystem *fileSystem, - PathObfuscator &recoverer) { - auto moduleBuf = fileSystem->getBufferForFile(modulePath); - if (!moduleBuf) - return moduleBuf.getError(); - + const ModuleFileSharedCore &loadedModuleFile, + ModuleLoadingBehavior transitiveBehavior, StringRef packageName) { llvm::StringSet<> importedModuleNames; std::string importedHeader = ""; - std::shared_ptr loadedModuleFile; - serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load( - "", "", std::move(moduleBuf.get()), nullptr, nullptr, isFramework, - isRequiredOSSAModules, - SDKName, recoverer, loadedModuleFile); - - // If failed to load, just ignore and return do not found. - if (loadInfo.status != serialization::Status::Valid) - return std::make_error_code(std::errc::no_such_file_or_directory); - - for (const auto &dependency : loadedModuleFile->getDependencies()) { + for (const auto &dependency : loadedModuleFile.getDependencies()) { if (dependency.isHeader()) { assert(importedHeader.empty() && "Unexpected more than one header dependency"); @@ -423,11 +407,11 @@ SerializedModuleLoaderBase::getImportsOfModule( } ModuleLoadingBehavior dependencyTransitiveBehavior = - loadedModuleFile->getTransitiveLoadingBehavior( + loadedModuleFile.getTransitiveLoadingBehavior( dependency, /*debuggerMode*/ false, /*isPartialModule*/ false, packageName, - loadedModuleFile->isTestable()); + loadedModuleFile.isTestable()); if (dependencyTransitiveBehavior > transitiveBehavior) continue; @@ -441,41 +425,60 @@ SerializedModuleLoaderBase::getImportsOfModule( importedModuleNames.insert(moduleName); } - return SerializedModuleLoaderBase::BinaryModuleImports{importedModuleNames, importedHeader}; + return SerializedModuleLoaderBase::BinaryModuleImports{importedModuleNames, + importedHeader}; } llvm::ErrorOr -SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework) { +SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework, + bool isTestableImport) { const std::string moduleDocPath; const std::string sourceInfoPath; + + // Read and valid module. + auto moduleBuf = Ctx.SourceMgr.getFileSystem()->getBufferForFile(modulePath); + if (!moduleBuf) + return moduleBuf.getError(); + + std::shared_ptr loadedModuleFile; + serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load( + "", "", std::move(moduleBuf.get()), nullptr, nullptr, isFramework, + isRequiredOSSAModules(), Ctx.LangOpts.SDKName, + Ctx.SearchPathOpts.DeserializedPathRecoverer, loadedModuleFile); + + if (!Ctx.SearchPathOpts.NoScannerModuleValidation) { + // If failed to load, just ignore and return do not found. + if (loadInfo.status != serialization::Status::Valid) { + if (Ctx.LangOpts.EnableModuleLoadingRemarks) + Ctx.Diags.diagnose(SourceLoc(), diag::skip_module_invalid, + modulePath.str()); + return std::make_error_code(std::errc::no_such_file_or_directory); + } + + if (loadedModuleFile->isTestable() && !isTestableImport) { + if (Ctx.LangOpts.EnableModuleLoadingRemarks) + Ctx.Diags.diagnose(SourceLoc(), diag::skip_module_testable, + modulePath.str()); + return std::make_error_code(std::errc::no_such_file_or_directory); + } + } + // Some transitive dependencies of binary modules are not required to be // imported during normal builds. // TODO: This is worth revisiting for debugger purposes where // loading the module is optional, and implementation-only imports // from modules with testing enabled where the dependency is // optional. - ModuleLoadingBehavior transitiveLoadingBehavior = - ModuleLoadingBehavior::Required; - auto binaryModuleImports = getImportsOfModule( - modulePath, transitiveLoadingBehavior, isFramework, - isRequiredOSSAModules(), - Ctx.LangOpts.SDKName, Ctx.LangOpts.PackageName, - Ctx.SourceMgr.getFileSystem().get(), - Ctx.SearchPathOpts.DeserializedPathRecoverer); - if (!binaryModuleImports) - return binaryModuleImports.getError(); + auto binaryModuleImports = + getImportsOfModule(*loadedModuleFile, ModuleLoadingBehavior::Required, + Ctx.LangOpts.PackageName); // Lookup optional imports of this module also - auto binaryModuleOptionalImports = getImportsOfModule( - modulePath, ModuleLoadingBehavior::Optional, isFramework, - isRequiredOSSAModules(), - Ctx.LangOpts.SDKName, Ctx.LangOpts.PackageName, - Ctx.SourceMgr.getFileSystem().get(), - Ctx.SearchPathOpts.DeserializedPathRecoverer); - if (!binaryModuleOptionalImports) - return binaryModuleImports.getError(); + auto binaryModuleOptionalImports = + getImportsOfModule(*loadedModuleFile, ModuleLoadingBehavior::Optional, + Ctx.LangOpts.PackageName); - auto importedModuleSet = binaryModuleImports.get().moduleImports; + auto importedModuleSet = binaryModuleImports.moduleImports; std::vector importedModuleNames; importedModuleNames.reserve(importedModuleSet.size()); llvm::transform(importedModuleSet.keys(), @@ -484,8 +487,8 @@ SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework) { return N.str(); }); - auto importedHeader = binaryModuleImports.get().headerImport; - auto &importedOptionalModuleSet = binaryModuleOptionalImports.get().moduleImports; + auto importedHeader = binaryModuleImports.headerImport; + auto &importedOptionalModuleSet = binaryModuleOptionalImports.moduleImports; std::vector importedOptionalModuleNames; for (const auto optionalImportedModule : importedOptionalModuleSet.keys()) if (!importedModuleSet.contains(optionalImportedModule)) @@ -794,7 +797,8 @@ bool SerializedModuleLoaderBase::findModule( auto result = findModuleFilesInDirectory( moduleID, absoluteBaseName, moduleInterfacePath, moduleInterfaceSourcePath, moduleBuffer, moduleDocBuffer, - moduleSourceInfoBuffer, skipBuildingInterface, isFramework); + moduleSourceInfoBuffer, skipBuildingInterface, isFramework, + isTestableDependencyLookup); if (!result) return true; if (result == std::errc::not_supported) diff --git a/test/ScanDependencies/testable-dependencies.swift b/test/ScanDependencies/testable-dependencies.swift new file mode 100644 index 0000000000000..b16300be032e1 --- /dev/null +++ b/test/ScanDependencies/testable-dependencies.swift @@ -0,0 +1,78 @@ +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +// RUN: %target-swift-frontend -emit-module -module-name B -o %t/internal/B.swiftmodule -swift-version 5 \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ +// RUN: -emit-module-interface-path %t/internal/B.swiftinterface -enable-library-evolution -I %t \ +// RUN: %t/B.swift + +// RUN: %target-swift-frontend -emit-module -module-name A -o %t/testable/A.swiftmodule -swift-version 5 \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ +// RUN: -emit-module-interface-path %t/testable/A.swiftinterface -enable-library-evolution -I %t/internal -enable-testing \ +// RUN: %t/A.swift + +// RUN: %target-swift-frontend -emit-module -module-name A -o %t/regular/A.swiftmodule -swift-version 5 \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ +// RUN: -emit-module-interface-path %t/regular/A.swiftinterface -enable-library-evolution -I %t/internal \ +// RUN: %t/A.swift + +/// Import testable build, should use interface. +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-serialized -module-name Test %t/main.swift \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ +// RUN: -o %t/deps1.json -I %t/testable -swift-version 5 -Rmodule-loading 2>&1 | %FileCheck %s --check-prefix DIAG +// DIAG: remark: skip swiftmodule built with '-enable-testing' +// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps1.json Test directDependencies | %FileCheck %s --check-prefix TEST1 +// TEST1: "swift": "A" +// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps1.json A directDependencies | %FileCheck %s --check-prefix EMPTY --allow-empty +// EMPTY-NOT: B + +/// Import regular build, should use binary. +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-serialized -module-name Test %t/main.swift \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ +// RUN: -o %t/deps2.json -I %t/regular -swift-version 5 -Rmodule-loading +// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps2.json Test directDependencies | %FileCheck %s --check-prefix TEST2 +// TEST2: "swiftPrebuiltExternal": "A" +// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps2.json swiftPrebuiltExternal:A directDependencies | %FileCheck %s --check-prefix EMPTY --allow-empty + +/// Testable import testable build, should use binary, even interface is preferred. +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-name Test %t/testable.swift \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -enable-testing \ +// RUN: -o %t/deps3.json -I %t/testable -I %t/internal -swift-version 5 -Rmodule-loading +// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps3.json Test directDependencies | %FileCheck %s --check-prefix TEST3 +// TEST3: "swiftPrebuiltExternal": "A" +// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps3.json swiftPrebuiltExternal:A directDependencies | %FileCheck %s --check-prefix TEST3-A +// TEST3-A: "swift": "B" + +/// Testable import non-testable build without enable testing. +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-name Test %t/testable.swift \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ +// RUN: -o %t/deps4.json -I %t/regular -swift-version 5 +// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps4.json Test directDependencies | %FileCheck %s --check-prefix TEST4 +// TEST4: "swiftPrebuiltExternal": "A" +// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps4.json swiftPrebuiltExternal:A directDependencies | %FileCheck %s --check-prefix EMPTY --allow-empty + +/// Testable import non-testable build enable testing, still succeed since swift-frontend can provide a better diagnostics when the module is actually imported. +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-name Test %t/testable.swift \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -enable-testing \ +// RUN: -o %t/deps5.json -I %t/regular -swift-version 5 -Rmodule-loading + +/// Regular import a testable module with no interface, this is a dependency scanning error. +// RUN: rm %t/testable/A.swiftinterface +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-name Test %t/main.swift \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -enable-testing \ +// RUN: -o %t/deps6.json -I %t/testable -swift-version 5 -Rmodule-loading 2>&1 | %FileCheck %s --check-prefix ERROR +// ERROR: error: Unable to find module dependency: 'A' + +//--- main.swift +import A + +//--- testable.swift +@testable import A + +//--- A.swift +internal import B +@_spi(Testing) public func a() {} + +//--- B.swift +public func b() {} + From 071e6e9c7b5d79509855d17e1df1c48fb9bea973 Mon Sep 17 00:00:00 2001 From: Steven Wu Date: Mon, 18 Dec 2023 15:53:26 -0800 Subject: [PATCH 3/6] [Caching] Preliminary simple macro support for caching Preliminary caching support for macro: * Inserting the plugin into the CASFS * Lookup plugin via physical file system For future better support, we should teach dependency scanner to resolve macros and return the resolved plugins to swift-frontend. rdar://121873571 (cherry picked from commit daa1065304861375fd540b48f03f05a853c2a656) --- lib/AST/ModuleDependencies.cpp | 53 ++++++++++++++++++++ lib/AST/PluginLoader.cpp | 16 ++++-- lib/Sema/TypeCheckMacros.cpp | 4 +- test/CAS/macro_option_set.swift | 53 ++++++++++++++++++++ test/CAS/macro_plugin.swift | 73 ++++++++++++++++++++++++++++ test/CAS/macro_plugin_external.swift | 73 ++++++++++++++++++++++++++++ 6 files changed, 268 insertions(+), 4 deletions(-) create mode 100644 test/CAS/macro_option_set.swift create mode 100644 test/CAS/macro_plugin.swift create mode 100644 test/CAS/macro_plugin_external.swift diff --git a/lib/AST/ModuleDependencies.cpp b/lib/AST/ModuleDependencies.cpp index 0210d0a8084fa..8f425281e69e5 100644 --- a/lib/AST/ModuleDependencies.cpp +++ b/lib/AST/ModuleDependencies.cpp @@ -21,6 +21,7 @@ #include "swift/Frontend/Frontend.h" #include "llvm/CAS/CASProvidingFileSystem.h" #include "llvm/CAS/CachingOnDiskFileSystem.h" +#include "llvm/Config/config.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrefixMapper.h" @@ -480,6 +481,58 @@ void SwiftDependencyTracker::addCommonSearchPathDeps( // Add VFSOverlay file. for (auto &Overlay: Opts.VFSOverlayFiles) FS->status(Overlay); + + // Add plugin dylibs from the toolchain only by look through the plugin search + // directory. + auto recordFiles = [&](StringRef Path) { + std::error_code EC; + for (auto I = FS->dir_begin(Path, EC); + !EC && I != llvm::vfs::directory_iterator(); I = I.increment(EC)) { + if (I->type() != llvm::sys::fs::file_type::regular_file) + continue; +#if defined(_WIN32) + constexpr StringRef libPrefix{}; + constexpr StringRef libSuffix = ".dll"; +#else + constexpr StringRef libPrefix = "lib"; + constexpr StringRef libSuffix = LTDL_SHLIB_EXT; +#endif + StringRef filename = llvm::sys::path::filename(I->path()); + if (filename.starts_with(libPrefix) && filename.ends_with(libSuffix)) + FS->status(I->path()); + } + }; + for (auto &entry : Opts.PluginSearchOpts) { + switch (entry.getKind()) { + + // '-load-plugin-library '. + case PluginSearchOption::Kind::LoadPluginLibrary: { + auto &val = entry.get(); + FS->status(val.LibraryPath); + break; + } + + // '-load-plugin-executable #, ...'. + case PluginSearchOption::Kind::LoadPluginExecutable: { + // We don't have executable plugin in toolchain. + break; + } + + // '-plugin-path '. + case PluginSearchOption::Kind::PluginPath: { + auto &val = entry.get(); + recordFiles(val.SearchPath); + break; + } + + // '-external-plugin-path #'. + case PluginSearchOption::Kind::ExternalPluginPath: { + auto &val = entry.get(); + recordFiles(val.SearchPath); + break; + } + } + } } void SwiftDependencyTracker::startTracking() { diff --git a/lib/AST/PluginLoader.cpp b/lib/AST/PluginLoader.cpp index 658b28348e1d4..95f1b01ed24a8 100644 --- a/lib/AST/PluginLoader.cpp +++ b/lib/AST/PluginLoader.cpp @@ -17,6 +17,7 @@ #include "swift/Basic/SourceManager.h" #include "swift/Parse/Lexer.h" #include "llvm/Config/config.h" +#include "llvm/Support/VirtualFileSystem.h" using namespace swift; @@ -59,6 +60,15 @@ static StringRef pluginModuleNameStringFromPath(StringRef path) { return ""; } +static llvm::IntrusiveRefCntPtr +getPluginLoadingFS(ASTContext &Ctx) { + // If there is a clang include tree FS, using real file system to load plugin + // as the FS in SourceMgr doesn't support directory iterator. + if (Ctx.ClangImporterOpts.HasClangIncludeTreeRoot) + return llvm::vfs::getRealFileSystem(); + return Ctx.SourceMgr.getFileSystem(); +} + llvm::DenseMap & PluginLoader::getPluginMap() { if (PluginMap.has_value()) { @@ -86,7 +96,7 @@ PluginLoader::getPluginMap() { (void)result; }; - auto fs = Ctx.SourceMgr.getFileSystem(); + auto fs = getPluginLoadingFS(Ctx); std::error_code ec; for (auto &entry : Ctx.SearchPathOpts.PluginSearchOpts) { @@ -162,7 +172,7 @@ PluginLoader::lookupPluginByModuleName(Identifier moduleName) { llvm::Expected PluginLoader::loadLibraryPlugin(StringRef path) { - auto fs = Ctx.SourceMgr.getFileSystem(); + auto fs = getPluginLoadingFS(Ctx); SmallString<128> resolvedPath; if (auto err = fs->getRealPath(path, resolvedPath)) { return llvm::createStringError(err, err.message()); @@ -186,7 +196,7 @@ PluginLoader::loadLibraryPlugin(StringRef path) { llvm::Expected PluginLoader::loadExecutablePlugin(StringRef path) { - auto fs = Ctx.SourceMgr.getFileSystem(); + auto fs = getPluginLoadingFS(Ctx); SmallString<128> resolvedPath; if (auto err = fs->getRealPath(path, resolvedPath)) { return llvm::createStringError(err, err.message()); diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index 84a0d273f150f..efdcc35414c02 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -290,7 +290,9 @@ initializeExecutablePlugin(ASTContext &ctx, if (!libraryPath.empty()) { #if SWIFT_BUILD_SWIFT_SYNTAX llvm::SmallString<128> resolvedLibraryPath; - auto fs = ctx.SourceMgr.getFileSystem(); + auto fs = ctx.ClangImporterOpts.HasClangIncludeTreeRoot + ? llvm::vfs::getRealFileSystem() + : ctx.SourceMgr.getFileSystem(); if (auto err = fs->getRealPath(libraryPath, resolvedLibraryPath)) { return llvm::createStringError(err, err.message()); } diff --git a/test/CAS/macro_option_set.swift b/test/CAS/macro_option_set.swift new file mode 100644 index 0000000000000..f2e95a4dd749b --- /dev/null +++ b/test/CAS/macro_option_set.swift @@ -0,0 +1,53 @@ +// REQUIRES: swift_swift_parser + +// RUN: %empty-directory(%t) + +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-serialized -module-name MyApp -module-cache-path %t/clang-module-cache -O \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \ +// RUN: %s -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas -plugin-path %swift-plugin-dir + +// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json MyApp casFSRootID > %t/fs.casid +// RUN: llvm-cas -cas %t/cas -ls-tree-recursive @%t/fs.casid | %FileCheck %s --check-prefix=FS + +// FS: SwiftMacros + +// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:SwiftShims > %t/SwiftShims.cmd +// RUN: %swift_frontend_plain @%t/SwiftShims.cmd + +// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json MyApp > %t/MyApp.cmd +// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps.json > %t/map.json +// RUN: llvm-cas --cas %t/cas --make-blob --data %t/map.json > %t/map.casid + +// RUN: %target-swift-frontend \ +// RUN: -typecheck -verify -cache-compile-job -cas-path %t/cas \ +// RUN: -swift-version 5 -disable-implicit-swift-modules \ +// RUN: -plugin-path %swift-plugin-dir \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \ +// RUN: -module-name MyApp -explicit-swift-module-map-file @%t/map.casid \ +// RUN: %s @%t/MyApp.cmd + +import Swift + +@attached(member, names: named(RawValue), named(rawValue), named(`init`), arbitrary) +@attached(extension, conformances: OptionSet) +public macro OptionSet() = + #externalMacro(module: "SwiftMacros", type: "OptionSetMacro") + +@OptionSet +struct ShippingOptions { + private enum Options: Int { + case nextDay + case secondDay + case priority + case standard + } + + static let express: ShippingOptions = [.nextDay, .secondDay] + static let all: ShippingOptions = [.express, .priority, .standard] +} + +let options = ShippingOptions.express +assert(options.contains(.nextDay)) +assert(options.contains(.secondDay)) +assert(!options.contains(.standard)) + diff --git a/test/CAS/macro_plugin.swift b/test/CAS/macro_plugin.swift new file mode 100644 index 0000000000000..71c26e32b675e --- /dev/null +++ b/test/CAS/macro_plugin.swift @@ -0,0 +1,73 @@ +// REQUIRES: swift_swift_parser + +/// Test loading and external library through `-load-plugin-library` +/// TODO: switch this test case to use `-external-plugin-path`. + +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/plugins) +// +//== Build the plugin library +// RUN: %host-build-swift \ +// RUN: -swift-version 5 \ +// RUN: -emit-library \ +// RUN: -o %t/plugins/%target-library-name(MacroDefinition) \ +// RUN: -module-name=MacroDefinition \ +// RUN: %S/../Macros/Inputs/syntax_macro_definitions.swift \ +// RUN: -g -no-toolchain-stdlib-rpath + +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-serialized -module-name MyApp -module-cache-path %t/clang-module-cache -O \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \ +// RUN: %s -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas -load-plugin-library %t/plugins/%target-library-name(MacroDefinition) + +// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json MyApp casFSRootID > %t/fs.casid +// RUN: llvm-cas -cas %t/cas -ls-tree-recursive @%t/fs.casid | %FileCheck %s --check-prefix=FS + +// FS: MacroDefinition + +// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:SwiftShims > %t/SwiftShims.cmd +// RUN: %swift_frontend_plain @%t/SwiftShims.cmd + +// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json MyApp > %t/MyApp.cmd +// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps.json > %t/map.json +// RUN: llvm-cas --cas %t/cas --make-blob --data %t/map.json > %t/map.casid + +// RUN: %target-swift-frontend \ +// RUN: -typecheck -verify -cache-compile-job -cas-path %t/cas \ +// RUN: -swift-version 5 -disable-implicit-swift-modules \ +// RUN: -load-plugin-library %t/plugins/%target-library-name(MacroDefinition) \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \ +// RUN: -module-name MyApp -explicit-swift-module-map-file @%t/map.casid \ +// RUN: %s @%t/MyApp.cmd + +@attached(extension, conformances: P, names: named(requirement)) +macro DelegatedConformance() = #externalMacro(module: "MacroDefinition", type: "DelegatedConformanceViaExtensionMacro") + +protocol P { + static func requirement() +} + +struct Wrapped: P { + static func requirement() { + print("Wrapped.requirement") + } +} + +@DelegatedConformance +struct Generic {} + +// CHECK: {"expandMacroResult":{"diagnostics":[],"expandedSource":"extension Generic: P where Element: P {\n static func requirement() {\n Element.requirement()\n }\n}"}} + +func requiresP(_ value: (some P).Type) { + value.requirement() +} + +requiresP(Generic.self) + +struct Outer { + @DelegatedConformance + struct Nested {} +} + +// CHECK: {"expandMacroResult":{"diagnostics":[],"expandedSource":"extension Outer.Nested: P where Element: P {\n static func requirement() {\n Element.requirement()\n }\n}"}} + +requiresP(Outer.Nested.self) diff --git a/test/CAS/macro_plugin_external.swift b/test/CAS/macro_plugin_external.swift new file mode 100644 index 0000000000000..7a904f4d3172a --- /dev/null +++ b/test/CAS/macro_plugin_external.swift @@ -0,0 +1,73 @@ +// REQUIRES: swift_swift_parser + +/// Test loading and external library through `-load-plugin-library` +/// TODO: switch this test case to use `-external-plugin-path`. + +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/plugins) +// +//== Build the plugin library +// RUN: %host-build-swift \ +// RUN: -swift-version 5 \ +// RUN: -emit-library \ +// RUN: -o %t/plugins/%target-library-name(MacroDefinition) \ +// RUN: -module-name=MacroDefinition \ +// RUN: %S/../Macros/Inputs/syntax_macro_definitions.swift \ +// RUN: -g -no-toolchain-stdlib-rpath + +// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-serialized -module-name MyApp -module-cache-path %t/clang-module-cache -O \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \ +// RUN: %s -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas -external-plugin-path %t/plugins#%swift-plugin-server + +// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json MyApp casFSRootID > %t/fs.casid +// RUN: llvm-cas -cas %t/cas -ls-tree-recursive @%t/fs.casid | %FileCheck %s --check-prefix=FS + +// FS: MacroDefinition + +// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:SwiftShims > %t/SwiftShims.cmd +// RUN: %swift_frontend_plain @%t/SwiftShims.cmd + +// RUN: %S/Inputs/BuildCommandExtractor.py %t/deps.json MyApp > %t/MyApp.cmd +// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps.json > %t/map.json +// RUN: llvm-cas --cas %t/cas --make-blob --data %t/map.json > %t/map.casid + +// RUN: %target-swift-frontend \ +// RUN: -typecheck -verify -cache-compile-job -cas-path %t/cas \ +// RUN: -swift-version 5 -disable-implicit-swift-modules \ +// RUN: -external-plugin-path %t/plugins/#%swift-plugin-server \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \ +// RUN: -module-name MyApp -explicit-swift-module-map-file @%t/map.casid \ +// RUN: %s @%t/MyApp.cmd + +@attached(extension, conformances: P, names: named(requirement)) +macro DelegatedConformance() = #externalMacro(module: "MacroDefinition", type: "DelegatedConformanceViaExtensionMacro") + +protocol P { + static func requirement() +} + +struct Wrapped: P { + static func requirement() { + print("Wrapped.requirement") + } +} + +@DelegatedConformance +struct Generic {} + +// CHECK: {"expandMacroResult":{"diagnostics":[],"expandedSource":"extension Generic: P where Element: P {\n static func requirement() {\n Element.requirement()\n }\n}"}} + +func requiresP(_ value: (some P).Type) { + value.requirement() +} + +requiresP(Generic.self) + +struct Outer { + @DelegatedConformance + struct Nested {} +} + +// CHECK: {"expandMacroResult":{"diagnostics":[],"expandedSource":"extension Outer.Nested: P where Element: P {\n static func requirement() {\n Element.requirement()\n }\n}"}} + +requiresP(Outer.Nested.self) From dfa91a221ab6f50e9c16f0ea995612871e46733e Mon Sep 17 00:00:00 2001 From: Steven Wu Date: Wed, 3 Apr 2024 08:50:34 -0700 Subject: [PATCH 4/6] [Caching] Embed bridging header in binary module correctly when caching When caching is enabled with include-tree, the bridging header PCH is created from the include tree directly. Setup the rewriter correctly when embedding the bridging header into swift binary module. rdar://125719747 (cherry picked from commit 7a68d364f449efdf4f7437a9f51d294971ae3977) --- .../swift/AST/DiagnosticsClangImporter.def | 2 + include/swift/ClangImporter/ClangImporter.h | 6 +- lib/ClangImporter/ClangImporter.cpp | 70 +++++++++++++++++-- lib/ClangImporter/ImporterImpl.h | 1 + lib/Serialization/Serialization.cpp | 18 +++-- test/CAS/bridging-header.swift | 57 ++++++++++++++- 6 files changed, 137 insertions(+), 17 deletions(-) diff --git a/include/swift/AST/DiagnosticsClangImporter.def b/include/swift/AST/DiagnosticsClangImporter.def index 600709b3f2805..288f23b9d4c5d 100644 --- a/include/swift/AST/DiagnosticsClangImporter.def +++ b/include/swift/AST/DiagnosticsClangImporter.def @@ -42,6 +42,8 @@ WARNING(could_not_rewrite_bridging_header,none, ERROR(bridging_header_pch_error,Fatal, "failed to emit precompiled header '%0' for bridging header '%1'", (StringRef, StringRef)) +ERROR(err_rewrite_bridging_header,none, + "failed to serialize bridging header: '%0'", (StringRef)) ERROR(emit_pcm_error,Fatal, "failed to emit precompiled module '%0' for module map '%1'", diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index e5fc22588da83..01d6415d525d1 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -402,8 +402,10 @@ class ClangImporter final : public ClangModuleLoader { getWrapperForModule(const clang::Module *mod, bool returnOverlayIfPossible = false) const override; - std::string getBridgingHeaderContents(StringRef headerPath, off_t &fileSize, - time_t &fileModTime); + std::string + getBridgingHeaderContents(StringRef headerPath, off_t &fileSize, + time_t &fileModTime, + StringRef pchIncludeTree); /// Makes a temporary replica of the ClangImporter's CompilerInstance, reads /// an Objective-C header file into the replica and emits a PCH file of its diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index a9b15c6871231..2b7b55ed87bb7 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -55,13 +55,16 @@ #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileEntry.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangStandard.h" #include "clang/Basic/Module.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" #include "clang/CAS/CASOptions.h" +#include "clang/CAS/IncludeTree.h" #include "clang/CodeGen/ObjectFilePCHContainerOperations.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/IncludeTreePPActions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Frontend/Utils.h" #include "clang/Index/IndexingAction.h" @@ -80,7 +83,11 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/CAS/CASReference.h" +#include "llvm/CAS/ObjectStore.h" #include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileCollector.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Memory.h" @@ -1752,16 +1759,46 @@ bool ClangImporter::importBridgingHeader(StringRef header, ModuleDecl *adapter, std::move(sourceBuffer), implicitImport); } -std::string ClangImporter::getBridgingHeaderContents(StringRef headerPath, - off_t &fileSize, - time_t &fileModTime) { +static llvm::Expected +setupIncludeTreeInput(clang::CompilerInvocation &invocation, + StringRef headerPath, StringRef pchIncludeTree) { + auto DB = invocation.getCASOpts().getOrCreateDatabases(); + if (!DB) + return DB.takeError(); + auto CAS = DB->first; + auto ID = CAS->parseID(pchIncludeTree); + if (!ID) + return ID.takeError(); + auto includeTreeRef = CAS->getReference(*ID); + if (!includeTreeRef) + return llvm::cas::ObjectStore::createUnknownObjectError(*ID); + + invocation.getFrontendOpts().Inputs.push_back(clang::FrontendInputFile( + *includeTreeRef, headerPath, clang::Language::ObjC)); + + return *includeTreeRef; +} + +std::string ClangImporter::getBridgingHeaderContents( + StringRef headerPath, off_t &fileSize, time_t &fileModTime, + StringRef pchIncludeTree) { auto invocation = std::make_shared(*Impl.Invocation); invocation->getFrontendOpts().DisableFree = false; invocation->getFrontendOpts().Inputs.clear(); - invocation->getFrontendOpts().Inputs.push_back( - clang::FrontendInputFile(headerPath, clang::Language::ObjC)); + + std::optional includeTreeRef; + if (pchIncludeTree.empty()) + invocation->getFrontendOpts().Inputs.push_back( + clang::FrontendInputFile(headerPath, clang::Language::ObjC)); + else if (auto err = + setupIncludeTreeInput(*invocation, headerPath, pchIncludeTree) + .moveInto(includeTreeRef)) { + Impl.diagnose({}, diag::err_rewrite_bridging_header, + toString(std::move(err))); + return ""; + } invocation->getPreprocessorOpts().resetNonModularOptions(); @@ -1782,18 +1819,36 @@ std::string ClangImporter::getBridgingHeaderContents(StringRef headerPath, // write to an in-memory buffer. class RewriteIncludesAction : public clang::PreprocessorFrontendAction { raw_ostream &OS; + std::optional includeTreeRef; void ExecuteAction() override { clang::CompilerInstance &compiler = getCompilerInstance(); + // If the input is include tree, setup the IncludeTreePPAction. + if (includeTreeRef) { + auto IncludeTreeRoot = clang::cas::IncludeTreeRoot::get( + compiler.getOrCreateObjectStore(), *includeTreeRef); + if (!IncludeTreeRoot) + llvm::report_fatal_error(IncludeTreeRoot.takeError()); + auto PPCachedAct = + clang::createPPActionsFromIncludeTree(*IncludeTreeRoot); + if (!PPCachedAct) + llvm::report_fatal_error(PPCachedAct.takeError()); + compiler.getPreprocessor().setPPCachedActions( + std::move(*PPCachedAct)); + } + clang::RewriteIncludesInInput(compiler.getPreprocessor(), &OS, compiler.getPreprocessorOutputOpts()); } + public: - explicit RewriteIncludesAction(raw_ostream &os) : OS(os) {} + explicit RewriteIncludesAction( + raw_ostream &os, std::optional includeTree) + : OS(os), includeTreeRef(includeTree) {} }; llvm::raw_string_ostream os(result); - RewriteIncludesAction action(os); + RewriteIncludesAction action(os, includeTreeRef); rewriteInstance.ExecuteAction(action); }); @@ -2514,6 +2569,7 @@ ClangImporter::Implementation::Implementation( !ctx.ClangImporterOpts.BridgingHeader.empty()), DisableOverlayModules(ctx.ClangImporterOpts.DisableOverlayModules), EnableClangSPI(ctx.ClangImporterOpts.EnableClangSPI), + UseClangIncludeTree(ctx.ClangImporterOpts.UseClangIncludeTree), importSymbolicCXXDecls( ctx.LangOpts.hasFeature(Feature::ImportSymbolicCXXDecls)), IsReadingBridgingPCH(false), diff --git a/lib/ClangImporter/ImporterImpl.h b/lib/ClangImporter/ImporterImpl.h index c31d51f4279d4..094b06e7aa02e 100644 --- a/lib/ClangImporter/ImporterImpl.h +++ b/lib/ClangImporter/ImporterImpl.h @@ -467,6 +467,7 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation const bool BridgingHeaderExplicitlyRequested; const bool DisableOverlayModules; const bool EnableClangSPI; + const bool UseClangIncludeTree; bool importSymbolicCXXDecls; bool IsReadingBridgingPCH; diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index ce21cc0863e84..3e44ab7148a7d 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -1320,21 +1320,25 @@ void Serializer::writeInputBlock() { time_t importedHeaderModTime = 0; std::string contents; auto importedHeaderPath = Options.ImportedHeader; + std::string pchIncludeTree; // We do not want to serialize the explicitly-specified .pch path if one was // provided. Instead we write out the path to the original header source so // that clients can consume it. if (Options.ExplicitModuleBuild && llvm::sys::path::extension(importedHeaderPath) - .endswith(file_types::getExtension(file_types::TY_PCH))) - importedHeaderPath = clangImporter->getClangInstance() - .getASTReader() - ->getModuleManager() - .lookupByFileName(importedHeaderPath) - ->OriginalSourceFileName; + .ends_with(file_types::getExtension(file_types::TY_PCH))) { + auto *pch = clangImporter->getClangInstance() + .getASTReader() + ->getModuleManager() + .lookupByFileName(importedHeaderPath); + pchIncludeTree = pch->IncludeTreeID; + importedHeaderPath = pch->OriginalSourceFileName; + } if (!importedHeaderPath.empty()) { contents = clangImporter->getBridgingHeaderContents( - importedHeaderPath, importedHeaderSize, importedHeaderModTime); + importedHeaderPath, importedHeaderSize, importedHeaderModTime, + pchIncludeTree); } assert(publicImportSet.count(bridgingHeaderImport)); ImportedHeader.emit(ScratchRecord, diff --git a/test/CAS/bridging-header.swift b/test/CAS/bridging-header.swift index cae66faa194ae..52c6cd722d933 100644 --- a/test/CAS/bridging-header.swift +++ b/test/CAS/bridging-header.swift @@ -1,6 +1,11 @@ // RUN: %empty-directory(%t) // RUN: split-file %s %t +// RUN: %target-swift-frontend -emit-module -o %t/temp.swiftmodule -module-name Test -swift-version 5 \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \ +// RUN: -Xcc -fmodule-map-file=%t/a.modulemap -Xcc -fmodule-map-file=%t/b.modulemap -import-objc-header %t/Bridging.h \ +// RUN: %t/test.swift + // RUN: %target-swift-frontend -scan-dependencies -module-name Test -module-cache-path %t/clang-module-cache -O \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \ // RUN: %t/test.swift -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas \ @@ -27,9 +32,57 @@ // CHECK-NEXT: "-Xcc", // CHECK-NEXT: "llvmcas://{{.*}}" +/// Try build then import from a non-caching compilation. + +// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:SwiftShims > %t/shim.cmd +// RUN: %swift_frontend_plain @%t/shim.cmd +// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:B > %t/B.cmd +// RUN: %swift_frontend_plain @%t/B.cmd +// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json clang:A > %t/A.cmd +// RUN: %swift_frontend_plain @%t/A.cmd + +// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps.json > %t/map.json +// RUN: llvm-cas --cas %t/cas --make-blob --data %t/map.json > %t/map.casid + +// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json bridgingHeader | tail -n +2 > %t/header.cmd +// RUN: %target-swift-frontend @%t/header.cmd -disable-implicit-swift-modules %t/Bridging.h -O -o %t/bridging.pch +// RUN: %cache-tool -cas-path %t/cas -cache-tool-action print-output-keys -- \ +// RUN: %target-swift-frontend @%t/header.cmd -disable-implicit-swift-modules %t/Bridging.h -O -o %t/bridging.pch > %t/keys.json +// RUN: %{python} %S/Inputs/ExtractOutputKey.py %t/keys.json %t/Bridging.h > %t/key + +// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json Test > %t/MyApp.cmd +// RUN: echo "\"-disable-implicit-string-processing-module-import\"" >> %t/MyApp.cmd +// RUN: echo "\"-disable-implicit-concurrency-module-import\"" >> %t/MyApp.cmd +// RUN: echo "\"-disable-implicit-swift-modules\"" >> %t/MyApp.cmd +// RUN: echo "\"-import-objc-header\"" >> %t/MyApp.cmd +// RUN: echo "\"%t/bridging.pch\"" >> %t/MyApp.cmd +// RUN: echo "\"-bridging-header-pch-key\"" >> %t/MyApp.cmd +// RUN: echo "\"@%t/key\"" >> %t/MyApp.cmd +// RUN: echo "\"-explicit-swift-module-map-file\"" >> %t/MyApp.cmd +// RUN: echo "\"@%t/map.casid\"" >> %t/MyApp.cmd + +// RUN: %target-swift-frontend -cache-compile-job -module-name Test -O -cas-path %t/cas @%t/MyApp.cmd %t/test.swift \ +// RUN: -emit-module -o %t/Test.swiftmodule + +// RUN: %target-swift-frontend -typecheck -module-name User -swift-version 5 \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \ +// RUN: -Xcc -fmodule-map-file=%t/a.modulemap -Xcc -fmodule-map-file=%t/b.modulemap \ +// RUN: -I %t %t/user.swift + //--- test.swift import B -public func test() {} +public func test() { + b() +} +public class TestB: B {} + +//--- user.swift +import Test + +func user() { + var b: TestB + test() +} //--- Bridging.h #include "Foo.h" @@ -42,6 +95,8 @@ public func test() {} //--- b.h void b(void); +@interface B +@end //--- a.modulemap module A { From 9c65afaa532facc34a9adc145bbf25c16114cf3f Mon Sep 17 00:00:00 2001 From: Steven Wu Date: Fri, 5 Apr 2024 17:30:23 -0700 Subject: [PATCH 5/6] [BridgingHeader] Implicit import bridging header from CAS module The binary module built from a CAS build will have the embeded bridging header info with 0 modTime. Allow a regular build to import such a module with the same behavior as if the module is built from a regular build. rdar://126221616 (cherry picked from commit e654e371de66b078a2f820475be99d512c08fef3) --- lib/ClangImporter/ClangImporter.cpp | 7 +++++- test/CAS/bridging-header.swift | 37 +++++++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 2b7b55ed87bb7..ec580ce31c305 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -1703,8 +1703,13 @@ bool ClangImporter::importHeader(StringRef header, ModuleDecl *adapter, StringRef cachedContents, SourceLoc diagLoc) { clang::FileManager &fileManager = Impl.Instance->getFileManager(); auto headerFile = fileManager.getFile(header, /*OpenFile=*/true); + // Prefer importing the header directly if the header content matches by + // checking size and mod time. This allows correct import if some no-modular + // headers are already imported into clang importer. If mod time is zero, then + // the module should be built from CAS and there is no mod time to verify. if (headerFile && (*headerFile)->getSize() == expectedSize && - (*headerFile)->getModificationTime() == expectedModTime) { + (expectedModTime == 0 || + (*headerFile)->getModificationTime() == expectedModTime)) { return importBridgingHeader(header, adapter, diagLoc, false, true); } diff --git a/test/CAS/bridging-header.swift b/test/CAS/bridging-header.swift index 52c6cd722d933..bc0691e9af0f9 100644 --- a/test/CAS/bridging-header.swift +++ b/test/CAS/bridging-header.swift @@ -1,3 +1,4 @@ +// REQUIRES: objc_interop // RUN: %empty-directory(%t) // RUN: split-file %s %t @@ -64,13 +65,28 @@ // RUN: %target-swift-frontend -cache-compile-job -module-name Test -O -cas-path %t/cas @%t/MyApp.cmd %t/test.swift \ // RUN: -emit-module -o %t/Test.swiftmodule +/// Importing binary module with bridging header built from CAS from a regluar build. +/// This should succeed even it is also importing a bridging header that shares same header dependencies (with proper header guard). // RUN: %target-swift-frontend -typecheck -module-name User -swift-version 5 \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \ // RUN: -Xcc -fmodule-map-file=%t/a.modulemap -Xcc -fmodule-map-file=%t/b.modulemap \ -// RUN: -I %t %t/user.swift +// RUN: -I %t %t/user.swift -import-objc-header %t/Bridging2.h + +/// Importing binary module with bridging header built from CAS from a cached build. This should work without additional bridging header deps. +// RUN: %target-swift-frontend -scan-dependencies -module-name User -module-cache-path %t/clang-module-cache -O \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \ +// RUN: %t/user.swift -o %t/deps2.json -swift-version 5 -cache-compile-job -cas-path %t/cas \ +// RUN: -Xcc -fmodule-map-file=%t/a.modulemap -Xcc -fmodule-map-file=%t/b.modulemap -I %t + +// RUN: %{python} %S/Inputs/GenerateExplicitModuleMap.py %t/deps2.json > %t/map2.json +// RUN: llvm-cas --cas %t/cas --make-blob --data %t/map2.json > %t/map2.casid +// RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps2.json User > %t/User.cmd +// RUN: %target-swift-frontend -cache-compile-job -module-name User -O -cas-path %t/cas \ +// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -disable-implicit-swift-modules \ +// RUN: -explicit-swift-module-map-file @%t/map2.casid @%t/User.cmd %t/user.swift \ +// RUN: -emit-module -o %t/User.swiftmodule //--- test.swift -import B public func test() { b() } @@ -84,14 +100,31 @@ func user() { test() } +extension A { + public func testA() {} +} + + //--- Bridging.h #include "Foo.h" +#include "Foo2.h" + +//--- Bridging2.h +#include "Foo.h" +#include "Foo2.h" //--- Foo.h #import "a.h" +//--- Foo2.h +#pragma once +int Foo = 0; + //--- a.h #include "b.h" +struct A { + int a; +}; //--- b.h void b(void); From 9d9d3e2b23f5fba7875e2a21158ba6750c2242c9 Mon Sep 17 00:00:00 2001 From: Steven Wu Date: Wed, 17 Apr 2024 12:08:55 -0700 Subject: [PATCH 6/6] [ScanDependencies] Do not count optional dependencies when not needed If a testable module is loaded from a non-testable import, ignore its optional dependencies because the consumer should not use them. This matches the behavior of the implicit build or the behavior how forwarding module is created. (cherry picked from commit 77fefe9a759c478d34906ce6e2c4fdbb6de945b9) --- .../Serialization/SerializedModuleLoader.h | 2 +- lib/Serialization/SerializedModuleLoader.cpp | 17 +++++------------ .../testable-dependencies.swift | 16 +++++++++------- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index fd13631f17342..8e32a130a7979 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -174,7 +174,7 @@ class SerializedModuleLoaderBase : public ModuleLoader { static BinaryModuleImports getImportsOfModule(const ModuleFileSharedCore &loadedModule, ModuleLoadingBehavior transitiveBehavior, - StringRef packageName); + StringRef packageName, bool isTestableImport); /// Load the module file into a buffer and also collect its module name. static std::unique_ptr diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index d63c8c1a4082e..6f888e8243cb9 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -395,7 +395,8 @@ std::error_code SerializedModuleLoaderBase::openModuleFile( SerializedModuleLoaderBase::BinaryModuleImports SerializedModuleLoaderBase::getImportsOfModule( const ModuleFileSharedCore &loadedModuleFile, - ModuleLoadingBehavior transitiveBehavior, StringRef packageName) { + ModuleLoadingBehavior transitiveBehavior, StringRef packageName, + bool isTestableImport) { llvm::StringSet<> importedModuleNames; std::string importedHeader = ""; for (const auto &dependency : loadedModuleFile.getDependencies()) { @@ -410,8 +411,7 @@ SerializedModuleLoaderBase::getImportsOfModule( loadedModuleFile.getTransitiveLoadingBehavior( dependency, /*debuggerMode*/ false, - /*isPartialModule*/ false, packageName, - loadedModuleFile.isTestable()); + /*isPartialModule*/ false, packageName, isTestableImport); if (dependencyTransitiveBehavior > transitiveBehavior) continue; @@ -454,13 +454,6 @@ SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework, modulePath.str()); return std::make_error_code(std::errc::no_such_file_or_directory); } - - if (loadedModuleFile->isTestable() && !isTestableImport) { - if (Ctx.LangOpts.EnableModuleLoadingRemarks) - Ctx.Diags.diagnose(SourceLoc(), diag::skip_module_testable, - modulePath.str()); - return std::make_error_code(std::errc::no_such_file_or_directory); - } } // Some transitive dependencies of binary modules are not required to be @@ -471,12 +464,12 @@ SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework, // optional. auto binaryModuleImports = getImportsOfModule(*loadedModuleFile, ModuleLoadingBehavior::Required, - Ctx.LangOpts.PackageName); + Ctx.LangOpts.PackageName, isTestableImport); // Lookup optional imports of this module also auto binaryModuleOptionalImports = getImportsOfModule(*loadedModuleFile, ModuleLoadingBehavior::Optional, - Ctx.LangOpts.PackageName); + Ctx.LangOpts.PackageName, isTestableImport); auto importedModuleSet = binaryModuleImports.moduleImports; std::vector importedModuleNames; diff --git a/test/ScanDependencies/testable-dependencies.swift b/test/ScanDependencies/testable-dependencies.swift index b16300be032e1..87c5166ae0282 100644 --- a/test/ScanDependencies/testable-dependencies.swift +++ b/test/ScanDependencies/testable-dependencies.swift @@ -16,13 +16,12 @@ // RUN: -emit-module-interface-path %t/regular/A.swiftinterface -enable-library-evolution -I %t/internal \ // RUN: %t/A.swift -/// Import testable build, should use interface. +/// Import testable build, should use binary but no extra dependencies. // RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-serialized -module-name Test %t/main.swift \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib \ -// RUN: -o %t/deps1.json -I %t/testable -swift-version 5 -Rmodule-loading 2>&1 | %FileCheck %s --check-prefix DIAG -// DIAG: remark: skip swiftmodule built with '-enable-testing' +// RUN: -o %t/deps1.json -I %t/testable -swift-version 5 -Rmodule-loading // RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps1.json Test directDependencies | %FileCheck %s --check-prefix TEST1 -// TEST1: "swift": "A" +// TEST1: "swiftPrebuiltExternal": "A" // RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps1.json A directDependencies | %FileCheck %s --check-prefix EMPTY --allow-empty // EMPTY-NOT: B @@ -56,12 +55,15 @@ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -enable-testing \ // RUN: -o %t/deps5.json -I %t/regular -swift-version 5 -Rmodule-loading -/// Regular import a testable module with no interface, this is a dependency scanning error. +/// Regular import a testable module with no interface, don't load optional dependencies. // RUN: rm %t/testable/A.swiftinterface // RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-name Test %t/main.swift \ // RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -enable-testing \ -// RUN: -o %t/deps6.json -I %t/testable -swift-version 5 -Rmodule-loading 2>&1 | %FileCheck %s --check-prefix ERROR -// ERROR: error: Unable to find module dependency: 'A' +// RUN: -o %t/deps6.json -I %t/testable -swift-version 5 -Rmodule-loading +// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps6.json Test directDependencies | %FileCheck %s --check-prefix TEST6 +// TEST6: "swiftPrebuiltExternal": "A" +// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps6.json swiftPrebuiltExternal:A directDependencies | %FileCheck %s --check-prefix EMPTY --allow-empty + //--- main.swift import A