Skip to content

Commit ecd94e4

Browse files
committed
[Concurrency] Diagnose @GlobalActor(unsafe) attributes with a fix-it to use
`@preconcurrency` instead. This diagnosic is a warning until Swift 6, and it's ignored in swiftinterfaces.
1 parent d6f27a8 commit ecd94e4

11 files changed

+56
-29
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5743,8 +5743,13 @@ ERROR(global_actor_on_local_variable,none,
57435743
ERROR(global_actor_on_storage_of_value_type,none,
57445744
"stored property %0 within struct cannot have a global actor",
57455745
(DeclName))
5746-
ERROR(global_actor_non_unsafe_init,none,
5747-
"global actor attribute %0 argument can only be '(unsafe)'", (Type))
5746+
ERROR(unsafe_global_actor,none,
5747+
"'(unsafe)' global actors are deprecated; "
5748+
"use '@preconcurrency' instead",
5749+
())
5750+
ERROR(global_actor_arg,none,
5751+
"global actor attribute %0 cannot have arguments",
5752+
(Type))
57485753
ERROR(global_actor_non_final_class,none,
57495754
"non-final class %0 cannot be a global actor", (DeclName))
57505755
ERROR(global_actor_top_level_var,none,

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4110,17 +4110,28 @@ getIsolationFromAttributes(const Decl *decl, bool shouldDiagnose = true,
41104110
return ActorIsolation::forUnspecified();
41114111

41124112
// Handle @<global attribute type>(unsafe).
4113-
bool isUnsafe = globalActorAttr->first->isArgUnsafe();
4114-
if (globalActorAttr->first->hasArgs() && !isUnsafe) {
4115-
ctx.Diags.diagnose(
4116-
globalActorAttr->first->getLocation(),
4117-
diag::global_actor_non_unsafe_init, globalActorType);
4113+
auto *attr = globalActorAttr->first;
4114+
bool isUnsafe = attr->isArgUnsafe();
4115+
if (attr->hasArgs()) {
4116+
if (isUnsafe) {
4117+
SourceFile *file = decl->getDeclContext()->getParentSourceFile();
4118+
bool inSwiftinterface =
4119+
file && file->Kind == SourceFileKind::Interface;
4120+
ctx.Diags.diagnose(
4121+
attr->getLocation(),
4122+
diag::unsafe_global_actor)
4123+
.fixItRemove(attr->getArgs()->getSourceRange())
4124+
.fixItInsert(attr->getLocation(), "@preconcurrency ")
4125+
.warnUntilSwiftVersion(6)
4126+
.limitBehaviorIf(inSwiftinterface, DiagnosticBehavior::Ignore);
4127+
} else {
4128+
ctx.Diags.diagnose(
4129+
attr->getLocation(),
4130+
diag::global_actor_arg, globalActorType)
4131+
.fixItRemove(attr->getArgs()->getSourceRange());
4132+
}
41184133
}
41194134

4120-
// If the declaration predates concurrency, it has unsafe actor isolation.
4121-
if (decl->preconcurrency())
4122-
isUnsafe = true;
4123-
41244135
return ActorIsolation::forGlobalActor(
41254136
globalActorType->mapTypeOutOfContext())
41264137
.withPreconcurrency(decl->preconcurrency() || isUnsafe);

test/Concurrency/actor_isolation_unsafe.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,18 @@ actor SomeGlobalActor {
1111
static let shared = SomeGlobalActor()
1212
}
1313

14+
// expected-warning@+1 {{'(unsafe)' global actors are deprecated; use '@preconcurrency' instead}}
1415
@MainActor(unsafe) func globalMain() { } // expected-note {{calls to global function 'globalMain()' from outside of its actor context are implicitly asynchronous}}
1516

17+
// expected-warning@+1 {{'(unsafe)' global actors are deprecated; use '@preconcurrency' instead}}
1618
@SomeGlobalActor(unsafe) func globalSome() { } // expected-note 2{{calls to global function 'globalSome()' from outside of its actor context are implicitly asynchronous}}
1719
// expected-complete-tns-note @-1 {{calls to global function 'globalSome()' from outside of its actor context are implicitly asynchronous}}
1820

1921
// ----------------------------------------------------------------------
2022
// Witnessing and unsafe global actor
2123
// ----------------------------------------------------------------------
2224
protocol P1 {
25+
// expected-warning@+1 {{'(unsafe)' global actors are deprecated; use '@preconcurrency' instead}}
2326
@MainActor(unsafe) func onMainActor() // expected-note 2{{mark the protocol requirement 'onMainActor()' 'async' to allow actor-isolated conformances}}
2427
}
2528

@@ -45,7 +48,7 @@ struct S4_P1: P1 {
4548
@SomeGlobalActor func onMainActor() { } // expected-warning{{global actor 'SomeGlobalActor'-isolated instance method 'onMainActor()' cannot be used to satisfy main actor-isolated protocol requirement}}
4649
}
4750

48-
51+
// expected-warning@+1 {{'(unsafe)' global actors are deprecated; use '@preconcurrency' instead}}
4952
@MainActor(unsafe)
5053
protocol P2 {
5154
func f() // expected-note{{calls to instance method 'f()' from outside of its actor context are implicitly asynchronous}}
@@ -80,6 +83,7 @@ func testP2_noconcurrency(x: S5_P2, p2: P2) {
8083
// Overriding and unsafe global actor
8184
// ----------------------------------------------------------------------
8285
class C1 {
86+
// expected-warning@+1 {{'(unsafe)' global actors are deprecated; use '@preconcurrency' instead}}
8387
@MainActor(unsafe) func method() { } // expected-note{{overridden declaration is here}}
8488
}
8589

@@ -114,12 +118,14 @@ class C6: C2 {
114118
}
115119

116120
class C7: C2 {
121+
// expected-warning@+1 {{'(unsafe)' global actors are deprecated; use '@preconcurrency' instead}}
117122
@SomeGlobalActor(unsafe) override func method() { // expected-error{{global actor 'SomeGlobalActor'-isolated instance method 'method()' has different actor isolation from main actor-isolated overridden declaration}}
118123
globalMain() // expected-warning{{call to main actor-isolated global function 'globalMain()' in a synchronous global actor 'SomeGlobalActor'-isolated context}}
119124
globalSome() // okay
120125
}
121126
}
122127

128+
// expected-warning@+1 {{'(unsafe)' global actors are deprecated; use '@preconcurrency' instead}}
123129
@MainActor(unsafe) // expected-note {{'GloballyIsolatedProto' is isolated to global actor 'MainActor' here}}
124130
protocol GloballyIsolatedProto {
125131
}

test/Concurrency/actor_keypath_isolation.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ actor Door {
2626
@MainActor var globActor_mutable : Int = 0
2727
@MainActor let globActor_immutable : Int = 0
2828

29-
@MainActor(unsafe) var unsafeGlobActor_mutable : Int = 0
30-
@MainActor(unsafe) let unsafeGlobActor_immutable : Int = 0
29+
@preconcurrency @MainActor var unsafeGlobActor_mutable : Int = 0
30+
@preconcurrency @MainActor let unsafeGlobActor_immutable : Int = 0
3131

3232
subscript(byIndex: Int) -> Int { 0 }
3333

test/Concurrency/actor_keypath_isolation_swift6.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ actor Door {
2525
@MainActor var globActor_mutable : Int = 0
2626
@MainActor let globActor_immutable : Int = 0
2727

28-
@MainActor(unsafe) var unsafeGlobActor_mutable : Int = 0
29-
@MainActor(unsafe) let unsafeGlobActor_immutable : Int = 0
28+
@preconcurrency @MainActor var unsafeGlobActor_mutable : Int = 0
29+
@preconcurrency @MainActor let unsafeGlobActor_immutable : Int = 0
3030

3131
subscript(byIndex: Int) -> Int { 0 }
3232

test/Concurrency/async_initializer.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,13 @@ enum E {
112112
struct SomeStruct {
113113
@MainActor init(asyncMainActor: Int) async {}
114114
@MainActor init(mainActor: Int) {} // expected-note {{calls to initializer 'init(mainActor:)' from outside of its actor context are implicitly asynchronous}}
115+
116+
// expected-warning@+1 {{'(unsafe)' global actors are deprecated; use '@preconcurrency' instead}}
115117
@MainActor(unsafe) init(asyncMainActorUnsafe: Int) async {}
116-
@MainActor(unsafe) init(mainActorUnsafe: Int) {} // expected-complete-and-tns-note {{calls to initializer 'init(mainActorUnsafe:)' from outside of its actor context are implicitly asynchronous}}
118+
119+
// expected-warning@+2 {{'(unsafe)' global actors are deprecated; use '@preconcurrency' instead}}
120+
// expected-complete-and-tns-note@+1 {{calls to initializer 'init(mainActorUnsafe:)' from outside of its actor context are implicitly asynchronous}}
121+
@MainActor(unsafe) init(mainActorUnsafe: Int) {}
117122
}
118123

119124
// expected-complete-and-tns-note @+3 {{add '@MainActor' to make global function 'globActorTest1()' part of global actor 'MainActor'}}

test/Concurrency/global_actor_function_types.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ func testConversions(f: @escaping @SomeGlobalActor (Int) -> Void, g: @escaping (
2828
}
2929

3030
@SomeGlobalActor func onSomeGlobalActor() -> Int { 5 }
31-
@SomeGlobalActor(unsafe) func onSomeGlobalActorUnsafe() -> Int { 5 }
31+
@preconcurrency @SomeGlobalActor func onSomeGlobalActorUnsafe() -> Int { 5 }
3232

3333
@OtherGlobalActor func onOtherGlobalActor() -> Int { 5 } // expected-note{{calls to global function 'onOtherGlobalActor()' from outside of its actor context are implicitly asynchronous}}
34-
@OtherGlobalActor(unsafe) func onOtherGlobalActorUnsafe() -> Int { 5 } // expected-note 2{{calls to global function 'onOtherGlobalActorUnsafe()' from outside of its actor context are implicitly asynchronous}}
34+
@preconcurrency @OtherGlobalActor func onOtherGlobalActorUnsafe() -> Int { 5 } // expected-note 2{{calls to global function 'onOtherGlobalActorUnsafe()' from outside of its actor context are implicitly asynchronous}}
3535
// expected-complete-tns-note @-1 {{calls to global function 'onOtherGlobalActorUnsafe()' from outside of its actor context are implicitly asynchronous}}
3636

3737
func someSlowOperation() async -> Int { 5 }

test/Concurrency/global_actor_inference.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ struct Carbon {
4949
// ----------------------------------------------------------------------
5050
// Check that @MainActor(blah) doesn't work
5151
// ----------------------------------------------------------------------
52-
// expected-error@+1{{global actor attribute 'MainActor' argument can only be '(unsafe)'}}
52+
// expected-error@+1{{global actor attribute 'MainActor' cannot have arguments}}
5353
@MainActor(blah) func brokenMainActorAttr() { }
5454

5555
// ----------------------------------------------------------------------
@@ -504,7 +504,7 @@ class WrappedContainsNonisolatedAttr {
504504
// Unsafe global actors
505505
// ----------------------------------------------------------------------
506506
protocol UGA {
507-
@SomeGlobalActor(unsafe) func req() // expected-note{{calls to instance method 'req()' from outside of its actor context are implicitly asynchronous}}
507+
@preconcurrency @SomeGlobalActor func req() // expected-note{{calls to instance method 'req()' from outside of its actor context are implicitly asynchronous}}
508508
}
509509

510510
struct StructUGA1: UGA {
@@ -528,7 +528,7 @@ func testUGA<T: UGA>(_ value: T) {
528528
}
529529

530530
class UGAClass {
531-
@SomeGlobalActor(unsafe) func method() { }
531+
@preconcurrency @SomeGlobalActor func method() { }
532532
}
533533

534534
class UGASubclass1: UGAClass {
@@ -540,20 +540,20 @@ class UGASubclass2: UGAClass {
540540
}
541541

542542
@propertyWrapper
543-
@OtherGlobalActor(unsafe)
543+
@preconcurrency @OtherGlobalActor
544544
struct WrapperOnUnsafeActor<Wrapped> {
545545
private var stored: Wrapped
546546

547547
init(wrappedValue: Wrapped) {
548548
stored = wrappedValue
549549
}
550550

551-
@MainActor(unsafe) var wrappedValue: Wrapped {
551+
@preconcurrency @MainActor var wrappedValue: Wrapped {
552552
get { }
553553
set { }
554554
}
555555

556-
@SomeGlobalActor(unsafe) var projectedValue: Wrapped {
556+
@preconcurrency @SomeGlobalActor var projectedValue: Wrapped {
557557
get { }
558558
set { }
559559
}

test/Concurrency/require-explicit-sendable.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ open class TestThing {}
112112
open class TestSubThing : TestThing {}
113113

114114
@available(SwiftStdlib 5.1, *)
115-
@MainActor(unsafe)
115+
@MainActor(unsafe) // expected-warning {{'(unsafe)' global actors are deprecated; use '@preconcurrency' instead}}
116116
open class TestThing2 {}
117117

118118
@available(SwiftStdlib 5.1, *)

test/Sema/availability_main_actor.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
@MainActor
99
struct AlwaysAvailable {}
1010

11-
@MainActor(unsafe)
11+
@preconcurrency @MainActor
1212
struct AlwaysAvailableUnsafe {}
1313

1414
@available(SwiftStdlib 5.1, *)
1515
@MainActor
1616
struct AvailableSwift5_1 {}
1717

1818
@available(SwiftStdlib 5.1, *)
19-
@MainActor(unsafe)
19+
@preconcurrency @MainActor
2020
struct AvailableSwift5_1Unsafe {}

test/decl/class/actor/global_actor_conformance.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ extension OnMain: NonIsolatedRequirement {
5858
}
5959

6060
// expected-note@+1 {{calls to global function 'downgrade()' from outside of its actor context are implicitly asynchronous}}
61-
@MainActor(unsafe) func downgrade() {}
61+
@preconcurrency @MainActor func downgrade() {}
6262

6363
extension OnMain {
6464
struct Nested {

0 commit comments

Comments
 (0)