Skip to content

Commit a3ed8cc

Browse files
authored
Merge pull request #69837 from hborla/5.10-downgrade-isolated-static-let
[5.10][Concurrency] Downgrade the error for accessing isolated static `let`s across actors.
2 parents 0079583 + a0725b6 commit a3ed8cc

File tree

4 files changed

+68
-9
lines changed

4 files changed

+68
-9
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,8 @@ Type swift::getExplicitGlobalActor(ClosureExpr *closure) {
495495
/// nonisolated or it is accessed from within the same module.
496496
static bool varIsSafeAcrossActors(const ModuleDecl *fromModule,
497497
VarDecl *var,
498-
const ActorIsolation &varIsolation) {
498+
const ActorIsolation &varIsolation,
499+
ActorReferenceResult::Options &options) {
499500
// must be immutable
500501
if (!var->isLet())
501502
return false;
@@ -516,8 +517,12 @@ static bool varIsSafeAcrossActors(const ModuleDecl *fromModule,
516517

517518
// Static 'let's are initialized upon first access, so they cannot be
518519
// synchronously accessed across actors.
519-
if (var->isGlobalStorage() && var->isLazilyInitializedGlobal())
520+
if (var->isGlobalStorage() && var->isLazilyInitializedGlobal()) {
521+
// Compiler versions <= 5.9 accepted this code, so downgrade to a
522+
// warning prior to Swift 6.
523+
options = ActorReferenceResult::Flags::Preconcurrency;
520524
return false;
525+
}
521526

522527
// If it's distributed, generally variable access is not okay...
523528
if (auto nominalParent = var->getDeclContext()->getSelfNominalTypeDecl()) {
@@ -533,7 +538,8 @@ static bool varIsSafeAcrossActors(const ModuleDecl *fromModule,
533538
bool swift::isLetAccessibleAnywhere(const ModuleDecl *fromModule,
534539
VarDecl *let) {
535540
auto isolation = getActorIsolation(let);
536-
return varIsSafeAcrossActors(fromModule, let, isolation);
541+
ActorReferenceResult::Options options = llvm::None;
542+
return varIsSafeAcrossActors(fromModule, let, isolation, options);
537543
}
538544

539545
namespace {
@@ -5829,7 +5835,8 @@ static bool isNonValueReference(const ValueDecl *value) {
58295835

58305836
bool swift::isAccessibleAcrossActors(
58315837
ValueDecl *value, const ActorIsolation &isolation,
5832-
const DeclContext *fromDC, llvm::Optional<ReferencedActor> actorInstance) {
5838+
const DeclContext *fromDC, ActorReferenceResult::Options &options,
5839+
llvm::Optional<ReferencedActor> actorInstance) {
58335840
// Initializers and enum elements are accessible across actors unless they
58345841
// are global-actor qualified.
58355842
if (isa<ConstructorDecl>(value) || isa<EnumElementDecl>(value)) {
@@ -5849,12 +5856,22 @@ bool swift::isAccessibleAcrossActors(
58495856
// 'let' declarations are immutable, so some of them can be accessed across
58505857
// actors.
58515858
if (auto var = dyn_cast<VarDecl>(value)) {
5852-
return varIsSafeAcrossActors(fromDC->getParentModule(), var, isolation);
5859+
return varIsSafeAcrossActors(
5860+
fromDC->getParentModule(), var, isolation, options);
58535861
}
58545862

58555863
return false;
58565864
}
58575865

5866+
bool swift::isAccessibleAcrossActors(
5867+
ValueDecl *value, const ActorIsolation &isolation,
5868+
const DeclContext *fromDC,
5869+
llvm::Optional<ReferencedActor> actorInstance) {
5870+
ActorReferenceResult::Options options = llvm::None;
5871+
return isAccessibleAcrossActors(
5872+
value, isolation, fromDC, options, actorInstance);
5873+
}
5874+
58585875
ActorReferenceResult ActorReferenceResult::forSameConcurrencyDomain(
58595876
ActorIsolation isolation) {
58605877
return ActorReferenceResult{SameConcurrencyDomain, llvm::None, isolation};
@@ -5993,16 +6010,18 @@ ActorReferenceResult ActorReferenceResult::forReference(
59936010
(isa<ConstructorDecl>(fromDC) || isa<DestructorDecl>(fromDC)))
59946011
return forSameConcurrencyDomain(declIsolation);
59956012

6013+
// Determine what adjustments we need to perform for cross-actor
6014+
// references.
6015+
Options options = llvm::None;
6016+
59966017
// At this point, we are accessing the target from outside the actor.
59976018
// First, check whether it is something that can be accessed directly,
59986019
// without any kind of promotion.
59996020
if (isAccessibleAcrossActors(
6000-
declRef.getDecl(), declIsolation, fromDC, actorInstance))
6021+
declRef.getDecl(), declIsolation, fromDC, options, actorInstance))
60016022
return forEntersActor(declIsolation, llvm::None);
60026023

6003-
// This is a cross-actor reference, so determine what adjustments we need
6004-
// to perform.
6005-
Options options = llvm::None;
6024+
// This is a cross-actor reference.
60066025

60076026
// Note if the reference originates from a @preconcurrency-isolated context.
60086027
if (contextIsolation.preconcurrency() || declIsolation.preconcurrency())

lib/Sema/TypeCheckConcurrency.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,20 @@ VarDecl *getReferencedParamOrCapture(
525525
Expr *expr,
526526
llvm::function_ref<Expr *(OpaqueValueExpr *)> getExistentialValue);
527527

528+
/// Determine whether the given value can be accessed across actors
529+
/// without from normal synchronous code.
530+
///
531+
/// \param value The value we are checking.
532+
/// \param isolation The actor isolation of the value.
533+
/// \param fromDC The context where we are performing the access.
534+
/// \param options The reference options, such as whether reference
535+
/// violations should be downgraded to warnings prior to Swift 6.
536+
bool isAccessibleAcrossActors(
537+
ValueDecl *value, const ActorIsolation &isolation,
538+
const DeclContext *fromDC,
539+
ActorReferenceResult::Options &options,
540+
llvm::Optional<ReferencedActor> actorInstance = llvm::None);
541+
528542
/// Determine whether the given value can be accessed across actors
529543
/// without from normal synchronous code.
530544
///

test/Concurrency/actor_isolation.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,3 +1569,16 @@ actor AnotherActor {
15691569
_ = a.ns
15701570
}
15711571
}
1572+
1573+
@MainActor
1574+
class MainActorIsolated {
1575+
init() {}
1576+
1577+
// expected-note@+1 {{static property declared here}}
1578+
static let shared = MainActorIsolated()
1579+
}
1580+
1581+
nonisolated func accessAcrossActors() {
1582+
// expected-warning@+1 {{main actor-isolated static property 'shared' can not be referenced from a non-isolated context; this is an error in Swift 6}}
1583+
let _ = MainActorIsolated.shared
1584+
}

test/Concurrency/actor_isolation_swift6.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,16 @@ struct NoGlobalActorValueType {
8080
}
8181

8282
/// -----------------------------------------------------------------
83+
84+
@MainActor
85+
class MainActorIsolated {
86+
init() {}
87+
88+
// expected-note@+1 {{static property declared here}}
89+
static let shared = MainActorIsolated()
90+
}
91+
92+
nonisolated func accessAcrossActors() {
93+
// expected-error@+1 {{main actor-isolated static property 'shared' can not be referenced from a non-isolated context}}
94+
let _ = MainActorIsolated.shared
95+
}

0 commit comments

Comments
 (0)