mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Don't force a capture of an isolated parameter in defer bodies.
SILGen already has an exception for this from -enable-actor-data-race-checks, so there's no need for it, and it causes problems in actor inits. Fixes rdar://155239032
This commit is contained in:
@@ -136,7 +136,8 @@ void SILGenFunction::emitExpectedExecutorProlog() {
|
|||||||
// Defer bodies are always called synchronously within their enclosing
|
// Defer bodies are always called synchronously within their enclosing
|
||||||
// function, so the check is unnecessary; in addition, we cannot
|
// function, so the check is unnecessary; in addition, we cannot
|
||||||
// necessarily perform the check because the defer may not have
|
// necessarily perform the check because the defer may not have
|
||||||
// captured the isolated parameter of the enclosing function.
|
// captured the isolated parameter of the enclosing function, and
|
||||||
|
// forcing a capture would cause DI problems in actor initializers.
|
||||||
bool wantDataRaceChecks = [&] {
|
bool wantDataRaceChecks = [&] {
|
||||||
if (F.isAsync() || F.isDefer())
|
if (F.isAsync() || F.isDefer())
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -744,6 +744,31 @@ public:
|
|||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
/// Given that a local function is isolated to the given var, should we
|
||||||
|
/// force a capture of the var?
|
||||||
|
static bool shouldCaptureIsolationInLocalFunc(AbstractFunctionDecl *AFD,
|
||||||
|
VarDecl *var) {
|
||||||
|
assert(isa<ParamDecl>(var));
|
||||||
|
|
||||||
|
// Don't try to capture an isolated parameter of the function itself.
|
||||||
|
if (var->getDeclContext() == AFD)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// We only *need* to force a capture of the isolation in an async function
|
||||||
|
// (in which case it's needed for executor switching) or if we're in the
|
||||||
|
// mode that forces an executor check in all synchronous functions. But
|
||||||
|
// it's a simpler rule if we just do it unconditionally.
|
||||||
|
|
||||||
|
// However, don't do it for the implicit functions that represent defer
|
||||||
|
// bodies, where it is both unnecessary and likely to lead to bad diagnostics.
|
||||||
|
// We already suppress the executor check in defer bodies.
|
||||||
|
if (auto FD = dyn_cast<FuncDecl>(AFD))
|
||||||
|
if (FD->isDeferBody())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
CaptureInfo CaptureInfoRequest::evaluate(Evaluator &evaluator,
|
CaptureInfo CaptureInfoRequest::evaluate(Evaluator &evaluator,
|
||||||
AbstractFunctionDecl *AFD) const {
|
AbstractFunctionDecl *AFD) const {
|
||||||
auto type = AFD->getInterfaceType();
|
auto type = AFD->getInterfaceType();
|
||||||
@@ -767,10 +792,7 @@ CaptureInfo CaptureInfoRequest::evaluate(Evaluator &evaluator,
|
|||||||
auto actorIsolation = getActorIsolation(AFD);
|
auto actorIsolation = getActorIsolation(AFD);
|
||||||
if (actorIsolation.getKind() == ActorIsolation::ActorInstance) {
|
if (actorIsolation.getKind() == ActorIsolation::ActorInstance) {
|
||||||
if (auto *var = actorIsolation.getActorInstance()) {
|
if (auto *var = actorIsolation.getActorInstance()) {
|
||||||
assert(isa<ParamDecl>(var));
|
if (shouldCaptureIsolationInLocalFunc(AFD, var))
|
||||||
// Don't capture anything if the isolation parameter is a parameter
|
|
||||||
// of the local function.
|
|
||||||
if (var->getDeclContext() != AFD)
|
|
||||||
finder.addCapture(CapturedValue(var, 0, AFD->getLoc()));
|
finder.addCapture(CapturedValue(var, 0, AFD->getLoc()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ actor GenericActor<K> {
|
|||||||
// Make sure defer doesn't capture anything.
|
// Make sure defer doesn't capture anything.
|
||||||
actor DeferInsideInitActor {
|
actor DeferInsideInitActor {
|
||||||
init(foo: ()) async throws {
|
init(foo: ()) async throws {
|
||||||
// CHECK-LABEL: sil private [ossa] @$s24local_function_isolation20DeferInsideInitActorC3fooACyt_tYaKcfc6$deferL_yyF : $@convention(thin) (@sil_isolated @guaranteed DeferInsideInitActor) -> () {
|
// CHECK-LABEL: sil private [ossa] @$s24local_function_isolation20DeferInsideInitActorC3fooACyt_tYaKcfc6$deferL_yyF : $@convention(thin) () -> () {
|
||||||
defer {}
|
defer {}
|
||||||
self.init()
|
self.init()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
func neverReturn() -> Never { fatalError("quit!") }
|
func neverReturn() -> Never { fatalError("quit!") }
|
||||||
func arbitraryAsync() async {}
|
func arbitraryAsync() async {}
|
||||||
|
func makeIntOrThrow() throws -> Int { return 0 }
|
||||||
|
|
||||||
actor BoringActor {
|
actor BoringActor {
|
||||||
|
|
||||||
@@ -402,3 +403,40 @@ actor Ahmad {
|
|||||||
// CHECK: } // end sil function '$s4test5AhmadCACyYacfc'
|
// CHECK: } // end sil function '$s4test5AhmadCACyYacfc'
|
||||||
nonisolated init() async {}
|
nonisolated init() async {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This should not complain about needing self in the defer prior to it being
|
||||||
|
// fully initialized.
|
||||||
|
actor Customer {
|
||||||
|
var x: Int
|
||||||
|
var y: Int
|
||||||
|
|
||||||
|
// CHECK-LABEL: sil hidden @$s4test8CustomerCACyYaKcfc :
|
||||||
|
init() async throws {
|
||||||
|
// CHECK: [[GENERIC:%[0-9]+]] = enum $Optional<Builtin.Executor>, #Optional.none!enumelt
|
||||||
|
// CHECK-NEXT: hop_to_executor [[GENERIC]]
|
||||||
|
// CHECK: [[SELF:%.*]] = end_init_let_ref %0 : $Customer
|
||||||
|
|
||||||
|
defer { print("I have a complaint") }
|
||||||
|
|
||||||
|
// CHECK: try_apply {{.*}}, error [[FAIL1:bb[0-9]+]]
|
||||||
|
self.x = try makeIntOrThrow()
|
||||||
|
|
||||||
|
// CHECK: try_apply {{.*}}, error [[FAIL2:bb[0-9]+]]
|
||||||
|
// CHECK: hop_to_executor [[SELF]] : $Customer
|
||||||
|
self.y = try makeIntOrThrow()
|
||||||
|
|
||||||
|
// CHECK: [[DEFER:%.*]] = function_ref @$s4test8CustomerCACyYaKcfc6$deferL_yyF :
|
||||||
|
// CHECK-NEXT: apply [[DEFER]]()
|
||||||
|
// CHECK-NEXT: return [[SELF]] : $Customer
|
||||||
|
|
||||||
|
// CHECK: [[FAIL1]]({{%.*}} : $any Error):
|
||||||
|
// CHECK-NEXT: // function_ref
|
||||||
|
// CHECK-NEXT: [[DEFER:%.*]] = function_ref @$s4test8CustomerCACyYaKcfc6$deferL_yyF :
|
||||||
|
// CHECK-NEXT: apply [[DEFER]]()
|
||||||
|
|
||||||
|
// CHECK: [[FAIL2]]({{%.*}} : $any Error):
|
||||||
|
// CHECK-NEXT: // function_ref
|
||||||
|
// CHECK-NEXT: [[DEFER:%.*]] = function_ref @$s4test8CustomerCACyYaKcfc6$deferL_yyF :
|
||||||
|
// CHECK-NEXT: apply [[DEFER]]()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user