Skip to content

Add unsafeLifetime APIs and fix RawSpan initializer lifetime dependencies #77912

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions stdlib/public/core/LifetimeManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,39 @@ extension String {
public func _copy<T>(_ value: T) -> T {
copy value
}

/// Unsafely discard any lifetime dependency on the `dependent` argument. Return
/// a value identical to `dependent` with a lifetime dependency on the caller's
/// borrow scope of the `source` argument.
@unsafe
@_unsafeNonescapableResult
@_alwaysEmitIntoClient
@_transparent
@lifetime(borrow source)
internal func _overrideLifetime<
T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable
>(
_ dependent: consuming T, borrowing source: borrowing U
) -> T {
// TODO: Remove @_unsafeNonescapableResult. Instead, the unsafe dependence
// should be expressed by a builtin that is hidden within the function body.
dependent
}

/// Unsafely discard any lifetime dependency on the `dependent` argument. Return
/// a value identical to `dependent` that inherits all lifetime dependencies from
/// the `source` argument.
@unsafe
@_unsafeNonescapableResult
@_alwaysEmitIntoClient
@_transparent
@lifetime(source)
internal func _overrideLifetime<
T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable
>(
_ dependent: consuming T, copying source: borrowing U
) -> T {
// TODO: Remove @_unsafeNonescapableResult. Instead, the unsafe dependence
// should be expressed by a builtin that is hidden within the function body.
dependent
}
79 changes: 58 additions & 21 deletions stdlib/public/core/Span/RawSpan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,11 @@ extension RawSpan {
public init(
_unsafeBytes buffer: UnsafeRawBufferPointer
) {
self.init(
_unchecked: buffer.baseAddress, byteCount: buffer.count
)
let baseAddress = buffer.baseAddress
let span = RawSpan(_unchecked: baseAddress, byteCount: buffer.count)
// As a trivial value, 'baseAddress' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Unsafely create a `RawSpan` over initialized memory.
Expand All @@ -115,7 +117,11 @@ extension RawSpan {
public init(
_unsafeBytes buffer: borrowing Slice<UnsafeRawBufferPointer>
) {
self.init(_unsafeBytes: UnsafeRawBufferPointer(rebasing: buffer))
let rawBuffer = UnsafeRawBufferPointer(rebasing: buffer)
let span = RawSpan(_unsafeBytes: rawBuffer)
// As a trivial value, 'rawBuffer' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Unsafely create a `RawSpan` over initialized memory.
Expand All @@ -131,15 +137,24 @@ extension RawSpan {
public init(
_unsafeBytes buffer: UnsafeMutableRawBufferPointer
) {
self.init(_unsafeBytes: UnsafeRawBufferPointer(buffer))
let rawBuffer = UnsafeRawBufferPointer(buffer)
let span = RawSpan(_unsafeBytes: rawBuffer)
// As a trivial value, 'rawBuffer' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

@_alwaysEmitIntoClient
@lifetime(borrow buffer)
public init(
_unsafeBytes buffer: borrowing Slice<UnsafeMutableRawBufferPointer>
) {
self.init(_unsafeBytes: UnsafeRawBufferPointer(rebasing: buffer))
let rawBuffer =
UnsafeRawBufferPointer(UnsafeMutableRawBufferPointer(rebasing: buffer))
let span = RawSpan(_unsafeBytes: rawBuffer)
// As a trivial value, 'rawBuffer' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Unsafely create a `RawSpan` over initialized memory.
Expand Down Expand Up @@ -175,7 +190,11 @@ extension RawSpan {
public init<T: BitwiseCopyable>(
_unsafeElements buffer: UnsafeBufferPointer<T>
) {
self.init(_unsafeBytes: UnsafeRawBufferPointer(buffer))
let rawBuffer = UnsafeRawBufferPointer(buffer)
let span = RawSpan(_unsafeBytes: rawBuffer)
// As a trivial value, 'rawBuffer' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Unsafely create a `RawSpan` over initialized memory.
Expand All @@ -191,9 +210,11 @@ extension RawSpan {
public init<T: BitwiseCopyable>(
_unsafeElements buffer: borrowing Slice<UnsafeBufferPointer<T>>
) {
self.init(
_unsafeBytes: .init(UnsafeBufferPointer(rebasing: buffer))
)
let rawBuffer = UnsafeRawBufferPointer(UnsafeBufferPointer(rebasing: buffer))
let span = RawSpan(_unsafeBytes: rawBuffer)
// As a trivial value, 'rawBuffer' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Unsafely create a `RawSpan` over initialized memory.
Expand All @@ -209,7 +230,11 @@ extension RawSpan {
public init<T: BitwiseCopyable>(
_unsafeElements buffer: UnsafeMutableBufferPointer<T>
) {
self.init(_unsafeElements: UnsafeBufferPointer(buffer))
let rawBuffer = UnsafeRawBufferPointer(buffer)
let span = RawSpan(_unsafeBytes: rawBuffer)
// As a trivial value, 'rawBuffer' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Unsafely create a `RawSpan` over initialized memory.
Expand All @@ -225,9 +250,12 @@ extension RawSpan {
public init<T: BitwiseCopyable>(
_unsafeElements buffer: borrowing Slice<UnsafeMutableBufferPointer<T>>
) {
self.init(
_unsafeBytes: .init(UnsafeBufferPointer(rebasing: buffer))
)
let rawBuffer =
UnsafeRawBufferPointer(UnsafeMutableBufferPointer(rebasing: buffer))
let span = RawSpan(_unsafeBytes: rawBuffer)
// As a trivial value, 'rawBuffer' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Unsafely create a `RawSpan` over initialized memory.
Expand Down Expand Up @@ -344,10 +372,9 @@ extension RawSpan {
@_alwaysEmitIntoClient
@lifetime(self)
public func _extracting(unchecked bounds: Range<Int>) -> Self {
RawSpan(
_unchecked: _pointer?.advanced(by: bounds.lowerBound),
byteCount: bounds.count
)
let newStart = _pointer?.advanced(by: bounds.lowerBound)
let newSpan = RawSpan(_unchecked: newStart, byteCount: bounds.count)
return _overrideLifetime(newSpan, copying: self)
}

/// Constructs a new span over the bytes within the supplied range of
Expand Down Expand Up @@ -457,7 +484,11 @@ extension RawSpan {
consuming public func _unsafeView<T: BitwiseCopyable>(
as type: T.Type
) -> Span<T> {
Span(_unsafeBytes: .init(start: _pointer, count: _count))
let rawBuffer = UnsafeRawBufferPointer(start: _pointer, count: _count)
let newSpan = Span<T>(_unsafeBytes: rawBuffer)
// As a trivial value, 'rawBuffer' does not formally depend on the
// lifetime of 'self'. Make the dependence explicit.
return _overrideLifetime(newSpan, copying: self)
}
}

Expand Down Expand Up @@ -677,7 +708,10 @@ extension RawSpan {
_precondition(maxLength >= 0, "Can't have a suffix of negative length")
let newCount = min(maxLength, byteCount)
let newStart = _pointer?.advanced(by: byteCount &- newCount)
return Self(_unchecked: newStart, byteCount: newCount)
let newSpan = RawSpan(_unchecked: newStart, byteCount: newCount)
// As a trivial value, 'newStart' does not formally depend on the
// lifetime of 'self'. Make the dependence explicit.
return _overrideLifetime(newSpan, copying: self)
}

/// Returns a span over all but the given number of initial bytes.
Expand All @@ -700,6 +734,9 @@ extension RawSpan {
_precondition(k >= 0, "Can't drop a negative number of elements")
let droppedCount = min(k, byteCount)
let newStart = _pointer?.advanced(by: droppedCount)
return Self(_unchecked: newStart, byteCount: byteCount &- droppedCount)
let newSpan = RawSpan(_unchecked: newStart, byteCount: byteCount &- droppedCount)
// As a trivial value, 'newStart' does not formally depend on the
// lifetime of 'self'. Make the dependence explicit.
return _overrideLifetime(newSpan, copying: self)
}
}
85 changes: 68 additions & 17 deletions stdlib/public/core/Span/Span.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,16 @@ extension Span where Element: ~Copyable {
_unsafeElements buffer: UnsafeBufferPointer<Element>
) {
//FIXME: Workaround for https://github.com/swiftlang/swift/issues/77235
let baseAddress = buffer.baseAddress
let baseAddress = UnsafeRawPointer(buffer.baseAddress)
_precondition(
((Int(bitPattern: baseAddress) &
(MemoryLayout<Element>.alignment &- 1)) == 0),
"baseAddress must be properly aligned to access Element"
)
self.init(_unchecked: baseAddress, count: buffer.count)
let span = Span(_unchecked: baseAddress, count: buffer.count)
// As a trivial value, 'baseAddress' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Unsafely create a `Span` over initialized memory.
Expand All @@ -122,7 +125,11 @@ extension Span where Element: ~Copyable {
public init(
_unsafeElements buffer: UnsafeMutableBufferPointer<Element>
) {
self.init(_unsafeElements: UnsafeBufferPointer(buffer))
let buf = UnsafeBufferPointer(buffer)
let span = Span(_unsafeElements: buf)
// As a trivial value, 'buf' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Unsafely create a `Span` over initialized memory.
Expand All @@ -142,7 +149,11 @@ extension Span where Element: ~Copyable {
count: Int
) {
_precondition(count >= 0, "Count must not be negative")
self.init(_unsafeElements: .init(start: pointer, count: count))
let buf = UnsafeBufferPointer(start: pointer, count: count)
let span = Span(_unsafeElements: buf)
// As a trivial value, 'buf' does not formally depend on the
// lifetime of 'pointer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: pointer)
}
}

Expand All @@ -162,7 +173,11 @@ extension Span {
public init(
_unsafeElements buffer: borrowing Slice<UnsafeBufferPointer<Element>>
) {
self.init(_unsafeElements: UnsafeBufferPointer(rebasing: buffer))
let buf = UnsafeBufferPointer(rebasing: buffer)
let span = Span(_unsafeElements: buf)
// As a trivial value, 'buf' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Unsafely create a `Span` over initialized memory.
Expand All @@ -178,7 +193,11 @@ extension Span {
public init(
_unsafeElements buffer: borrowing Slice<UnsafeMutableBufferPointer<Element>>
) {
self.init(_unsafeElements: UnsafeBufferPointer(rebasing: buffer))
let buf = UnsafeBufferPointer(rebasing: buffer)
let span = Span(_unsafeElements: buf)
// As a trivial value, 'buf' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}
}

Expand Down Expand Up @@ -214,7 +233,10 @@ extension Span where Element: BitwiseCopyable {
_precondition(
remainder == 0, "Span must contain a whole number of elements"
)
self.init(_unchecked: baseAddress, count: count)
let span = Span(_unchecked: baseAddress, count: count)
// As a trivial value, 'baseAddress' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Unsafely create a `Span` over initialized memory.
Expand All @@ -234,7 +256,11 @@ extension Span where Element: BitwiseCopyable {
public init(
_unsafeBytes buffer: UnsafeMutableRawBufferPointer
) {
self.init(_unsafeBytes: UnsafeRawBufferPointer(buffer))
let rawBuffer = UnsafeRawBufferPointer(buffer)
let span = Span(_unsafeBytes: rawBuffer)
// As a trivial value, 'buf' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Unsafely create a `Span` over initialized memory.
Expand All @@ -258,7 +284,11 @@ extension Span where Element: BitwiseCopyable {
byteCount: Int
) {
_precondition(byteCount >= 0, "Count must not be negative")
self.init(_unsafeBytes: .init(start: pointer, count: byteCount))
let rawBuffer = UnsafeRawBufferPointer(start: pointer, count: byteCount)
let span = Span(_unsafeBytes: rawBuffer)
// As a trivial value, 'rawBuffer' does not formally depend on the
// lifetime of 'pointer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: pointer)
}

/// Unsafely create a `Span` over initialized memory.
Expand All @@ -278,7 +308,11 @@ extension Span where Element: BitwiseCopyable {
public init(
_unsafeBytes buffer: borrowing Slice<UnsafeRawBufferPointer>
) {
self.init(_unsafeBytes: UnsafeRawBufferPointer(rebasing: buffer))
let rawBuffer = UnsafeRawBufferPointer(rebasing: buffer)
let span = Span(_unsafeBytes: rawBuffer)
// As a trivial value, 'rawBuffer' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Unsafely create a `Span` over initialized memory.
Expand All @@ -298,7 +332,11 @@ extension Span where Element: BitwiseCopyable {
public init(
_unsafeBytes buffer: borrowing Slice<UnsafeMutableRawBufferPointer>
) {
self.init(_unsafeBytes: UnsafeRawBufferPointer(rebasing: buffer))
let rawBuffer = UnsafeRawBufferPointer(rebasing: buffer)
let span = Span(_unsafeBytes: rawBuffer)
// As a trivial value, 'rawBuffer' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
self = _overrideLifetime(span, borrowing: buffer)
}

/// Create a `Span` over the bytes represented by a `RawSpan`
Expand All @@ -309,9 +347,12 @@ extension Span where Element: BitwiseCopyable {
@_alwaysEmitIntoClient
@lifetime(bytes)
public init(_bytes bytes: consuming RawSpan) {
self.init(
_unsafeBytes: .init(start: bytes._pointer, count: bytes.byteCount)
)
let rawBuffer =
UnsafeRawBufferPointer(start: bytes._pointer, count: bytes.byteCount)
let span = Span(_unsafeBytes: rawBuffer)
// As a trivial value, 'rawBuffer' does not formally depend on the
// lifetime of 'bytes'. Make the dependence explicit.
self = _overrideLifetime(span, copying: bytes)
}
}

Expand Down Expand Up @@ -481,7 +522,11 @@ extension Span where Element: ~Copyable {
@lifetime(self)
public func _extracting(unchecked bounds: Range<Index>) -> Self {
let delta = bounds.lowerBound &* MemoryLayout<Element>.stride
return Span(_unchecked: _pointer?.advanced(by: delta), count: bounds.count)
let newStart = _pointer?.advanced(by: delta)
let newSpan = Span(_unchecked: newStart, count: bounds.count)
// As a trivial value, 'newStart' does not formally depend on the
// lifetime of 'self'. Make the dependence explicit.
return _overrideLifetime(newSpan, copying: self)
}

/// Constructs a new span over the items within the supplied range of
Expand Down Expand Up @@ -704,7 +749,10 @@ extension Span where Element: ~Copyable {
let newCount = min(maxLength, count)
let offset = (count &- newCount) * MemoryLayout<Element>.stride
let newStart = _pointer?.advanced(by: offset)
return Self(_unchecked: newStart, count: newCount)
let newSpan = Span(_unchecked: newStart, count: newCount)
// As a trivial value, 'newStart' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
return _overrideLifetime(newSpan, copying: self)
}

/// Returns a span over all but the given number of initial elements.
Expand All @@ -728,6 +776,9 @@ extension Span where Element: ~Copyable {
let droppedCount = min(k, count)
let offset = droppedCount * MemoryLayout<Element>.stride
let newStart = _pointer?.advanced(by: offset)
return Self(_unchecked: newStart, count: count &- droppedCount)
let newSpan = Span(_unchecked: newStart, count: count &- droppedCount)
// As a trivial value, 'newStart' does not formally depend on the
// lifetime of 'buffer'. Make the dependence explicit.
return _overrideLifetime(newSpan, copying: self)
}
}