Skip to content

Commit 093a6dd

Browse files
authored
Merge pull request #36266 from DougGregor/global-actor-unsafe
Enforce safe access to unsafe global actor declarations only from "new" code
2 parents 864d159 + 1de83ac commit 093a6dd

File tree

11 files changed

+173
-52
lines changed

11 files changed

+173
-52
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ class ActorIsolation {
5656
/// The declaration is isolated to a global actor. It can refer to other
5757
/// entities with the same global actor.
5858
GlobalActor,
59+
/// The declaration is isolated to a global actor but with the "unsafe"
60+
/// annotation, which means that we only enforce the isolation if we're
61+
/// coming from something with specific isolation.
62+
GlobalActorUnsafe,
5963
};
6064

6165
private:
@@ -93,8 +97,9 @@ class ActorIsolation {
9397
return ActorIsolation(ActorInstance, actor);
9498
}
9599

96-
static ActorIsolation forGlobalActor(Type globalActor) {
97-
return ActorIsolation(GlobalActor, globalActor);
100+
static ActorIsolation forGlobalActor(Type globalActor, bool unsafe) {
101+
return ActorIsolation(
102+
unsafe ? GlobalActorUnsafe : GlobalActor, globalActor);
98103
}
99104

100105
Kind getKind() const { return kind; }
@@ -108,8 +113,12 @@ class ActorIsolation {
108113
return actor;
109114
}
110115

116+
bool isGlobalActor() const {
117+
return getKind() == GlobalActor || getKind() == GlobalActorUnsafe;
118+
}
119+
111120
Type getGlobalActor() const {
112-
assert(getKind() == GlobalActor);
121+
assert(isGlobalActor());
113122
return globalActor;
114123
}
115124

@@ -135,6 +144,7 @@ class ActorIsolation {
135144
return lhs.actor == rhs.actor;
136145

137146
case GlobalActor:
147+
case GlobalActorUnsafe:
138148
return areTypesEqual(lhs.globalActor, rhs.globalActor);
139149
}
140150
}

lib/AST/Decl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8085,7 +8085,8 @@ ActorIsolation swift::getActorIsolationOfContext(DeclContext *dc) {
80858085
return ActorIsolation::forIndependent(ActorIndependentKind::Safe);
80868086

80878087
case ClosureActorIsolation::GlobalActor: {
8088-
return ActorIsolation::forGlobalActor(isolation.getGlobalActor());
8088+
return ActorIsolation::forGlobalActor(
8089+
isolation.getGlobalActor(), /*unsafe=*/false);
80898090
}
80908091

80918092
case ClosureActorIsolation::ActorInstance: {

lib/AST/DiagnosticEngine.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,7 @@ static void formatDiagnosticArgument(StringRef Modifier,
690690
break;
691691

692692
case ActorIsolation::GlobalActor:
693+
case ActorIsolation::GlobalActorUnsafe:
693694
Out << "global actor " << FormatOpts.OpeningQuotationMark
694695
<< isolation.getGlobalActor().getString()
695696
<< FormatOpts.ClosingQuotationMark << "-isolated";

lib/AST/TypeCheckRequests.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,7 @@ bool ActorIsolation::requiresSubstitution() const {
15191519
return false;
15201520

15211521
case GlobalActor:
1522+
case GlobalActorUnsafe:
15221523
return getGlobalActor()->hasTypeParameter();
15231524
}
15241525
llvm_unreachable("unhandled actor isolation kind!");
@@ -1533,7 +1534,9 @@ ActorIsolation ActorIsolation::subst(SubstitutionMap subs) const {
15331534
return *this;
15341535

15351536
case GlobalActor:
1536-
return forGlobalActor(getGlobalActor().subst(subs));
1537+
case GlobalActorUnsafe:
1538+
return forGlobalActor(
1539+
getGlobalActor().subst(subs), kind == GlobalActorUnsafe);
15371540
}
15381541
llvm_unreachable("unhandled actor isolation kind!");
15391542
}
@@ -1558,8 +1561,12 @@ void swift::simple_display(
15581561
break;
15591562

15601563
case ActorIsolation::GlobalActor:
1564+
case ActorIsolation::GlobalActorUnsafe:
15611565
out << "actor-isolated to global actor "
15621566
<< state.getGlobalActor().getString();
1567+
1568+
if (state == ActorIsolation::GlobalActorUnsafe)
1569+
out << "(unsafe)";
15631570
break;
15641571
}
15651572
}

lib/SILGen/SILGenApply.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4303,6 +4303,7 @@ Optional<SILValue> SILGenFunction::emitLoadActorExecutorForCallee(
43034303
}
43044304

43054305
case ActorIsolation::GlobalActor:
4306+
case ActorIsolation::GlobalActorUnsafe:
43064307
return emitLoadGlobalActorExecutor(actorIso.getGlobalActor());
43074308
}
43084309
}

