Skip to content

Commit a76a3fc

Browse files
author
Gabor Horvath
committed
[cxx-interop] Support lifetime_capture_by in ClangImporter
Import it as lifetime dependencies. rdar://137671377
1 parent f88b29b commit a76a3fc

File tree

2 files changed

+61
-5
lines changed

2 files changed

+61
-5
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/AST/ConformanceLookup.h"
2626
#include "swift/AST/Decl.h"
2727
#include "swift/AST/DiagnosticsClangImporter.h"
28+
#include "swift/AST/LifetimeDependence.h"
2829
#include "swift/ClangImporter/ClangImporter.h"
2930
#include "swift/AST/ExistentialLayout.h"
3031
#include "swift/AST/Expr.h"
@@ -56,6 +57,7 @@
5657
#include "swift/Strings.h"
5758
#include "clang/AST/ASTContext.h"
5859
#include "clang/AST/Attr.h"
60+
#include "clang/AST/Attrs.inc"
5961
#include "clang/AST/Decl.h"
6062
#include "clang/AST/DeclCXX.h"
6163
#include "clang/AST/DeclObjCCommon.h"
@@ -66,6 +68,7 @@
6668
#include "clang/Sema/Lookup.h"
6769

6870
#include "llvm/ADT/STLExtras.h"
71+
#include "llvm/ADT/SmallBitVector.h"
6972
#include "llvm/ADT/SmallString.h"
7073
#include "llvm/ADT/Statistic.h"
7174
#include "llvm/ADT/StringExtras.h"
@@ -3892,10 +3895,10 @@ namespace {
38923895
auto swiftParams = result->getParameters();
38933896
bool hasSelf =
38943897
result->hasImplicitSelfDecl() && !isa<ConstructorDecl>(result);
3895-
SmallBitVector inheritLifetimeParamIndicesForReturn(swiftParams->size() +
3896-
hasSelf);
3897-
SmallBitVector scopedLifetimeParamIndicesForReturn(swiftParams->size() +
3898-
hasSelf);
3898+
const auto dependencyVecSize = swiftParams->size() + hasSelf;
3899+
SmallBitVector inheritLifetimeParamIndicesForReturn(dependencyVecSize);
3900+
SmallBitVector scopedLifetimeParamIndicesForReturn(dependencyVecSize);
3901+
std::map<unsigned, SmallBitVector> inheritedArgDependences;
38993902
for (auto [idx, param] : llvm::enumerate(decl->parameters())) {
39003903
if (param->hasAttr<clang::LifetimeBoundAttr>()) {
39013904
warnForEscapableReturnType();
@@ -3904,6 +3907,26 @@ namespace {
39043907
else
39053908
inheritLifetimeParamIndicesForReturn[idx] = true;
39063909
}
3910+
if (const auto *captureAttr = param->getAttr<clang::LifetimeCaptureByAttr>()) {
3911+
// FIXME: support scoped inheritance. This is not straightforward as const T& is imported as taking a value
3912+
// and we assume the address of T would not escape. An annotation in this case contradicts our assumptions.
3913+
// We should diagnose that, and support this for the non-const case.
3914+
if (swiftParams->get(idx)->getInterfaceType()->isEscapable())
3915+
continue;
3916+
for (auto param : captureAttr->params()) {
3917+
// FIXME: Swift assumes no escaping to globals. We should diagnose this.
3918+
if (param == clang::LifetimeCaptureByAttr::GLOBAL || param == clang::LifetimeCaptureByAttr::UNKNOWN || param == clang::LifetimeCaptureByAttr::INVALID)
3919+
continue;
3920+
3921+
if (isa<clang::CXXMethodDecl>(decl) && param == clang::LifetimeCaptureByAttr::THIS) {
3922+
auto [it, inserted] = inheritedArgDependences.try_emplace(result->getSelfIndex(), SmallBitVector(dependencyVecSize));
3923+
it->second[idx] = true;
3924+
} else {
3925+
auto [it, inserted] = inheritedArgDependences.try_emplace(param, SmallBitVector(dependencyVecSize));
3926+
it->second[idx] = true;
3927+
}
3928+
}
3929+
}
39073930
}
39083931
if (implicitObjectParamIsLifetimeBound(decl)) {
39093932
warnForEscapableReturnType();
@@ -3914,6 +3937,11 @@ namespace {
39143937
inheritLifetimeParamIndicesForReturn[idx] = true;
39153938
}
39163939

3940+
for (auto& [idx, inheritedDepVec]: inheritedArgDependences) {
3941+
lifetimeDependencies.push_back(LifetimeDependenceInfo(inheritedDepVec.any() ? IndexSubset::get(Impl.SwiftContext,
3942+
inheritedDepVec): nullptr, nullptr, idx, /*isImmortal=*/false));
3943+
}
3944+
39173945
if (inheritLifetimeParamIndicesForReturn.any() ||
39183946
scopedLifetimeParamIndicesForReturn.any())
39193947
lifetimeDependencies.push_back(LifetimeDependenceInfo(

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

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,29 @@ View returnsImmortal() SWIFT_RETURNS_INDEPENDENT_VALUE {
8282
return View();
8383
}
8484

85+
void copyView(View view1 [[clang::lifetime_capture_by(view2)]], View &view2) {
86+
view2 = view1;
87+
}
88+
89+
struct SWIFT_NONESCAPABLE CaptureView {
90+
CaptureView() : view(nullptr) {}
91+
CaptureView(View p [[clang::lifetimebound]]) : view(p) {}
92+
93+
void captureView(View v [[clang::lifetime_capture_by(this)]]) {
94+
view = v;
95+
}
96+
97+
void handOut(View &v) const [[clang::lifetime_capture_by(v)]] {
98+
v = view;
99+
}
100+
101+
View view;
102+
};
103+
104+
CaptureView getCaptureView(const Owner& owner [[clang::lifetimebound]]) {
105+
return CaptureView(View{&owner.data});
106+
}
107+
85108
// CHECK: sil [clang makeOwner] {{.*}}: $@convention(c) () -> Owner
86109
// CHECK: sil [clang getView] {{.*}} : $@convention(c) (@in_guaranteed Owner) -> @lifetime(borrow 0) @autoreleased View
87110
// CHECK: sil [clang getViewFromFirst] {{.*}} : $@convention(c) (@in_guaranteed Owner, @in_guaranteed Owner) -> @lifetime(borrow 0) @autoreleased View
@@ -100,7 +123,7 @@ import Test
100123
public func test() {
101124
let o = makeOwner()
102125
let o2 = makeOwner()
103-
let v1 = getView(o)
126+
var v1 = getView(o)
104127
let v2 = getViewFromFirst(o, o2)
105128
let _ = getViewFromEither(o, o2)
106129
let _ = o.handOutView()
@@ -109,4 +132,9 @@ public func test() {
109132
let defaultView = View()
110133
let _ = OtherView(defaultView)
111134
let _ = returnsImmortal()
135+
// FIXME: triggers crash in StaticExclusivityCheck pass.
136+
//copyView(v2, &v1)
137+
//var cv = getCaptureView(o)
138+
//cv.captureView(v1)
139+
//cv.handOut(&v1)
112140
}

0 commit comments

Comments
 (0)