Files
swift-mirror/test/Interop/Cxx/stdlib/std-span-interface.swift
Henrik G. Olsson 87f5309144 [Swiftify] enable mutable span (#80387)
* [Swiftify] Emit Mutable[Raw]Span when possible

Previously wrappers would use UnsafeMutable[Raw]Pointer for mutable
pointers, and Span for non-const std::span, to prevent the compiler from
complaining that MutableSpan didn't exist.

Now that MutableSpan has landed we can finally emit MutableSpan without
causing compilation errors. While we had (disabled) support for MutableSpan
syntax already, some unexpected semantic errors required additional
changes:
 - Mutable[Raw]Span parameters need to be inout (for mutation)
 - inout ~Escapable paramters need explicit lifetime annotations
 - MutableSpan cannot be directly bitcast to std::span, because it is
   ~Copyable, so they need unwrapping to UnsafeMutableBufferPointer

rdar://147883022

* [Swiftify] Wrap if-expressions in Immediately Called Closures

When parameters in swiftified wrapper functions are nullable, we use
separate branches for the nil and nonnil cases, because
`withUnsafeBufferPointer` (and similar) cannot be called on nil.
If-expressions have some limitations on where they are allowed in the
grammar, and cannot be passed as arguments to a function. As such, when
the return value is also swiftified, we get an error when trying to
pass the if-expression to the UnsafeBufferPointer/Span constructor.
While it isn't pretty, the best way forward seems to be by wrapping the
if-expressions in Immediately Called Closures.

The closures have the side-effect of acting as a barrier for 'unsafe':
unsafe keywords outside the closure do not "reach" unsafe expressions
inside the closure. We therefore have to emit "unsafe" where unsafe
expressions are used, rather than just when returning.

rdar://148153063
2025-03-29 05:05:01 -07:00

74 lines
4.8 KiB
Swift

// RUN: %empty-directory(%t)
// RUN: %target-swift-ide-test -plugin-path %swift-plugin-dir -I %S/Inputs -enable-experimental-feature SafeInteropWrappers -print-module -module-to-print=StdSpan -source-filename=x -enable-experimental-cxx-interop -Xcc -std=c++20 -module-cache-path %t > %t/interface.swift
// RUN: %FileCheck %s < %t/interface.swift
// REQUIRES: swift_feature_SafeInteropWrappers
// FIXME swift-ci linux tests do not support std::span
// UNSUPPORTED: OS=linux-gnu
#if !BRIDGING_HEADER
import StdSpan
#endif
import CxxStdlib
// CHECK: struct DependsOnSelf {
// CHECK: @lifetime(borrow self)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public borrowing func get() -> Span<CInt>
// CHECK-NEXT: borrowing func get() -> ConstSpanOfInt
// CHECK: mutating func set(_ x: borrowing std.{{.*}}vector<CInt, std.{{.*}}allocator<CInt>>)
// CHECK: func funcWithSafeWrapper(_ s: ConstSpanOfInt)
// CHECK-NEXT: func funcWithSafeWrapper2(_ s: ConstSpanOfInt) -> ConstSpanOfInt
// CHECK-NEXT: func funcWithSafeWrapper3(_ v: borrowing VecOfInt) -> ConstSpanOfInt
// CHECK: struct X {
// CHECK-NEXT: init()
// CHECK-NEXT: @_alwaysEmitIntoClient public mutating func methodWithSafeWrapper(_ s: Span<CInt>)
// CHECK-NEXT: mutating func methodWithSafeWrapper(_ s: ConstSpanOfInt)
// CHECK-NEXT: }
// CHECK: struct SpanWithoutTypeAlias {
// CHECK-NEXT: init()
// CHECK-NEXT: @lifetime(borrow self)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public mutating func bar() -> Span<CInt>
// CHECK-NEXT: mutating func bar() -> std.{{.*}}span<__cxxConst<CInt>, _C{{.*}}_{{.*}}>
// CHECK-NEXT: @_alwaysEmitIntoClient public mutating func foo(_ s: Span<CInt>)
// CHECK-NEXT: mutating func foo(_ s: std.{{.*}}span<__cxxConst<CInt>, _C{{.*}}_{{.*}}>)
// CHECK-NEXT: }
// CHECK: @lifetime(s: copy s)
// CHECK-NEXT: @_alwaysEmitIntoClient public func FuncWithMutableSafeWrapper(_ s: inout MutableSpan<CInt>)
// CHECK-NEXT: @lifetime(copy s)
// CHECK-NEXT: @lifetime(s: copy s)
// CHECK-NEXT: @_alwaysEmitIntoClient public func FuncWithMutableSafeWrapper2(_ s: inout MutableSpan<CInt>) -> MutableSpan<CInt>
// CHECK-NEXT: @lifetime(borrow v)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func FuncWithMutableSafeWrapper3(_ v: inout VecOfInt) -> MutableSpan<CInt>
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper1(_ p: inout MutableSpan<Int32>) -> MutableSpan<CInt>
// CHECK-NEXT: @lifetime(borrow v)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func MixedFuncWithMutableSafeWrapper2(_ v: inout VecOfInt, _ len: Int32) -> MutableSpan<Int32>
// CHECK-NEXT: @lifetime(s: copy s)
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper3(_ s: inout MutableSpan<CInt>, _ p: UnsafeMutableBufferPointer<Int32>)
// CHECK-NEXT: @lifetime(s: copy s)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper4(_ s: inout MutableSpan<CInt>, _ p: inout MutableSpan<Int32>)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper5(_ s: SpanOfInt, _ p: inout MutableSpan<Int32>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper6(_ s: SpanOfInt, _ p: UnsafeMutableBufferPointer<Int32>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper7(_ p: UnsafeMutableBufferPointer<Int32>) -> SpanOfInt
// CHECK: @_alwaysEmitIntoClient public func funcWithSafeWrapper(_ s: Span<CInt>)
// CHECK-NEXT: @lifetime(copy s)
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper2(_ s: Span<CInt>) -> Span<CInt>
// CHECK-NEXT: @lifetime(borrow v)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func funcWithSafeWrapper3(_ v: borrowing VecOfInt) -> Span<CInt>
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper1(_ p: Span<Int32>) -> Span<CInt>
// CHECK-NEXT: @lifetime(borrow v)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func mixedFuncWithSafeWrapper2(_ v: borrowing VecOfInt, _ len: Int32) -> Span<Int32>
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper3(_ s: Span<CInt>, _ p: UnsafeMutableBufferPointer<Int32>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper4(_ s: Span<CInt>, _ p: Span<Int32>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper5(_ s: ConstSpanOfInt, _ p: Span<Int32>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper6(_ s: ConstSpanOfInt, _ p: UnsafeMutableBufferPointer<Int32>)
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper7(_ p: UnsafeBufferPointer<Int32>) -> ConstSpanOfInt