Files
swift-mirror/test/Interop/Cxx/class/nonescapable-lifetimebound.swift
Gabor Horvath 6b24af65f0 [cxx-interop] Always import the lifetime annotations
Importing these annotations were behind the LifetimeDependence
experimental flag. However, this feature flag is intended to guard the
use of @lifetime annotations on the Swift side and lifetime inference.
The checking of imported lifetime contracts should work even when this
flag is off. Removing the flag from the importer caused some fallout.
This was mostly due to calling getInterfaceType functions before the
import of some Swift declarations were fully done so the code was
slightly improved to make decisions only based on the C++ types.
There was also a crash when on-member functions imported as methods into
Swift. That is worked around in this PR.

There is one last feature check that we cannot remove yet, we generate
@lifetime annotations in the SwiftifyImport macro.
2025-03-05 15:36:59 +00:00

152 lines
5.2 KiB
Swift

// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: %target-swift-frontend -I %swift_src_root/lib/ClangImporter/SwiftBridging -I %t/Inputs -emit-sil %t/test.swift -enable-experimental-feature LifetimeDependence -cxx-interoperability-mode=default -diagnostic-style llvm 2>&1 | %FileCheck %s
// RUN: %target-swift-frontend -I %swift_src_root/lib/ClangImporter/SwiftBridging -I %t/Inputs -emit-sil %t/test.swift -cxx-interoperability-mode=default -diagnostic-style llvm 2>&1 | %FileCheck %s
// REQUIRES: swift_feature_LifetimeDependence
//--- Inputs/module.modulemap
module Test {
header "nonescapable.h"
requires cplusplus
}
//--- Inputs/nonescapable.h
#include "swift/bridging"
struct SWIFT_NONESCAPABLE View {
View() : member(nullptr) {}
View(const int *p [[clang::lifetimebound]]) : member(p) {}
View(const View&) = default;
private:
const int *member;
friend struct OtherView;
};
struct SWIFT_NONESCAPABLE OtherView {
OtherView(View v [[clang::lifetimebound]]) : member(v.member) {}
OtherView(const OtherView&) = default;
private:
const int *member;
};
struct Owner {
int data;
View handOutView() const [[clang::lifetimebound]] {
return View(&data);
}
View handOutView2(View v) const [[clang::lifetimebound]] {
return View(&data);
}
};
Owner makeOwner() {
return Owner{42};
}
View getView(const Owner& owner [[clang::lifetimebound]]) {
return View(&owner.data);
}
View getViewFromFirst(const Owner& owner [[clang::lifetimebound]], const Owner& owner2) {
return View(&owner.data);
}
bool coinFlip;
View getViewFromEither(const Owner& owner [[clang::lifetimebound]], const Owner& owner2 [[clang::lifetimebound]]) {
if (coinFlip)
return View(&owner.data);
else
return View(&owner2.data);
}
View getViewFromEither(View view1 [[clang::lifetimebound]], View view2 [[clang::lifetimebound]]) {
if (coinFlip)
return view1;
else
return view2;
}
struct SWIFT_NONESCAPABLE TestAnnotationTranslation {
TestAnnotationTranslation() : member(nullptr) {}
TestAnnotationTranslation(const int *p [[clang::lifetimebound]]) : member(p) {}
TestAnnotationTranslation(const TestAnnotationTranslation& [[clang::lifetimebound]]) = default;
private:
const int *member;
};
View returnsImmortal() SWIFT_RETURNS_INDEPENDENT_VALUE {
return View();
}
void copyView(View view1 [[clang::lifetime_capture_by(view2)]], View &view2) {
view2 = view1;
}
struct SWIFT_NONESCAPABLE CaptureView {
CaptureView() : view(nullptr) {}
CaptureView(View p [[clang::lifetimebound]]) : view(p) {}
void captureView(View v [[clang::lifetime_capture_by(this)]]) {
view = v;
}
void handOut(View &v) const [[clang::lifetime_capture_by(v)]] {
v = view;
}
View view;
};
CaptureView getCaptureView(const Owner& owner [[clang::lifetimebound]]) {
return CaptureView(View{&owner.data});
}
struct SWIFT_NONESCAPABLE AggregateView {
const int *member;
};
// CHECK: sil [clang makeOwner] {{.*}}: $@convention(c) () -> Owner
// CHECK: sil [clang getView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow 0) @owned View
// CHECK: sil [clang getViewFromFirst] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> @lifetime(borrow 0) @owned View
// 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) (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) (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
// CHECK: sil [clang CaptureView.captureView] {{.*}} : $@convention(cxx_method) (View, @lifetime(copy 0) @inout CaptureView) -> ()
// CHECK: sil [clang CaptureView.handOut] {{.*}} : $@convention(cxx_method) (@lifetime(copy 1) @inout View, @in_guaranteed CaptureView) -> ()
//--- test.swift
import Test
public func test() {
let o = makeOwner()
let o2 = makeOwner()
var v1 = getView(o)
let v2 = getViewFromFirst(o, o2)
let _ = getViewFromEither(o, o2)
let _ = o.handOutView()
let _ = o.handOutView2(v1)
let _ = getViewFromEither(v1, v2)
let defaultView = View()
let _ = OtherView(defaultView)
let _ = returnsImmortal()
copyView(v2, &v1)
var cv = getCaptureView(o)
cv.captureView(v1)
cv.handOut(&v1)
}
public func test2(_ x: AggregateView) {
let _ = AggregateView(member: x.member)
}