Skip to content

Commit 05bcc25

Browse files
committed
SIL: Local functions should inherit isolation from context
If the outer context is actor isolated, we need to force a capture the actor variable, since otherwise it might not appear in the capture list.
1 parent 24857ab commit 05bcc25

File tree

3 files changed

+71
-2
lines changed

3 files changed

+71
-2
lines changed

lib/SIL/IR/TypeLowering.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4312,6 +4312,20 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
43124312
PrettyStackTraceAnyFunctionRef("lowering local captures", curFn);
43134313
collectCaptures(curFn.getCaptureInfo());
43144314

4315+
if (auto *afd = curFn.getAbstractFunctionDecl()) {
4316+
// If a local function inherits isolation from the enclosing context,
4317+
// make sure we capture the isolated parameter, if we haven't already.
4318+
if (afd->isLocalCapture()) {
4319+
auto actorIsolation = getActorIsolation(afd);
4320+
if (actorIsolation.getKind() == ActorIsolation::ActorInstance) {
4321+
if (auto *var = actorIsolation.getActorInstance()) {
4322+
assert(isa<ParamDecl>(var));
4323+
recordCapture(CapturedValue(var, 0, afd->getLoc()));
4324+
}
4325+
}
4326+
}
4327+
}
4328+
43154329
// A function's captures also include its default arguments, because
43164330
// when we reference a function we don't track which default arguments
43174331
// are referenced too.

lib/SILGen/SILGenConcurrency.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ void SILGenFunction::emitExpectedExecutor() {
107107
// completely.
108108
if (F.isAsync() ||
109109
(wantDataRaceChecks && funcDecl->isLocalCapture())) {
110-
if (auto isolatedParam = funcDecl->getCaptureInfo()
111-
.getIsolatedParamCapture()) {
110+
auto loweredCaptures = SGM.Types.getLoweredLocalCaptures(SILDeclRef(funcDecl));
111+
if (auto isolatedParam = loweredCaptures.getIsolatedParamCapture()) {
112112
loadExpectedExecutorForLocalVar(isolatedParam);
113113
} else {
114114
auto loc = RegularLocation::getAutoGeneratedLocation(F.getLocation());
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s -disable-availability-checking | %FileCheck %s
2+
3+
// REQUIRES: concurrency
4+
5+
class NotSendable {}
6+
7+
func callee(_ ns: NotSendable) {}
8+
9+
actor MyActor {
10+
func isolatedToSelf(ns: NotSendable) {
11+
// CHECK-LABEL: sil private [ossa] @$s24local_function_isolation7MyActorC14isolatedToSelf2nsyAA11NotSendableC_tF08implicitH7CaptureL_yyYaF : $@convention(thin) @async (@guaranteed NotSendable, @sil_isolated @guaranteed MyActor) -> () {
12+
func implicitSelfCapture() async {
13+
14+
// CHECK: [[COPY:%.*]] = copy_value %1 : $MyActor
15+
// CHECK-NEXT: [[BORROW:%.*]] = begin_borrow [[COPY]] : $MyActor
16+
// CHECK-NEXT: hop_to_executor [[BORROW]] : $MyActor
17+
18+
// CHECK: [[FN:%.*]] = function_ref @$s24local_function_isolation4testyyYaF : $@convention(thin) @async () -> ()
19+
// CHECK-NEXT: apply [[FN]]() : $@convention(thin) @async () -> ()
20+
await test()
21+
22+
// CHECK: hop_to_executor [[BORROW]] : $MyActor
23+
// CHECK: [[FN:%.*]] = function_ref @$s24local_function_isolation6calleeyyAA11NotSendableCF : $@convention(thin) (@guaranteed NotSendable) -> ()
24+
// CHECK-NEXT: apply [[FN]](%0) : $@convention(thin) (@guaranteed NotSendable) -> ()
25+
26+
// we need to hop back to 'self' here
27+
callee(ns)
28+
29+
// CHECK: end_borrow [[BORROW]] : $MyActor
30+
// CHECK-NEXT: destroy_value [[COPY]] : $MyActor
31+
}
32+
}
33+
}
34+
35+
func f(isolation: isolated MyActor, ns: NotSendable) {
36+
// CHECK-LABEL: sil private [ossa] @$s24local_function_isolation1f0C02nsyAA7MyActorCYi_AA11NotSendableCtF23implicitIsolatedCaptureL_yyYaF : $@convention(thin) @async (@guaranteed NotSendable, @sil_isolated @guaranteed MyActor) -> () {
37+
func implicitIsolatedCapture() async {
38+
39+
// CHECK: [[COPY:%.*]] = copy_value %1 : $MyActor
40+
// CHECK-NEXT: [[BORROW:%.*]] = begin_borrow [[COPY]] : $MyActor
41+
// CHECK-NEXT: hop_to_executor [[BORROW]] : $MyActor
42+
43+
// CHECK: [[FN:%.*]] = function_ref @$s24local_function_isolation4testyyYaF : $@convention(thin) @async () -> ()
44+
// CHECK-NEXT: apply [[FN]]() : $@convention(thin) @async () -> ()
45+
await test()
46+
47+
// we need to hop back to 'isolation' here
48+
callee(ns)
49+
50+
// CHECK: end_borrow [[BORROW]] : $MyActor
51+
// CHECK-NEXT: destroy_value [[COPY]] : $MyActor
52+
}
53+
}
54+
55+
func test() async {}

0 commit comments

Comments
 (0)