Files
swift-mirror/stdlib/public/core/Availability.swift
Doug Gregor 0ec13f9a90 Build compiler and runtimes without Swift
Remove dependency on macros from compiler and stdlib build when
bootstrapping the compiler without Swift available.
2025-03-06 13:32:52 -08:00

261 lines
9.4 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import SwiftShims
/// Returns 1 if the running OS version is greater than or equal to
/// major.minor.patchVersion and 0 otherwise.
///
/// This is a magic entry point known to the compiler. It is called in
/// generated code for API availability checking.
///
/// This is marked @_transparent on iOS to work around broken availability
/// checking for iOS apps running on macOS (rdar://83378814). libswiftCore uses
/// the macOS platform identifier for its version check in that scenario,
/// causing all queries to return true. When this function is inlined into the
/// caller, the compiler embeds the correct platform identifier in the client
/// code, and we get the right answer.
///
/// @_transparent breaks the optimizer's ability to remove availability checks
/// that are unnecessary due to the current deployment target. We call through
/// to the _stdlib_isOSVersionAtLeast_AEIC function below to work around this,
/// as the optimizer is able to perform this optimization for a
/// @_alwaysEmitIntoClient function. We can't use @_alwaysEmitIntoClient
/// directly on this call because it would break ABI for existing apps.
///
/// `@_transparent` breaks the interpreter mode on macOS, as it creates a direct
/// reference to ___isPlatformVersionAtLeast from compiler-rt, and the
/// interpreter doesn't currently know how to load symbols from compiler-rt.
/// Since `@_transparent` is only necessary for iOS apps, we only apply it on
/// iOS, not any other which would inherit/remap iOS availability.
#if os(iOS) && !os(visionOS)
@_effects(readnone)
@_transparent
@_noLocks
public func _stdlib_isOSVersionAtLeast(
_ major: Builtin.Word,
_ minor: Builtin.Word,
_ patch: Builtin.Word
) -> Builtin.Int1 {
return _stdlib_isOSVersionAtLeast_AEIC(major, minor, patch)
}
#else
@_semantics("availability.osversion")
@_effects(readnone)
@_unavailableInEmbedded
#if hasFeature(Macros)
@_noLocks
#endif
public func _stdlib_isOSVersionAtLeast(
_ major: Builtin.Word,
_ minor: Builtin.Word,
_ patch: Builtin.Word
) -> Builtin.Int1 {
return _stdlib_isOSVersionAtLeast_AEIC(major, minor, patch)
}
#endif
@_semantics("availability.osversion")
@_effects(readnone)
@_alwaysEmitIntoClient
#if hasFeature(Macros)
@_noLocks
#endif
public func _stdlib_isOSVersionAtLeast_AEIC(
_ major: Builtin.Word,
_ minor: Builtin.Word,
_ patch: Builtin.Word
) -> Builtin.Int1 {
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(visionOS)) && SWIFT_RUNTIME_OS_VERSIONING
if Int(major) == 9999 {
return true._value
}
let queryVersion = (Int(major), Int(minor), Int(patch))
let major32 = Int32(truncatingIfNeeded:Int(queryVersion.0))
let minor32 = Int32(truncatingIfNeeded:Int(queryVersion.1))
let patch32 = Int32(truncatingIfNeeded:Int(queryVersion.2))
// Defer to a builtin that calls clang's version checking builtin from
// compiler-rt.
let result32 = Int32(Builtin.targetOSVersionAtLeast(major32._value,
minor32._value,
patch32._value))
return (result32 != (0 as Int32))._value
#else
// FIXME: As yet, there is no obvious versioning standard for platforms other
// than Darwin-based OSes, so we just assume false for now.
// rdar://problem/18881232
return false._value
#endif
}
// Performs an availability check in macCatalyst code to support back
// deployment. This entry point takes in a variant OS version
// (i.e, an iOS version).
//
// This is not inlinable because we
// don't want to inline the messy implementation details of the
// compiler-rt support into apps and expose those as ABI surface.
//
// This is a magic entry point known to the compiler. It is called in
// generated code for API availability checking.
#if (os(macOS) || os(iOS) && targetEnvironment(macCatalyst)) && SWIFT_RUNTIME_OS_VERSIONING
@_semantics("availability.osversion")
@_effects(readnone)
@available(macOS 10.15, iOS 13.0, *)
#if hasFeature(Macros)
@_noLocks
#endif
public func _stdlib_isVariantOSVersionAtLeast(
_ major: Builtin.Word,
_ minor: Builtin.Word,
_ patch: Builtin.Word
) -> Builtin.Int1 {
if Int(major) == 9999 {
return true._value
}
let queryVersion = (Int(major), Int(minor), Int(patch))
let major32 = Int32(truncatingIfNeeded:Int(queryVersion.0))
let minor32 = Int32(truncatingIfNeeded:Int(queryVersion.1))
let patch32 = Int32(truncatingIfNeeded:Int(queryVersion.2))
// Defer to a builtin that calls clang's version checking builtin from
// compiler-rt.
let result32 = Int32(Builtin.targetVariantOSVersionAtLeast(major32._value,
minor32._value,
patch32._value))
return (result32 != (0 as Int32))._value
}
#endif
// Performs an availability check in zippered code to support back
// deployment. This entry point takes in both a primary OS version
// (i.e., a macOS version) and a variant OS version (i.e, an iOS version).
//
// In a normal macOS process it will return 1 if the running OS version is
// greater than or equal to major.minor.patchVersion and 0 otherwise. For an
// macCatalyst process it will return 1 if the running macCatalyst version is greater
// than or equal to the passed-in variant version.
//
// Unlike _stdlib_isOSVersionAtLeast, this is not inlinable because we
// don't want to inline the messy implementation details of the
// compiler-rt support into apps and expose those as ABI surface.
//
// This is a magic entry point known to the compiler. It is called in
// generated code for API availability checking.
#if (os(macOS) || os(iOS) && targetEnvironment(macCatalyst)) && SWIFT_RUNTIME_OS_VERSIONING
@_semantics("availability.osversion")
@_effects(readnone)
@_unavailableInEmbedded
#if hasFeature(Macros)
@_noLocks
#endif
public func _stdlib_isOSVersionAtLeastOrVariantVersionAtLeast(
_ major: Builtin.Word,
_ minor: Builtin.Word,
_ patch: Builtin.Word,
_ variantMajor: Builtin.Word,
_ variantMinor: Builtin.Word,
_ variantPatch: Builtin.Word
) -> Builtin.Int1 {
if Int(major) == 9999 {
return true._value
}
let queryVersion = (Int(major), Int(minor), Int(patch))
let queryVariantVersion =
(Int(variantMajor), Int(variantMinor), Int(variantPatch))
let major32 = UInt32(truncatingIfNeeded:Int(queryVersion.0))
let minor32 = UInt32(truncatingIfNeeded:Int(queryVersion.1))
let patch32 = UInt32(truncatingIfNeeded:Int(queryVersion.2))
let variantMajor32 = UInt32(truncatingIfNeeded:Int(queryVariantVersion.0))
let variantMinor32 = UInt32(truncatingIfNeeded:Int(queryVariantVersion.1))
let variantPatch32 = UInt32(truncatingIfNeeded:Int(queryVariantVersion.2))
// Defer to a builtin that calls clang's version checking builtin from
// compiler-rt.
let result32 = Int32(Builtin.targetOSVersionOrVariantOSVersionAtLeast(
major32._value, minor32._value, patch32._value,
variantMajor32._value, variantMinor32._value, variantPatch32._value))
return (result32 != (0 as UInt32))._value
}
#endif
public typealias _SwiftStdlibVersion = SwiftShims._SwiftStdlibVersion
/// Return true if the main executable was linked with an SDK version
/// corresponding to the given Swift Stdlib release, or later. Otherwise, return
/// false.
///
/// This is useful to maintain compatibility with older binaries after a
/// behavioral change in the stdlib.
///
/// This function must not be called from inlinable code.
@inline(__always)
@_unavailableInEmbedded
internal func _isExecutableLinkedOnOrAfter(
_ stdlibVersion: _SwiftStdlibVersion
) -> Bool {
#if SWIFT_RUNTIME_OS_VERSIONING
return _swift_stdlib_isExecutableLinkedOnOrAfter(stdlibVersion)
#else
return true
#endif
}
extension _SwiftStdlibVersion {
@_alwaysEmitIntoClient
public static var v5_6_0: Self { Self(_value: 0x050600) }
@_alwaysEmitIntoClient
public static var v5_7_0: Self { Self(_value: 0x050700) }
// Note: As of now, there is no bincompat level defined for the versions
// below. If you need to use one of these in a call to
// `_isExecutableLinkedOnOrAfter`, then you'll need to define the
// corresponding version in the runtime.
@_alwaysEmitIntoClient
public static var v5_8_0: Self { Self(_value: 0x050800) }
@_alwaysEmitIntoClient
public static var v5_9_0: Self { Self(_value: 0x050900) }
@_alwaysEmitIntoClient
public static var v5_10_0: Self { Self(_value: 0x050A00) }
@_alwaysEmitIntoClient
public static var v6_0_0: Self { Self(_value: 0x060000) }
@_alwaysEmitIntoClient
public static var v6_1_0: Self { Self(_value: 0x060100) }
@_alwaysEmitIntoClient
public static var v6_2_0: Self { Self(_value: 0x060200) }
@available(SwiftStdlib 5.7, *)
public static var current: Self { .v6_2_0 }
}
@available(SwiftStdlib 5.7, *)
@_unavailableInEmbedded
extension _SwiftStdlibVersion: CustomStringConvertible {
@available(SwiftStdlib 5.7, *)
public var description: String {
let major = _value >> 16
let minor = (_value >> 8) & 0xFF
let patch = _value & 0xFF
return "\(major).\(minor).\(patch)"
}
}