Skip to content

Commit e28a656

Browse files
committed
[Modules] Allow implicit conversions when loading interfaces with invalid os versions.
Initially, the compiler rejected building dependencies that contained OS versions in an invalid range. This happens to be quite disruptive, so instead allow it and request that these versions be implicitly bumped based on what `llvm::getCanonicalVersionForOS` computes
1 parent e42b564 commit e28a656

File tree

6 files changed

+148
-37
lines changed

6 files changed

+148
-37
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -895,10 +895,6 @@ ERROR(map_os_version_from_textual_interface_failed,none,
895895
"failed to map OS version from %0 to %1 in %2",
896896
(StringRef, StringRef, StringRef))
897897

898-
ERROR(target_os_version_from_textual_interface_invalid,none,
899-
"invalid target triple %0 in %1",
900-
(StringRef, StringRef))
901-
902898
ERROR(serialization_load_failed,Fatal,
903899
"failed to load module '%0'", (StringRef))
904900
ERROR(module_interface_build_failed,Fatal,

include/swift/Basic/Platform.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,16 @@ namespace swift {
123123
llvm::VersionTuple getTargetSDKVersion(clang::DarwinSDKInfo &SDKInfo,
124124
const llvm::Triple &triple);
125125

126+
/// Compute a target triple that is canonicalized using the passed triple.
127+
/// \returns nullopt if computation fails.
128+
std::optional<llvm::Triple> getCanonicalTriple(const llvm::Triple &triple);
129+
130+
/// Compare triples for equality but also including OSVersion.
131+
inline bool areTriplesEqual(const llvm::Triple &lhs,
132+
const llvm::Triple &rhs) {
133+
return (lhs == rhs) && (lhs.getOSVersion() == rhs.getOSVersion());
134+
}
135+
126136
/// Get SDK build version.
127137
std::string getSDKBuildVersion(StringRef SDKPath);
128138
std::string getSDKBuildVersionFromPlist(StringRef Path);

lib/Basic/Platform.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,37 @@ llvm::VersionTuple swift::getTargetSDKVersion(clang::DarwinSDKInfo &SDKInfo,
848848
return SDKVersion;
849849
}
850850

851+
std::optional<llvm::Triple>
852+
swift::getCanonicalTriple(const llvm::Triple &triple) {
853+
llvm::Triple Result = triple;
854+
// Non-darwin targets do not require canonicalization.
855+
if (!triple.isOSDarwin())
856+
return Result;
857+
858+
// If the OS versions stay the same, return back the same triple.
859+
const llvm::VersionTuple inputOSVersion = triple.getOSVersion();
860+
const bool isOSVersionInValidRange =
861+
llvm::Triple::isValidVersionForOS(triple.getOS(), inputOSVersion);
862+
const llvm::VersionTuple canonicalVersion =
863+
llvm::Triple::getCanonicalVersionForOS(
864+
triple.getOS(), triple.getOSVersion(), isOSVersionInValidRange);
865+
if (canonicalVersion == triple.getOSVersion())
866+
return Result;
867+
868+
const std::string inputOSName = triple.getOSName().str();
869+
const std::string inputOSVersionAsStr = inputOSVersion.getAsString();
870+
const int platformNameLength =
871+
inputOSName.size() - inputOSVersionAsStr.size();
872+
if (!StringRef(inputOSName).ends_with(inputOSVersionAsStr) ||
873+
(platformNameLength <= 0))
874+
return std::nullopt;
875+
876+
llvm::SmallString<64> buffer(inputOSName.substr(0, platformNameLength));
877+
buffer.append(canonicalVersion.getAsString());
878+
Result.setOSName(buffer.str());
879+
return Result;
880+
}
881+
851882
static std::string getPlistEntry(const llvm::Twine &Path, StringRef KeyName) {
852883
auto BufOrErr = llvm::MemoryBuffer::getFile(Path);
853884
if (!BufOrErr) {

lib/ClangImporter/ClangImporter.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,12 @@ void importer::getNormalInvocationArguments(
478478
if (LangOpts.ClangTarget.has_value() && !ignoreClangTarget) {
479479
triple = LangOpts.ClangTarget.value();
480480
}
481+
auto canonicalTriple = getCanonicalTriple(triple);
482+
const bool updateTargetTriple =
483+
canonicalTriple.has_value() && !areTriplesEqual(*canonicalTriple, triple);
484+
if (updateTargetTriple)
485+
triple = *canonicalTriple;
486+
481487
SearchPathOptions &searchPathOpts = ctx.SearchPathOpts;
482488
ClangImporterOptions &importerOpts = ctx.ClangImporterOpts;
483489
auto languageVersion = ctx.LangOpts.EffectiveLanguageVersion;
@@ -578,8 +584,9 @@ void importer::getNormalInvocationArguments(
578584
if (LangOpts.hasFeature(Feature::SafeInteropWrappers))
579585
invocationArgStrs.push_back("-fexperimental-bounds-safety-attributes");
580586

581-
// Set C language options.
587+
std::optional<llvm::Triple> variantTripleToUpdate = std::nullopt;
582588
if (triple.isOSDarwin()) {
589+
// Set C language options.
583590
invocationArgStrs.insert(invocationArgStrs.end(), {
584591
// Avoid including the iso646.h header because some headers from OS X
585592
// frameworks are broken by it.
@@ -648,6 +655,17 @@ void importer::getNormalInvocationArguments(
648655
1}), // b
649656
});
650657
}
658+
659+
if (auto variantTriple = ctx.LangOpts.TargetVariant) {
660+
if (ctx.LangOpts.ClangTargetVariant.has_value() && !ignoreClangTarget)
661+
variantTriple = ctx.LangOpts.ClangTargetVariant.value();
662+
663+
auto canonicalVariantTriple = getCanonicalTriple(*variantTriple);
664+
if (canonicalVariantTriple.has_value() &&
665+
!areTriplesEqual(*canonicalVariantTriple, *variantTriple)) {
666+
*variantTripleToUpdate = *canonicalVariantTriple;
667+
}
668+
}
651669
} else {
652670
// Ideally we should turn this on for all Glibc targets that are actually
653671
// using Glibc or a libc that respects that flag. This will cause some
@@ -781,6 +799,17 @@ void importer::getNormalInvocationArguments(
781799
invocationArgStrs.push_back("-iapinotes-modules");
782800
invocationArgStrs.push_back(path.str().str());
783801
}
802+
803+
// If the target triple needs to be replaced, pass the argument at the end of
804+
// the invocation.
805+
if (updateTargetTriple) {
806+
invocationArgStrs.push_back("-target");
807+
invocationArgStrs.push_back(triple.str());
808+
}
809+
if (variantTripleToUpdate.has_value()) {
810+
invocationArgStrs.push_back("-darwin-target-variant");
811+
invocationArgStrs.push_back(variantTripleToUpdate->str());
812+
}
784813
}
785814

786815
static void
@@ -808,6 +837,10 @@ importer::addCommonInvocationArguments(
808837
if (ctx.LangOpts.ClangTarget.has_value() && !ignoreClangTarget) {
809838
triple = ctx.LangOpts.ClangTarget.value();
810839
}
840+
auto canonicalTriple = getCanonicalTriple(triple);
841+
if (canonicalTriple.has_value() && !areTriplesEqual(*canonicalTriple, triple))
842+
triple = *canonicalTriple;
843+
811844
SearchPathOptions &searchPathOpts = ctx.SearchPathOpts;
812845
const ClangImporterOptions &importerOpts = ctx.ClangImporterOpts;
813846

@@ -856,6 +889,12 @@ importer::addCommonInvocationArguments(
856889
invocationArgStrs.push_back("-darwin-target-variant");
857890
if (ctx.LangOpts.ClangTargetVariant.has_value() && !ignoreClangTarget)
858891
variantTriple = ctx.LangOpts.ClangTargetVariant.value();
892+
893+
auto canonicalVariantTriple = getCanonicalTriple(*variantTriple);
894+
if (canonicalVariantTriple.has_value() &&
895+
!areTriplesEqual(*canonicalVariantTriple, *variantTriple))
896+
*variantTriple = *canonicalVariantTriple;
897+
859898
invocationArgStrs.push_back(variantTriple->str());
860899
}
861900

lib/Serialization/SerializedModuleLoader.cpp

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1497,43 +1497,27 @@ bool swift::extractCompilerFlagsFromInterface(
14971497
shouldModify = true;
14981498
}
14991499

1500-
// Diagnose if the version in the target triple parsed from the
1501-
// swiftinterface is invalid for the OS.
1502-
const llvm::VersionTuple originalVer = triple.getOSVersion();
1503-
bool isValidVersion =
1504-
llvm::Triple::isValidVersionForOS(triple.getOS(), originalVer);
1505-
if (!isValidVersion) {
1500+
// Canonicalize the version in the target triple parsed from the
1501+
// swiftinterface.
1502+
auto canonicalTriple = getCanonicalTriple(triple);
1503+
if (!canonicalTriple.has_value()) {
15061504
if (Diag) {
1505+
const llvm::VersionTuple OSVersion = triple.getOSVersion();
1506+
const bool isOSVersionInValidRange =
1507+
llvm::Triple::isValidVersionForOS(triple.getOS(), OSVersion);
1508+
const llvm::VersionTuple canonicalVersion =
1509+
llvm::Triple::getCanonicalVersionForOS(
1510+
triple.getOS(), triple.getOSVersion(), isOSVersionInValidRange);
15071511
Diag->diagnose(SourceLoc(),
1508-
diag::target_os_version_from_textual_interface_invalid,
1509-
triple.str(), interfacePath);
1512+
diag::map_os_version_from_textual_interface_failed,
1513+
OSVersion.getAsString(), canonicalVersion.getAsString(),
1514+
interfacePath);
15101515
}
15111516
break;
15121517
}
1513-
1514-
// Canonicalize the version in the target triple parsed from the
1515-
// swiftinterface.
1516-
llvm::VersionTuple newVer = llvm::Triple::getCanonicalVersionForOS(
1517-
triple.getOS(), originalVer, isValidVersion);
1518-
if (originalVer != newVer) {
1519-
std::string originalOSName = triple.getOSName().str();
1520-
std::string originalVerStr = originalVer.getAsString();
1521-
std::string newVerStr = newVer.getAsString();
1522-
const int OSNameWithoutVersionLength =
1523-
originalOSName.size() - originalVerStr.size();
1524-
if (!StringRef(originalOSName).ends_with(originalVerStr) ||
1525-
(OSNameWithoutVersionLength <= 0)) {
1526-
if (Diag) {
1527-
Diag->diagnose(SourceLoc(),
1528-
diag::map_os_version_from_textual_interface_failed,
1529-
originalVerStr, newVerStr, interfacePath);
1530-
}
1531-
break;
1532-
}
1533-
llvm::SmallString<64> buffer(
1534-
originalOSName.substr(0, OSNameWithoutVersionLength));
1535-
buffer.append(newVerStr);
1536-
triple.setOSName(buffer.str());
1518+
// Update the triple to use if it differs.
1519+
if (!areTriplesEqual(triple, *canonicalTriple)) {
1520+
triple = *canonicalTriple;
15371521
shouldModify = true;
15381522
}
15391523
if (shouldModify)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %empty-directory(%t/module-cache)
3+
// RUN: split-file %s %t
4+
5+
// First test the swift interface with a invalid os version behaves fine.
6+
// RUN: %target-swift-typecheck-module-from-interface(%t/Modules/Simple.swiftmodule/arm64-apple-macos.swiftinterface) -module-name Simple
7+
8+
// Next build transitive dependencies in zippered mode.
9+
// 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
10+
// RUN: %validate-json %t/deps.json | %FileCheck %s --check-prefix=DEPS
11+
12+
DEPS: "arm64-apple-macos26.4"
13+
DEPS-NOT: "arm64-apple-macos16.4"
14+
DEPS-NOT: "arm64-apple-ios22.0-macabi"
15+
16+
//--- Modules/Simple.swiftmodule/arm64-apple-macos.swiftinterface
17+
// swift-interface-format-version: 1.0
18+
// swift-module-flags: -target arm64-apple-macos16.4
19+
public struct S {
20+
}
21+
22+
//--- Modules/Simple.swiftmodule/arm64-apple-ios-macabi.swiftinterface
23+
// swift-interface-format-version: 1.0
24+
// swift-module-flags: -target arm64-apple-ios22.0-macabi
25+
public struct S {
26+
}
27+
28+
//--- Modules/module.modulemap
29+
module ClangDep {
30+
header "ClangDep.h"
31+
export *
32+
}
33+
34+
//--- Modules/ClangDep.h
35+
typedef int my_int;
36+
37+
38+
//--- Modules/Interopt.swiftmodule/arm64-apple-macos.swiftinterface
39+
// swift-interface-format-version: 1.0
40+
// swift-module-flags: -target arm64-apple-macos16.4
41+
import Simple
42+
import ClangDep
43+
44+
//--- Modules/Interopt.swiftmodule/arm64-apple-ios-macabi.swiftinterface
45+
// swift-interface-format-version: 1.0
46+
// swift-module-flags: -target arm64-apple-ios22.0-macabi
47+
import Simple
48+
import ClangDep
49+
50+
//--- input.swift
51+
import Interopt

0 commit comments

Comments
 (0)