Skip to content

Commit 313a05d

Browse files
committed
nonisolated(unsafe) to opt out of strict concurrency static checking for global variables
1 parent e9b01a3 commit 313a05d

31 files changed

+208
-48
lines changed

include/swift/AST/ActorIsolation.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ class ActorIsolation {
6060
/// meaning that it can be used from any actor but is also unable to
6161
/// refer to the isolated state of any given actor.
6262
Nonisolated,
63+
/// The declaration is explicitly specified to be not isolated and with the
64+
/// "unsafe" annotation, which means that we do not enforce isolation.
65+
NonisolatedUnsafe,
6366
/// The declaration is isolated to a global actor. It can refer to other
6467
/// entities with the same global actor.
6568
GlobalActor,
@@ -97,8 +100,8 @@ class ActorIsolation {
97100
return ActorIsolation(Unspecified, nullptr);
98101
}
99102

100-
static ActorIsolation forNonisolated() {
101-
return ActorIsolation(Nonisolated, nullptr);
103+
static ActorIsolation forNonisolated(bool unsafe) {
104+
return ActorIsolation(unsafe ? NonisolatedUnsafe : Nonisolated, nullptr);
102105
}
103106

104107
static ActorIsolation forActorInstanceSelf(NominalTypeDecl *actor) {
@@ -124,8 +127,10 @@ class ActorIsolation {
124127
operator Kind() const { return getKind(); }
125128

126129
bool isUnspecified() const { return kind == Unspecified; }
127-
128-
bool isNonisolated() const { return kind == Nonisolated; }
130+
131+
bool isNonisolated() const {
132+
return (kind == Nonisolated) || (kind == NonisolatedUnsafe);
133+
}
129134

130135
/// Retrieve the parameter to which actor-instance isolation applies.
131136
///
@@ -144,6 +149,7 @@ class ActorIsolation {
144149

145150
case Unspecified:
146151
case Nonisolated:
152+
case NonisolatedUnsafe:
147153
return false;
148154
}
149155
}
@@ -192,6 +198,7 @@ class ActorIsolation {
192198

193199
switch (lhs.getKind()) {
194200
case Nonisolated:
201+
case NonisolatedUnsafe:
195202
case Unspecified:
196203
return true;
197204

include/swift/AST/Attr.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(async, Async,
498498
SIMPLE_DECL_ATTR(reasync, Reasync,
499499
OnFunc | OnConstructor | RejectByParser | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
500500
109)
501-
CONTEXTUAL_SIMPLE_DECL_ATTR(nonisolated, Nonisolated,
501+
CONTEXTUAL_DECL_ATTR(nonisolated, Nonisolated,
502502
DeclModifier | OnFunc | OnConstructor | OnVar | OnSubscript | ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
503503
112)
504504
CONTEXTUAL_SIMPLE_DECL_ATTR(distributed, DistributedActor,

include/swift/AST/Attr.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ class DeclAttribute : public AttributeBase {
183183
SWIFT_INLINE_BITFIELD(ObjCImplementationAttr, DeclAttribute, 1,
184184
isCategoryNameInvalid : 1
185185
);
186+
187+
SWIFT_INLINE_BITFIELD(NonisolatedAttr, DeclAttribute, 1,
188+
isUnsafe : 1
189+
);
186190
} Bits;
187191
// clang-format on
188192

@@ -2404,6 +2408,26 @@ class ObjCImplementationAttr final : public DeclAttribute {
24042408
}
24052409
};
24062410

2411+
/// Represents nonisolated modifier.
2412+
class NonisolatedAttr final : public DeclAttribute {
2413+
public:
2414+
NonisolatedAttr(SourceLoc atLoc, SourceRange range, bool unsafe,
2415+
bool implicit)
2416+
: DeclAttribute(DAK_Nonisolated, atLoc, range, implicit) {
2417+
Bits.NonisolatedAttr.isUnsafe = unsafe;
2418+
assert((isUnsafe() == unsafe) && "not enough bits for unsafe state");
2419+
}
2420+
2421+
NonisolatedAttr(bool unsafe, bool implicit)
2422+
: NonisolatedAttr({}, {}, unsafe, implicit) {}
2423+
2424+
bool isUnsafe() const { return Bits.NonisolatedAttr.isUnsafe; }
2425+
2426+
static bool classof(const DeclAttribute *DA) {
2427+
return DA->getKind() == DAK_Nonisolated;
2428+
}
2429+
};
2430+
24072431
/// A macro role attribute, spelled with either @attached or @freestanding,
24082432
/// which declares one of the roles that a given macro can inhabit.
24092433
class MacroRoleAttr final

include/swift/AST/Decl.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6109,7 +6109,10 @@ class VarDecl : public AbstractStorageDecl {
61096109
/// True if this is a top-level global variable from the main source file.
61106110
bool isTopLevelGlobal() const { return Bits.VarDecl.IsTopLevelGlobal; }
61116111
void setTopLevelGlobal(bool b) { Bits.VarDecl.IsTopLevelGlobal = b; }
6112-
6112+
6113+
/// True if this is any storage of static duration (global scope or static).
6114+
bool isGlobalStorage() const;
6115+
61136116
/// Retrieve the custom attributes that attach property wrappers to this
61146117
/// property. The returned list contains all of the attached property wrapper
61156118
/// attributes in source order, which means the outermost wrapper attribute

lib/AST/ASTDumper.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,8 +1429,10 @@ namespace {
14291429
});
14301430
}
14311431

1432-
printFlag(D->getAttrs().hasAttribute<NonisolatedAttr>(), "nonisolated",
1433-
ExprModifierColor);
1432+
if (auto *attr = D->getAttrs().getAttribute<NonisolatedAttr>()) {
1433+
printFlag(attr->isUnsafe() ? "nonisolated(unsafe)" : "nonisolated",
1434+
ExprModifierColor);
1435+
}
14341436
printFlag(D->isDistributed(), "distributed", ExprModifierColor);
14351437
printFlag(D->isDistributedThunk(), "distributed_thunk",ExprModifierColor);
14361438
}
@@ -2702,6 +2704,7 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
27022704
switch (auto isolation = E->getActorIsolation()) {
27032705
case ActorIsolation::Unspecified:
27042706
case ActorIsolation::Nonisolated:
2707+
case ActorIsolation::NonisolatedUnsafe:
27052708
break;
27062709

27072710
case ActorIsolation::ActorInstance:

lib/AST/Attr.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,6 +1387,14 @@ bool DeclAttribute::printImpl(ASTPrinter &Printer, const PrintOptions &Options,
13871387
break;
13881388
}
13891389

1390+
case DAK_Nonisolated: {
1391+
Printer.printAttrName("nonisolated");
1392+
if (cast<NonisolatedAttr>(this)->isUnsafe()) {
1393+
Printer << "(unsafe)";
1394+
}
1395+
break;
1396+
}
1397+
13901398
case DAK_MacroRole: {
13911399
auto Attr = cast<MacroRoleAttr>(this);
13921400

@@ -1707,6 +1715,12 @@ StringRef DeclAttribute::getAttrName() const {
17071715
return "_section";
17081716
case DAK_Documentation:
17091717
return "_documentation";
1718+
case DAK_Nonisolated:
1719+
if (cast<NonisolatedAttr>(this)->isUnsafe()) {
1720+
return "nonisolated(unsafe)";
1721+
} else {
1722+
return "nonisolated";
1723+
}
17101724
case DAK_MacroRole:
17111725
switch (cast<MacroRoleAttr>(this)->getMacroSyntax()) {
17121726
case MacroSyntax::Freestanding:

lib/AST/Decl.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2402,6 +2402,7 @@ static bool deferMatchesEnclosingAccess(const FuncDecl *defer) {
24022402

24032403
switch (getActorIsolation(type)) {
24042404
case ActorIsolation::Unspecified:
2405+
case ActorIsolation::NonisolatedUnsafe:
24052406
case ActorIsolation::GlobalActorUnsafe:
24062407
break;
24072408

@@ -7832,6 +7833,14 @@ VarDecl *VarDecl::getLazyStorageProperty() const {
78327833
{});
78337834
}
78347835

7836+
bool VarDecl::isGlobalStorage() const {
7837+
if (!hasStorage()) {
7838+
return false;
7839+
}
7840+
return isStatic() || getDeclContext()->isModuleScopeContext() ||
7841+
(getDeclContext()->isTypeContext() && !isInstanceMember());
7842+
}
7843+
78357844
bool VarDecl::isPropertyMemberwiseInitializedWithWrappedType() const {
78367845
auto customAttrs = getAttachedPropertyWrappers();
78377846
if (customAttrs.empty())
@@ -10439,6 +10448,7 @@ bool VarDecl::isSelfParamCaptureIsolated() const {
1043910448
switch (auto isolation = closure->getActorIsolation()) {
1044010449
case ActorIsolation::Unspecified:
1044110450
case ActorIsolation::Nonisolated:
10451+
case ActorIsolation::NonisolatedUnsafe:
1044210452
case ActorIsolation::GlobalActor:
1044310453
case ActorIsolation::GlobalActorUnsafe:
1044410454
return false;
@@ -10492,7 +10502,7 @@ ActorIsolation swift::getActorIsolationOfContext(
1049210502
if (ctx.LangOpts.hasFeature(Feature::IsolatedDefaultValues) &&
1049310503
var->isInstanceMember() &&
1049410504
!var->getAttrs().hasAttribute<LazyAttr>()) {
10495-
return ActorIsolation::forNonisolated();
10505+
return ActorIsolation::forNonisolated(/*unsafe*/ false);
1049610506
}
1049710507

1049810508
return getActorIsolation(var);

lib/AST/DiagnosticEngine.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,8 +921,12 @@ static void formatDiagnosticArgument(StringRef Modifier,
921921
}
922922

923923
case ActorIsolation::Nonisolated:
924+
case ActorIsolation::NonisolatedUnsafe:
924925
case ActorIsolation::Unspecified:
925926
Out << "nonisolated";
927+
if (isolation == ActorIsolation::NonisolatedUnsafe) {
928+
Out << "(unsafe)";
929+
}
926930
break;
927931
}
928932
break;

lib/AST/TypeCheckRequests.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1739,7 +1739,11 @@ void swift::simple_display(
17391739
break;
17401740

17411741
case ActorIsolation::Nonisolated:
1742+
case ActorIsolation::NonisolatedUnsafe:
17421743
out << "nonisolated";
1744+
if (state == ActorIsolation::NonisolatedUnsafe) {
1745+
out << "(unsafe)";
1746+
}
17431747
break;
17441748

17451749
case ActorIsolation::Unspecified:

lib/ClangImporter/ImportDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7838,7 +7838,8 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) {
78387838
// Hard-code @actorIndependent, until Objective-C clients start
78397839
// using nonisolated.
78407840
if (swiftAttr->getAttribute() == "@actorIndependent") {
7841-
auto attr = new (SwiftContext) NonisolatedAttr(/*isImplicit=*/true);
7841+
auto attr = new (SwiftContext)
7842+
NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true);
78427843
MappedDecl->getAttrs().add(attr);
78437844
continue;
78447845
}

lib/ClangImporter/SwiftDeclSynthesizer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,8 @@ ValueDecl *SwiftDeclSynthesizer::createConstant(
422422

423423
// Mark the function transparent so that we inline it away completely.
424424
func->getAttrs().add(new (C) TransparentAttr(/*implicit*/ true));
425-
auto nonisolatedAttr = new (C) NonisolatedAttr(/*IsImplicit=*/true);
425+
auto nonisolatedAttr =
426+
new (C) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true);
426427
var->getAttrs().add(nonisolatedAttr);
427428

428429
// Set the function up as the getter.

lib/IDE/CompletionLookup.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,7 @@ void CompletionLookup::analyzeActorIsolation(
789789
}
790790
case ActorIsolation::Unspecified:
791791
case ActorIsolation::Nonisolated:
792+
case ActorIsolation::NonisolatedUnsafe:
792793
return;
793794
}
794795

lib/Parse/ParseDecl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3809,6 +3809,20 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
38093809
return makeParserSuccess();
38103810
break;
38113811
}
3812+
case DAK_Nonisolated: {
3813+
auto isUnsafe =
3814+
parseSingleAttrOption<bool>(*this, Loc, AttrRange, AttrName, DK,
3815+
{{Context.Id_unsafe, true}}, false);
3816+
if (!isUnsafe) {
3817+
return makeParserSuccess();
3818+
}
3819+
3820+
if (!DiscardAttribute) {
3821+
Attributes.add(new (Context) NonisolatedAttr(AtLoc, AttrRange, *isUnsafe,
3822+
/*implicit*/ false));
3823+
}
3824+
break;
3825+
}
38123826
case DAK_MacroRole: {
38133827
auto syntax = (AttrName == "freestanding" ? MacroSyntax::Freestanding
38143828
: MacroSyntax::Attached);

lib/SILGen/SILGenApply.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5515,6 +5515,7 @@ RValue SILGenFunction::emitApply(
55155515

55165516
case ActorIsolation::Unspecified:
55175517
case ActorIsolation::Nonisolated:
5518+
case ActorIsolation::NonisolatedUnsafe:
55185519
llvm_unreachable("Not isolated");
55195520
break;
55205521
}

lib/SILGen/SILGenConstructor.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,7 @@ static bool ctorHopsInjectedByDefiniteInit(ConstructorDecl *ctor,
610610

611611
case ActorIsolation::Unspecified:
612612
case ActorIsolation::Nonisolated:
613+
case ActorIsolation::NonisolatedUnsafe:
613614
case ActorIsolation::GlobalActor:
614615
case ActorIsolation::GlobalActorUnsafe:
615616
return false;
@@ -1554,6 +1555,7 @@ void SILGenFunction::emitMemberInitializer(DeclContext *dc, VarDecl *selfDecl,
15541555
// 'nonisolated' expressions can be evaluated from anywhere
15551556
case ActorIsolation::Unspecified:
15561557
case ActorIsolation::Nonisolated:
1558+
case ActorIsolation::NonisolatedUnsafe:
15571559
break;
15581560

15591561
case ActorIsolation::GlobalActor:

lib/SILGen/SILGenProlog.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,7 @@ void SILGenFunction::emitProlog(
12811281
return false;
12821282

12831283
case ActorIsolation::Nonisolated:
1284+
case ActorIsolation::NonisolatedUnsafe:
12841285
case ActorIsolation::Unspecified:
12851286
return false;
12861287
}
@@ -1332,6 +1333,7 @@ void SILGenFunction::emitProlog(
13321333
switch (actorIsolation.getKind()) {
13331334
case ActorIsolation::Unspecified:
13341335
case ActorIsolation::Nonisolated:
1336+
case ActorIsolation::NonisolatedUnsafe:
13351337
break;
13361338

13371339
case ActorIsolation::ActorInstance: {
@@ -1384,6 +1386,7 @@ void SILGenFunction::emitProlog(
13841386
switch (actorIsolation.getKind()) {
13851387
case ActorIsolation::Unspecified:
13861388
case ActorIsolation::Nonisolated:
1389+
case ActorIsolation::NonisolatedUnsafe:
13871390
break;
13881391

13891392
case ActorIsolation::ActorInstance: {
@@ -1572,6 +1575,7 @@ SILGenFunction::emitExecutor(SILLocation loc, ActorIsolation isolation,
15721575
switch (isolation.getKind()) {
15731576
case ActorIsolation::Unspecified:
15741577
case ActorIsolation::Nonisolated:
1578+
case ActorIsolation::NonisolatedUnsafe:
15751579
return llvm::None;
15761580

15771581
case ActorIsolation::ActorInstance: {
@@ -1597,8 +1601,9 @@ void SILGenFunction::emitHopToActorValue(SILLocation loc, ManagedValue actor) {
15971601
getActorIsolationOfContext(FunctionDC, [](AbstractClosureExpr *CE) {
15981602
return CE->getActorIsolation();
15991603
});
1600-
if (isolation != ActorIsolation::Nonisolated
1601-
&& isolation != ActorIsolation::Unspecified) {
1604+
if (isolation != ActorIsolation::Nonisolated &&
1605+
isolation != ActorIsolation::NonisolatedUnsafe &&
1606+
isolation != ActorIsolation::Unspecified) {
16021607
// TODO: Explicit hop with no hop-back should only be allowed in nonisolated
16031608
// async functions. But it needs work for any closure passed to
16041609
// Task.detached, which currently has unspecified isolation.

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,7 @@ void LifetimeChecker::injectActorHops() {
10461046

10471047
case ActorIsolation::Unspecified:
10481048
case ActorIsolation::Nonisolated:
1049+
case ActorIsolation::NonisolatedUnsafe:
10491050
case ActorIsolation::GlobalActorUnsafe:
10501051
case ActorIsolation::GlobalActor:
10511052
return;

lib/Sema/CodeSynthesis.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1621,7 +1621,8 @@ bool swift::addNonIsolatedToSynthesized(NominalTypeDecl *nominal,
16211621
return false;
16221622

16231623
ASTContext &ctx = nominal->getASTContext();
1624-
value->getAttrs().add(new (ctx) NonisolatedAttr(/*isImplicit=*/true));
1624+
value->getAttrs().add(
1625+
new (ctx) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true));
16251626
return true;
16261627
}
16271628

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ static VarDecl *addImplicitDistributedActorIDProperty(
108108

109109
// mark as nonisolated, allowing access to it from everywhere
110110
propDecl->getAttrs().add(
111-
new (C) NonisolatedAttr(/*IsImplicit=*/true));
111+
new (C) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true));
112112
// mark as @_compilerInitialized, since we synthesize the initializing
113113
// assignment during SILGen.
114114
propDecl->getAttrs().add(
@@ -158,7 +158,7 @@ static VarDecl *addImplicitDistributedActorActorSystemProperty(
158158

159159
// mark as nonisolated, allowing access to it from everywhere
160160
propDecl->getAttrs().add(
161-
new (C) NonisolatedAttr(/*IsImplicit=*/true));
161+
new (C) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true));
162162

163163
auto idProperty = nominal->getDistributedActorIDProperty();
164164
// If the id was not yet synthesized, we need to ensure that eventually
@@ -734,7 +734,8 @@ static FuncDecl *createDistributedThunkFunction(FuncDecl *func) {
734734

735735
thunk->setSynthesized(true);
736736
thunk->setDistributedThunk(true);
737-
thunk->getAttrs().add(new (C) NonisolatedAttr(/*isImplicit=*/true));
737+
thunk->getAttrs().add(
738+
new (C) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true));
738739

739740
if (isa<ClassDecl>(DC))
740741
thunk->getAttrs().add(new (C) FinalAttr(/*isImplicit=*/true));

lib/Sema/DerivedConformanceActor.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ static ValueDecl *deriveActor_unownedExecutor(DerivedConformance &derived) {
147147
property->getAttrs().add(new (ctx) SemanticsAttr(SEMANTICS_DEFAULT_ACTOR,
148148
SourceLoc(), SourceRange(),
149149
/*implicit*/ true));
150-
property->getAttrs().add(new (ctx) NonisolatedAttr(/*IsImplicit=*/true));
150+
property->getAttrs().add(
151+
new (ctx) NonisolatedAttr(/*unsafe=*/false, /*implicit=*/true));
151152

152153
// Make the property implicitly final.
153154
property->getAttrs().add(new (ctx) FinalAttr(/*IsImplicit=*/true));

0 commit comments

Comments
 (0)