mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
@@ -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 *
|
||||
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
}
|
||||
95
test/Interop/C/swiftify-import/sized-by-lifetimebound.swift
Normal file
95
test/Interop/C/swiftify-import/sized-by-lifetimebound.swift
Normal 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)
|
||||
}
|
||||
@@ -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: }
|
||||
|
||||
@@ -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: }
|
||||
|
||||
62
test/Macros/SwiftifyImport/SizedBy/PointerReturn.swift
Normal file
62
test/Macros/SwiftifyImport/SizedBy/PointerReturn.swift
Normal 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: }
|
||||
Reference in New Issue
Block a user