diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 8aed91cf2d1ef..f12bd7a6c03cf 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -895,10 +895,6 @@ ERROR(map_os_version_from_textual_interface_failed,none, "failed to map OS version from %0 to %1 in %2", (StringRef, StringRef, StringRef)) -ERROR(target_os_version_from_textual_interface_invalid,none, - "invalid target triple %0 in %1", - (StringRef, StringRef)) - ERROR(serialization_load_failed,Fatal, "failed to load module '%0'", (StringRef)) ERROR(module_interface_build_failed,Fatal, diff --git a/include/swift/Basic/Platform.h b/include/swift/Basic/Platform.h index 94515f6dbd890..61337e45c4404 100644 --- a/include/swift/Basic/Platform.h +++ b/include/swift/Basic/Platform.h @@ -123,6 +123,16 @@ namespace swift { llvm::VersionTuple getTargetSDKVersion(clang::DarwinSDKInfo &SDKInfo, const llvm::Triple &triple); + /// Compute a target triple that is canonicalized using the passed triple. + /// \returns nullopt if computation fails. + std::optional getCanonicalTriple(const llvm::Triple &triple); + + /// Compare triples for equality but also including OSVersion. + inline bool areTriplesStrictlyEqual(const llvm::Triple &lhs, + const llvm::Triple &rhs) { + return (lhs == rhs) && (lhs.getOSVersion() == rhs.getOSVersion()); + } + /// Get SDK build version. std::string getSDKBuildVersion(StringRef SDKPath); std::string getSDKBuildVersionFromPlist(StringRef Path); diff --git a/lib/Basic/Platform.cpp b/lib/Basic/Platform.cpp index 107159f9dab37..40959a1b95b25 100644 --- a/lib/Basic/Platform.cpp +++ b/lib/Basic/Platform.cpp @@ -848,6 +848,37 @@ llvm::VersionTuple swift::getTargetSDKVersion(clang::DarwinSDKInfo &SDKInfo, return SDKVersion; } +std::optional +swift::getCanonicalTriple(const llvm::Triple &triple) { + llvm::Triple Result = triple; + // Non-darwin targets do not require canonicalization. + if (!triple.isOSDarwin()) + return Result; + + // If the OS versions stay the same, return back the same triple. + const llvm::VersionTuple inputOSVersion = triple.getOSVersion(); + const bool isOSVersionInValidRange = + llvm::Triple::isValidVersionForOS(triple.getOS(), inputOSVersion); + const llvm::VersionTuple canonicalVersion = + llvm::Triple::getCanonicalVersionForOS( + triple.getOS(), triple.getOSVersion(), isOSVersionInValidRange); + if (canonicalVersion == triple.getOSVersion()) + return Result; + + const std::string inputOSName = triple.getOSName().str(); + const std::string inputOSVersionAsStr = inputOSVersion.getAsString(); + const int platformNameLength = + inputOSName.size() - inputOSVersionAsStr.size(); + if (!StringRef(inputOSName).ends_with(inputOSVersionAsStr) || + (platformNameLength <= 0)) + return std::nullopt; + + llvm::SmallString<64> buffer(inputOSName.substr(0, platformNameLength)); + buffer.append(canonicalVersion.getAsString()); + Result.setOSName(buffer.str()); + return Result; +} + static std::string getPlistEntry(const llvm::Twine &Path, StringRef KeyName) { auto BufOrErr = llvm::MemoryBuffer::getFile(Path); if (!BufOrErr) { diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 9db9c4ca8b89d..365b5e7aac00e 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -478,6 +478,11 @@ void importer::getNormalInvocationArguments( if (LangOpts.ClangTarget.has_value() && !ignoreClangTarget) { triple = LangOpts.ClangTarget.value(); } + auto canonicalTriple = getCanonicalTriple(triple); + if (canonicalTriple.has_value() && + !areTriplesStrictlyEqual(*canonicalTriple, triple)) + triple = *canonicalTriple; + SearchPathOptions &searchPathOpts = ctx.SearchPathOpts; ClangImporterOptions &importerOpts = ctx.ClangImporterOpts; auto languageVersion = ctx.LangOpts.EffectiveLanguageVersion; @@ -808,6 +813,11 @@ importer::addCommonInvocationArguments( if (ctx.LangOpts.ClangTarget.has_value() && !ignoreClangTarget) { triple = ctx.LangOpts.ClangTarget.value(); } + auto canonicalTriple = getCanonicalTriple(triple); + if (canonicalTriple.has_value() && + !areTriplesStrictlyEqual(*canonicalTriple, triple)) + triple = *canonicalTriple; + SearchPathOptions &searchPathOpts = ctx.SearchPathOpts; const ClangImporterOptions &importerOpts = ctx.ClangImporterOpts; @@ -856,6 +866,12 @@ importer::addCommonInvocationArguments( invocationArgStrs.push_back("-darwin-target-variant"); if (ctx.LangOpts.ClangTargetVariant.has_value() && !ignoreClangTarget) variantTriple = ctx.LangOpts.ClangTargetVariant.value(); + + auto canonicalVariantTriple = getCanonicalTriple(*variantTriple); + if (canonicalVariantTriple.has_value() && + !areTriplesStrictlyEqual(*canonicalVariantTriple, *variantTriple)) + *variantTriple = *canonicalVariantTriple; + invocationArgStrs.push_back(variantTriple->str()); } diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 5862adf180171..06e4339f5aba0 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -1497,43 +1497,27 @@ bool swift::extractCompilerFlagsFromInterface( shouldModify = true; } - // Diagnose if the version in the target triple parsed from the - // swiftinterface is invalid for the OS. - const llvm::VersionTuple originalVer = triple.getOSVersion(); - bool isValidVersion = - llvm::Triple::isValidVersionForOS(triple.getOS(), originalVer); - if (!isValidVersion) { + // Canonicalize the version in the target triple parsed from the + // swiftinterface. + auto canonicalTriple = getCanonicalTriple(triple); + if (!canonicalTriple.has_value()) { if (Diag) { + const llvm::VersionTuple OSVersion = triple.getOSVersion(); + const bool isOSVersionInValidRange = + llvm::Triple::isValidVersionForOS(triple.getOS(), OSVersion); + const llvm::VersionTuple canonicalVersion = + llvm::Triple::getCanonicalVersionForOS( + triple.getOS(), triple.getOSVersion(), isOSVersionInValidRange); Diag->diagnose(SourceLoc(), - diag::target_os_version_from_textual_interface_invalid, - triple.str(), interfacePath); + diag::map_os_version_from_textual_interface_failed, + OSVersion.getAsString(), canonicalVersion.getAsString(), + interfacePath); } break; } - - // Canonicalize the version in the target triple parsed from the - // swiftinterface. - llvm::VersionTuple newVer = llvm::Triple::getCanonicalVersionForOS( - triple.getOS(), originalVer, isValidVersion); - if (originalVer != newVer) { - std::string originalOSName = triple.getOSName().str(); - std::string originalVerStr = originalVer.getAsString(); - std::string newVerStr = newVer.getAsString(); - const int OSNameWithoutVersionLength = - originalOSName.size() - originalVerStr.size(); - if (!StringRef(originalOSName).ends_with(originalVerStr) || - (OSNameWithoutVersionLength <= 0)) { - if (Diag) { - Diag->diagnose(SourceLoc(), - diag::map_os_version_from_textual_interface_failed, - originalVerStr, newVerStr, interfacePath); - } - break; - } - llvm::SmallString<64> buffer( - originalOSName.substr(0, OSNameWithoutVersionLength)); - buffer.append(newVerStr); - triple.setOSName(buffer.str()); + // Update the triple to use if it differs. + if (!areTriplesStrictlyEqual(triple, *canonicalTriple)) { + triple = *canonicalTriple; shouldModify = true; } if (shouldModify) diff --git a/test/ModuleInterface/canonicalized-os-version.swift b/test/ModuleInterface/canonicalized-os-version.swift new file mode 100644 index 0000000000000..f8137024b3478 --- /dev/null +++ b/test/ModuleInterface/canonicalized-os-version.swift @@ -0,0 +1,53 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/module-cache) +// RUN: split-file %s %t + +// REQUIRES: OS=macosx || OS=maccatalyst + +// First, test that the swift interface with an invalid os version behaves fine. +// RUN: %target-swift-typecheck-module-from-interface(%t/Modules/Simple.swiftmodule/arm64-apple-macos.swiftinterface) -module-name Simple + +// Next, build transitive dependencies in zippered mode. +// RUN: %target-swift-frontend -module-name input %t/input.swift -target arm64-apple-macosx50.1 -target-variant arm64-apple-ios50.1-macabi -I%t/Modules -scan-dependencies -module-cache-path %t/module-cache-path -o %t/deps.json 2>&1 | Filecheck --allow-empty --implicit-check-not warning: --implicit-check-not error: %s +// RUN: %validate-json %t/deps.json | %FileCheck %s --check-prefix=DEPS + +DEPS-NOT: "arm64-apple-macos16.4" +DEPS-NOT: "arm64-apple-ios22.0-macabi" +DEPS: "arm64-apple-macos26.4" + +//--- Modules/Simple.swiftmodule/arm64-apple-macos.swiftinterface +// swift-interface-format-version: 1.0 +// swift-module-flags: -target arm64-apple-macos16.4 +public struct S { +} + +//--- Modules/Simple.swiftmodule/arm64-apple-ios-macabi.swiftinterface +// swift-interface-format-version: 1.0 +// swift-module-flags: -target arm64-apple-ios22.0-macabi +public struct S { +} + +//--- Modules/module.modulemap +module ClangDep { + header "ClangDep.h" + export * +} + +//--- Modules/ClangDep.h +typedef int my_int; + + +//--- Modules/Interopt.swiftmodule/arm64-apple-macos.swiftinterface +// swift-interface-format-version: 1.0 +// swift-module-flags: -target arm64-apple-macos16.4 +import Simple +import ClangDep + +//--- Modules/Interopt.swiftmodule/arm64-apple-ios-macabi.swiftinterface +// swift-interface-format-version: 1.0 +// swift-module-flags: -target arm64-apple-ios22.0-macabi +import Simple +import ClangDep + +//--- input.swift +import Interopt