Skip to content

Commit ab497d9

Browse files
committed
[Concurrency] Downgrade the error for accessing isolated static lets across
actors to a warning.
1 parent cabb5e1 commit ab497d9

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
@@ -496,7 +496,8 @@ Type swift::getExplicitGlobalActor(ClosureExpr *closure) {
496496
/// nonisolated or it is accessed from within the same module.
497497
static bool varIsSafeAcrossActors(const ModuleDecl *fromModule,
498498
VarDecl *var,
499-
const ActorIsolation &varIsolation) {
499+
const ActorIsolation &varIsolation,
500+
ActorReferenceResult::Options &options) {
500501
// must be immutable
501502
if (!var->isLet())
502503
return false;
@@ -517,8 +518,12 @@ static bool varIsSafeAcrossActors(const ModuleDecl *fromModule,
517518

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

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

540546
namespace {
@@ -5814,7 +5820,8 @@ static bool isNonValueReference(const ValueDecl *value) {
58145820

58155821
bool swift::isAccessibleAcrossActors(
58165822
ValueDecl *value, const ActorIsolation &isolation,
5817-
const DeclContext *fromDC, llvm::Optional<ReferencedActor> actorInstance) {
5823+
const DeclContext *fromDC, ActorReferenceResult::Options &options,
5824+
llvm::Optional<ReferencedActor> actorInstance) {
58185825
// Initializers and enum elements are accessible across actors unless they
58195826
// are global-actor qualified.
58205827
if (isa<ConstructorDecl>(value) || isa<EnumElementDecl>(value)) {
@@ -5834,12 +5841,22 @@ bool swift::isAccessibleAcrossActors(
58345841
// 'let' declarations are immutable, so some of them can be accessed across
58355842
// actors.
58365843
if (auto var = dyn_cast<VarDecl>(value)) {
5837-
return varIsSafeAcrossActors(fromDC->getParentModule(), var, isolation);
5844+
return varIsSafeAcrossActors(
5845+
fromDC->getParentModule(), var, isolation, options);
58385846
}
58395847

58405848
return false;
58415849
}
58425850

5851+
bool swift::isAccessibleAcrossActors(
5852+
ValueDecl *value, const ActorIsolation &isolation,
5853+
const DeclContext *fromDC,
5854+
llvm::Optional<ReferencedActor> actorInstance) {
5855+
ActorReferenceResult::Options options = llvm::None;
5856+
return isAccessibleAcrossActors(
5857+
value, isolation, fromDC, options, actorInstance);
5858+
}
5859+
58435860
ActorReferenceResult ActorReferenceResult::forSameConcurrencyDomain(
58445861
ActorIsolation isolation) {
58455862
return ActorReferenceResult{SameConcurrencyDomain, llvm::None, isolation};
@@ -5978,16 +5995,18 @@ ActorReferenceResult ActorReferenceResult::forReference(
59785995
(isa<ConstructorDecl>(fromDC) || isa<DestructorDecl>(fromDC)))
59795996
return forSameConcurrencyDomain(declIsolation);
59805997

5998+
// Determine what adjustments we need to perform for cross-actor
5999+
// references.
6000+
Options options = llvm::None;
6001+
59816002
// At this point, we are accessing the target from outside the actor.
59826003
// First, check whether it is something that can be accessed directly,
59836004
// without any kind of promotion.
59846005
if (isAccessibleAcrossActors(
5985-
declRef.getDecl(), declIsolation, fromDC, actorInstance))
6006+
declRef.getDecl(), declIsolation, fromDC, options, actorInstance))
59866007
return forEntersActor(declIsolation, llvm::None);
59876008

5988-
// This is a cross-actor reference, so determine what adjustments we need
5989-
// to perform.
5990-
Options options = llvm::None;
6009+
// This is a cross-actor reference.
59916010

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

lib/Sema/TypeCheckConcurrency.h

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

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

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)