Skip to content

Commit 8dcb761

Browse files
committed
downgrade actor deinit accesses to warnings in more contexts
previous downgrade did not properly account for accesses within closures, because it was done hastily.
1 parent 6d97905 commit 8dcb761

File tree

3 files changed

+72
-23
lines changed

3 files changed

+72
-23
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4500,9 +4500,10 @@ NOTE(note_distributed_actor_system_conformance_missing_adhoc_requirement,none,
45004500
ERROR(override_implicit_unowned_executor,none,
45014501
"cannot override an actor's 'unownedExecutor' property that wasn't "
45024502
"explicitly defined", ())
4503-
ERROR(actor_isolated_from_deinit,none,
4504-
"actor-isolated %0 %1 can not be referenced from a non-isolated deinit",
4505-
(DescriptiveDeclKind, DeclName))
4503+
ERROR(actor_isolated_from_decl,none,
4504+
"actor-isolated %0 %1 can not be referenced from a non-isolated "
4505+
"%select{deinit|autoclosure|closure}2",
4506+
(DescriptiveDeclKind, DeclName, unsigned))
45064507
ERROR(actor_isolated_non_self_reference,none,
45074508
"actor-isolated %0 %1 can not be "
45084509
"%select{referenced|mutated|used 'inout'}2 "

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2686,6 +2686,52 @@ namespace {
26862686
});
26872687
}
26882688

