Skip to content

Commit 51c1543

Browse files
authored
Merge pull request #72332 from hborla/isolated-default-value-crash
[Concurrency] Don't attempt to hop to executor inside default argument generators and stored property initializers.
2 parents 735e28b + 2260957 commit 51c1543

File tree

2 files changed

+56
-23
lines changed

2 files changed

+56
-23
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3045,35 +3045,47 @@ static void emitDelayedArguments(SILGenFunction &SGF,
30453045
done:
30463046

30473047
if (defaultArgIsolation) {
3048-
assert(SGF.F.isAsync());
30493048
assert(!isolatedArgs.empty());
30503049

3051-
auto &firstArg = *std::get<0>(isolatedArgs[0]);
3052-
auto loc = firstArg.getDefaultArgLoc();
3050+
// Only hop to the default arg isolation if the callee is async.
3051+
// If we're in a synchronous function, the isolation has to match,
3052+
// so no hop is required. This is enforced by the actor isolation
3053+
// checker.
3054+
//
3055+
// FIXME: Note that we don't end up in this situation for user-written
3056+
// synchronous functions, because the default argument is only considered
3057+
// isolated to the callee if the call crosses an isolation boundary. We
3058+
// do end up here for default argument generators and stored property
3059+
// initializers. An alternative (and better) approach is to formally model
3060+
// those generator functions as isolated.
3061+
if (SGF.F.isAsync()) {
3062+
auto &firstArg = *std::get<0>(isolatedArgs[0]);
3063+
auto loc = firstArg.getDefaultArgLoc();
3064+
3065+
SILValue executor;
3066+
switch (*defaultArgIsolation) {
3067+
case ActorIsolation::GlobalActor:
3068+
executor = SGF.emitLoadGlobalActorExecutor(
3069+
defaultArgIsolation->getGlobalActor());
3070+
break;
30533071

3054-
SILValue executor;
3055-
switch (*defaultArgIsolation) {
3056-
case ActorIsolation::GlobalActor:
3057-
executor = SGF.emitLoadGlobalActorExecutor(
3058-
defaultArgIsolation->getGlobalActor());
3059-
break;
3072+
case ActorIsolation::ActorInstance:
3073+
llvm_unreachable("default arg cannot be actor instance isolated");
30603074

3061-
case ActorIsolation::ActorInstance:
3062-
llvm_unreachable("default arg cannot be actor instance isolated");
3075+
case ActorIsolation::Erased:
3076+
llvm_unreachable("default arg cannot have erased isolation");
30633077

3064-
case ActorIsolation::Erased:
3065-
llvm_unreachable("default arg cannot have erased isolation");
3078+
case ActorIsolation::Unspecified:
3079+
case ActorIsolation::Nonisolated:
3080+
case ActorIsolation::NonisolatedUnsafe:
3081+
llvm_unreachable("Not isolated");
3082+
}
30663083

3067-
case ActorIsolation::Unspecified:
3068-
case ActorIsolation::Nonisolated:
3069-
case ActorIsolation::NonisolatedUnsafe:
3070-
llvm_unreachable("Not isolated");
3084+
// Hop to the target isolation domain once to evaluate all
3085+
// default arguments.
3086+
SGF.emitHopToTargetExecutor(loc, executor);
30713087
}
30723088

3073-
// Hop to the target isolation domain once to evaluate all
3074-
// default arguments.
3075-
SGF.emitHopToTargetExecutor(loc, executor);
3076-
30773089
size_t argsEmitted = 0;
30783090
for (auto &isolatedArg : isolatedArgs) {
30793091
auto &delayedArg = *std::get<0>(isolatedArg);

test/Concurrency/isolated_default_argument_eval.swift

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@
66
@MainActor
77
func requiresMainActor() -> Int { 0 }
88

9+
// CHECK-LABEL: sil hidden [ossa] @$s30isolated_default_argument_eval19mainActorDefaultArg5valueS2i_tFfA_
10+
@discardableResult
911
@MainActor
10-
func mainActorDefaultArg(value: Int = requiresMainActor()) {}
12+
func mainActorDefaultArg(value: Int = requiresMainActor()) -> Int {
13+
value
14+
}
1115

1216
@MainActor
1317
func mainActorMultiDefaultArg(x: Int = requiresMainActor(),
@@ -25,7 +29,7 @@ func mainActorMultiDefaultArg(x: Int = requiresMainActor(),
2529
func nonisolatedAsyncCaller() async {
2630
// CHECK: hop_to_executor {{.*}} : $Optional<Builtin.Executor>
2731
// CHECK: hop_to_executor {{.*}} : $MainActor
28-
// CHECK: [[GET_VALUE:%[0-9]+]] = function_ref @$s30isolated_default_argument_eval19mainActorDefaultArg5valueySi_tFfA_
32+
// CHECK: [[GET_VALUE:%[0-9]+]] = function_ref @$s30isolated_default_argument_eval19mainActorDefaultArg5valueS2i_tFfA_
2933
// CHECK-NEXT: apply [[GET_VALUE]]()
3034
// CHECK: hop_to_executor {{.*}} : $Optional<Builtin.Executor>
3135
await mainActorDefaultArg()
@@ -68,3 +72,20 @@ func passInoutWithDefault() async {
6872
// CHECK: hop_to_executor {{.*}} : $Optional<Builtin.Executor>
6973
await isolatedDefaultInoutMix(x: &x, y: argValue)
7074
}
75+
76+
// default argument 0 of noSuspensionInDefaultArgGenerator(_:)
77+
// CHECK-LABEL: sil hidden [ossa] @$s30isolated_default_argument_eval33noSuspensionInDefaultArgGeneratoryySiFfA_
78+
// CHECK: [[NESTED_DEFAULT_REF:%[0-9]+]] = function_ref @$s30isolated_default_argument_eval19mainActorDefaultArg5valueS2i_tFfA_ : $@convention(thin) () -> Int
79+
// CHECK-NEXT: [[NESTED_DEFAULT:%[0-9]+]] = apply [[NESTED_DEFAULT_REF]]() : $@convention(thin) () -> Int
80+
// CHECK: [[DEFAULT_REF:%[0-9]+]] = function_ref @$s30isolated_default_argument_eval19mainActorDefaultArg5valueS2i_tF : $@convention(thin) (Int) -> Int
81+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[DEFAULT_REF]]([[NESTED_DEFAULT]]) : $@convention(thin) (Int) -> Int
82+
// CHECK-NEXT: return [[RESULT]] : $Int
83+
84+
// CHECK-LABEL: sil hidden [ossa] @$s30isolated_default_argument_eval33noSuspensionInDefaultArgGeneratoryySiF
85+
@MainActor func noSuspensionInDefaultArgGenerator(
86+
_ x: Int = mainActorDefaultArg()
87+
) {}
88+
89+
func testNoSuspensionInDefaultArgGenerator() async {
90+
await noSuspensionInDefaultArgGenerator()
91+
}

0 commit comments

Comments
 (0)