Skip to content

Commit dd3db51

Browse files
author
Gabor Horvath
committed
[cxx-interop] Make borrowing specifiers more precise
We do not need to borrow from view objects passed by value but we need to borrow from owners taken by const reference regardless of whether it was annotated using lifetimebound or lifetime_capture_by.
1 parent 44fa650 commit dd3db51

File tree

4 files changed

+19
-7
lines changed

4 files changed

+19
-7
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2687,14 +2687,18 @@ static ParamDecl *getParameterInfo(ClangImporter::Implementation *impl,
26872687
}
26882688
}
26892689

2690+
// Parameters of type const T& imported as T, make sure we borrow from them
2691+
// when they have lifetime annotations.
2692+
bool isBorrowing = (param->getAttr<clang::LifetimeBoundAttr>() ||
2693+
param->getAttr<clang::LifetimeCaptureByAttr>()) &&
2694+
param->getType()->isReferenceType();
26902695
// Foreign references are already references so they don't need to be passed
26912696
// as inout.
26922697
paramInfo->setSpecifier(
26932698
isConsuming ? ParamSpecifier::Consuming
26942699
: (isInOut ? ParamSpecifier::InOut
2695-
: (param->getAttr<clang::LifetimeBoundAttr>()
2696-
? ParamSpecifier::Borrowing
2697-
: ParamSpecifier::Default)));
2700+
: (isBorrowing ? ParamSpecifier::Borrowing
2701+
: ParamSpecifier::Default)));
26982702
paramInfo->setInterfaceType(swiftParamTy);
26992703
impl->recordImplicitUnwrapForDecl(paramInfo, isParamTypeImplicitlyUnwrapped);
27002704

test/Interop/Cxx/class/nonescapable-lifetimebound.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ CaptureView getCaptureView(const Owner& owner [[clang::lifetimebound]]) {
111111
// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> @lifetime(borrow 0, borrow 1) @owned View
112112
// CHECK: sil [clang Owner.handOutView] {{.*}} : $@convention(cxx_method) (@in_guaranteed Owner) -> @lifetime(borrow 0) @owned View
113113
// CHECK: sil [clang Owner.handOutView2] {{.*}} : $@convention(cxx_method) (View, @in_guaranteed Owner) -> @lifetime(borrow 1) @owned View
114-
// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@guaranteed View, @guaranteed View) -> @lifetime(copy 0, copy 1) @owned View
114+
// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (View, View) -> @lifetime(copy 0, copy 1) @owned View
115115
// CHECK: sil [clang View.init] {{.*}} : $@convention(c) () -> @lifetime(immortal) @out View
116-
// CHECK: sil [clang OtherView.init] {{.*}} : $@convention(c) (@guaranteed View) -> @lifetime(copy 0) @out OtherView
116+
// CHECK: sil [clang OtherView.init] {{.*}} : $@convention(c) (View) -> @lifetime(copy 0) @out OtherView
117117
// CHECK: sil [clang returnsImmortal] {{.*}} : $@convention(c) () -> @lifetime(immortal) @owned View
118118
// CHECK: sil [clang copyView] {{.*}} : $@convention(c) (View, @lifetime(copy 0) @inout View) -> ()
119119
// CHECK: sil [clang getCaptureView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow 0) @owned CaptureView

test/Interop/Cxx/stdlib/Inputs/std-span.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ struct DependsOnSelf {
6262

6363
inline struct SpanBox getStructSpanBox() { return {iarray, iarray, sarray, sarray}; }
6464

65+
struct CaptureByReference {
66+
void set(const std::vector<int>& x [[clang::lifetime_capture_by(this)]]) {
67+
this->x = ConstSpanOfInt(x.data(), x.size());
68+
};
69+
ConstSpanOfInt x;
70+
};
71+
6572
inline void funcWithSafeWrapper(ConstSpanOfInt s [[clang::noescape]]) {}
6673

6774
inline ConstSpanOfInt funcWithSafeWrapper2(ConstSpanOfInt s

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ import CxxStdlib
1919
// CHECK-NEXT: @_alwaysEmitIntoClient public mutating func get() -> Span<CInt>
2020
// CHECK-NEXT: mutating func get() -> ConstSpanOfInt
2121

22+
// CHECK: mutating func set(_ x: borrowing std.{{.*}}vector<CInt, std.{{.*}}allocator<CInt>>)
2223
// CHECK: func funcWithSafeWrapper(_ s: ConstSpanOfInt)
23-
// CHECK-NEXT: func funcWithSafeWrapper2(_ s: borrowing ConstSpanOfInt) -> ConstSpanOfInt
24+
// CHECK-NEXT: func funcWithSafeWrapper2(_ s: ConstSpanOfInt) -> ConstSpanOfInt
2425
// CHECK-NEXT: func funcWithSafeWrapper3(_ v: borrowing VecOfInt) -> ConstSpanOfInt
2526
// CHECK: struct X {
2627
// CHECK-NEXT: init()
@@ -29,6 +30,6 @@ import CxxStdlib
2930
// CHECK-NEXT: }
3031
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper(_ s: Span<CInt>)
3132
// CHECK-NEXT: @lifetime(s)
32-
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper2(_ s: borrowing Span<CInt>) -> Span<CInt>
33+
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper2(_ s: Span<CInt>) -> Span<CInt>
3334
// CHECK-NEXT: @lifetime(borrow v)
3435
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper3(_ v: borrowing VecOfInt) -> Span<CInt>

0 commit comments

Comments
 (0)