2689+
static bool isStoredProperty(ValueDecl const *member) {
2690+
if (auto *var = dyn_cast<VarDecl>(member))
2691+
if (var->hasStorage() && var->isInstanceMember())
2692+
return true;
2693+
return false;
2694+
}
2695+
2696+
/// an ad-hoc check specific to member isolation checking.
2697+
static bool memberAccessWasAllowedInSwift5(DeclContext const *refCxt,
2698+
ValueDecl const *member,
2699+
SourceLoc memberLoc) {
2700+
// no need for this in Swift 6+
2701+
if (refCxt->getASTContext().isSwiftVersionAtLeast(6))
2702+
return false;
2703+
2704+
// In Swift 5, we were allowing all members to be referenced from a
2705+
// deinit, nested within a wide variety of contexts.
2706+
if (auto oldFn = isActorInitOrDeInitContext(refCxt)) {
2707+
if (isa<DestructorDecl>(oldFn) && member->isInstanceMember()) {
2708+
auto &diags = refCxt->getASTContext().Diags;
2709+
2710+
// if the context in which we consider the access matches between
2711+
// old and new, and its a stored property, then skip the warning
2712+
// because it will still be allowed in Swift 6.
2713+
if (!(refCxt == oldFn && isStoredProperty(member))) {
2714+
unsigned cxtKind = 0; // deinit
2715+
2716+
// try to get a better name for this context.
2717+
if (isa<AutoClosureExpr>(refCxt)) {
2718+
cxtKind = 1;
2719+
} else if (isa<AbstractClosureExpr>(refCxt)) {
2720+
cxtKind = 2;
2721+
}
2722+
2723+
diags.diagnose(memberLoc, diag::actor_isolated_from_decl,
2724+
member->getDescriptiveKind(),
2725+
member->getName(),
2726+
cxtKind).warnUntilSwiftVersion(6);
2727+
}
2728+
return true;
2729+
}
2730+
}
2731+
2732+
return false;
2733+
}
2734+
26892735
/// To support flow-isolation, some member accesses in inits / deinits
26902736
/// must be permitted, despite the isolation of 'self' not being
26912737
/// correct in Sema.
@@ -2697,7 +2743,7 @@ namespace {
26972743
///
26982744
/// \returns true iff the member access is permitted in Sema because it will
26992745
/// be verified later by flow-isolation.
2700-
bool checkedByFlowIsolation(DeclContext const *refCxt,
2746+
static bool checkedByFlowIsolation(DeclContext const *refCxt,
27012747
ReferencedActor &baseActor,
27022748
ValueDecl const *member,
27032749
SourceLoc memberLoc) {
@@ -2716,7 +2762,7 @@ namespace {
27162762
while (true) {
27172763
fnDecl = dyn_cast_or_null<AbstractFunctionDecl>(refCxt->getAsDecl());
27182764
if (!fnDecl)
2719-
return false;
2765+
break;
27202766

27212767
// go up one level if this context is a defer.
27222768
if (auto *d = dyn_cast<FuncDecl>(fnDecl)) {
@@ -2728,25 +2774,15 @@ namespace {
27282774
break;
27292775
}
27302776

2777+
if (memberAccessWasAllowedInSwift5(refCxt, member, memberLoc))
2778+
return true; // then permit it now.
2779+
27312780
if (!usesFlowSensitiveIsolation(fnDecl))
27322781
return false;
27332782

27342783
// Stored properties are definitely OK.
2735-
if (auto *var = dyn_cast<VarDecl>(member))
2736-
if (var->hasStorage() && var->isInstanceMember())
2737-
return true;
2738-
2739-
// In Swift 5, we were allowing all members to be referenced from a
2740-
// deinit, but that will not be valid in Swift 6+, so warn about it.
2741-
if (!refCxt->getASTContext().isSwiftVersionAtLeast(6)) {
2742-
if (isa<DestructorDecl>(fnDecl) && member->isInstanceMember()) {
2743-
auto &diags = refCxt->getASTContext().Diags;
2744-
diags.diagnose(memberLoc, diag::actor_isolated_from_deinit,
2745-
member->getDescriptiveKind(),
2746-
member->getName()).warnUntilSwiftVersion(6);
2784+
if (isStoredProperty(member))
27472785
return true;
2748-
}
2749-
}
27502786

27512787
return false;
27522788
}

test/Concurrency/actor_isolation.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ extension SomeClassInActor.ID {
811811
// ----------------------------------------------------------------------
812812
@available(SwiftStdlib 5.1, *)
813813
actor SomeActorWithInits {
814-
var mutableState: Int = 17 // expected-note 3 {{mutation of this property is only permitted within the actor}}
814+
var mutableState: Int = 17 // expected-note 2 {{mutation of this property is only permitted within the actor}}
815815
var otherMutableState: Int
816816
let nonSendable: SomeClass
817817

@@ -911,16 +911,16 @@ actor SomeActorWithInits {
911911

912912
let _ = {
913913
defer {
914-
isolated() // expected-error{{actor-isolated instance method 'isolated()' can not be referenced from a non-isolated context}}
915-
mutableState += 1 // expected-error{{actor-isolated property 'mutableState' can not be mutated from a non-isolated context}}
914+
isolated() // expected-warning{{actor-isolated instance method 'isolated()' can not be referenced from a non-isolated closure; this is an error in Swift 6}}
915+
mutableState += 1 // expected-warning{{actor-isolated property 'mutableState' can not be referenced from a non-isolated closure; this is an error in Swift 6}}
916916
nonisolated()
917917
}
918918
nonisolated()
919919
}()
920920
}
921921

922922

923-
func isolated() { } // expected-note 8 {{calls to instance method 'isolated()' from outside of its actor context are implicitly asynchronous}}
923+
func isolated() { } // expected-note 7 {{calls to instance method 'isolated()' from outside of its actor context are implicitly asynchronous}}
924924
nonisolated func nonisolated() {}
925925
}
926926

@@ -1344,3 +1344,15 @@ final class MainActorInit: Sendable {
13441344

13451345
func f() {}
13461346
}
1347+
1348+
actor DunkTracker {
1349+
private var lebron: Int?
1350+
private var curry: Int?
1351+
1352+
deinit {
1353+
// expected-warning@+1 {{actor-isolated property 'curry' can not be referenced from a non-isolated autoclosure; this is an error in Swift 6}}
1354+
if lebron != nil || curry != nil {
1355+
1356+
}
1357+
}
1358+
}

0 commit comments

Comments
 (0)