Skip to content

Commit 68ff41a

Browse files
committed
[Swiftify] Update availability for CxxSpan<->Span, ignore lifetimebound
on parameters with reference type Because swift-ide-test doesn't care about typechecking, std-span-interface.swift passed despite containing 2 separate errors. This updates the test file to properly exercise the entire compilation pipeline for the macro expansions, by running swift-frontend -emit-module and calling each macro expansion. The first issue was that CxxSpan initializers taking [Mutable]Span still had their availability set to Swift 6.2+, even after back-deploying caused [Mutable]Span to have availability back to Swift 5.0. Since _SwiftifyImport expansions copy the availbility of Span, this resulted in the macro expansions calling unavailable initializers. Interestingly enough, this manifested itself in the form of a tripped assert in SIL verification, because although we do now typecheck the expansions from _SwiftifyImport, the compilation can still keep going after `shouldEmitFunctionBody` returns false: the macro expansion declaration is still there, but is now missing its definition, despite not being external. The second issue was when parameters with C++ reference types were annotated with `[[clang::lifetimebound]]`. C++ reference parameters are imported as `inout`, but lifetimebound results in the macro expansion having a lifetime dependence on the parameter. For parameters with a type that is `Escapable`, this is done using `@lifetime(borrow foo)`. However, you can't borrow an inout paramter. For parameters with a type that is `~Escapable` it's done using `@lifetime(copy foo)`, which works with inout. When the parameter is `inout Escapable` however, neither annotation works. Because of this we now ignore lifetimebound on parameters with an `Escapable` type when they are imported as inout. rdar://151493400 rdar://151678415
1 parent c4b0e97 commit 68ff41a

File tree

3 files changed

+112
-15
lines changed

3 files changed

+112
-15
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9268,11 +9268,16 @@ void ClangImporter::Implementation::swiftify(FuncDecl *MappedDecl) {
92689268
paramHasLifetimeInfo = true;
92699269
}
92709270
if (clangParam->hasAttr<clang::LifetimeBoundAttr>()) {
9271-
printer.printLifetimeboundReturn(
9272-
index, !paramHasBoundsInfo &&
9273-
swiftParamTy->isEscapable());
9274-
paramHasLifetimeInfo = true;
9275-
returnHasLifetimeInfo = true;
9271+
// If this parameter has bounds info we will tranform it into a Span,
9272+
// so then it will no longer be Escapable.
9273+
bool willBeEscapable = swiftParamTy->isEscapable() && !paramHasBoundsInfo;
9274+
// We can't borrow the lifetime of an inout parameter,
9275+
// but we can't copy the lifetime of an Escapable type. Simply ignore.
9276+
if (!willBeEscapable || !swiftParam->isInOut()) {
9277+
printer.printLifetimeboundReturn(index, willBeEscapable);
9278+
paramHasLifetimeInfo = true;
9279+
returnHasLifetimeInfo = true;
9280+
}
92769281
}
92779282
if (paramIsStdSpan && paramHasLifetimeInfo)
92789283
attachMacro = true;

stdlib/public/Cxx/CxxSpan.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ extension CxxSpan {
8888
unsafe self.init(unsafeMutableBufferPointer.baseAddress!, Size(unsafeMutableBufferPointer.count))
8989
}
9090

91-
@available(SwiftStdlib 6.2, *)
91+
@available(SwiftCompatibilitySpan 5.0, *)
9292
@inlinable
9393
@unsafe
9494
public init(_ span: Span<Element>) {
@@ -99,7 +99,7 @@ extension CxxSpan {
9999
}
100100
}
101101

102-
@available(SwiftStdlib 6.2, *)
102+
@available(SwiftCompatibilitySpan 5.0, *)
103103
extension Span {
104104
@_alwaysEmitIntoClient
105105
@unsafe
@@ -115,7 +115,7 @@ extension Span {
115115
}
116116
}
117117

