Skip to content

Commit 2ca38a6

Browse files
committed
CxxSpanReturnThunkBuilder: use _cxxOverrideLifetime(_:copying:)
Do not rely on the @_unsafeNonescapableResult attribute. That attribute is only for temporarily working around bugs! And it only affects lifetime diagnostics within the function. It has no affect on the caller's diagnostics, so it won't solve this problem: func macroGeneratedThunk() -> CxxSpan<Int> { return _unsafeRemoveLifetime(Span...) } We cannot simply add @_unsafeRemoveLifetime to the thunk, because SwiftSyntax does not natively support the attribute. We don't want to add SwiftSyntax support because this attribute will never be supported syntax! Instead, use `_overrideLifetime` copying the `Void` type to remove a dependency: func macroGeneratedThunk() -> CxxSpan<Int> { return _cxxOverrideLifetime(Span..., copying: ()) }
1 parent ba5596d commit 2ca38a6

File tree

3 files changed

+28
-16
lines changed

3 files changed

+28
-16
lines changed

lib/Macros/Sources/SwiftMacros/SwiftifyImportMacro.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ struct CxxSpanReturnThunkBuilder: BoundsCheckedThunkBuilder {
468468

469469
func buildFunctionCall(_ pointerArgs: [Int: ExprSyntax]) throws -> ExprSyntax {
470470
let call = try base.buildFunctionCall(pointerArgs)
471-
return "_unsafeRemoveLifetime(Span(_unsafeCxxSpan: \(call)))"
471+
return "_cxxOverrideLifetime(Span(_unsafeCxxSpan: \(call)), copying: ())"
472472
}
473473
}
474474

stdlib/public/Cxx/CxxSpan.swift

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,40 @@ internal func unsafeBitCast<T: ~Escapable, U>(
1818
Builtin.reinterpretCast(x)
1919
}
2020

