diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 4e60303ec39c2..a435ceff672bc 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -47,6 +47,7 @@ #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/VersionTuple.h" #include "llvm/Support/VirtualOutputBackend.h" #include #include @@ -409,9 +410,17 @@ class ASTContext final { /// Cache of module names that fail the 'canImport' test in this context. mutable llvm::StringSet<> FailedModuleImportNames; + /// Versions of the modules found during versioned canImport checks. + struct ImportedModuleVersionInfo { + llvm::VersionTuple Version; + llvm::VersionTuple UnderlyingVersion; + }; + /// Cache of module names that passed the 'canImport' test. This cannot be - /// mutable since it needs to be queried for dependency discovery. - llvm::StringSet<> SucceededModuleImportNames; + /// mutable since it needs to be queried for dependency discovery. Keep sorted + /// so caller of `forEachCanImportVersionCheck` can expect deterministic + /// ordering. + std::map CanImportModuleVersions; /// Set if a `-module-alias` was passed. Used to store mapping between module aliases and /// their corresponding real names, and vice versa for a reverse lookup, which is needed to check @@ -1102,7 +1111,12 @@ class ASTContext final { /// module is loaded in full. bool canImportModuleImpl(ImportPath::Module ModulePath, llvm::VersionTuple version, bool underlyingVersion, - bool updateFailingList) const; + bool updateFailingList, + llvm::VersionTuple &foundVersion) const; + + /// Add successful canImport modules. + void addSucceededCanImportModule(StringRef moduleName, bool underlyingVersion, + const llvm::VersionTuple &versionInfo); public: namelookup::ImportCache &getImportCache() const; @@ -1144,10 +1158,10 @@ class ASTContext final { llvm::VersionTuple version = llvm::VersionTuple(), bool underlyingVersion = false) const; - /// \returns a set of names from all successfully canImport module checks. - const llvm::StringSet<> &getSuccessfulCanImportCheckNames() const { - return SucceededModuleImportNames; - } + /// Callback on each successful imported. + void forEachCanImportVersionCheck( + std::function) const; /// \returns a module with a given name that was already loaded. If the /// module was not loaded, returns nullptr. diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index 01125333b40e1..d1eaf7e6096da 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -481,6 +481,8 @@ ERROR(unknown_forced_module_loading_mode,none, (StringRef)) ERROR(error_creating_remark_serializer,none, "error while creating remark serializer: '%0'", (StringRef)) +ERROR(invalid_can_import_module_version,none, + "invalid version passed to -module-can-import-version: '%0'", (StringRef)) REMARK(interface_file_lock_failure,none, "building module interface without lock file", ()) diff --git a/include/swift/AST/SearchPathOptions.h b/include/swift/AST/SearchPathOptions.h index c26a381b96bf1..f58abedcd2e4b 100644 --- a/include/swift/AST/SearchPathOptions.h +++ b/include/swift/AST/SearchPathOptions.h @@ -20,6 +20,7 @@ #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/Error.h" +#include "llvm/Support/VersionTuple.h" #include "llvm/Support/VirtualFileSystem.h" #include @@ -509,6 +510,14 @@ class SearchPathOptions { using CrossImportMap = llvm::StringMap>; CrossImportMap CrossImportInfo; + /// CanImport information passed from scanning. + struct CanImportInfo { + std::string ModuleName; + llvm::VersionTuple Version; + llvm::VersionTuple UnderlyingVersion; + }; + std::vector CanImportModuleInfo; + /// Whether to search for cross import overlay on file system. bool DisableCrossImportOverlaySearch = false; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index 16081dee45216..a50cf5cd7c6ad 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -224,6 +224,14 @@ def swift_module_cross_import: MultiArg<["-"], "swift-module-cross-import", 2>, MetaVarName<" ">, HelpText<"Specify the cross import module">; +def module_can_import: Separate<["-"], "module-can-import">, + MetaVarName<"">, + HelpText<"Specify canImport module name">; + +def module_can_import_version: MultiArg<["-"], "module-can-import-version", 3>, + MetaVarName<" ">, + HelpText<"Specify canImport module and versions">; + def disable_cross_import_overlay_search: Flag<["-"], "disable-cross-import-overlay-search">, HelpText<"Disable searching for cross import overlay file">; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 577297363385c..43156febacf8c 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -74,6 +74,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/VersionTuple.h" #include "llvm/Support/VirtualOutputBackend.h" #include "llvm/Support/VirtualOutputBackends.h" #include @@ -786,6 +787,12 @@ ASTContext::ASTContext( registerAccessRequestFunctions(evaluator); registerNameLookupRequestFunctions(evaluator); + // Register canImport module info. + for (auto &info: SearchPathOpts.CanImportModuleInfo) { + addSucceededCanImportModule(info.ModuleName, false, info.Version); + addSucceededCanImportModule(info.ModuleName, true, info.UnderlyingVersion); + } + // Provide a default OnDiskOutputBackend if user didn't supply one. if (!OutputBackend) OutputBackend = llvm::makeIntrusiveRefCnt(); @@ -2385,23 +2392,56 @@ getModuleVersionKindString(const ModuleLoader::ModuleVersionInfo &info) { } } -bool ASTContext::canImportModuleImpl(ImportPath::Module ModuleName, - llvm::VersionTuple version, - bool underlyingVersion, - bool updateFailingList) const { +void ASTContext::addSucceededCanImportModule( + StringRef moduleName, bool underlyingVersion, + const llvm::VersionTuple &versionInfo) { + auto &entry = CanImportModuleVersions[moduleName.str()]; + if (!versionInfo.empty()) { + if (underlyingVersion) + entry.UnderlyingVersion = versionInfo; + else + entry.Version = versionInfo; + } +} + +bool ASTContext::canImportModuleImpl( + ImportPath::Module ModuleName, llvm::VersionTuple version, + bool underlyingVersion, bool updateFailingList, + llvm::VersionTuple &foundVersion) const { SmallString<64> FullModuleName; ModuleName.getString(FullModuleName); - auto ModuleNameStr = FullModuleName.str(); + auto ModuleNameStr = FullModuleName.str().str(); // If we've failed loading this module before, don't look for it again. if (FailedModuleImportNames.count(ModuleNameStr)) return false; - if (version.empty()) { - // If this module has already been checked successfully, it is importable. - if (SucceededModuleImportNames.count(ModuleNameStr)) + // If this module has already been checked or there is information for the + // module from commandline, use that information instead of loading the + // module. + auto Found = CanImportModuleVersions.find(ModuleNameStr); + if (Found != CanImportModuleVersions.end()) { + if (version.empty()) return true; + if (underlyingVersion) { + if (!Found->second.UnderlyingVersion.empty()) + return version <= Found->second.UnderlyingVersion; + } else { + if (!Found->second.Version.empty()) + return version <= Found->second.Version; + } + + // If the canImport information is coming from the command-line, then no + // need to continue the search, return false. For checking modules that are + // not passed from command-line, allow fallback to the module loading since + // this is not in a canImport request context that has already been resolved + // by scanner. + if (!SearchPathOpts.CanImportModuleInfo.empty()) + return false; + } + + if (version.empty()) { // If this module has already been successfully imported, it is importable. if (getLoadedModule(ModuleName) != nullptr) return true; @@ -2453,28 +2493,38 @@ bool ASTContext::canImportModuleImpl(ImportPath::Module ModuleName, return true; } + foundVersion = bestVersionInfo.getVersion(); return version <= bestVersionInfo.getVersion(); } -bool ASTContext::canImportModule(ImportPath::Module ModuleName, +void ASTContext::forEachCanImportVersionCheck( + std::function + Callback) const { + for (auto &entry : CanImportModuleVersions) + Callback(entry.first, entry.second.Version, entry.second.UnderlyingVersion); +} + +bool ASTContext::canImportModule(ImportPath::Module moduleName, llvm::VersionTuple version, bool underlyingVersion) { - if (!canImportModuleImpl(ModuleName, version, underlyingVersion, true)) + llvm::VersionTuple versionInfo; + if (!canImportModuleImpl(moduleName, version, underlyingVersion, true, + versionInfo)) return false; - // If checked successfully, add the top level name to success list as - // dependency to handle clang submodule correctly. Swift does not have - // submodule so the name should be the same. - SmallString<64> TopModuleName; - ModuleName.getTopLevelPath().getString(TopModuleName); - SucceededModuleImportNames.insert(TopModuleName.str()); + SmallString<64> fullModuleName; + moduleName.getString(fullModuleName); + addSucceededCanImportModule(fullModuleName, underlyingVersion, versionInfo); return true; } bool ASTContext::testImportModule(ImportPath::Module ModuleName, llvm::VersionTuple version, bool underlyingVersion) const { - return canImportModuleImpl(ModuleName, version, underlyingVersion, false); + llvm::VersionTuple versionInfo; + return canImportModuleImpl(ModuleName, version, underlyingVersion, false, + versionInfo); } ModuleDecl * diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 5ebe4908e2bdd..7be37d3953d38 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -2120,7 +2120,8 @@ bool ClangImporter::isModuleImported(const clang::Module *M) { return M->NameVisibility == clang::Module::NameVisibilityKind::AllVisible; } -static llvm::VersionTuple getCurrentVersionFromTBD(StringRef path, +static llvm::VersionTuple getCurrentVersionFromTBD(llvm::vfs::FileSystem &FS, + StringRef path, StringRef moduleName) { std::string fwName = (moduleName + ".framework").str(); auto pos = path.find(fwName); @@ -2130,7 +2131,7 @@ static llvm::VersionTuple getCurrentVersionFromTBD(StringRef path, llvm::sys::path::append(buffer, moduleName + ".tbd"); auto tbdPath = buffer.str(); llvm::ErrorOr> tbdBufOrErr = - llvm::MemoryBuffer::getFile(tbdPath); + FS.getBufferForFile(tbdPath); // .tbd file doesn't exist, exit. if (!tbdBufOrErr) return {}; @@ -2193,8 +2194,8 @@ bool ClangImporter::canImportModule(ImportPath::Module modulePath, // Look for the .tbd file inside .framework dir to get the project version // number. - llvm::VersionTuple currentVersion = - getCurrentVersionFromTBD(path, topModule.Item.str()); + llvm::VersionTuple currentVersion = getCurrentVersionFromTBD( + Impl.Instance->getVirtualFileSystem(), path, topModule.Item.str()); versionInfo->setVersion(currentVersion, ModuleVersionSourceKind::ClangModuleTBD); return true; diff --git a/lib/DependencyScan/ModuleDependencyScanner.cpp b/lib/DependencyScan/ModuleDependencyScanner.cpp index 899fe59c5c7bd..636b2522e16ee 100644 --- a/lib/DependencyScan/ModuleDependencyScanner.cpp +++ b/lib/DependencyScan/ModuleDependencyScanner.cpp @@ -31,6 +31,7 @@ #include "llvm/CAS/CachingOnDiskFileSystem.h" #include "llvm/Support/Error.h" #include "llvm/Support/Threading.h" +#include "llvm/Support/VersionTuple.h" #include "llvm/Support/VirtualFileSystem.h" #include @@ -464,15 +465,26 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(ModuleDecl *mainModule) { &ScanASTContext.SourceMgr); } - // Add all the successful canImport checks from the ASTContext as part of - // the dependency since only mainModule can have `canImport` check. This - // needs to happen after visiting all the top-level decls from all + // Pass all the successful canImport checks from the ASTContext as part of + // build command to main module to ensure frontend gets the same result. + // This needs to happen after visiting all the top-level decls from all // SourceFiles. - for (auto &Module : - mainModule->getASTContext().getSuccessfulCanImportCheckNames()) - mainDependencies.addModuleImport(Module.first(), - &alreadyAddedModules); - } + auto buildArgs = mainDependencies.getCommandline(); + mainModule->getASTContext().forEachCanImportVersionCheck( + [&](StringRef moduleName, const llvm::VersionTuple &Version, + const llvm::VersionTuple &UnderlyingVersion) { + if (Version.empty() && UnderlyingVersion.empty()) { + buildArgs.push_back("-module-can-import"); + buildArgs.push_back(moduleName.str()); + } else { + buildArgs.push_back("-module-can-import-version"); + buildArgs.push_back(moduleName.str()); + buildArgs.push_back(Version.getAsString()); + buildArgs.push_back(UnderlyingVersion.getAsString()); + } + }); + mainDependencies.updateCommandLine(buildArgs); + } return mainDependencies; } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 671868399bccb..836a0958399ca 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -25,6 +25,7 @@ #include "swift/Strings.h" #include "swift/SymbolGraphGen/SymbolGraphOptions.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/VersionTuple.h" #include "llvm/TargetParser/Triple.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" @@ -2144,6 +2145,21 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts, ArgList &Args, for (auto *A : Args.filtered(OPT_swift_module_cross_import)) Opts.CrossImportInfo[A->getValue(0)].push_back(A->getValue(1)); + for (auto &Name : Args.getAllArgValues(OPT_module_can_import)) + Opts.CanImportModuleInfo.push_back({Name, {}, {}}); + + for (auto *A: Args.filtered(OPT_module_can_import_version)) { + llvm::VersionTuple Version, UnderlyingVersion; + if (Version.tryParse(A->getValue(1))) + Diags.diagnose(SourceLoc(), diag::invalid_can_import_module_version, + A->getValue(1)); + if (UnderlyingVersion.tryParse(A->getValue(2))) + Diags.diagnose(SourceLoc(), diag::invalid_can_import_module_version, + A->getValue(2)); + Opts.CanImportModuleInfo.push_back( + {A->getValue(0), Version, UnderlyingVersion}); + } + Opts.DisableCrossImportOverlaySearch |= Args.hasArg(OPT_disable_cross_import_overlay_search); diff --git a/test/CAS/can-import.swift b/test/CAS/can-import.swift index 8483483cf0a3b..efcd420435c8f 100644 --- a/test/CAS/can-import.swift +++ b/test/CAS/can-import.swift @@ -3,13 +3,7 @@ // 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 -parse-stdlib \ -// RUN: %t/main.swift -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas -I %t/include - -// 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/BuildCommandExtractor.py %t/deps.json clang:B > %t/B.cmd -// RUN: %swift_frontend_plain @%t/B.cmd +// RUN: %t/main.swift -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas -I %t/include -F %t/frameworks // RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json C > %t/C.cmd // RUN: %swift_frontend_plain @%t/C.cmd @@ -18,6 +12,22 @@ // RUN: llvm-cas --cas %t/cas --make-blob --data %t/map.json > %t/map.casid // RUN: %{python} %S/Inputs/BuildCommandExtractor.py %t/deps.json Test > %t/MyApp.cmd +// RUN: %FileCheck %s --check-prefix=CMD --input-file=%t/MyApp.cmd +// CMD: "-module-can-import" +// CMD-NEXT: "A.Sub" +// CMD-NEXT: "-module-can-import" +// CMD-NEXT: "B" +// CMD-NEXT: "-module-can-import-version" +// CMD-NEXT: "C" +// CMD-NEXT: "1.0" +// CMD-NEXT: "0" +// CMD-NEXT: "-module-can-import" +// CMD-NEXT: "D" +// CMD-NEXT: "-module-can-import-version" +// CMD-NEXT: "Simple" +// CMD-NEXT: "0" +// CMD-NEXT: "1000.0.0" + // RUN: %target-swift-frontend \ // RUN: -typecheck -cache-compile-job -cas-path %t/cas \ // RUN: -swift-version 5 -disable-implicit-swift-modules \ @@ -38,6 +48,7 @@ import A.Missing func b() {} #endif +// check version. #if canImport(C, _version: 1.0) import C #endif @@ -46,10 +57,29 @@ import C import Missing #endif +// check succeeded canImport followed by unsuccessful versioned canImport check. +#if canImport(D) +func imported() {} +#endif + +#if canImport(D, _version: 2.0) +import Missing +#endif + +// check underlyingVersion. +#if canImport(Simple, _underlyingVersion: 10) +func simple() {} +#endif + +#if canImport(Simple, _underlyingVersion: 2000) +#error("wrong version") +#endif + func useA() { a() b() c() + simple() } //--- include/module.modulemap @@ -75,3 +105,30 @@ void notused2(void); // swift-interface-format-version: 1.0 // swift-module-flags: -module-name C -O -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -user-module-version 1.0 public func c() { } + +//--- include/D.swiftinterface +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name D -O -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -user-module-version 1.0 +public func d() { } + +//--- frameworks/Simple.framework/Modules/module.modulemap +framework module Simple { + umbrella header "Simple.h" + export * + module * { + export * + } +} + +//--- frameworks/Simple.framework/Headers/Simple.h +void simple(void); + +//--- frameworks/Simple.framework/Simple.tbd +--- !tapi-tbd +tbd-version: 4 +targets: [ arm64-macos, arm64-ios, arm64-watchos, arm64-tvos, + arm64-ios-simulator, arm64-watchos-simulator, arm64-tvos-simulator ] +flags: [ not_app_extension_safe ] +install-name: '/System/Library/Frameworks/Simple.framework/Versions/A/Simple' +current-version: 1000 +... diff --git a/test/Parse/ConditionalCompilation/can_import_options.swift b/test/Parse/ConditionalCompilation/can_import_options.swift new file mode 100644 index 0000000000000..65533085997f6 --- /dev/null +++ b/test/Parse/ConditionalCompilation/can_import_options.swift @@ -0,0 +1,145 @@ +// RUN: %empty-directory(%t) +// RUN: %target-typecheck-verify-swift -disable-implicit-concurrency-module-import \ +// RUN: -disable-implicit-string-processing-module-import \ +// RUN: -module-can-import Foo -module-can-import-version Bar 113.330.1.2 0.0 \ +// RUN: -module-can-import-version Baz 113.330.1.2 113.330.1.2 + +func canImport() { +#if canImport(Foo) + let basicCheck = 1 // expected-warning {{initialization of immutable value 'basicCheck' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Foo, _version: 1) + // No actual Foo to be imported since it is not versioned. + let versionCheck = 1 +#endif +} + +func canImportVersioned() { +#if canImport(Bar, _version: 0) + let majorZero = 1 // expected-warning {{initialization of immutable value 'majorZero' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Bar, _version: 112) + let majorSmaller = 1 // expected-warning {{initialization of immutable value 'majorSmaller' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Bar, _version: 113) + let majorEqual = 1 // expected-warning {{initialization of immutable value 'majorEqual' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Bar, _version: 114) + let majorLarger = 1 +#endif + +#if canImport(Bar, _version: 113.329) + let minorSmaller = 1 // expected-warning {{initialization of immutable value 'minorSmaller' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Bar, _version: 113.330) + let minorEqual = 1 // expected-warning {{initialization of immutable value 'minorEqual' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Bar, _version: 113.331) + let minorLarger = 1 +#endif + +#if canImport(Bar, _version: 113.330.0) + let patchSmaller = 1 // expected-warning {{initialization of immutable value 'patchSmaller' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Bar, _version: 113.330.1) + let patchEqual = 1 // expected-warning {{initialization of immutable value 'patchEqual' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Bar, _version: 113.330.2) + let patchLarger = 1 +#endif + +#if canImport(Bar, _version: 113.330.1.1) + let buildSmaller = 1 // expected-warning {{initialization of immutable value 'buildSmaller' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Bar, _version: 113.330.1.2) + let buildEqual = 1 // expected-warning {{initialization of immutable value 'buildEqual' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Bar, _version: 113.330.1.3) + let buildLarger = 1 +#endif + +#if canImport(Bar, _version: 113.330.1.2.0) // expected-warning {{trailing components of version '113.330.1.2' are ignored}} + let extraComponent = 1 // expected-warning {{initialization of immutable value 'extraComponent' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Bar, _underlyingVersion: 113.33) + // Bar is a Swift module with no underlying clang module. + let underlyingMinorSmaller = 1 +#endif + +#if canImport(Bar) + let noVersion = 1 // expected-warning {{initialization of immutable value 'noVersion' was never used; consider replacing with assignment to '_' or removing it}} +#endif +} + +func canImportUnderlyingVersion() { +#if canImport(Baz, _underlyingVersion: 0) + let majorZero = 1 // expected-warning {{initialization of immutable value 'majorZero' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Baz, _underlyingVersion: 112) + let majorSmaller = 1 // expected-warning {{initialization of immutable value 'majorSmaller' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Baz, _underlyingVersion: 113) + let majorEqual = 1 // expected-warning {{initialization of immutable value 'majorEqual' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Baz, _underlyingVersion: 114) + let majorLarger = 1 +#endif + +#if canImport(Baz, _underlyingVersion: 113.329) + let minorSmaller = 1 // expected-warning {{initialization of immutable value 'minorSmaller' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Baz, _underlyingVersion: 113.330) + let minorEqual = 1 // expected-warning {{initialization of immutable value 'minorEqual' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Baz, _underlyingVersion: 113.331) + let minorLarger = 1 +#endif + +#if canImport(Baz, _underlyingVersion: 113.330.0) + let patchSmaller = 1 // expected-warning {{initialization of immutable value 'patchSmaller' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Baz, _underlyingVersion: 113.330.1) + let patchEqual = 1 // expected-warning {{initialization of immutable value 'patchEqual' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Baz, _underlyingVersion: 113.330.2) + let patchLarger = 1 +#endif + +#if canImport(Baz, _underlyingVersion: 113.330.1.1) + let buildSmaller = 1 // expected-warning {{initialization of immutable value 'buildSmaller' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Baz, _underlyingVersion: 113.330.1.2) + let buildEqual = 1 // expected-warning {{initialization of immutable value 'buildEqual' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Baz, _underlyingVersion: 113.330.1.3) + let buildLarger = 1 +#endif + +#if canImport(Baz, _underlyingVersion: 113.330.1.2.0) // expected-warning {{trailing components of version '113.330.1.2' are ignored}} + let extraComponent = 1 // expected-warning {{initialization of immutable value 'extraComponent' was never used; consider replacing with assignment to '_' or removing it}} +#endif + +#if canImport(Baz, _version: 113.33) + let version = 1 // expected-warning {{initialization of immutable value 'version' was never used; consider replacing with assignment to '_' or removing it}} +#endif +} diff --git a/test/ScanDependencies/module_deps_can_import.swift b/test/ScanDependencies/module_deps_can_import.swift index 2ec33713d3301..64f503e77a4fa 100644 --- a/test/ScanDependencies/module_deps_can_import.swift +++ b/test/ScanDependencies/module_deps_can_import.swift @@ -4,14 +4,24 @@ // RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps.json Test directDependencies | %FileCheck %s -// CHECK-DAG: "clang": "C" -// CHECK-DAG: "clang": "ClangTest" // CHECK-DAG: "swift": "A" -// CHECK-DAG: "swift": "F" +// CHECK-DAG: "clang": "ClangTest" // CHECK-NOT: "swift": "G" // CHECK-NOT: "swift": "B" // CHECK-NOT: "Missing" +// RUN: %{python} %S/../CAS/Inputs/BuildCommandExtractor.py %t/deps.json Test | %FileCheck %s -check-prefix=CMD +// CMD: "-module-can-import" +// CMD-NEXT: "C" +// CMD-NEXT: "-module-can-import" +// CMD-NEXT: "ClangTest.Sub" +// CMD-NEXT: "-module-can-import" +// CMD-NEXT: "F" +// CMD-NEXT: "-module-can-import-version" +// CMD-NEXT: "Version" +// CMD-NEXT: "100.1" +// CMD-NEXT: "0" + //--- main.swift #if canImport(Missing) @@ -35,10 +45,16 @@ import Missing // B is short circuited #if canImport(C) || canImport(B) +import B #endif -// Check clang submodule, this should import ClangTest, not ClangTest.Sub +// Check clang submodule #if canImport(ClangTest.Sub) +import ClangTest.Sub +#endif + +// Versioned check +#if canImport(Version, _version: 10.0) #endif //--- include/module.modulemap @@ -51,3 +67,7 @@ module ClangTest { //--- include/sub.h void notused(void); + +//--- include/Version.swiftinterface +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name Version -O -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -parse-stdlib -user-module-version 100.1