Skip to content

Commit a0c47cb

Browse files
committed
[SILGen] Emitted [defined] borrow scopes for lets.
When -enable-experimental-defined-lifetimes is passed, SILGen emits lexical scopes for lets.
1 parent d002471 commit a0c47cb

File tree

2 files changed

+80
-5
lines changed

2 files changed

+80
-5
lines changed

lib/SILGen/SILGenDecl.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,10 @@ class DestroyLocalVariable : public Cleanup {
262262

263263
void emit(SILGenFunction &SGF, CleanupLocation l,
264264
ForUnwind_t forUnwind) override {
265+
SILValue val = SGF.VarLocs[Var].value;
266+
if (SGF.getASTContext().LangOpts.EnableExperimentalDefinedLifetimes &&
267+
val->getOwnershipKind() != OwnershipKind::None)
268+
SGF.B.createEndBorrow(l, val);
265269
SGF.destroyLocalVariable(l, Var);
266270
}
267271

@@ -528,13 +532,18 @@ class LetValueInitialization : public Initialization {
528532
// an argument, for example.
529533
if (value->getType().isAddress())
530534
address = value;
535+
SILLocation PrologueLoc(vd);
536+
537+
if (SGF.getASTContext().LangOpts.EnableExperimentalDefinedLifetimes &&
538+
value->getOwnershipKind() != OwnershipKind::None)
539+
value = SILValue(
540+
SGF.B.createBeginBorrow(PrologueLoc, value, /*defined*/ true));
531541
SGF.VarLocs[vd] = SILGenFunction::VarLoc::get(value);
532542

533543
// Emit a debug_value[_addr] instruction to record the start of this value's
534544
// lifetime, if permitted to do so.
535545
if (!EmitDebugValueOnInit)
536546
return;
537-
SILLocation PrologueLoc(vd);
538547
PrologueLoc.markAsPrologue();
539548
SILDebugVariable DbgVar(vd->isLet(), /*ArgNo=*/0);
540549
SGF.B.emitDebugDescription(PrologueLoc, value, DbgVar);
@@ -1714,8 +1723,16 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
17141723
// For 'let' bindings, we emit a release_value or destroy_addr, depending on
17151724
// whether we have an address or not.
17161725
SILValue Val = loc.value;
1717-
if (!Val->getType().isAddress())
1718-
B.emitDestroyValueOperation(silLoc, Val);
1719-
else
1726+
if (!Val->getType().isAddress()) {
1727+
SILValue valueToBeDestroyed;
1728+
if (getASTContext().LangOpts.EnableExperimentalDefinedLifetimes &&
1729+
Val->getOwnershipKind() != OwnershipKind::None) {
1730+
auto *inst = cast<BeginBorrowInst>(Val.getDefiningInstruction());
1731+
valueToBeDestroyed = inst->getOperand();
1732+
} else {
1733+
valueToBeDestroyed = Val;
1734+
}
1735+
B.emitDestroyValueOperation(silLoc, valueToBeDestroyed);
1736+
} else
17201737
B.createDestroyAddr(silLoc, Val);
17211738
}

test/SILGen/borrow.swift

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
// RUN: %target-swift-emit-silgen -module-name borrow -parse-stdlib %s | %FileCheck %s
2+
// RUN: %target-swift-emit-silgen -enable-experimental-defined-lifetimes -module-name borrow -parse-stdlib %s | %FileCheck %s
33

44
import Swift
55

@@ -8,9 +8,12 @@ final class D {}
88
// Make sure that we insert the borrow for a ref_element_addr lvalue in the
99
// proper place.
1010
final class C {
11+
init() {}
12+
init?(failably: ()) {}
1113
var d: D = D()
1214
}
1315

16+
func use<T>(_ t: T) {}
1417
func useD(_ d: D) {}
1518

1619
// CHECK-LABEL: sil hidden [ossa] @$s6borrow44lvalueBorrowShouldBeAtEndOfFormalAccessScope{{.*}} : $@convention(thin) () -> () {
@@ -33,3 +36,58 @@ func lvalueBorrowShouldBeAtEndOfFormalAccessScope() {
3336
var c = C()
3437
useD(c.d)
3538
}
39+
40+
// CHECK-LABEL: sil hidden [ossa] @defined_borrow_let_class
41+
// CHECK: [[INIT_C:%[^,]+]] = function_ref @$s6borrow1CCACycfC
42+
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_C]]({{%[0-9]+}})
43+
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [defined] [[INSTANCE]] : $C
44+
// CHECK: end_borrow [[BORROW:%[^,]+]]
45+
// CHECK-LABEL: } // end sil function 'defined_borrow_let_class'
46+
@_silgen_name("defined_borrow_let_class")
47+
func defined_borrow_let_class() {
48+
let c = C()
49+
}
50+
51+
// CHECK-LABEL: sil hidden [ossa] @defined_borrow_if_let_class
52+
// CHECK: [[INIT_C:%[^,]+]] = function_ref @$s6borrow1CC8failablyACSgyt_tcfC
53+
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_C]]({{%[^,]+}})
54+
// CHECK: switch_enum [[INSTANCE]] : $Optional<C>, case #Optional.some!enumelt: [[BASIC_BLOCK2:bb[^,]+]], case #Optional.none!enumelt: {{bb[^,]+}}
55+
// CHECK: [[BASIC_BLOCK2]]([[INSTANCE:%[^,]+]] : @owned $C):
56+
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [defined] [[INSTANCE]] : $C
57+
// CHECK: end_borrow [[BORROW]] : $C
58+
// CHECK-LABEL: // end sil function 'defined_borrow_if_let_class'
59+
@_silgen_name("defined_borrow_if_let_class")
60+
func defined_borrow_if_let_class() {
61+
if let c = C(failably: ()) {
62+
use(())
63+
}
64+
}
65+
66+
struct S {
67+
let c: C
68+
}
69+
70+
// CHECK-LABEL: sil hidden [ossa] @defined_borrow_let_class_in_struct
71+
// CHECK: [[INIT_S:%[^,]+]] = function_ref @$s6borrow1SV1cAcA1CC_tcfC
72+
// CHECK: [[INSTANCE:%[^,]+]] = apply [[INIT_S]]({{%[0-9]+}}, {{%[0-9]+}})
73+
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [defined] [[INSTANCE]] : $S
74+
// CHECK: end_borrow [[BORROW:%[^,]+]]
75+
// CHECK-LABEL: } // end sil function 'defined_borrow_let_class_in_struct'
76+
@_silgen_name("defined_borrow_let_class_in_struct")
77+
func defined_borrow_let_class_in_struct() {
78+
let s = S(c: C())
79+
}
80+
81+
enum E {
82+
case e(C)
83+
}
84+
85+
// CHECK-LABEL: sil hidden [ossa] @defined_borrow_let_class_in_enum
86+
// CHECK: [[INSTANCE:%[^,]+]] = enum $E, #E.e!enumelt, {{%[0-9]+}} : $C
87+
// CHECK: [[BORROW:%[^,]+]] = begin_borrow [defined] [[INSTANCE]] : $E
88+
// CHECK: end_borrow [[BORROW:%[^,]+]]
89+
// CHECK-LABEL: } // end sil function 'defined_borrow_let_class_in_enum'
90+
@_silgen_name("defined_borrow_let_class_in_enum")
91+
func defined_borrow_let_class_in_enum() {
92+
let s = E.e(C())
93+
}

0 commit comments

Comments
 (0)