Skip to content

Commit e68b6a7

Browse files
Merge pull request swiftlang#39283 from nate-chandler/lexical_lifetimes/let/initial
[SILGen] Added [defined] lifetimes for lets behind flag.
2 parents 8ff863e + a0c47cb commit e68b6a7

File tree

5 files changed

+90
-5
lines changed

5 files changed

+90
-5
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,9 @@ namespace swift {
301301
/// Enable experimental concurrency model.
302302
bool EnableExperimentalConcurrency = false;
303303

304+
/// Enable experimental support for emitting defined borrow scopes.
305+
bool EnableExperimentalDefinedLifetimes = false;
306+
304307
/// Enable experimental support for named opaque result types, e.g.
305308
/// `func f() -> <T> T`.
306309
bool EnableExperimentalNamedOpaqueTypes = false;

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,10 @@ def enable_experimental_concurrency :
247247
Flag<["-"], "enable-experimental-concurrency">,
248248
HelpText<"Enable experimental concurrency model">;
249249

250+
def enable_experimental_defined_lifetimes :
251+
Flag<["-"], "enable-experimental-defined-lifetimes">,
252+
HelpText<"Enable experimental defined lifetimes">;
253+
250254
def enable_experimental_distributed :
251255
Flag<["-"], "enable-experimental-distributed">,
252256
HelpText<"Enable experimental 'distributed' actors and functions">;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
429429
Opts.EnableExperimentalConcurrency |=
430430
Args.hasArg(OPT_enable_experimental_concurrency);
431431

432+
Opts.EnableExperimentalDefinedLifetimes |=
433+
Args.hasArg(OPT_enable_experimental_defined_lifetimes);
434+
432435
Opts.EnableExperimentalNamedOpaqueTypes |=
433436
Args.hasArg(OPT_enable_experimental_named_opaque_types);
434437

lib/SILGen/SILGenDecl.cpp

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

272272
void emit(SILGenFunction &SGF, CleanupLocation l,
273273
ForUnwind_t forUnwind) override {
274+
SILValue val = SGF.VarLocs[Var].value;
275+
if (SGF.getASTContext().LangOpts.EnableExperimentalDefinedLifetimes &&
276+
val->getOwnershipKind() != OwnershipKind::None)
277+
SGF.B.createEndBorrow(l, val);
274278
SGF.destroyLocalVariable(l, Var);
275279
}
276280

@@ -537,13 +541,18 @@ class LetValueInitialization : public Initialization {
537541
// an argument, for example.
538542
if (value->getType().isAddress())
539543
address = value;
544+
SILLocation PrologueLoc(vd);
545+
546+
if (SGF.getASTContext().LangOpts.EnableExperimentalDefinedLifetimes &&
547+
value->getOwnershipKind() != OwnershipKind::None)
548+
value = SILValue(
549+
SGF.B.createBeginBorrow(PrologueLoc, value, /*defined*/ true));
540550
SGF.VarLocs[vd] = SILGenFunction::VarLoc::get(value);
541551

542552
// Emit a debug_value[_addr] instruction to record the start of this value's
543553
// lifetime, if permitted to do so.
544554
if (!EmitDebugValueOnInit)
545555
return;
546-
SILLocation PrologueLoc(vd);
547556
PrologueLoc.markAsPrologue();
548557
SILDebugVariable DbgVar(vd->isLet(), /*ArgNo=*/0);
549558
SGF.B.emitDebugDescription(PrologueLoc, value, DbgVar);
@@ -1723,8 +1732,16 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
17231732
// For 'let' bindings, we emit a release_value or destroy_addr, depending on
17241733
// whether we have an address or not.
17251734
SILValue Val = loc.value;
1726-
if (!Val->getType().isAddress())
1727-
B.emitDestroyValueOperation(silLoc, Val);
1728-
else
1735+
if (!Val->getType().isAddress()) {
1736+
SILValue valueToBeDestroyed;
1737+
if (getASTContext().LangOpts.EnableExperimentalDefinedLifetimes &&
1738+
Val->getOwnershipKind() != OwnershipKind::None) {
1739+
auto *inst = cast<BeginBorrowInst>(Val.getDefiningInstruction());
1740+
valueToBeDestroyed = inst->getOperand();
1741+
} else {
1742+
valueToBeDestroyed = Val;
1743+
}
1744+
B.emitDestroyValueOperation(silLoc, valueToBeDestroyed);
1745+
} else
17291746
B.createDestroyAddr(silLoc, Val);
17301747
}

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)