21-
/// Used by SwiftifyImport to work around a compiler diagnostic. It should be removed once the
22-
/// workaround is no longer needed.
21+
/// Unsafely discard any lifetime dependency on the `dependent` argument. Return
22+
/// a value identical to `dependent` with a lifetime dependency on the caller's
23+
/// borrow scope of the `source` argument.
24+
///
25+
/// This mimics the stdlib definition. It is public for use with import macros.
26+
@unsafe
2327
@_unsafeNonescapableResult
2428
@_alwaysEmitIntoClient
2529
@_transparent
26-
@lifetime(copy dependent)
27-
public func _unsafeRemoveLifetime<T: ~Copyable & ~Escapable>(_ dependent: consuming T) -> T {
30+
@lifetime(borrow source)
31+
public func _cxxOverrideLifetime<
32+
T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable
33+
>(
34+
_ dependent: consuming T, borrowing source: borrowing U
35+
) -> T {
36+
// TODO: Remove @_unsafeNonescapableResult. Instead, the unsafe dependence
37+
// should be expressed by a builtin that is hidden within the function body.
2838
dependent
2939
}
3040

3141
/// Unsafely discard any lifetime dependency on the `dependent` argument. Return
32-
/// a value identical to `dependent` with a lifetime dependency on the caller's
33-
/// borrow scope of the `source` argument.
42+
/// a value identical to `dependent` that inherits all lifetime dependencies from
43+
/// the `source` argument.
44+
///
45+
/// This mimics the stdlib definition. It is public for use with import macros.
3446
@unsafe
3547
@_unsafeNonescapableResult
3648
@_alwaysEmitIntoClient
3749
@_transparent
38-
@lifetime(borrow source)
39-
internal func _overrideLifetime<
50+
@lifetime(copy source)
51+
public func _cxxOverrideLifetime<
4052
T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable
4153
>(
42-
_ dependent: consuming T, borrowing source: borrowing U
54+
_ dependent: consuming T, copying source: borrowing U
4355
) -> T {
4456
// TODO: Remove @_unsafeNonescapableResult. Instead, the unsafe dependence
4557
// should be expressed by a builtin that is hidden within the function body.
@@ -99,7 +111,7 @@ extension Span {
99111
let buffer = unsafe UnsafeBufferPointer(start: span.__dataUnsafe(), count: Int(span.size()))
100112
let newSpan = unsafe Span(_unsafeElements: buffer)
101113
// 'self' is limited to the caller's scope of the variable passed to the 'span' argument.
102-
self = unsafe _overrideLifetime(newSpan, borrowing: span)
114+
self = unsafe _cxxOverrideLifetime(newSpan, borrowing: span)
103115
}
104116
}
105117

test/Macros/SwiftifyImport/CxxSpan/LifetimeboundSpan.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,25 +34,25 @@ struct X {
3434

3535
// CHECK: @_alwaysEmitIntoClient @lifetime(copy span)
3636
// CHECK-NEXT: func myFunc(_ span: Span<CInt>) -> Span<CInt> {
37-
// CHECK-NEXT: return unsafe _unsafeRemoveLifetime(Span(_unsafeCxxSpan: myFunc(SpanOfInt(span))))
37+
// CHECK-NEXT: return unsafe _cxxOverrideLifetime(Span(_unsafeCxxSpan: myFunc(SpanOfInt(span))), copying: ())
3838
// CHECK-NEXT: }
3939

4040
// CHECK: @_alwaysEmitIntoClient @lifetime(borrow vec) @_disfavoredOverload
4141
// CHECK-NEXT: func myFunc2(_ vec: borrowing VecOfInt) -> Span<CInt> {
42-
// CHECK-NEXT: return unsafe _unsafeRemoveLifetime(Span(_unsafeCxxSpan: myFunc2(vec)))
42+
// CHECK-NEXT: return unsafe _cxxOverrideLifetime(Span(_unsafeCxxSpan: myFunc2(vec)), copying: ())
4343
// CHECK-NEXT: }
4444

4545
// CHECK: @_alwaysEmitIntoClient @lifetime(copy span1, copy span2)
4646
// CHECK-NEXT: func myFunc3(_ span1: Span<CInt>, _ span2: Span<CInt>) -> Span<CInt> {
47-
// CHECK-NEXT: return unsafe _unsafeRemoveLifetime(Span(_unsafeCxxSpan: myFunc3(SpanOfInt(span1), SpanOfInt(span2))))
47+
// CHECK-NEXT: return unsafe _cxxOverrideLifetime(Span(_unsafeCxxSpan: myFunc3(SpanOfInt(span1), SpanOfInt(span2))), copying: ())
4848
// CHECK-NEXT: }
4949

5050
// CHECK: @_alwaysEmitIntoClient @lifetime(borrow vec, copy span)
5151
// CHECK-NEXT: func myFunc4(_ vec: borrowing VecOfInt, _ span: Span<CInt>) -> Span<CInt> {
52-
// CHECK-NEXT: return unsafe _unsafeRemoveLifetime(Span(_unsafeCxxSpan: myFunc4(vec, SpanOfInt(span))))
52+
// CHECK-NEXT: return unsafe _cxxOverrideLifetime(Span(_unsafeCxxSpan: myFunc4(vec, SpanOfInt(span))), copying: ())
5353
// CHECK-NEXT: }
5454

5555
// CHECK: @_alwaysEmitIntoClient @lifetime(borrow self) @_disfavoredOverload
5656
// CHECK-NEXT: func myFunc5() -> Span<CInt> {
57-
// CHECK-NEXT: return unsafe _unsafeRemoveLifetime(Span(_unsafeCxxSpan: myFunc5()))
57+
// CHECK-NEXT: return unsafe _cxxOverrideLifetime(Span(_unsafeCxxSpan: myFunc5()), copying: ())
5858
// CHECK-NEXT: }

0 commit comments

Comments
 (0)