Frontend: Replace the abi magic value accepted by -target-min-inlining-version with a min magic value instead. The new value corresponds to the OS versions in which Swift was introduced. The introduction OS is a better floor for availability checking than the OS in which Swift became ABI stable because inlinable functions may reference clang declarations which have availability between Swift's introduction and ABI stability and framework developers ought to get diagnostics for unguarded use of those APIs in inlinable code.

This commit is contained in:
Allan Shortlidge
2022-03-14 11:23:26 -07:00
parent f807ef92e6
commit b563dc0736
4 changed files with 64 additions and 27 deletions

View File

@@ -55,8 +55,10 @@ namespace swift {
bool triplesAreValidForZippering(const llvm::Triple &target,
const llvm::Triple &targetVariant);
/// Returns the VersionTuple at which Swift first became available for the OS
/// represented by `triple`.
const Optional<llvm::VersionTuple>
minimumABIStableOSVersionForTriple(const llvm::Triple &triple);
minimumAvailableOSVersionForTriple(const llvm::Triple &triple);
/// Returns true if the given triple represents an OS that has all the
/// "built-in" ABI-stable libraries (stdlib and _Concurrency)

View File

@@ -80,15 +80,20 @@ bool swift::triplesAreValidForZippering(const llvm::Triple &target,
}
const Optional<llvm::VersionTuple>
swift::minimumABIStableOSVersionForTriple(const llvm::Triple &triple) {
swift::minimumAvailableOSVersionForTriple(const llvm::Triple &triple) {
if (triple.isMacOSX())
return llvm::VersionTuple(10, 14, 4);
return llvm::VersionTuple(10, 10, 0);
if (triple.isiOS() /* including tvOS */)
return llvm::VersionTuple(12, 2);
// Note: this must come before checking iOS since that returns true for
// both iOS and tvOS.
if (triple.isTvOS())
return llvm::VersionTuple(9, 0);
if (triple.isiOS())
return llvm::VersionTuple(8, 0);
if (triple.isWatchOS())
return llvm::VersionTuple(5, 2);
return llvm::VersionTuple(2, 0);
return None;
}

View File

@@ -803,15 +803,12 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
// First, set up default minimum inlining target versions.
auto getDefaultMinimumInliningTargetVersion =
[&](const llvm::Triple &triple) -> llvm::VersionTuple {
#if SWIFT_DEFAULT_TARGET_MIN_INLINING_VERSION_TO_ABI
// In ABI-stable modules, default to the version where the target's ABI
// was first frozen; older versions will use that one's backwards
// compatibility libraries.
#if SWIFT_DEFAULT_TARGET_MIN_INLINING_VERSION_TO_MIN
// In ABI-stable modules, default to the version when Swift first became
// available.
if (FrontendOpts.EnableLibraryEvolution)
if (auto abiStability = minimumABIStableOSVersionForTriple(triple))
// FIXME: Should we raise it to the minimum supported OS version for
// architectures which were born ABI-stable?
return *abiStability;
if (auto minTriple = minimumAvailableOSVersionForTriple(triple))
return minTriple;
#endif
// In ABI-unstable modules, we will never have to interoperate with
@@ -834,10 +831,10 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
if (!A)
return None;
if (StringRef(A->getValue()) == "min")
return minimumAvailableOSVersionForTriple(Opts.Target);
if (StringRef(A->getValue()) == "target")
return Opts.getMinPlatformVersion();
if (StringRef(A->getValue()) == "abi")
return minimumABIStableOSVersionForTriple(Opts.Target);
if (auto vers = version::Version::parseVersionString(A->getValue(),
SourceLoc(), &Diags))

View File

@@ -11,10 +11,9 @@
// REQUIRES: swift_stable_abi
// Primary execution of this test. Uses the default minimum inlining version,
// which is the version when the ABI became stable.
// RUN: %target-typecheck-verify-swift -swift-version 5 -enable-library-evolution -target %target-next-stable-abi-triple -target-min-inlining-version abi
// which is the version when Swift was introduced.
// RUN: %target-typecheck-verify-swift -swift-version 5 -enable-library-evolution -target %target-next-stable-abi-triple -target-min-inlining-version min
// Check that these rules are only applied when requested and that at least some
@@ -34,12 +33,12 @@ public struct NoAvailable {
@usableFromInline internal init() {}
}
@available(macOS 10.14.3, iOS 12.1, tvOS 12.1, watchOS 5.1, *)
@available(macOS 10.9, iOS 7.0, tvOS 8.0, watchOS 1.0, *)
public struct BeforeInliningTarget {
@usableFromInline internal init() {}
}
@available(macOS 10.14.4, iOS 12.2, tvOS 12.2, watchOS 5.2, *)
@available(macOS 10.10, iOS 8.0, tvOS 9.0, watchOS 2.0, *)
public struct AtInliningTarget {
@usableFromInline internal init() {}
}
@@ -90,7 +89,7 @@ public func deployedUseNoAvailable( // expected-note 5 {{add @available attribut
}
}
@available(macOS 10.14.3, iOS 12.1, tvOS 12.1, watchOS 5.1, *)
@available(macOS 10.9, iOS 7.0, tvOS 8.0, watchOS 1.0, *)
public func deployedUseBeforeInliningTarget(
_: NoAvailable,
_: BeforeInliningTarget,
@@ -115,7 +114,7 @@ public func deployedUseBeforeInliningTarget(
}
}
@available(macOS 10.14.4, iOS 12.2, tvOS 12.2, watchOS 5.2, *)
@available(macOS 10.10, iOS 8.0, tvOS 9.0, watchOS 2.0, *)
public func deployedUseAtInliningTarget(
_: NoAvailable,
_: BeforeInliningTarget,
@@ -248,7 +247,7 @@ public func deployedUseAfterDeploymentTarget(
}
}
@available(macOS 10.14.3, iOS 12.1, tvOS 12.1, watchOS 5.1, *)
@available(macOS 10.9, iOS 7.0, tvOS 8.0, watchOS 1.0, *)
@inlinable public func inlinedUseBeforeInliningTarget(
_: NoAvailable,
_: BeforeInliningTarget,
@@ -264,7 +263,7 @@ public func deployedUseAfterDeploymentTarget(
_ = NoAvailable()
_ = BeforeInliningTarget()
_ = AtInliningTarget()
_ = BetweenTargets() // expected-error {{'BetweenTargets' is only available in}} {{18-25=10.14.5}} || {{31-35=12.3}} || {{42-46=12.3}} || {{56-59=5.3}}
_ = BetweenTargets() // expected-error {{'BetweenTargets' is only available in}} expected-note {{add 'if #available'}}
_ = AtDeploymentTarget() // expected-error {{'AtDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
_ = AfterDeploymentTarget() // expected-error {{'AfterDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
@@ -279,7 +278,7 @@ public func deployedUseAfterDeploymentTarget(
}
}
@available(macOS 10.14.4, iOS 12.2, tvOS 12.2, watchOS 5.2, *)
@available(macOS 10.10, iOS 8.0, tvOS 9.0, watchOS 2.0, *)
@inlinable public func inlinedUseAtInliningTarget(
_: NoAvailable,
_: BeforeInliningTarget,
@@ -295,7 +294,7 @@ public func deployedUseAfterDeploymentTarget(
_ = NoAvailable()
_ = BeforeInliningTarget()
_ = AtInliningTarget()
_ = BetweenTargets() // expected-error {{'BetweenTargets' is only available in}} {{18-25=10.14.5}} || {{31-35=12.3}} || {{42-46=12.3}} || {{56-59=5.3}}
_ = BetweenTargets() // expected-error {{'BetweenTargets' is only available in}} expected-note {{add 'if #available'}}
_ = AtDeploymentTarget() // expected-error {{'AtDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
_ = AfterDeploymentTarget() // expected-error {{'AfterDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
@@ -426,6 +425,40 @@ internal func fn() {
}
}
// @_backDeploy acts like @inlinable.
@available(macOS 10.10, iOS 8.0, tvOS 9.0, watchOS 2.0, *)
@_backDeploy(macOS 999.0, iOS 999.0, tvOS 999.0, watchOS 999.0)
public func backDeployedToInliningTarget(
_: NoAvailable,
_: BeforeInliningTarget,
_: AtInliningTarget,
_: BetweenTargets, // expected-error {{'BetweenTargets' is only available in}}
_: AtDeploymentTarget, // expected-error {{'AtDeploymentTarget' is only available in}}
_: AfterDeploymentTarget // expected-error {{'AfterDeploymentTarget' is only available in}}
) {
defer {
_ = AtDeploymentTarget() // expected-error {{'AtDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
_ = AfterDeploymentTarget() // expected-error {{'AfterDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
}
_ = NoAvailable()
_ = BeforeInliningTarget()
_ = AtInliningTarget()
_ = BetweenTargets() // expected-error {{'BetweenTargets' is only available in}} expected-note {{add 'if #available'}}
_ = AtDeploymentTarget() // expected-error {{'AtDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
_ = AfterDeploymentTarget() // expected-error {{'AfterDeploymentTarget' is only available in}} expected-note {{add 'if #available'}}
if #available(macOS 10.14.5, iOS 12.3, tvOS 12.3, watchOS 5.3, *) {
_ = BetweenTargets()
}
if #available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) {
_ = AtDeploymentTarget()
}
if #available(macOS 11, iOS 14, tvOS 14, watchOS 7, *) {
_ = AfterDeploymentTarget()
}
}
// Default arguments act like @inlinable.
public func defaultArgsUseNoAvailable( // expected-note 3 {{add @available attribute}}