Skip to content

Commit 26f4272

Browse files
authored
Merge pull request #69607 from hborla/5.10-isolated-static-let
[5.10][Concurrency] Isolated `static let`s are not safe to access across actors.
2 parents cec2ab4 + 9e922d6 commit 26f4272

File tree

4 files changed

+28
-3
lines changed

4 files changed

+28
-3
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,11 @@ static bool varIsSafeAcrossActors(const ModuleDecl *fromModule,
514514
if (var->getAttrs().hasAttribute<NonisolatedAttr>())
515515
return true;
516516

517+
// Static 'let's are initialized upon first access, so they cannot be
518+
// synchronously accessed across actors.
519+
if (var->isGlobalStorage() && var->isLazilyInitializedGlobal())
520+
return false;
521+
517522
// If it's distributed, generally variable access is not okay...
518523
if (auto nominalParent = var->getDeclContext()->getSelfNominalTypeDecl()) {
519524
if (nominalParent->isDistributedActor())

test/Concurrency/Runtime/actor_assert_precondition_executor.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,17 @@ actor Someone {
6161
}
6262
}
6363

64+
@MainActor let global = TestStaticVar()
65+
66+
@MainActor
67+
struct TestStaticVar {
68+
@MainActor static let shared = TestStaticVar()
69+
70+
init() {
71+
checkPreconditionMainActor()
72+
}
73+
}
74+
6475
@main struct Main {
6576
static func main() async {
6677
let tests = TestSuite("AssertPreconditionActorExecutor")
@@ -78,6 +89,11 @@ actor Someone {
7889
await MainFriend().callCheckMainActor()
7990
}
8091

92+
tests.test("MainActor.assertIsolated() from static let initializer") {
93+
_ = await TestStaticVar.shared
94+
_ = await global
95+
}
96+
8197
#if !os(WASI)
8298
tests.test("precondition on actor (main): wrongly assume the main executor, from actor on other executor") {
8399
expectCrashLater(withMessage: "Incorrect actor executor assumption; Expected 'MainActor' executor.")

test/Concurrency/actor_existentials.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func from_isolated_concrete(_ x: isolated A) async {
4949
actor Act {
5050
var i = 0 // expected-note {{mutation of this property is only permitted within the actor}}
5151
}
52-
let act = Act()
52+
nonisolated let act = Act()
5353

5454
func bad() async {
5555
// expected-warning@+2 {{no 'async' operations occur within 'await' expression}}

test/Concurrency/concurrent_value_checking.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ func globalAsync(_: NotConcurrent?) async {
116116
}
117117

118118
func globalTest() async {
119-
let a = globalValue // expected-warning{{non-sendable type 'NotConcurrent?' in asynchronous access to global actor 'SomeGlobalActor'-isolated let 'globalValue' cannot cross actor boundary}}
119+
// expected-error@+2 {{expression is 'async' but is not marked with 'await'}}
120+
// expected-note@+1 {{property access is 'async'}}
121+
let a = globalValue // expected-warning{{non-sendable type 'NotConcurrent?' in implicitly asynchronous access to global actor 'SomeGlobalActor'-isolated let 'globalValue' cannot cross actor boundary}}
120122
await globalAsync(a) // expected-complete-warning{{passing argument of non-sendable type 'NotConcurrent?' into global actor 'SomeGlobalActor'-isolated context may introduce data races}}
121123
await globalSync(a) // expected-complete-warning{{passing argument of non-sendable type 'NotConcurrent?' into global actor 'SomeGlobalActor'-isolated context may introduce data races}}
122124
}
@@ -137,7 +139,9 @@ class ClassWithGlobalActorInits { // expected-note 2{{class 'ClassWithGlobalActo
137139

138140
@MainActor
139141
func globalTestMain(nc: NotConcurrent) async {
140-
let a = globalValue // expected-warning{{non-sendable type 'NotConcurrent?' in asynchronous access to global actor 'SomeGlobalActor'-isolated let 'globalValue' cannot cross actor boundary}}
142+
// expected-error@+2 {{expression is 'async' but is not marked with 'await'}}
143+
// expected-note@+1 {{property access is 'async'}}
144+
let a = globalValue // expected-warning{{non-sendable type 'NotConcurrent?' in implicitly asynchronous access to global actor 'SomeGlobalActor'-isolated let 'globalValue' cannot cross actor boundary}}
141145
await globalAsync(a) // expected-complete-warning{{passing argument of non-sendable type 'NotConcurrent?' into global actor 'SomeGlobalActor'-isolated context may introduce data races}}
142146
await globalSync(a) // expected-complete-warning{{passing argument of non-sendable type 'NotConcurrent?' into global actor 'SomeGlobalActor'-isolated context may introduce data races}}
143147
_ = await ClassWithGlobalActorInits(nc) // expected-complete-warning{{passing argument of non-sendable type 'NotConcurrent' into global actor 'SomeGlobalActor'-isolated context may introduce data races}}

0 commit comments

Comments
 (0)