Skip to content

Commit 4d0b624

Browse files
Make deinit non-isolated by default
Failing: Distributed/Runtime/distributed_actor_deinit.swift
1 parent 9dcea15 commit 4d0b624

18 files changed

+814
-299
lines changed

include/swift/AST/DeclAttr.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,9 @@ SIMPLE_DECL_ATTR(rethrows, Rethrows,
434434
CONTEXTUAL_SIMPLE_DECL_ATTR(indirect, Indirect,
435435
DeclModifier | OnEnum | OnEnumElement | ABIBreakingToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
436436
60)
437+
CONTEXTUAL_SIMPLE_DECL_ATTR(isolated, Isolated,
438+
DeclModifier | OnDestructor | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
439+
103)
437440
CONTEXTUAL_SIMPLE_DECL_ATTR(async, Async,
438441
DeclModifier | OnVar | OnFunc | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
439442
106)

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5903,9 +5903,12 @@ ERROR(global_actor_not_usable_from_inline,none,
59035903
NOTE(move_global_actor_attr_to_storage_decl,none,
59045904
"move global actor attribute to %kind0", (const ValueDecl *))
59055905

5906-
ERROR(actor_isolation_multiple_attr,none,
5906+
ERROR(actor_isolation_multiple_attr_2,none,
59075907
"%kind0 has multiple actor-isolation attributes ('%1' and '%2')",
59085908
(const Decl *, StringRef, StringRef))
5909+
ERROR(actor_isolation_multiple_attr_3,none,
5910+
"%0 %1 has multiple actor-isolation attributes ('%2', '%3' and '%4')",
5911+
(const Decl *, StringRef, StringRef, StringRef))
59095912
ERROR(actor_isolation_override_mismatch,none,
59105913
"%0 %kind1 has different actor isolation from %2 overridden declaration",
59115914
(ActorIsolation, const ValueDecl *, ActorIsolation))
@@ -5922,6 +5925,11 @@ ERROR(async_named_decl_must_be_available_from_async,none,
59225925
ERROR(async_unavailable_decl,none,
59235926
"%kindbase0 is unavailable from asynchronous contexts%select{|; %1}1",
59245927
(const ValueDecl *, StringRef))
5928+
5929+
5930+
ERROR(isolated_deinit_no_isolation,none,
5931+
"deinit is marked isolated, but containing class %0 is not isolated to an actor",
5932+
(DeclName))
59255933

59265934
//------------------------------------------------------------------------------
59275935
// MARK: String Processing

lib/ASTGen/Sources/ASTGen/DeclAttrs.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ extension ASTGenVisitor {
221221
.inheritActorContext,
222222
.inheritsConvenienceInitializers,
223223
.inlinable,
224+
.isolated,
224225
.lexicalLifetimes,
225226
.lldbDebuggerFunction,
226227
.marker,

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
129129
IGNORED_ATTR(HasMissingDesignatedInitializers)
130130
IGNORED_ATTR(InheritsConvenienceInitializers)
131131
IGNORED_ATTR(Inline)
132+
IGNORED_ATTR(Isolated)
132133
IGNORED_ATTR(ObjCBridged)
133134
IGNORED_ATTR(ObjCNonLazyRealization)
134135
IGNORED_ATTR(ObjCRuntimeName)

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 136 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333

3434
using namespace swift;
3535

36+
static ActorIsolation getOverriddenIsolationFor(const ValueDecl *value);
37+
3638
/// Determine whether it makes sense to infer an attribute in the given
3739
/// context.
3840
static bool shouldInferAttributeInContext(const DeclContext *dc) {
@@ -1663,32 +1665,42 @@ static bool wasLegacyEscapingUseRestriction(AbstractFunctionDecl *fn) {
16631665
assert(fn->getDeclContext()->getSelfClassDecl()->isAnyActor());
16641666
assert(isa<ConstructorDecl>(fn) || isa<DestructorDecl>(fn));
16651667

1666-
// according to today's isolation, determine whether it use to have the
1667-
// escaping-use restriction
1668-
switch (getActorIsolation(fn).getKind()) {
1668+
auto isolationKind = getActorIsolation(fn).getKind();
1669+
if (isa<DestructorDecl>(fn)) {
1670+
switch (isolationKind) {
1671+
case ActorIsolation::GlobalActor:
1672+
case ActorIsolation::ActorInstance:
1673+
// Isolated deinits did not exist before
1674+
return false;
1675+
case ActorIsolation::Nonisolated:
1676+
case ActorIsolation::NonisolatedUnsafe:
1677+
case ActorIsolation::Unspecified:
1678+
assert(!fn->hasAsync());
1679+
return true;
1680+
case ActorIsolation::Erased:
1681+
llvm_unreachable("destructor decl cannot have erased isolation");
1682+
}
1683+
} else if (auto *ctor = dyn_cast<ConstructorDecl>(fn)) {
1684+
switch (isolationKind) {
16691685
case ActorIsolation::Nonisolated:
16701686
case ActorIsolation::NonisolatedUnsafe:
16711687
case ActorIsolation::GlobalActor:
16721688
// convenience inits did not have the restriction.
1673-
if (auto *ctor = dyn_cast<ConstructorDecl>(fn))
1674-
if (ctor->isConvenienceInit())
1675-
return false;
1676-
1677-
break; // goto basic case
1678-
1689+
if (ctor->isConvenienceInit())
1690+
return false;
1691+
break;
16791692
case ActorIsolation::ActorInstance:
16801693
// none of these had the restriction affect them.
16811694
assert(fn->hasAsync());
16821695
return false;
1683-
16841696
case ActorIsolation::Erased:
16851697
llvm_unreachable("function decl cannot have erased isolation");
16861698

16871699
case ActorIsolation::Unspecified:
16881700
// this is basically just objc-marked inits.
16891701
break;
1690-
};
1691-
1702+
}
1703+
}
16921704
return !(fn->hasAsync()); // basic case: not async = had restriction.
16931705
}
16941706

@@ -4388,30 +4400,64 @@ getIsolationFromAttributes(const Decl *decl, bool shouldDiagnose = true,
43884400
bool onlyExplicit = false) {
43894401
// Look up attributes on the declaration that can affect its actor isolation.
43904402
// If any of them are present, use that attribute.
4403+
auto isolatedAttr = decl->getAttrs().getAttribute<IsolatedAttr>();
43914404
auto nonisolatedAttr = decl->getAttrs().getAttribute<NonisolatedAttr>();
43924405
auto globalActorAttr = decl->getGlobalActorAttr();
43934406

43944407
// Remove implicit attributes if we only care about explicit ones.
43954408
if (onlyExplicit) {
43964409
if (nonisolatedAttr && nonisolatedAttr->isImplicit())
43974410
nonisolatedAttr = nullptr;
4411+
if (isolatedAttr && isolatedAttr->isImplicit())
4412+
isolatedAttr = nullptr;
43984413
if (globalActorAttr && globalActorAttr->first->isImplicit())
43994414
globalActorAttr = std::nullopt;
44004415
}
44014416

4402-
unsigned numIsolationAttrs =
4403-
(nonisolatedAttr ? 1 : 0) + (globalActorAttr ? 1 : 0);
4404-
if (numIsolationAttrs == 0)
4417+
unsigned numIsolationAttrs = (isolatedAttr ? 1 : 0) +
4418+
(nonisolatedAttr ? 1 : 0) +
4419+
(globalActorAttr ? 1 : 0);
4420+
if (numIsolationAttrs == 0) {
4421+
if (isa<DestructorDecl>(decl) && !decl->isImplicit()) {
4422+
return ActorIsolation::forNonisolated(false);
4423+
}
44054424
return std::nullopt;
4425+
}
44064426

44074427
// Only one such attribute is valid, but we only actually care of one of
44084428
// them is a global actor.
44094429
if (numIsolationAttrs > 1 && globalActorAttr && shouldDiagnose) {
4410-
decl->diagnose(diag::actor_isolation_multiple_attr, decl,
4411-
nonisolatedAttr->getAttrName(),
4412-
globalActorAttr->second->getName().str())
4413-
.highlight(nonisolatedAttr->getRangeWithAt())
4414-
.highlight(globalActorAttr->first->getRangeWithAt());
4430+
struct NameAndRange {
4431+
StringRef name;
4432+
SourceRange range;
4433+
};
4434+
4435+
llvm::SmallVector<NameAndRange, 3> attributes;
4436+
if (isolatedAttr) {
4437+
attributes.push_back({.name = isolatedAttr->getAttrName(),
4438+
.range = isolatedAttr->getRangeWithAt()});
4439+
}
4440+
if (nonisolatedAttr) {
4441+
attributes.push_back({.name = nonisolatedAttr->getAttrName(),
4442+
.range = nonisolatedAttr->getRangeWithAt()});
4443+
}
4444+
if (globalActorAttr) {
4445+
attributes.push_back({.name = globalActorAttr->second->getName().str(),
4446+
.range = globalActorAttr->first->getRangeWithAt()});
4447+
}
4448+
if (attributes.size() == 3) {
4449+
decl->diagnose(diag::actor_isolation_multiple_attr_3, decl,
4450+
attributes[0].name, attributes[1].name, attributes[2].name)
4451+
.highlight(attributes[0].range)
4452+
.highlight(attributes[1].range)
4453+
.highlight(attributes[2].range);
4454+
} else {
4455+
assert(attributes.size() == 2);
4456+
decl->diagnose(diag::actor_isolation_multiple_attr_2, decl,
4457+
attributes[0].name, attributes[1].name)
4458+
.highlight(attributes[0].range)
4459+
.highlight(attributes[1].range);
4460+
}
44154461
}
44164462

44174463
// If the declaration is explicitly marked 'nonisolated', report it as
@@ -4420,6 +4466,54 @@ getIsolationFromAttributes(const Decl *decl, bool shouldDiagnose = true,
44204466
return ActorIsolation::forNonisolated(nonisolatedAttr->isUnsafe());
44214467
}
44224468

4469+
// If the declaration is explicitly marked 'isolated', infer actor isolation
4470+
// from the context. Currently applies only to DestructorDecl
4471+
if (isolatedAttr) {
4472+
assert(isa<DestructorDecl>(decl));
4473+
4474+
auto dc = decl->getDeclContext();
4475+
auto selfTypeDecl = dc->getSelfNominalTypeDecl();
4476+
std::optional<ActorIsolation> result;
4477+
if (selfTypeDecl) {
4478+
if (selfTypeDecl->isAnyActor()) {
4479+
result = ActorIsolation::forActorInstanceSelf(selfTypeDecl);
4480+
} else {
4481+
// If the declaration is in an extension that has one of the isolation
4482+
// attributes, use that.
4483+
if (auto ext = dyn_cast<ExtensionDecl>(dc)) {
4484+
result = getIsolationFromAttributes(ext);
4485+
}
4486+
4487+
if (!result) {
4488+
result = getActorIsolation(selfTypeDecl);
4489+
}
4490+
}
4491+
4492+
if (!result || !result->isActorIsolated()) {
4493+
if (shouldDiagnose) {
4494+
ASTContext &ctx = decl->getASTContext();
4495+
ctx.Diags.diagnose(isolatedAttr->getLocation(),
4496+
diag::isolated_deinit_no_isolation,
4497+
selfTypeDecl->getName());
4498+
}
4499+
// Try to use isolation of the overridden decl as a recovery strategy.
4500+
// This prevents additions errors about mismatched isolation.
4501+
if (auto value = dyn_cast<ValueDecl>(decl)) {
4502+
ValueDecl *overriddenValue = value->getOverriddenDeclOrSuperDeinit();
4503+
if (overriddenValue) {
4504+
// use the overridden decl's iso as the default isolation for this
4505+
// decl.
4506+
auto overriddenIsolation = getOverriddenIsolationFor(value);
4507+
if (overriddenIsolation.isActorIsolated()) {
4508+
result = overriddenIsolation;
4509+
}
4510+
}
4511+
}
4512+
}
4513+
}
4514+
return result;
4515+
}
4516+
44234517
// If the declaration is marked with a global actor, report it as being
44244518
// part of that global actor.
44254519
if (globalActorAttr) {
@@ -4747,9 +4841,15 @@ getMemberIsolationPropagation(const ValueDecl *value) {
47474841
return MemberIsolationPropagation::GlobalActor;
47484842

47494843
case DeclKind::Constructor:
4750-
case DeclKind::Destructor:
47514844
return MemberIsolationPropagation::AnyIsolation;
47524845

4846+
case DeclKind::Destructor:
4847+
if (value->getAttrs().getAttribute<IsolatedAttr>()) {
4848+
return MemberIsolationPropagation::AnyIsolation;
4849+
} else {
4850+
return std::nullopt;
4851+
}
4852+
47534853
case DeclKind::Func:
47544854
case DeclKind::Accessor:
47554855
case DeclKind::Subscript:
@@ -4917,7 +5017,7 @@ namespace {
49175017

49185018
/// Return the isolation of the declaration overridden by this declaration,
49195019
/// in the context of the
4920-
static ActorIsolation getOverriddenIsolationFor(ValueDecl *value) {
5020+
static ActorIsolation getOverriddenIsolationFor(const ValueDecl *value) {
49215021
auto overridden = value->getOverriddenDeclOrSuperDeinit();
49225022
assert(overridden && "Doesn't have an overridden declaration");
49235023

@@ -5086,10 +5186,6 @@ static void addAttributesForActorIsolation(ValueDecl *value,
50865186
}
50875187
}
50885188

5089-
static bool isImplicitDeinit(ValueDecl *value) {
5090-
return isa<DestructorDecl>(value) && value->isImplicit();
5091-
}
5092-
50935189
ActorIsolation ActorIsolationRequest::evaluate(Evaluator &evaluator,
50945190
ValueDecl *value) const {
50955191
// If this declaration has actor-isolated "self", it's isolated to that
@@ -5098,16 +5194,6 @@ ActorIsolation ActorIsolationRequest::evaluate(Evaluator &evaluator,
50985194
auto actor = value->getDeclContext()->getSelfNominalTypeDecl();
50995195
assert(actor && "could not find the actor that 'self' is isolated to");
51005196

5101-
// Bootstrapping hack: force _Concurrency.MainActor.deinit() to be
5102-
// non-isolated even when importing from host SDK's swiftmodule without
5103-
// `nonisolated` attribute.
5104-
if (isa<DestructorDecl>(value) && actor->getName().is("MainActor") &&
5105-
actor->getDeclContext()->isModuleScopeContext() &&
5106-
actor->getDeclContext()->getParentModule()->getABIName().is("Swift")) {
5107-
auto isolation = ActorIsolation::forNonisolated(false);
5108-
addAttributesForActorIsolation(value, isolation);
5109-
return isolation;
5110-
}
51115197
return ActorIsolation::forActorInstanceSelf(value);
51125198
}
51135199

@@ -5444,12 +5530,7 @@ ActorIsolation ActorIsolationRequest::evaluate(Evaluator &evaluator,
54445530
// has isolation, use that.
54455531
if (auto selfTypeDecl = value->getDeclContext()->getSelfNominalTypeDecl()) {
54465532
if (auto selfTypeIsolation = getActorIsolation(selfTypeDecl)) {
5447-
if (isImplicitDeinit(value)) {
5448-
return inferredIsolation(ActorIsolation::forUnspecified(),
5449-
onlyGlobal);
5450-
} else {
5451-
return inferredIsolation(selfTypeIsolation, onlyGlobal);
5452-
}
5533+
return inferredIsolation(selfTypeIsolation, onlyGlobal);
54535534
}
54545535
}
54555536
}
@@ -5495,8 +5576,12 @@ bool HasIsolatedSelfRequest::evaluate(
54955576

54965577
// Check whether this member can be isolated to an actor at all.
54975578
auto memberIsolation = getMemberIsolationPropagation(value);
5498-
if (!memberIsolation)
5579+
if (!memberIsolation) {
5580+
// Actors don't have inheritance (except inheriting from NSObject),
5581+
// but if it were introduced, we would need to check for isolation
5582+
// of the deinit in the super class.
54995583
return false;
5584+
}
55005585

55015586
switch (*memberIsolation) {
55025587
case MemberIsolationPropagation::GlobalActor:
@@ -5508,13 +5593,15 @@ bool HasIsolatedSelfRequest::evaluate(
55085593

55095594
// Check whether the default isolation was overridden by any attributes on
55105595
// this declaration.
5511-
if (getIsolationFromAttributes(value))
5512-
return false;
5513-
5596+
auto attrIsolation = getIsolationFromAttributes(value);
55145597
// ... or its extension context.
5515-
if (auto ext = dyn_cast<ExtensionDecl>(dc)) {
5516-
if (getIsolationFromAttributes(ext))
5517-
return false;
5598+
if (!attrIsolation) {
5599+
if (auto ext = dyn_cast<ExtensionDecl>(dc)) {
5600+
attrIsolation = getIsolationFromAttributes(ext);
5601+
}
5602+
}
5603+
if (attrIsolation) {
5604+
return attrIsolation == ActorIsolation::forActorInstanceSelf(selfTypeDecl);
55185605
}
55195606

55205607
// If this is a variable, check for a property wrapper that alters its
@@ -5546,24 +5633,6 @@ bool HasIsolatedSelfRequest::evaluate(
55465633
return false;
55475634
}
55485635

5549-
if (isImplicitDeinit(value)) {
5550-
// Actors don't have inheritance (except inheriting from NSObject),
5551-
// but check for it anyway, just in case it will be re-introduced later.
5552-
ValueDecl *overriddenValue = value->getOverriddenDeclOrSuperDeinit();
5553-
if (overriddenValue) {
5554-
ActorIsolation isolation = getOverriddenIsolationFor(value);
5555-
if (isolation.isActorIsolated()) {
5556-
return isolation.getKind() == ActorIsolation::ActorInstance;
5557-
}
5558-
}
5559-
5560-
// No need to isolate implicit deinit, unless there is already an isolated
5561-
// one in the superclass
5562-
addAttributesForActorIsolation(value,
5563-
ActorIsolation::forNonisolated(false));
5564-
return false;
5565-
}
5566-
55675636
return true;
55685637
}
55695638

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,7 @@ namespace {
15061506
UNINTERESTING_ATTR(Indirect)
15071507
UNINTERESTING_ATTR(InheritsConvenienceInitializers)
15081508
UNINTERESTING_ATTR(Inline)
1509+
UNINTERESTING_ATTR(Isolated)
15091510
UNINTERESTING_ATTR(Optimize)
15101511
UNINTERESTING_ATTR(Exclusivity)
15111512
UNINTERESTING_ATTR(NoLocks)

test/Concurrency/Runtime/actor_deinit_escaping_self.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ actor EscapeLocked {
1717
k += 1
1818
}
1919

20-
deinit {
20+
isolated deinit {
2121
let g = DispatchGroup()
2222
g.enter()
2323
Task.detached {

test/Concurrency/Runtime/actor_recursive_deinit.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ actor Foo {
5656
self.child = child
5757
}
5858

59-
deinit {
59+
isolated deinit {
6060
print("DEINIT: \(name) isolated:\(isCurrent(self)) mainThread:\(isMainThread())")
6161
}
6262
}

0 commit comments

Comments
 (0)