Skip to content

Commit b319161

Browse files
committed
[Triple] Fix Apple-OS triple version mapping for the 26-aligned releases
Port LLVM's `isValidVersionForOS` / `getCanonicalVersionForOS` and rewrite `_iOSVersion` to match `getiOSVersion`: iOS & tvOS 19 -> 26, xrOS 1/2 -> iOS 17/18, xrOS 3 -> 26, watchOS 12 -> 26, with gap versions canonicalized into the 26+ space.
1 parent f70723b commit b319161

2 files changed

Lines changed: 93 additions & 6 deletions

File tree

Sources/SwiftDriver/Utilities/Triple.swift

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,60 @@ extension Triple {
15731573
// MARK: - Darwin Versions
15741574

15751575
extension Triple {
1576+
// Version 26 alignment helpers, ported from LLVM's `isValidVersionForOS` /
1577+
// `getCanonicalVersionForOS`. Each Apple OS jumped to the version 26, leaving
1578+
// an unshipped version gap below 26. Only `_iOSVersion` consumes these.
1579+
1580+
/// False if `version` is in the unshipped gap.
1581+
static func _isValidVersion(_ version: Version, for os: OS) -> Bool {
1582+
let commonMajor = 26
1583+
func valid(after starting: Int) -> Bool {
1584+
!(version.major > starting && version.major < commonMajor)
1585+
}
1586+
switch os {
1587+
case .watchos: return valid(after: 12)
1588+
case .ios, .tvos: return valid(after: 19)
1589+
case .macosx: return valid(after: 16)
1590+
case .visionos: return valid(after: 3)
1591+
default: return true
1592+
}
1593+
}
1594+
1595+
/// Canonicalize a pre-26 or gap version into the year-aligned (26+) space.
1596+
static func _canonicalVersion(_ version: Version, for os: OS,
1597+
isInValidRange: Bool) -> Version {
1598+
func bumped(by delta: Int) -> Version {
1599+
Version(version.major + delta, version.minor, version.micro)
1600+
}
1601+
func isExactly(_ major: Int) -> Bool {
1602+
version.major == major && version.minor == 0 && version.micro == 0
1603+
}
1604+
switch os {
1605+
case .macosx:
1606+
if version.major == 10 && version.minor == 16 { return Version(11, 0, 0) }
1607+
if isExactly(16) { return Version(26, 0, 0) }
1608+
if !isInValidRange { return bumped(by: 10) }
1609+
case .ios, .tvos:
1610+
if isExactly(19) { return Version(26, 0, 0) }
1611+
if !isInValidRange { return bumped(by: 7) }
1612+
case .visionos:
1613+
if isExactly(3) { return Version(26, 0, 0) }
1614+
if !isInValidRange { return bumped(by: 23) }
1615+
case .watchos:
1616+
if isExactly(12) { return Version(26, 0, 0) }
1617+
if !isInValidRange { return bumped(by: 14) }
1618+
default:
1619+
break
1620+
}
1621+
return version
1622+
}
1623+
1624+
/// Canonicalize using the platform's own validity check.
1625+
static func _canonicalVersion(_ version: Version, for os: OS) -> Version {
1626+
_canonicalVersion(version, for: os,
1627+
isInValidRange: _isValidVersion(version, for: os))
1628+
}
1629+
15761630
/// Parse the version number as with getOSVersion and then
15771631
/// translate generic "darwin" versions to the corresponding OS X versions.
15781632
/// This may also be called with IOS triples but the OS X version number is
@@ -1649,19 +1703,29 @@ extension Triple {
16491703
// toolchain that wants to know the iOS version number even when targeting
16501704
// OS X.
16511705
return Version(5, 0, 0)
1652-
case .ios:
1706+
case .ios, .tvos:
16531707
var version = self.osVersion
16541708
// Default to 5.0 (or 7.0 for arm64).
16551709
if version.major == 0 {
16561710
version.major = arch == .aarch64 ? 7 : 5
16571711
}
1658-
return version
1659-
case .tvos:
1660-
return osVersion
1712+
// iOS & tvOS 19 correspond to iOS 26.
1713+
if version.major == 19 {
1714+
return Version(26, 0, 0)
1715+
}
1716+
return Triple._canonicalVersion(version, for: .ios)
16611717
case .visionos:
1662-
return Version(15, 0, 0)
1718+
let version = self.osVersion
1719+
// xrOS 1/2 are aligned with iOS 17/18.
1720+
if version.major < 3 {
1721+
return Version(version.major + 16, version.minor, version.micro)
1722+
}
1723+
// visionOS 3 corresponds to iOS 26.
1724+
return Triple._canonicalVersion(version, for: .visionos)
16631725
case .watchos:
1664-
fatalError("conflicting triple info")
1726+
let version = self.osVersion
1727+
// watchOS 12 corresponds to iOS 26.
1728+
return Triple._canonicalVersion(version, for: .watchos)
16651729
default:
16661730
fatalError("unexpected OS for Darwin triple")
16671731
}

Tests/SwiftDriverTests/TripleTests.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,29 @@ import class TSCBasic.DiagnosticsEngine
11801180
#expect(!T.isMacCatalyst)
11811181
}
11821182

1183+
/// Mirrors LLVM `getiOSVersion` / `getCanonicalVersionForOS` year-26 alignment.
1184+
@Test func iOSVersionAlignment() {
1185+
func iOSVersion(_ triple: String) -> Triple.Version { Triple(triple)._iOSVersion }
1186+
1187+
// iOS / tvOS 19 -> iOS 26; already-aligned and pre-jump values pass through;
1188+
// a gap version (20-25) bumps by 7.
1189+
#expect(iOSVersion("arm64-apple-ios19.0") == Triple.Version(26, 0, 0))
1190+
#expect(iOSVersion("arm64-apple-ios26.0") == Triple.Version(26, 0, 0))
1191+
#expect(iOSVersion("arm64-apple-ios18.0") == Triple.Version(18, 0, 0))
1192+
#expect(iOSVersion("arm64-apple-ios21.0") == Triple.Version(28, 0, 0))
1193+
#expect(iOSVersion("arm64-apple-tvos19.0") == Triple.Version(26, 0, 0))
1194+
1195+
// visionOS (xrOS): 1/2 align with iOS 17/18, 3 -> iOS 26.
1196+
#expect(iOSVersion("arm64-apple-xros1.0") == Triple.Version(17, 0, 0))
1197+
#expect(iOSVersion("arm64-apple-xros2.0") == Triple.Version(18, 0, 0))
1198+
#expect(iOSVersion("arm64-apple-xros3.0") == Triple.Version(26, 0, 0))
1199+
#expect(iOSVersion("arm64-apple-xros26.0") == Triple.Version(26, 0, 0))
1200+
1201+
// watchOS 12 -> iOS 26.
1202+
#expect(iOSVersion("arm64-apple-watchos12.0") == Triple.Version(26, 0, 0))
1203+
#expect(iOSVersion("arm64-apple-watchos11.0") == Triple.Version(11, 0, 0))
1204+
}
1205+
11831206
@Test func fileFormat() {
11841207
#expect(.elf == Triple("i686-unknown-linux-gnu").objectFormat)
11851208
#expect(.elf == Triple("x86_64-unknown-linux-gnu").objectFormat)

0 commit comments

Comments
 (0)