Files
swift-mirror/stdlib/public/Cxx/CxxSpan.swift
Gabor Horvath df27b79579 [cxx-interop] Work around lifetime errors in SwiftifyImport generated code
Unfortunately, this was not discovered earlier as swift-ide-test is not
invoking the SIL passes that produce this diagnostic. When creating
Swift spans from C++ spans we have no lifetime dependency information to
propagate as C++ spans are modeled as escapable types. Hence, this PR
introduces a helper function to bypass the lifetime checks triggered by
this discepancy. Hopefully, the new utility will go away as the lifetime
analysis matures on the Swift side and we get standardized way to deal
with unsafe lifetimes.
2025-02-14 16:40:43 +00:00

121 lines
4.0 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 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 Builtin
@usableFromInline
internal func unsafeBitCast<T: ~Escapable, U>(
_ x: T, to type: U.Type
) -> U {
Builtin.reinterpretCast(x)
}
/// Used by SwiftifyImport to work around a compiler diagnostic. It should be removed once the
/// workaround is no longer needed.
@_unsafeNonescapableResult
@_alwaysEmitIntoClient
@_transparent
public func _unsafeRemoveLifetime<T: ~Copyable & ~Escapable>(_ dependent: consuming T) -> T {
dependent
}
/// 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
}
/// A C++ type that is an object that can refer to a contiguous sequence of objects.
///
/// C++ standard library type `std::span` conforms to this protocol.
public protocol CxxSpan<Element> {
associatedtype Element
associatedtype Size: BinaryInteger
init()
init(_ unsafePointer : UnsafePointer<Element>, _ count: Size)
func size() -> Size
func __dataUnsafe() -> UnsafePointer<Element>?
}
extension CxxSpan {
/// Creates a C++ span from a Swift UnsafeBufferPointer
@inlinable
public init(_ unsafeBufferPointer: UnsafeBufferPointer<Element>) {
precondition(unsafeBufferPointer.baseAddress != nil,
"UnsafeBufferPointer should not point to nil")
self.init(unsafeBufferPointer.baseAddress!, Size(unsafeBufferPointer.count))
}
@inlinable
public init(_ unsafeMutableBufferPointer: UnsafeMutableBufferPointer<Element>) {
precondition(unsafeMutableBufferPointer.baseAddress != nil,
"UnsafeMutableBufferPointer should not point to nil")
self.init(unsafeMutableBufferPointer.baseAddress!, Size(unsafeMutableBufferPointer.count))
}
@available(SwiftStdlib 6.1, *)
@inlinable
@unsafe
public init(_ span: Span<Element>) {
let (p, c) = unsafeBitCast(span, to: (UnsafeRawPointer?, Int).self)
precondition(p != nil, "Span should not point to nil")
let binding = p!.bindMemory(to: Element.self, capacity: c)
self.init(binding, Size(c))
}
}
@available(SwiftStdlib 6.1, *)
extension Span {
@_alwaysEmitIntoClient
@unsafe
@_unsafeNonescapableResult
public init<T: CxxSpan<Element>>(
_unsafeCxxSpan span: borrowing T,
) {
let buffer = UnsafeBufferPointer(start: span.__dataUnsafe(), count: Int(span.size()))
let newSpan = Span(_unsafeElements: buffer)
// 'self' is limited to the caller's scope of the variable passed to the 'span' argument.
self = _overrideLifetime(newSpan, borrowing: span)
}
}
public protocol CxxMutableSpan<Element> {
associatedtype Element
associatedtype Size: BinaryInteger
init()
init(_ unsafeMutablePointer : UnsafeMutablePointer<Element>, _ count: Size)
}
extension CxxMutableSpan {
/// Creates a C++ span from a Swift UnsafeMutableBufferPointer
@inlinable
public init(_ unsafeMutableBufferPointer: UnsafeMutableBufferPointer<Element>) {
precondition(unsafeMutableBufferPointer.baseAddress != nil,
"UnsafeMutableBufferPointer should not point to nil")
self.init(unsafeMutableBufferPointer.baseAddress!, Size(unsafeMutableBufferPointer.count))
}
}