118-
@available(SwiftStdlib 6.2, *)
118+
@available(SwiftCompatibilitySpan 5.0, *)
119119
extension MutableSpan {
120120
@_alwaysEmitIntoClient
121121
@unsafe
@@ -151,7 +151,7 @@ extension CxxMutableSpan {
151151
unsafe self.init(unsafeMutableBufferPointer.baseAddress!, Size(unsafeMutableBufferPointer.count))
152152
}
153153

154-
@available(SwiftStdlib 6.2, *)
154+
@available(SwiftCompatibilitySpan 5.0, *)
155155
@inlinable
156156
@unsafe
157157
public init(_ span: consuming MutableSpan<Element>) {

test/Interop/Cxx/stdlib/std-span-interface.swift

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
// 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
33
// RUN: %FileCheck %s < %t/interface.swift
44

5+
// Make sure we trigger typechecking and SIL diagnostics
6+
// RUN: %target-swift-frontend -emit-module -plugin-path %swift-plugin-dir -I %S/Inputs -enable-experimental-feature SafeInteropWrappers -enable-experimental-feature LifetimeDependence -cxx-interoperability-mode=default -strict-memory-safety -warnings-as-errors -Xcc -std=c++20 %s
7+
58
// REQUIRES: swift_feature_SafeInteropWrappers
9+
// REQUIRES: swift_feature_LifetimeDependence
610

711
// FIXME swift-ci linux tests do not support std::span
812
// UNSUPPORTED: OS=linux-gnu, OS=linux-android, OS=linux-androideabi
@@ -46,15 +50,10 @@ import CxxStdlib
4650
// CHECK-NEXT: @lifetime(s: copy s)
4751
// CHECK-NEXT: @_alwaysEmitIntoClient public func FuncWithMutableSafeWrapper2(_ s: inout MutableSpan<CInt>) -> MutableSpan<CInt>
4852
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
49-
// CHECK-NEXT: @lifetime(borrow v)
50-
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func FuncWithMutableSafeWrapper3(_ v: inout VecOfInt) -> MutableSpan<CInt>
51-
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
5253
// CHECK-NEXT: @lifetime(copy p)
5354
// CHECK-NEXT: @lifetime(p: copy p)
5455
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper1(_ p: inout MutableSpan<Int32>) -> MutableSpan<CInt>
55-
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
56-
// CHECK-NEXT: @lifetime(borrow v)
57-
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func MixedFuncWithMutableSafeWrapper2(_ v: inout VecOfInt, _ len: Int32) -> MutableSpan<Int32>
56+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func MixedFuncWithMutableSafeWrapper2(_ v: inout VecOfInt, _ len: Int32) -> UnsafeMutableBufferPointer<Int32>
5857
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
5958
// CHECK-NEXT: @lifetime(s: copy s)
6059
// CHECK-NEXT: @_alwaysEmitIntoClient public func MixedFuncWithMutableSafeWrapper3(_ s: inout MutableSpan<CInt>, _ p: UnsafeMutableBufferPointer<Int32>)
@@ -90,3 +89,96 @@ import CxxStdlib
9089
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper5(_ s: ConstSpanOfInt, _ p: Span<Int32>)
9190
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper6(_ s: ConstSpanOfInt, _ p: UnsafeMutableBufferPointer<Int32>)
9291
// CHECK-NEXT: @_alwaysEmitIntoClient public func mixedFuncWithSafeWrapper7(_ p: UnsafeBufferPointer<Int32>) -> ConstSpanOfInt
92+
93+
func callMethodWithSafeWrapper(_ x: inout X, s: Span<CInt>) {
94+
x.methodWithSafeWrapper(s)
95+
}
96+
97+
func callFooBar(_ x: inout SpanWithoutTypeAlias, _ s: ConstSpanOfInt) {
98+
let _: Span<CInt> = x.bar()
99+
unsafe x.foo(s)
100+
}
101+
102+
@lifetime(span: copy span)
103+
func callFuncWithMutableSafeWrapper(_ span: inout MutableSpan<CInt>, ) {
104+
FuncWithMutableSafeWrapper(&span)
105+
}
106+
107+
@lifetime(span: copy span)
108+
func callFuncWithMutableSafeWrapper2(_ span: inout MutableSpan<CInt>, ) {
109+
let _: MutableSpan<CInt> = FuncWithMutableSafeWrapper2(&span)
110+
}
111+
112+
@lifetime(span: copy span)
113+
func callMixedFuncWithMutableSafeWrapper1(_ span: inout MutableSpan<CInt>, ) {
114+
let _: MutableSpan<CInt> = MixedFuncWithMutableSafeWrapper1(&span)
115+
}
116+
117+
func MixedFuncWithMutableSafeWrapper2(_ v: VecOfInt) {
118+
var v2 = v
119+
let _ = MixedFuncWithMutableSafeWrapper2(&v2, 37)
120+
}
121+
122+
@lifetime(span: copy span)
123+
func callMixedFuncWithMutableSafeWrapper3(_ span: inout MutableSpan<CInt>, _ p: UnsafeMutableBufferPointer<CInt>) {
124+
unsafe MixedFuncWithMutableSafeWrapper3(&span, p)
125+
}
126+
127+
@lifetime(span1: copy span2)
128+
@lifetime(span2: copy span2)
129+
func callMixedFuncWithMutableSafeWrapper4(_ span1: inout MutableSpan<CInt>, _ span2: inout MutableSpan<CInt>) {
130+
MixedFuncWithMutableSafeWrapper4(&span1, &span2)
131+
}
132+
133+
@lifetime(span: copy span)
134+
func callMixedFuncWithMutableSafeWrapper5(_ span: inout MutableSpan<CInt>, _ s: SpanOfInt) {
135+
unsafe MixedFuncWithMutableSafeWrapper5(s, &span)
136+
}
137+
138+
func callMixedFuncWithMutableSafeWrapper6(_ s: SpanOfInt, _ p: UnsafeMutableBufferPointer<CInt>) {
139+
unsafe MixedFuncWithMutableSafeWrapper6(s, p)
140+
}
141+
142+
func callMixedFuncWithMutableSafeWrapper7(_ p: UnsafeMutableBufferPointer<CInt>) {
143+
let _ = unsafe MixedFuncWithMutableSafeWrapper7(p)
144+
}
145+
146+
func callFuncWithSafeWrapper(_ s: Span<CInt>) {
147+
funcWithSafeWrapper(s)
148+
}
149+
150+
func callFuncWithSafeWrapper2(_ s: Span<CInt>) {
151+
let _ = funcWithSafeWrapper2(s)
152+
}
153+
154+
func callFuncWithSafeWrapper3(_ v: borrowing VecOfInt) {
155+
let _: Span<CInt> = funcWithSafeWrapper3(v)
156+
}
157+
158+
func callMixedFuncWithSafeWrapper1(_ s: Span<CInt>) {
159+
let _: Span<CInt> = mixedFuncWithSafeWrapper1(s)
160+
}
161+
162+
func callMixedFuncWithSafeWrapper2(_ v: borrowing VecOfInt) {
163+
let _: Span<CInt> = mixedFuncWithSafeWrapper2(v, 73)
164+
}
165+
166+
func callMixedFuncWithSafeWrapper3(_ s: Span<CInt>, _ p: UnsafeMutableBufferPointer<CInt>) {
167+
unsafe mixedFuncWithSafeWrapper3(s, p)
168+
}
169+
170+
func callMixedFuncWithSafeWrapper4(_ s: Span<CInt>, _ s2: Span<CInt>) {
171+
mixedFuncWithSafeWrapper4(s, s2)
172+
}
173+
174+
func callMixedFuncWithSafeWrapper5(_ s: ConstSpanOfInt, _ s2: Span<CInt>) {
175+
unsafe mixedFuncWithSafeWrapper5(s, s2)
176+
}
177+
178+
func callMixedFuncWithSafeWrapper6(_ s: ConstSpanOfInt, _ p: UnsafeMutableBufferPointer<CInt>) {
179+
unsafe mixedFuncWithSafeWrapper6(s, p)
180+
}
181+
182+
func callMixedFuncWithSafeWrapper7(_ p: UnsafeBufferPointer<CInt>) {
183+
let _: ConstSpanOfInt = unsafe mixedFuncWithSafeWrapper7(p)
184+
}

0 commit comments

Comments
 (0)