lib/SILGen/SILGenProlog.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
472472
case ActorIsolation::Unspecified:
473473
case ActorIsolation::Independent:
474474
case ActorIsolation::IndependentUnsafe:
475+
case ActorIsolation::GlobalActorUnsafe:
475476
break;
476477

477478
case ActorIsolation::ActorInstance: {

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 98 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -554,12 +554,14 @@ ActorIsolationRestriction ActorIsolationRestriction::forDeclaration(
554554
return forActorSelf(isolation.getActor(),
555555
isAccessibleAcrossActors || isa<ConstructorDecl>(decl));
556556

557+
case ActorIsolation::GlobalActorUnsafe:
557558
case ActorIsolation::GlobalActor: {
558559
Type actorType = isolation.getGlobalActor();
559560
if (auto subs = declRef.getSubstitutions())
560561
actorType = actorType.subst(subs);
561562

562-
return forGlobalActor(actorType, isAccessibleAcrossActors);
563+
return forGlobalActor(actorType, isAccessibleAcrossActors,
564+
isolation == ActorIsolation::GlobalActorUnsafe);
563565
}
564566

565567
case ActorIsolation::Independent:
@@ -1293,7 +1295,14 @@ namespace {
12931295
case ActorIsolationRestriction::Unrestricted:
12941296
case ActorIsolationRestriction::Unsafe:
12951297
break;
1296-
case ActorIsolationRestriction::CrossGlobalActor:
1298+
case ActorIsolationRestriction::GlobalActorUnsafe:
1299+
// If we're not supposed to diagnose existing data races here,
1300+
// we're done.
1301+
if (!shouldDiagnoseExistingDataRaces(getDeclContext()))
1302+
break;
1303+
1304+
LLVM_FALLTHROUGH;
1305+
12971306
case ActorIsolationRestriction::GlobalActor: {
12981307
ctx.Diags.diagnose(argLoc, diag::actor_isolated_inout_state,
12991308
decl->getDescriptiveKind(), decl->getName(),
@@ -1361,8 +1370,10 @@ namespace {
13611370
return isolation;
13621371

13631372
case ActorIsolation::GlobalActor:
1373+
case ActorIsolation::GlobalActorUnsafe:
13641374
return ActorIsolation::forGlobalActor(
1365-
constDC->mapTypeIntoContext(isolation.getGlobalActor()));
1375+
constDC->mapTypeIntoContext(isolation.getGlobalActor()),
1376+
isolation == ActorIsolation::GlobalActorUnsafe);
13661377
}
13671378
};
13681379

@@ -1467,7 +1478,8 @@ namespace {
14671478
// Check whether we are within the same isolation context, in which
14681479
// case there is nothing further to check,
14691480
auto contextIsolation = getInnermostIsolatedContext(declContext);
1470-
if (contextIsolation == ActorIsolation::forGlobalActor(globalActor)) {
1481+
if (contextIsolation.isGlobalActor() &&
1482+
contextIsolation.getGlobalActor()->isEqual(globalActor)) {
14711483
return false;
14721484
}
14731485

@@ -1490,7 +1502,8 @@ namespace {
14901502
noteIsolatedActorMember(value);
14911503
return true;
14921504

1493-
case ActorIsolation::GlobalActor: {
1505+
case ActorIsolation::GlobalActor:
1506+
case ActorIsolation::GlobalActorUnsafe: {
14941507
// Check if this decl reference is the callee of the enclosing Apply,
14951508
// making it OK as an implicitly async call.
14961509
if (inspectForImplicitlyAsync())
@@ -1675,11 +1688,16 @@ namespace {
16751688
case ActorIsolationRestriction::ActorSelf:
16761689
llvm_unreachable("non-member reference into an actor");
16771690

1678-
case ActorIsolationRestriction::CrossGlobalActor:
1691+
case ActorIsolationRestriction::GlobalActorUnsafe:
1692+
// Only complain if we're in code that's adopted concurrency features.
1693+
if (!shouldDiagnoseExistingDataRaces(getDeclContext()))
1694+
return false;
1695+
1696+
LLVM_FALLTHROUGH;
1697+
16791698
case ActorIsolationRestriction::GlobalActor:
16801699
return checkGlobalActorReference(
1681-
valueRef, loc, isolation.getGlobalActor(),
1682-
isolation == ActorIsolationRestriction::CrossGlobalActor);
1700+
valueRef, loc, isolation.getGlobalActor(), isolation.isCrossActor);
16831701

16841702
case ActorIsolationRestriction::Unsafe:
16851703
return diagnoseReferenceToUnsafeGlobal(value, loc);
@@ -1829,6 +1847,7 @@ namespace {
18291847
}
18301848

18311849
case ActorIsolation::GlobalActor:
1850+
case ActorIsolation::GlobalActorUnsafe:
18321851
// Check for implicit async.
18331852
if (auto result = checkImplicitlyAsync())
18341853
return *result;
@@ -1846,11 +1865,17 @@ namespace {
18461865
llvm_unreachable("Unhandled actor isolation");
18471866
}
18481867

1849-
case ActorIsolationRestriction::CrossGlobalActor:
1868+
case ActorIsolationRestriction::GlobalActorUnsafe:
1869+
// Only complain if we're in code that's adopted concurrency features.
1870+
if (!shouldDiagnoseExistingDataRaces(getDeclContext()))
1871+
return false;
1872+
1873+
LLVM_FALLTHROUGH;
1874+
18501875
case ActorIsolationRestriction::GlobalActor:
18511876
return checkGlobalActorReference(
18521877
memberRef, memberLoc, isolation.getGlobalActor(),
1853-
isolation == ActorIsolationRestriction::CrossGlobalActor);
1878+
isolation.isCrossActor);
18541879

18551880
case ActorIsolationRestriction::Unsafe:
18561881
// This case is hit when passing actor state inout to functions in some
@@ -1880,7 +1905,8 @@ namespace {
18801905
case ActorIsolation::Unspecified:
18811906
return ClosureActorIsolation::forIndependent();
18821907

1883-
case ActorIsolation::GlobalActor: {
1908+
case ActorIsolation::GlobalActor:
1909+
case ActorIsolation::GlobalActorUnsafe: {
18841910
Type globalActorType = closure->mapTypeIntoContext(
18851911
parentIsolation.getGlobalActor()->mapTypeOutOfContext());
18861912
return ClosureActorIsolation::forGlobalActor(globalActorType);
@@ -2036,14 +2062,8 @@ static Optional<ActorIsolation> getIsolationFromAttributes(
20362062
diag::global_actor_non_unsafe_init, globalActorType);
20372063
}
20382064

2039-
// TODO: Model as unsafe from the actor-isolation perspective, which
2040-
// disables all checking. We probably want to model this as a separate kind
2041-
// of actor isolation to emit warnings.
2042-
if (isUnsafe)
2043-
return ActorIsolation::forIndependent(ActorIndependentKind::Unsafe);
2044-
20452065
return ActorIsolation::forGlobalActor(
2046-
globalActorType->mapTypeOutOfContext());
2066+
globalActorType->mapTypeOutOfContext(), isUnsafe);
20472067
}
20482068

20492069
llvm_unreachable("Forgot about an attribute?");
@@ -2113,7 +2133,8 @@ static Optional<ActorIsolation> getIsolationFromWitnessedRequirements(
21132133
case ActorIsolation::Unspecified:
21142134
return true;
21152135

2116-
case ActorIsolation::GlobalActor: {
2136+
case ActorIsolation::GlobalActor:
2137+
case ActorIsolation::GlobalActorUnsafe: {
21172138
// Substitute into the global actor type.
21182139
auto conformance = std::get<0>(isolated);
21192140
auto requirementSubs = SubstitutionMap::getProtocolSubstitutions(
@@ -2124,7 +2145,8 @@ static Optional<ActorIsolation> getIsolationFromWitnessedRequirements(
21242145
return true;
21252146

21262147
// Update the global actor type, now that we've done this substitution.
2127-
std::get<1>(isolated) = ActorIsolation::forGlobalActor(globalActor);
2148+
std::get<1>(isolated) = ActorIsolation::forGlobalActor(
2149+
globalActor, isolation == ActorIsolation::GlobalActorUnsafe);
21282150
return false;
21292151
}
21302152
}
@@ -2188,6 +2210,10 @@ ActorIsolation ActorIsolationRequest::evaluate(
21882210
ActorIndependentKind::Safe, /*IsImplicit=*/true));
21892211
break;
21902212

2213+
case ActorIsolation::GlobalActorUnsafe:
2214+
// Don't infer unsafe global actor isolation.
2215+
return ActorIsolation::forUnspecified();
2216+
21912217
case ActorIsolation::GlobalActor: {
21922218
auto typeExpr = TypeExpr::createImplicit(inferred.getGlobalActor(), ctx);
21932219
auto attr = CustomAttr::create(
@@ -2315,15 +2341,65 @@ void swift::checkOverrideActorIsolation(ValueDecl *value) {
23152341
// If the overridden declaration is @actorIndependent(unsafe) and the
23162342
// overriding declaration has been placed in a global actor, allow it.
23172343
if (overriddenIsolation.getKind() == ActorIsolation::IndependentUnsafe &&
2318-
isolation.getKind() == ActorIsolation::GlobalActor)
2344+
isolation.isGlobalActor())
23192345
return;
23202346

23212347
// If the overridden declaration is from Objective-C with no actor annotation,
23222348
// and the overriding declaration has been placed in a global actor, allow it.
23232349
if (overridden->hasClangNode() && !overriddenIsolation &&
2324-
isolation.getKind() == ActorIsolation::GlobalActor)
2350+
isolation.isGlobalActor())
23252351
return;
23262352

2353+
// If the overridden declaration uses an unsafe global actor, we can do
2354+
// anything except be actor-isolated or have a different global actor.
2355+
if (overriddenIsolation == ActorIsolation::GlobalActorUnsafe) {
2356+
switch (isolation) {
2357+
case ActorIsolation::Independent:
2358+
case ActorIsolation::IndependentUnsafe:
2359+
case ActorIsolation::Unspecified:
2360+
return;
2361+
2362+
case ActorIsolation::ActorInstance:
2363+
// Diagnose below.
2364+
break;
2365+
2366+
case ActorIsolation::GlobalActor:
2367+
case ActorIsolation::GlobalActorUnsafe:
2368+
// The global actors don't match; diagnose it.
2369+
if (overriddenIsolation.getGlobalActor()->isEqual(
2370+
isolation.getGlobalActor()))
2371+
return;
2372+
2373+
// Diagnose below.
2374+
break;
2375+
}
2376+
}
2377+
2378+
// If the overriding declaration uses an unsafe global actor, we can do
2379+
// anything that doesn't actively conflict with the overridden isolation.
2380+
if (isolation == ActorIsolation::GlobalActorUnsafe) {
2381+
switch (overriddenIsolation) {
2382+
case ActorIsolation::Unspecified:
2383+
return;
2384+
2385+
case ActorIsolation::ActorInstance:
2386+
case ActorIsolation::Independent:
2387+
case ActorIsolation::IndependentUnsafe:
2388+
// Diagnose below.
2389+
break;
2390+
2391+
case ActorIsolation::GlobalActor:
2392+
case ActorIsolation::GlobalActorUnsafe:
2393+
// The global actors don't match; diagnose it.
2394+
if (overriddenIsolation.getGlobalActor()->isEqual(
2395+
isolation.getGlobalActor()))
2396+
return;
2397+
2398+
// Diagnose below.
2399+
break;
2400+
}
2401+
}
2402+
23272403
// Isolation mismatch. Diagnose it.
23282404
value->diagnose(
23292405
diag::actor_isolation_override_mismatch, isolation,

0 commit comments

Comments
 (0)