[Swiftify] Fix __sized_by and nullable return values (#81693)

Nullable return Spans did not include __swiftifyOverrideLifetime,
resulting in a lifetime error when returning the Span. Meanwhile return
values for __sized_by did not use the correct label for the call to the
RawSpan initializer, using `count` instead of `byteCount`.

rdar://151804085
rdar://151799287
This commit is contained in:
Henrik G. Olsson
2025-05-22 15:34:58 -07:00
committed by GitHub
parent 789f657335
commit 526c68333c
9 changed files with 407 additions and 22 deletions

View File

@@ -643,6 +643,9 @@ extension PointerBoundsThunkBuilder {
return try transformType(oldType, generateSpan, isSizedBy, isParameter)
}
}
var countLabel: String {
return isSizedBy && generateSpan ? "byteCount" : "count"
}
}
protocol ParamBoundsThunkBuilder: BoundsThunkBuilder {
@@ -699,26 +702,28 @@ struct CountedOrSizedReturnPointerThunkBuilder: PointerBoundsThunkBuilder {
"start"
}
var cast = try newType
var expr: ExprSyntax
if nullable {
if let optType = cast.as(OptionalTypeSyntax.self) {
cast = optType.wrappedType
}
return """
{ () in
let _resultValue = \(call)
if unsafe _resultValue == nil {
return nil
} else {
return unsafe \(raw: cast)(\(raw: startLabel): _resultValue!, count: Int(\(countExpr)))
}
}()
"""
expr =
"""
{ () in
let _resultValue = \(call)
if unsafe _resultValue == nil {
return nil
} else {
return unsafe _swiftifyOverrideLifetime(\(raw: cast)(\(raw: startLabel): _resultValue!, \(raw: countLabel): Int(\(countExpr))), copying: ())
}
}()
"""
} else {
expr =
"""
\(raw: cast)(\(raw: startLabel): \(call), \(raw: countLabel): Int(\(countExpr)))
"""
}
var expr = ExprSyntax(
"""
\(raw: cast)(\(raw: startLabel): \(call), count: Int(\(countExpr)))
"""
)
if generateSpan {
expr = "_swiftifyOverrideLifetime(\(expr), copying: ())"
}
@@ -823,11 +828,10 @@ struct CountedOrSizedPointerThunkBuilder: ParamBoundsThunkBuilder, PointerBounds
}
func getCount() -> ExprSyntax {
let countName = isSizedBy && generateSpan ? "byteCount" : "count"
if nullable {
return ExprSyntax("\(name)?.\(raw: countName) ?? 0")
return ExprSyntax("\(name)?.\(raw: countLabel) ?? 0")
}
return ExprSyntax("\(name).\(raw: countName)")
return ExprSyntax("\(name).\(raw: countLabel)")
}
func peelOptionalType(_ type: TypeSyntax) -> TypeSyntax {

View File

@@ -0,0 +1,21 @@
#pragma once
#define __counted_by(x) __attribute__((__counted_by__(x)))
#define __lifetimebound __attribute__((lifetimebound))
int * __counted_by(len) simple(int len, int len2, int * __counted_by(len2) __lifetimebound p);
int * __counted_by(len) shared(int len, int * __counted_by(len) __lifetimebound p);
int * __counted_by(len - offset) complexExpr(int len, int offset, int len2, int * __counted_by(len2) __lifetimebound p);
int * __counted_by(len) _Null_unspecified nullUnspecified(int len, int len2, int * __counted_by(len2) __lifetimebound _Null_unspecified p);
int * __counted_by(len) _Nonnull nonnull(int len, int len2, int * __counted_by(len2) __lifetimebound _Nonnull p);
int * __counted_by(len) _Nullable nullable(int len, int len2, int * __counted_by(len2) __lifetimebound _Nullable p);
typedef struct foo opaque_t;
opaque_t * __counted_by(len) opaque(int len, int len2, opaque_t * __counted_by(len2) __lifetimebound p);
int * __counted_by(len) noncountedLifetime(int len, int * __lifetimebound p);

View File

@@ -14,6 +14,14 @@ module SizedByNoEscapeClang {
header "sized-by-noescape.h"
export *
}
module SizedByLifetimeboundClang {
header "sized-by-lifetimebound.h"
export *
}
module CountedByLifetimeboundClang {
header "counted-by-lifetimebound.h"
export *
}
module CommentsClang {
header "comments.h"
export *

View File

@@ -0,0 +1,21 @@
#pragma once
#define __sized_by(x) __attribute__((__sized_by__(x)))
#define __lifetimebound __attribute__((lifetimebound))
const void * __sized_by(len) simple(int len, int len2, const void * __sized_by(len2) __lifetimebound p);
const void * __sized_by(len) shared(int len, const void * __sized_by(len) __lifetimebound p);
const void * __sized_by(len - offset) complexExpr(int len, int offset, int len2, const void * __sized_by(len2) __lifetimebound p);
const void * __sized_by(len) _Null_unspecified nullUnspecified(int len, int len2, const void * __sized_by(len2) __lifetimebound _Null_unspecified p);
const void * __sized_by(len) _Nonnull nonnull(int len, int len2, const void * __sized_by(len2) __lifetimebound _Nonnull p);
const void * __sized_by(len) _Nullable nullable(int len, int len2, const void * __sized_by(len2) __lifetimebound _Nullable p);
typedef struct foo opaque_t;
opaque_t * __sized_by(len) opaque(int len, int len2, opaque_t * __sized_by(len2) __lifetimebound p);
const void * __sized_by(len) nonsizedLifetime(int len, const void * __lifetimebound p);

View File

@@ -0,0 +1,96 @@
// REQUIRES: swift_feature_SafeInteropWrappers
// REQUIRES: swift_feature_LifetimeDependence
// RUN: %target-swift-ide-test -print-module -module-to-print=CountedByLifetimeboundClang -plugin-path %swift-plugin-dir -I %S/Inputs -source-filename=x -enable-experimental-feature SafeInteropWrappers | %FileCheck %s
// swift-ide-test doesn't currently typecheck the macro expansions, so run the compiler as well
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/CountedByLifetimebound.swiftmodule -I %S/Inputs -enable-experimental-feature SafeInteropWrappers -enable-experimental-feature LifetimeDependence %s
// Check that ClangImporter correctly infers and expands @_SwiftifyImport macros for functions with __sized_by __lifetimebound parameters and return values.
import CountedByLifetimeboundClang
// CHECK: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func complexExpr(_ len: Int32, _ offset: Int32, _ len2: Int32, _ p: inout MutableSpan<Int32>) -> MutableSpan<Int32>
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(borrow p)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func noncountedLifetime(_ len: Int32, _ p: UnsafeMutablePointer<Int32>!) -> MutableSpan<Int32>
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ len: Int32, _ p: inout MutableSpan<Int32>) -> MutableSpan<Int32>
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ len: Int32, _ p: inout MutableSpan<Int32>) -> MutableSpan<Int32>
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ len: Int32, _ p: inout MutableSpan<Int32>?) -> MutableSpan<Int32>?
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int32, _ p: inout MutableSpan<Int32>) -> MutableSpan<Int32>
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @lifetime(p: copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ len: Int32, _ p: inout MutableSpan<Int32>) -> MutableSpan<Int32>
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callComplexExpr(_ p: inout MutableSpan<CInt>) {
let _: MutableSpan<CInt> = complexExpr(73, 37, 42, &p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callNonnull(_ p: inout MutableSpan<CInt>) {
let _: MutableSpan<CInt> = nonnull(73, &p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callNullUnspecified(_ p: inout MutableSpan<CInt>) {
let _: MutableSpan<CInt> = nullUnspecified(73, &p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callNullable(_ p: inout MutableSpan<CInt>?) {
let _: MutableSpan<CInt> = nullable(73, &p)!
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callShared(_ p: inout MutableSpan<CInt>) {
let _: MutableSpan<CInt> = shared(CInt(p.count), &p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callSimple(_ p: inout MutableSpan<CInt>) {
let _: MutableSpan<CInt> = simple(73, &p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callNoncountedLifetime(_ p: UnsafeMutablePointer<CInt>) {
let _: MutableSpan<CInt> = noncountedLifetime(73, p)
}

View File

@@ -0,0 +1,95 @@
// REQUIRES: swift_feature_SafeInteropWrappers
// REQUIRES: swift_feature_LifetimeDependence
// RUN: %target-swift-ide-test -print-module -module-to-print=SizedByLifetimeboundClang -plugin-path %swift-plugin-dir -I %S/Inputs -source-filename=x -enable-experimental-feature SafeInteropWrappers | %FileCheck %s
// swift-ide-test doesn't currently typecheck the macro expansions, so run the compiler as well
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -o %t/SizedByLifetimebound.swiftmodule -I %S/Inputs -enable-experimental-feature SafeInteropWrappers -enable-experimental-feature LifetimeDependence %s
// Check that ClangImporter correctly infers and expands @_SwiftifyImport macros for functions with __sized_by __lifetimebound parameters and return values.
import SizedByLifetimeboundClang
// CHECK: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func complexExpr(_ len: Int32, _ offset: Int32, _ len2: Int32, _ p: RawSpan) -> RawSpan
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nonnull(_ len: Int32, _ p: RawSpan) -> RawSpan
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(borrow p)
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func nonsizedLifetime(_ len: Int32, _ p: UnsafeRawPointer!) -> RawSpan
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullUnspecified(_ len: Int32, _ p: RawSpan) -> RawSpan
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func nullable(_ len: Int32, _ p: RawSpan?) -> RawSpan?
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func opaque(_ len: Int32, _ p: RawSpan) -> RawSpan
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func shared(_ len: Int32, _ p: RawSpan) -> RawSpan
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
// CHECK-NEXT: @lifetime(copy p)
// CHECK-NEXT: @_alwaysEmitIntoClient public func simple(_ len: Int32, _ p: RawSpan) -> RawSpan
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callComplexExpr(_ p: RawSpan) {
let _: RawSpan = complexExpr(73, 37, 42, p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callNonnull(_ p: RawSpan) {
let _: RawSpan = nonnull(73, p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callNullUnspecified(_ p: RawSpan) {
let _: RawSpan = nullUnspecified(73, p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callNullable(_ p: RawSpan?) {
let _: RawSpan = nullable(73, p)!
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callShared(_ p: RawSpan) {
let _: RawSpan = shared(CInt(p.byteCount), p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callSimple(_ p: RawSpan) {
let _: RawSpan = simple(73, p)
}
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
@inlinable
public func callNonsizedLifetime(_ p: UnsafeRawPointer) {
let _: RawSpan = nonsizedLifetime(73, p)
}

View File

@@ -71,7 +71,7 @@ func myFunc4(_ ptr: UnsafeMutablePointer<CInt>?, _ len: CInt) -> UnsafeMutablePo
// CHECK-NEXT: if ptr?.count ?? 0 < _ptrCount || _ptrCount < 0 {
// CHECK-NEXT: fatalError("bounds check failure when calling unsafe function")
// CHECK-NEXT: }
// CHECK-NEXT: return { () in
// CHECK-NEXT: return unsafe _swiftifyOverrideLifetime({ () in
// CHECK-NEXT: let _resultValue = { () in
// CHECK-NEXT: return if ptr == nil {
// CHECK-NEXT: unsafe myFunc4(nil, len)
@@ -84,7 +84,7 @@ func myFunc4(_ ptr: UnsafeMutablePointer<CInt>?, _ len: CInt) -> UnsafeMutablePo
// CHECK-NEXT: if unsafe _resultValue == nil {
// CHECK-NEXT: return nil
// CHECK-NEXT: } else {
// CHECK-NEXT: return unsafe MutableSpan<CInt>(_unsafeStart: _resultValue!, count: Int(len))
// CHECK-NEXT: return unsafe _swiftifyOverrideLifetime(MutableSpan<CInt>(_unsafeStart: _resultValue!, count: Int(len)), copying: ())
// CHECK-NEXT: }
// CHECK-NEXT: }()
// CHECK-NEXT: }
// CHECK-NEXT: }(), copying: ())
// CHECK-NEXT: }

View File

@@ -6,7 +6,85 @@
func myFunc(_ ptr: UnsafeRawPointer?, _ size: CInt) {
}
@_SwiftifyImport(.sizedBy(pointer: .param(1), size: "len"), .nonescaping(pointer: .param(1)))
func myFunc2(_ ptr: UnsafeMutableRawPointer?, _ len: CInt) {
}
@_SwiftifyImport(.sizedBy(pointer: .param(1), size: "len"), .nonescaping(pointer: .param(1)), .sizedBy(pointer: .param(3), size: "len2"), .nonescaping(pointer: .param(3)))
func myFunc3(_ ptr: UnsafeMutableRawPointer?, _ len: CInt, _ ptr2: UnsafeMutableRawPointer?, _ len2: CInt) {
}
@_SwiftifyImport(.sizedBy(pointer: .param(1), size: "len"), .sizedBy(pointer: .return, size: "len"), .lifetimeDependence(dependsOn: .param(1), pointer: .return, type: .copy))
func myFunc4(_ ptr: UnsafeMutableRawPointer?, _ len: CInt) -> UnsafeMutableRawPointer? {
}
// CHECK: @_alwaysEmitIntoClient
// CHECK-NEXT: func myFunc(_ ptr: UnsafeRawBufferPointer?) {
// CHECK-NEXT: return unsafe myFunc(ptr?.baseAddress, CInt(exactly: ptr?.count ?? 0)!)
// CHECK-NEXT: }
// CHECK: @_alwaysEmitIntoClient @lifetime(ptr: copy ptr)
// CHECK-NEXT: func myFunc2(_ ptr: inout MutableRawSpan?) {
// CHECK-NEXT: return { () in
// CHECK-NEXT: return if ptr == nil {
// CHECK-NEXT: unsafe myFunc2(nil, CInt(exactly: ptr?.byteCount ?? 0)!)
// CHECK-NEXT: } else {
// CHECK-NEXT: unsafe ptr!.withUnsafeMutableBytes { _ptrPtr in
// CHECK-NEXT: return unsafe myFunc2(_ptrPtr.baseAddress, CInt(exactly: _ptrPtr.count)!)
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }()
// CHECK-NEXT: }
// CHECK: @_alwaysEmitIntoClient @lifetime(ptr: copy ptr) @lifetime(ptr2: copy ptr2)
// CHECK-NEXT: func myFunc3(_ ptr: inout MutableRawSpan?, _ ptr2: inout MutableRawSpan?) {
// CHECK-NEXT: return { () in
// CHECK-NEXT: return if ptr2 == nil {
// CHECK-NEXT: { () in
// CHECK-NEXT: return if ptr == nil {
// CHECK-NEXT: unsafe myFunc3(nil, CInt(exactly: ptr?.byteCount ?? 0)!, nil, CInt(exactly: ptr2?.byteCount ?? 0)!)
// CHECK-NEXT: } else {
// CHECK-NEXT: unsafe ptr!.withUnsafeMutableBytes { _ptrPtr in
// CHECK-NEXT: return unsafe myFunc3(_ptrPtr.baseAddress, CInt(exactly: _ptrPtr.count)!, nil, CInt(exactly: ptr2?.byteCount ?? 0)!)
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }()
// CHECK-NEXT: } else {
// CHECK-NEXT: unsafe ptr2!.withUnsafeMutableBytes { _ptr2Ptr in
// CHECK-NEXT: return { () in
// CHECK-NEXT: return if ptr == nil {
// CHECK-NEXT: unsafe myFunc3(nil, CInt(exactly: ptr?.byteCount ?? 0)!, _ptr2Ptr.baseAddress, CInt(exactly: _ptr2Ptr.count)!)
// CHECK-NEXT: } else {
// CHECK-NEXT: unsafe ptr!.withUnsafeMutableBytes { _ptrPtr in
// CHECK-NEXT: return unsafe myFunc3(_ptrPtr.baseAddress, CInt(exactly: _ptrPtr.count)!, _ptr2Ptr.baseAddress, CInt(exactly: _ptr2Ptr.count)!)
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }()
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }()
// CHECK-NEXT: }
// CHECK: @_alwaysEmitIntoClient @lifetime(copy ptr) @lifetime(ptr: copy ptr)
// CHECK-NEXT: func myFunc4(_ ptr: inout MutableRawSpan?, _ len: CInt) -> MutableRawSpan? {
// CHECK-NEXT: let _ptrCount: some BinaryInteger = len
// CHECK-NEXT: if ptr?.byteCount ?? 0 < _ptrCount || _ptrCount < 0 {
// CHECK-NEXT: fatalError("bounds check failure when calling unsafe function")
// CHECK-NEXT: }
// CHECK-NEXT: return unsafe _swiftifyOverrideLifetime({ () in
// CHECK-NEXT: let _resultValue = { () in
// CHECK-NEXT: return if ptr == nil {
// CHECK-NEXT: unsafe myFunc4(nil, len)
// CHECK-NEXT: } else {
// CHECK-NEXT: unsafe ptr!.withUnsafeMutableBytes { _ptrPtr in
// CHECK-NEXT: return unsafe myFunc4(_ptrPtr.baseAddress, len)
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }()
// CHECK-NEXT: if unsafe _resultValue == nil {
// CHECK-NEXT: return nil
// CHECK-NEXT: } else {
// CHECK-NEXT: return unsafe _swiftifyOverrideLifetime(MutableRawSpan(_unsafeStart: _resultValue!, byteCount: Int(len)), copying: ())
// CHECK-NEXT: }
// CHECK-NEXT: }(), copying: ())
// CHECK-NEXT: }

View File

@@ -0,0 +1,62 @@
// REQUIRES: swift_swift_parser
// REQUIRES: swift_feature_LifetimeDependence
// RUN: %target-swift-frontend %s -swift-version 5 -module-name main -disable-availability-checking -typecheck -plugin-path %swift-plugin-dir -enable-experimental-feature LifetimeDependence -strict-memory-safety -warnings-as-errors -dump-macro-expansions 2>&1 | %FileCheck --match-full-lines %s
@_SwiftifyImport(.sizedBy(pointer: .return, size: "len"))
func myFunc(_ len: CInt) -> UnsafeMutableRawPointer {
}
@_SwiftifyImport(.sizedBy(pointer: .return, size: "len"), .nonescaping(pointer: .return))
func nonEscaping(_ len: CInt) -> UnsafeRawPointer {
}
@_SwiftifyImport(.sizedBy(pointer: .return, size: "len2"), .sizedBy(pointer: .param(1), size: "len1"), .lifetimeDependence(dependsOn: .param(1), pointer: .return, type: .copy))
func lifetimeDependentCopy(_ p: UnsafeRawPointer, _ len1: CInt, _ len2: CInt) -> UnsafeRawPointer {
}
@_SwiftifyImport(.sizedBy(pointer: .return, size: "len2"), .sizedBy(pointer: .param(1), size: "len1"), .lifetimeDependence(dependsOn: .param(1), pointer: .return, type: .borrow))
func lifetimeDependentBorrow(_ p: borrowing UnsafeRawPointer, _ len1: CInt, _ len2: CInt) -> UnsafeRawPointer {
}
@_SwiftifyImport(.sizedBy(pointer: .return, size: "len2"), .sizedBy(pointer: .param(1), size: "len1"), .lifetimeDependence(dependsOn: .param(1), pointer: .return, type: .copy))
func lifetimeDependentCopyMut(_ p: UnsafeMutableRawPointer, _ len1: CInt, _ len2: CInt) -> UnsafeMutableRawPointer {
}
@_SwiftifyImport(.sizedBy(pointer: .return, size: "len2"), .sizedBy(pointer: .param(1), size: "len1"), .lifetimeDependence(dependsOn: .param(1), pointer: .return, type: .borrow))
func lifetimeDependentBorrowMut(_ p: borrowing UnsafeMutableRawPointer, _ len1: CInt, _ len2: CInt) -> UnsafeMutableRawPointer {
}
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
// CHECK-NEXT: func myFunc(_ len: CInt) -> UnsafeMutableRawBufferPointer {
// CHECK-NEXT: return unsafe UnsafeMutableRawBufferPointer(start: unsafe myFunc(len), count: Int(len))
// CHECK-NEXT: }
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
// CHECK-NEXT: func nonEscaping(_ len: CInt) -> UnsafeRawBufferPointer {
// CHECK-NEXT: return unsafe UnsafeRawBufferPointer(start: unsafe nonEscaping(len), count: Int(len))
// CHECK-NEXT: }
// CHECK: @_alwaysEmitIntoClient @lifetime(copy p)
// CHECK-NEXT: func lifetimeDependentCopy(_ p: RawSpan, _ len2: CInt) -> RawSpan {
// CHECK-NEXT: return unsafe _swiftifyOverrideLifetime(RawSpan(_unsafeStart: unsafe p.withUnsafeBytes { _pPtr in
// CHECK-NEXT: return unsafe lifetimeDependentCopy(_pPtr.baseAddress!, CInt(exactly: _pPtr.count)!, len2)
// CHECK-NEXT: }, byteCount: Int(len2)), copying: ())
// CHECK-NEXT: }
// CHECK: @_alwaysEmitIntoClient @lifetime(borrow p)
// CHECK-NEXT: func lifetimeDependentBorrow(_ p: borrowing UnsafeRawBufferPointer, _ len2: CInt) -> RawSpan {
// CHECK-NEXT: return unsafe _swiftifyOverrideLifetime(RawSpan(_unsafeStart: unsafe lifetimeDependentBorrow(p.baseAddress!, CInt(exactly: p.count)!, len2), byteCount: Int(len2)), copying: ())
// CHECK-NEXT: }
// CHECK: @_alwaysEmitIntoClient @lifetime(copy p) @lifetime(p: copy p)
// CHECK-NEXT: func lifetimeDependentCopyMut(_ p: inout MutableRawSpan, _ len2: CInt) -> MutableRawSpan {
// CHECK-NEXT: return unsafe _swiftifyOverrideLifetime(MutableRawSpan(_unsafeStart: unsafe p.withUnsafeMutableBytes { _pPtr in
// CHECK-NEXT: return unsafe lifetimeDependentCopyMut(_pPtr.baseAddress!, CInt(exactly: _pPtr.count)!, len2)
// CHECK-NEXT: }, byteCount: Int(len2)), copying: ())
// CHECK-NEXT: }
// CHECK: @_alwaysEmitIntoClient @lifetime(borrow p)
// CHECK-NEXT: func lifetimeDependentBorrowMut(_ p: borrowing UnsafeMutableRawBufferPointer, _ len2: CInt) -> MutableRawSpan {
// CHECK-NEXT: return unsafe _swiftifyOverrideLifetime(MutableRawSpan(_unsafeStart: unsafe lifetimeDependentBorrowMut(p.baseAddress!, CInt(exactly: p.count)!, len2), byteCount: Int(len2)), copying: ())
// CHECK-NEXT: }