Skip to content

Commit c0db6b6

Browse files
authored
Merge pull request #82868 from rjmccall/dont-capture-defer-isolation-6.2
[6.2] Don't force a capture of an isolated parameter in defer bodies
2 parents 0bf7b29 + fb9e730 commit c0db6b6

File tree

4 files changed

+67
-6
lines changed

4 files changed

+67
-6
lines changed

lib/SILGen/SILGenConcurrency.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ void SILGenFunction::emitExpectedExecutorProlog() {
136136
// Defer bodies are always called synchronously within their enclosing
137137
// function, so the check is unnecessary; in addition, we cannot
138138
// necessarily perform the check because the defer may not have
139-
// captured the isolated parameter of the enclosing function.
139+
// captured the isolated parameter of the enclosing function, and
140+
// forcing a capture would cause DI problems in actor initializers.
140141
bool wantDataRaceChecks = [&] {
141142
if (F.isAsync() || F.isDefer())
142143
return false;

lib/Sema/TypeCheckCaptures.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,31 @@ class FindCapturedVars : public ASTWalker {
745745

746746
} // end anonymous namespace
747747

748+
/// Given that a local function is isolated to the given var, should we
749+
/// force a capture of the var?
750+
static bool shouldCaptureIsolationInLocalFunc(AbstractFunctionDecl *AFD,
751+
VarDecl *var) {
752+
assert(isa<ParamDecl>(var));
753+
754+
// Don't try to capture an isolated parameter of the function itself.
755+
if (var->getDeclContext() == AFD)
756+
return false;
757+
758+
// We only *need* to force a capture of the isolation in an async function
759+
// (in which case it's needed for executor switching) or if we're in the
760+
// mode that forces an executor check in all synchronous functions. But
761+
// it's a simpler rule if we just do it unconditionally.
762+
763+
// However, don't do it for the implicit functions that represent defer
764+
// bodies, where it is both unnecessary and likely to lead to bad diagnostics.
765+
// We already suppress the executor check in defer bodies.
766+
if (auto FD = dyn_cast<FuncDecl>(AFD))
767+
if (FD->isDeferBody())
768+
return false;
769+
770+
return true;
771+
}
772+
748773
CaptureInfo CaptureInfoRequest::evaluate(Evaluator &evaluator,
749774
AbstractFunctionDecl *AFD) const {
750775
auto type = AFD->getInterfaceType();
@@ -768,10 +793,7 @@ CaptureInfo CaptureInfoRequest::evaluate(Evaluator &evaluator,
768793
auto actorIsolation = getActorIsolation(AFD);
769794
if (actorIsolation.getKind() == ActorIsolation::ActorInstance) {
770795
if (auto *var = actorIsolation.getActorInstance()) {
771-
assert(isa<ParamDecl>(var));
772-
// Don't capture anything if the isolation parameter is a parameter
773-
// of the local function.
774-
if (var->getDeclContext() != AFD)
796+
if (shouldCaptureIsolationInLocalFunc(AFD, var))
775797
finder.addCapture(CapturedValue(var, 0, AFD->getLoc()));
776798
}
777799
}

test/SILGen/local_function_isolation.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ actor GenericActor<K> {
7171
// Make sure defer doesn't capture anything.
7272
actor DeferInsideInitActor {
7373
init(foo: ()) async throws {
74-
// CHECK-LABEL: sil private [ossa] @$s24local_function_isolation20DeferInsideInitActorC3fooACyt_tYaKcfc6$deferL_yyF : $@convention(thin) (@sil_isolated @guaranteed DeferInsideInitActor) -> () {
74+
// CHECK-LABEL: sil private [ossa] @$s24local_function_isolation20DeferInsideInitActorC3fooACyt_tYaKcfc6$deferL_yyF : $@convention(thin) () -> () {
7575
defer {}
7676
self.init()
7777
}

test/SILOptimizer/definite_init_actor.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
func neverReturn() -> Never { fatalError("quit!") }
1212
func arbitraryAsync() async {}
13+
func makeIntOrThrow() throws -> Int { return 0 }
1314

1415
actor BoringActor {
1516

@@ -402,3 +403,40 @@ actor Ahmad {
402403
// CHECK: } // end sil function '$s4test5AhmadCACyYacfc'
403404
nonisolated init() async {}
404405
}
406+
407+
// This should not complain about needing self in the defer prior to it being
408+
// fully initialized.
409+
actor Customer {
410+
var x: Int
411+
var y: Int
412+
413+
// CHECK-LABEL: sil hidden @$s4test8CustomerCACyYaKcfc :
414+
init() async throws {
415+
// CHECK: [[GENERIC:%[0-9]+]] = enum $Optional<Builtin.Executor>, #Optional.none!enumelt
416+
// CHECK-NEXT: hop_to_executor [[GENERIC]]
417+
// CHECK: [[SELF:%.*]] = end_init_let_ref %0 : $Customer
418+
419+
defer { print("I have a complaint") }
420+
421+
// CHECK: try_apply {{.*}}, error [[FAIL1:bb[0-9]+]]
422+
self.x = try makeIntOrThrow()
423+
424+
// CHECK: try_apply {{.*}}, error [[FAIL2:bb[0-9]+]]
425+
// CHECK: hop_to_executor [[SELF]] : $Customer
426+
self.y = try makeIntOrThrow()
427+
428+
// CHECK: [[DEFER:%.*]] = function_ref @$s4test8CustomerCACyYaKcfc6$deferL_yyF :
429+
// CHECK-NEXT: apply [[DEFER]]()
430+
// CHECK-NEXT: return [[SELF]] : $Customer
431+
432+
// CHECK: [[FAIL1]]({{%.*}} : $any Error):
433+
// CHECK-NEXT: // function_ref
434+
// CHECK-NEXT: [[DEFER:%.*]] = function_ref @$s4test8CustomerCACyYaKcfc6$deferL_yyF :
435+
// CHECK-NEXT: apply [[DEFER]]()
436+
437+
// CHECK: [[FAIL2]]({{%.*}} : $any Error):
438+
// CHECK-NEXT: // function_ref
439+
// CHECK-NEXT: [[DEFER:%.*]] = function_ref @$s4test8CustomerCACyYaKcfc6$deferL_yyF :
440+
// CHECK-NEXT: apply [[DEFER]]()
441+
}
442+
}

0 commit comments

Comments
 (0)