Skip to content

[cxx-interop] Make borrowing specifiers more precise #78946

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions lib/ClangImporter/ImportType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2687,14 +2687,18 @@ static ParamDecl *getParameterInfo(ClangImporter::Implementation *impl,
}
}

// Parameters of type const T& imported as T, make sure we borrow from them
// when they have lifetime annotations.
bool isBorrowing = (param->getAttr<clang::LifetimeBoundAttr>() ||
param->getAttr<clang::LifetimeCaptureByAttr>()) &&
param->getType()->isReferenceType();
// Foreign references are already references so they don't need to be passed
// as inout.
paramInfo->setSpecifier(
isConsuming ? ParamSpecifier::Consuming
: (isInOut ? ParamSpecifier::InOut
: (param->getAttr<clang::LifetimeBoundAttr>()
? ParamSpecifier::Borrowing
: ParamSpecifier::Default)));
: (isBorrowing ? ParamSpecifier::Borrowing
: ParamSpecifier::Default)));
paramInfo->setInterfaceType(swiftParamTy);
impl->recordImplicitUnwrapForDecl(paramInfo, isParamTypeImplicitlyUnwrapped);

Expand Down
4 changes: 2 additions & 2 deletions test/Interop/Cxx/class/nonescapable-lifetimebound.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ CaptureView getCaptureView(const Owner& owner [[clang::lifetimebound]]) {
// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> @lifetime(borrow 0, borrow 1) @owned View
// CHECK: sil [clang Owner.handOutView] {{.*}} : $@convention(cxx_method) (@in_guaranteed Owner) -> @lifetime(borrow 0) @owned View
// CHECK: sil [clang Owner.handOutView2] {{.*}} : $@convention(cxx_method) (View, @in_guaranteed Owner) -> @lifetime(borrow 1) @owned View
// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (@guaranteed View, @guaranteed View) -> @lifetime(copy 0, copy 1) @owned View
// CHECK: sil [clang getViewFromEither] {{.*}} : $@convention(c) (View, View) -> @lifetime(copy 0, copy 1) @owned View
// CHECK: sil [clang View.init] {{.*}} : $@convention(c) () -> @lifetime(immortal) @out View
// CHECK: sil [clang OtherView.init] {{.*}} : $@convention(c) (@guaranteed View) -> @lifetime(copy 0) @out OtherView
// CHECK: sil [clang OtherView.init] {{.*}} : $@convention(c) (View) -> @lifetime(copy 0) @out OtherView
// CHECK: sil [clang returnsImmortal] {{.*}} : $@convention(c) () -> @lifetime(immortal) @owned View
// CHECK: sil [clang copyView] {{.*}} : $@convention(c) (View, @lifetime(copy 0) @inout View) -> ()
// CHECK: sil [clang getCaptureView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow 0) @owned CaptureView
Expand Down
7 changes: 7 additions & 0 deletions test/Interop/Cxx/stdlib/Inputs/std-span.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ struct DependsOnSelf {

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

struct CaptureByReference {
void set(const std::vector<int>& x [[clang::lifetime_capture_by(this)]]) {
this->x = ConstSpanOfInt(x.data(), x.size());
};
ConstSpanOfInt x;
};

inline void funcWithSafeWrapper(ConstSpanOfInt s [[clang::noescape]]) {}

inline ConstSpanOfInt funcWithSafeWrapper2(ConstSpanOfInt s
Expand Down
5 changes: 3 additions & 2 deletions test/Interop/Cxx/stdlib/std-span-interface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ import CxxStdlib
// CHECK-NEXT: @_alwaysEmitIntoClient public mutating func get() -> Span<CInt>
// CHECK-NEXT: mutating func get() -> ConstSpanOfInt

// CHECK: mutating func set(_ x: borrowing std.{{.*}}vector<CInt, std.{{.*}}allocator<CInt>>)
// CHECK: func funcWithSafeWrapper(_ s: ConstSpanOfInt)
// CHECK-NEXT: func funcWithSafeWrapper2(_ s: borrowing ConstSpanOfInt) -> ConstSpanOfInt
// CHECK-NEXT: func funcWithSafeWrapper2(_ s: ConstSpanOfInt) -> ConstSpanOfInt
// CHECK-NEXT: func funcWithSafeWrapper3(_ v: borrowing VecOfInt) -> ConstSpanOfInt
// CHECK: struct X {
// CHECK-NEXT: init()
Expand All @@ -29,6 +30,6 @@ import CxxStdlib
// CHECK-NEXT: }
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper(_ s: Span<CInt>)
// CHECK-NEXT: @lifetime(s)
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper2(_ s: borrowing Span<CInt>) -> Span<CInt>
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper2(_ s: Span<CInt>) -> Span<CInt>
// CHECK-NEXT: @lifetime(borrow v)
// CHECK-NEXT: @_alwaysEmitIntoClient public func funcWithSafeWrapper3(_ v: borrowing VecOfInt) -> Span<CInt>