From a86fe4fa30b22182aff7e8f58ae302b99918e3f6 Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Mon, 7 Apr 2025 17:45:35 -0700 Subject: [PATCH 1/2] Add a "lazy" lifetime inference for mutating interface methods When type checking a .swiftinterface file, Assume that a mutating methods does not depend on its parameters. This is unsafe but needed because some MutableSpan APIs snuck into the standard library interface without specifying dependencies. Fixes rdar://148697444 error: a mutating method with a ~Escapable 'self' requires '@lifetime(self: ...)' --- lib/AST/LifetimeDependence.cpp | 18 ++++++++++++++++++ .../lifetime_depend_infer.swiftinterface | 12 ++++++++++++ 2 files changed, 30 insertions(+) diff --git a/lib/AST/LifetimeDependence.cpp b/lib/AST/LifetimeDependence.cpp index d64e3d2576046..964e3b5dfa145 100644 --- a/lib/AST/LifetimeDependence.cpp +++ b/lib/AST/LifetimeDependence.cpp @@ -1069,6 +1069,13 @@ class LifetimeDependenceChecker { return; } if (afd->getParameters()->size() > 0) { + if (useLazyInference()) { + // Assume that a mutating method does not depend on its parameters. + // This is unsafe but needed because some MutableSpan APIs snuck into + // the standard library interface without specifying dependencies. + pushDeps(createDeps(selfIndex).add(selfIndex, + LifetimeDependenceKind::Inherit)); + } return; } pushDeps(createDeps(selfIndex).add(selfIndex, @@ -1115,6 +1122,17 @@ class LifetimeDependenceChecker { .add(newValIdx, *kind)); break; } + case AccessorKind::MutableAddress: + if (useLazyInference()) { + // Assume that a mutating method does not depend on its parameters. + // Currently only for backward interface compatibility. Even though this + // is the only useful dependence (a borrow of self is possible but not + // useful), explicit annotation is required for now to confirm that the + // mutated self cannot depend on anything stored at this address. + pushDeps(createDeps(selfIndex).add(selfIndex, + LifetimeDependenceKind::Inherit)); + } + break; default: // Unknown mutating accessor. break; diff --git a/test/Sema/Inputs/lifetime_depend_infer.swiftinterface b/test/Sema/Inputs/lifetime_depend_infer.swiftinterface index f7982508c5773..14017799cc816 100644 --- a/test/Sema/Inputs/lifetime_depend_infer.swiftinterface +++ b/test/Sema/Inputs/lifetime_depend_infer.swiftinterface @@ -71,6 +71,18 @@ public struct NonEscapableSelf : ~Swift.Escapable { public mutating func mutatingMethodOneParamBorrow(_: Swift.Int) -> lifetime_depend_infer.NonEscapableSelf #endif } + +public struct NoncopyableInoutMethods : ~Swift.Copyable & ~Swift.Escapable { +#if $LifetimeDependence +public mutating func mutatingMethodOneParamFunctionType(_ body: (Swift.Int) throws(E) -> Result) throws(E) -> Result where E : Swift.Error, Result : ~Swift.Copyable + +public subscript(position: Swift.Int) -> Swift.Int { + unsafeAddress + unsafeMutableAddress +} +#endif +} + public struct EscapableTrivialSelf { #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence @lifetime(self) From 7613c5e52e684ffd250edf297bdd87bd5d436f5a Mon Sep 17 00:00:00 2001 From: Andrew Trick Date: Mon, 7 Apr 2025 18:11:12 -0700 Subject: [PATCH 2/2] [NFC] cleanup feature flags in lifetime_depend_infer.swiftinterface --- .../lifetime_depend_infer.swiftinterface | 239 ++++++------------ 1 file changed, 83 insertions(+), 156 deletions(-) diff --git a/test/Sema/Inputs/lifetime_depend_infer.swiftinterface b/test/Sema/Inputs/lifetime_depend_infer.swiftinterface index 14017799cc816..95ed90aaca1a7 100644 --- a/test/Sema/Inputs/lifetime_depend_infer.swiftinterface +++ b/test/Sema/Inputs/lifetime_depend_infer.swiftinterface @@ -6,359 +6,286 @@ import Swift import _Concurrency import _StringProcessing import _SwiftConcurrencyShims + @_hasMissingDesignatedInitializers public class C {} + +#if $LifetimeDependence public struct NE : ~Swift.Escapable { } public struct NEImmortal : ~Swift.Escapable { - #if $LifetimeDependence @lifetime(immortal) public init() - #endif + } + public struct NonEscapableSelf : ~Swift.Escapable { - #if $LifetimeDependence public func methodNoParam() -> lifetime_depend_infer.NonEscapableSelf - #endif - #if $LifetimeDependence + @lifetime(self) public func methodNoParamLifetime() -> lifetime_depend_infer.NonEscapableSelf - #endif - #if $LifetimeDependence + @lifetime(copy self) public func methodNoParamCopy() -> lifetime_depend_infer.NonEscapableSelf - #endif - #if $LifetimeDependence + @lifetime(borrow self) public func methodNoParamBorrow() -> lifetime_depend_infer.NonEscapableSelf - #endif - #if $LifetimeDependence + @lifetime(self) public mutating func mutatingMethodNoParamLifetime() -> lifetime_depend_infer.NonEscapableSelf - #endif - #if $LifetimeDependence + @lifetime(copy self) public mutating func mutatingMethodNoParamCopy() -> lifetime_depend_infer.NonEscapableSelf - #endif - #if $LifetimeDependence + @lifetime(&self) public mutating func mutatingMethodNoParamBorrow() -> lifetime_depend_infer.NonEscapableSelf - #endif - #if $LifetimeDependence + public func methodOneParam(_: Swift.Int) -> lifetime_depend_infer.NonEscapableSelf - #endif - #if $LifetimeDependence + @lifetime(self) public func methodOneParamLifetime(_: Swift.Int) -> lifetime_depend_infer.NonEscapableSelf - #endif - #if $LifetimeDependence + @lifetime(copy self) public func methodOneParamCopy(_: Swift.Int) -> lifetime_depend_infer.NonEscapableSelf - #endif - #if $LifetimeDependence + @lifetime(borrow self) public func methodOneParamBorrow(_: Swift.Int) -> lifetime_depend_infer.NonEscapableSelf - #endif - #if $LifetimeDependence + @lifetime(self) public mutating func mutatingMethodOneParamLifetime(_: Swift.Int) -> lifetime_depend_infer.NonEscapableSelf - #endif - #if $LifetimeDependence + @lifetime(copy self) public mutating func mutatingMethodOneParamCopy(_: Swift.Int) -> lifetime_depend_infer.NonEscapableSelf - #endif - #if $LifetimeDependence + @lifetime(&self) - public mutating func mutatingMethodOneParamBorrow(_: Swift.Int) -> lifetime_depend_infer.NonEscapableSelf - #endif + public mutating func mutatingMethodOneParamBorrow(_: Swift.Int) -> lifetime_depend_infer.NonEscapableSelf } public struct NoncopyableInoutMethods : ~Swift.Copyable & ~Swift.Escapable { -#if $LifetimeDependence -public mutating func mutatingMethodOneParamFunctionType(_ body: (Swift.Int) throws(E) -> Result) throws(E) -> Result where E : Swift.Error, Result : ~Swift.Copyable + public mutating func mutatingMethodOneParamFunctionType(_ body: (Swift.Int) throws(E) -> Result) throws(E) -> Result where E : Swift.Error, Result : ~Swift.Copyable -public subscript(position: Swift.Int) -> Swift.Int { - unsafeAddress - unsafeMutableAddress -} -#endif + public subscript(position: Swift.Int) -> Swift.Int { + unsafeAddress + unsafeMutableAddress + } } public struct EscapableTrivialSelf { - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence @lifetime(self) public func methodNoParamLifetime() -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(borrow self) public func methodNoParamBorrow() -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(self) public mutating func mutatingMethodNoParamLifetime() -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(&self) public mutating func mutatingMethodNoParamBorrow() -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(self) public func methodOneParamLifetime(_: Swift.Int) -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(borrow self) public func methodOneParamBorrow(_: Swift.Int) -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(self) public mutating func mutatingMethodOneParamLifetime(_: Swift.Int) -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(&self) public mutating func mutatingMethodOneParamBorrow(_: Swift.Int) -> lifetime_depend_infer.NEImmortal - #endif + } public struct EscapableNonTrivialSelf { public init(c: lifetime_depend_infer.C) - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence public func methodNoParam() -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(self) public func methodNoParamLifetime() -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(borrow self) public func methodNoParamBorrow() -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + public func mutatingMethodNoParam() -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(self) public mutating func mutatingMethodNoParamLifetime() -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(&self) public mutating func mutatingMethodNoParamBorrow() -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + public func methodOneParam(_: Swift.Int) -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(self) public func methodOneParamLifetime(_: Swift.Int) -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(borrow self) public func methodOneParamBorrow(_: Swift.Int) -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + public mutating func mutatingMethodOneParam(_: Swift.Int) -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(self) public mutating func mutatingMethodOneParamLifetime(_: Swift.Int) -> lifetime_depend_infer.NEImmortal - #endif - #if compiler(>=5.3) && $NonescapableTypes && $LifetimeDependence + @lifetime(&self) public mutating func mutatingMethodOneParamBorrow(_: Swift.Int) -> lifetime_depend_infer.NEImmortal - #endif + } public struct NonescapableInitializers : ~Swift.Escapable { public var c: lifetime_depend_infer.C - #if $LifetimeDependence public init(ne: lifetime_depend_infer.NE) - #endif + } public struct NonescapableConsumingInitializers : ~Swift.Escapable { public var c: lifetime_depend_infer.C - #if $LifetimeDependence public init(ne: consuming lifetime_depend_infer.NE) - #endif + } public struct NonescapableBorrowingInitializers : ~Swift.Escapable { public var c: lifetime_depend_infer.C - #if $LifetimeDependence public init(c: borrowing lifetime_depend_infer.C) - #endif - #if $LifetimeDependence + public init(c: borrowing lifetime_depend_infer.C, _: Swift.Int) - #endif - #if $LifetimeDependence + public init(ne: borrowing lifetime_depend_infer.NE) - #endif + } public struct NonescapableInoutInitializers : ~Swift.Escapable { public var c: lifetime_depend_infer.C - #if $LifetimeDependence public init(c: inout lifetime_depend_infer.C) - #endif + } -#if $LifetimeDependence @lifetime(immortal) public func noParamImmortal() -> lifetime_depend_infer.NEImmortal -#endif -#if $LifetimeDependence + @lifetime(c) public func oneParamLifetime(c: lifetime_depend_infer.C) -> lifetime_depend_infer.NEImmortal -#endif -#if $LifetimeDependence + public func oneParamBorrow(c: borrowing lifetime_depend_infer.C) -> lifetime_depend_infer.NEImmortal -#endif -#if $LifetimeDependence + @lifetime(c) public func oneParamBorrowLifetime(c: borrowing lifetime_depend_infer.C) -> lifetime_depend_infer.NEImmortal -#endif -#if $LifetimeDependence + public func oneParamInout(c: inout lifetime_depend_infer.C) -> lifetime_depend_infer.NEImmortal -#endif -#if $LifetimeDependence + @lifetime(c) public func oneParamInoutLifetime(c: inout lifetime_depend_infer.C) -> lifetime_depend_infer.NEImmortal -#endif -#if $LifetimeDependence + @lifetime(c) public func twoParamsLifetime(c: lifetime_depend_infer.C, _: Swift.Int) -> lifetime_depend_infer.NEImmortal -#endif -#if $LifetimeDependence + public func twoParamsBorrow(c: borrowing lifetime_depend_infer.C, _: Swift.Int) -> lifetime_depend_infer.NEImmortal -#endif -#if $LifetimeDependence + public func neParam(ne: lifetime_depend_infer.NE) -> lifetime_depend_infer.NE -#endif -#if $LifetimeDependence + @lifetime(ne) public func neParamLifetime(ne: lifetime_depend_infer.NE) -> lifetime_depend_infer.NE -#endif -#if $LifetimeDependence + public func neParamBorrow(ne: borrowing lifetime_depend_infer.NE) -> lifetime_depend_infer.NE -#endif -#if $LifetimeDependence + @lifetime(ne) public func neParamBorrowLifetime(ne: borrowing lifetime_depend_infer.NE) -> lifetime_depend_infer.NE -#endif -#if $LifetimeDependence + public func neParamConsume(ne: consuming lifetime_depend_infer.NE) -> lifetime_depend_infer.NE -#endif -#if $LifetimeDependence + @lifetime(ne) public func neParamConsumeLifetime(ne: consuming lifetime_depend_infer.NE) -> lifetime_depend_infer.NE -#endif -#if $LifetimeDependence + public func neTwoParam(ne: lifetime_depend_infer.NE, _: Swift.Int) -> lifetime_depend_infer.NE -#endif + public struct Accessors { - #if $LifetimeDependence public var neYielded: lifetime_depend_infer.NEImmortal { _read _modify } - #endif + } public struct NonescapableSelfAccessors : ~Swift.Escapable { public var ne: lifetime_depend_infer.NE - #if $LifetimeDependence public init(ne: lifetime_depend_infer.NE) - #endif - #if $LifetimeDependence + public var neComputed: lifetime_depend_infer.NE { get } - #endif - #if $LifetimeDependence + public var neYielded: lifetime_depend_infer.NE { _read @lifetime(&self) _modify } - #endif + } public struct NoncopyableSelfAccessors : ~Copyable & ~Escapable { public var ne: lifetime_depend_infer.NE - #if $LifetimeDependence public var neComputed: lifetime_depend_infer.NE { get set } - #endif - #if $LifetimeDependence + public var neYielded: lifetime_depend_infer.NE { _read @lifetime(&self) _modify } - #endif - #if $LifetimeDependence + public var neComputedLifetime: lifetime_depend_infer.NE { @lifetime(self) get @lifetime(self) set } - #endif - #if $LifetimeDependence + public var neYieldedLifetime: lifetime_depend_infer.NE { @lifetime(self) _read @lifetime(self) _modify } - #endif - #if $LifetimeDependence + public var neComputedCopy: lifetime_depend_infer.NE { @lifetime(copy self) get @lifetime(copy self) set } - #endif - #if $LifetimeDependence + public var neYieldedCopy: lifetime_depend_infer.NE { @lifetime(copy self) _read @lifetime(copy self) _modify } - #endif - #if $LifetimeDependence + public var neComputedBorrow: lifetime_depend_infer.NE { @lifetime(borrow self) get @lifetime(&self) set } - #endif - #if $LifetimeDependence + public var neYieldedBorrow: lifetime_depend_infer.NE { @lifetime(borrow self) _read @lifetime(&self) _modify } - #endif } + public struct NonEscapableMutableSelf : ~Swift.Escapable { - #if $LifetimeDependence public mutating func mutatingMethodNoParam() - #endif - #if $LifetimeDependence + @lifetime(self: self) public mutating func mutatingMethodNoParamLifetime() - #endif - #if $LifetimeDependence + @lifetime(self: copy self) public mutating func mutatingMethodNoParamCopy() - #endif - #if $LifetimeDependence + @lifetime(self: self) public mutating func mutatingMethodOneParamLifetime(_: lifetime_depend_infer.NE) - #endif - #if $LifetimeDependence + @lifetime(copy self) public mutating func mutatingMethodOneParamCopy(_: lifetime_depend_infer.NE) - #endif - #if $LifetimeDependence + @lifetime(&self) public mutating func mutatingMethodOneParamBorrow(_: lifetime_depend_infer.NE) - #endif } +#endif