Skip to content

Commit 73e0b9a

Browse files
authored
Merge pull request #73589 from simanerush/nonisolated-unsafe-diag-6.0
[6.0🍒][Concurrency] Diagnose a redundant `nonisolated(unsafe)`
2 parents 4c1e9d3 + 9360e90 commit 73e0b9a

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5731,6 +5731,18 @@ NOTE(nonisolated_mutable_storage_note,none,
57315731
"convert %0 to a 'let' constant or consider declaring it "
57325732
"'nonisolated(unsafe)' if manually managing concurrency safety",
57335733
(const VarDecl *))
5734+
WARNING(nonisolated_unsafe_sendable_constant,none,
5735+
"'nonisolated(unsafe)' is unnecessary for a constant with 'Sendable' type "
5736+
"%0, consider removing it",
5737+
(Type))
5738+
WARNING(unsafe_sendable_actor_constant,none,
5739+
"'(unsafe)' is unnecessary for a constant public actor property with "
5740+
"'Sendable' type %0, consider removing it",
5741+
(Type))
5742+
WARNING(nonisolated_unsafe_sendable_actor_constant,none,
5743+
"'nonisolated(unsafe)' is unnecessary for a constant actor-isolated "
5744+
"property with 'Sendable' type %0, consider removing it",
5745+
(Type))
57345746
ERROR(nonisolated_non_sendable,none,
57355747
"'nonisolated' can not be applied to variable with non-'Sendable' "
57365748
"type %0",

lib/Sema/TypeCheckAttr.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6970,6 +6970,40 @@ void AttributeChecker::visitNonisolatedAttr(NonisolatedAttr *attr) {
69706970
return;
69716971
}
69726972
}
6973+
6974+
// 'nonisolated(unsafe)' is redundant for 'Sendable' immutables.
6975+
if (attr->isUnsafe() &&
6976+
type->isSendableType() &&
6977+
var->isLet()) {
6978+
6979+
// '(unsafe)' is redundant for a public actor-isolated 'Sendable'
6980+
// immutable.
6981+
auto nominal = dyn_cast<NominalTypeDecl>(dc);
6982+
if (nominal && nominal->isActor()) {
6983+
auto access = nominal->getFormalAccessScope(
6984+
/*useDC=*/nullptr,
6985+
/*treatUsableFromInlineAsPublic=*/true);
6986+
if (access.isPublic()) {
6987+
// Get the location where '(unsafe)' starts.
6988+
SourceLoc unsafeStart = Lexer::getLocForEndOfToken(
6989+
Ctx.SourceMgr, attr->getRange().Start);
6990+
diagnose(unsafeStart, diag::unsafe_sendable_actor_constant, type)
6991+
.fixItRemoveChars(unsafeStart,
6992+
attr->getRange().End.getAdvancedLoc(1));
6993+
} else {
6994+
// This actor is not public, so suggest to remove
6995+
// 'nonisolated(unsafe)'.
6996+
diagnose(attr->getLocation(),
6997+
diag::nonisolated_unsafe_sendable_actor_constant, type)
6998+
.fixItRemove(attr->getRange());
6999+
}
7000+
7001+
} else {
7002+
diagnose(attr->getLocation(),
7003+
diag::nonisolated_unsafe_sendable_constant, type)
7004+
.fixItRemove(attr->getRange());
7005+
}
7006+
}
69737007
}
69747008

69757009
// Using 'nonisolated' with wrapped properties is unsupported, because

test/Concurrency/global_variables.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ public struct TestWrapper {
3737
}
3838
}
3939

40+
// https://github.com/apple/swift/issues/71546
41+
actor TestActor {
42+
nonisolated(unsafe) let immutableActorIsolated = TestSendable()
43+
// expected-warning@-1 {{'nonisolated(unsafe)' is unnecessary for a constant actor-isolated property with 'Sendable' type 'TestSendable', consider removing it}} {{3-23=}}
44+
}
45+
4046
struct TestStatics {
4147
static let immutableExplicitSendable = TestSendable()
4248
static let immutableNonsendable = TestNonsendable() // expected-error{{static property 'immutableNonsendable' is not concurrency-safe because non-'Sendable' type 'TestNonsendable' may have shared mutable state}}
@@ -45,6 +51,8 @@ struct TestStatics {
4551
static nonisolated let immutableNonisolated = TestNonsendable() // expected-error{{static property 'immutableNonisolated' is not concurrency-safe because non-'Sendable' type 'TestNonsendable' may have shared mutable state}}
4652
// expected-note@-1 {{isolate 'immutableNonisolated' to a global actor, or conform 'TestNonsendable' to 'Sendable'}}
4753
// expected-error@-2 {{'nonisolated' can not be applied to variable with non-'Sendable' type 'TestNonsendable'}}
54+
static nonisolated(unsafe) let immutableNonisolatedUnsafeSendable = TestSendable()
55+
// expected-warning@-1 {{'nonisolated(unsafe)' is unnecessary for a constant with 'Sendable' type 'TestSendable', consider removing it}} {{10-30=}}
4856
static let immutableInferredSendable = 0
4957
static var mutable = 0 // expected-error{{static property 'mutable' is not concurrency-safe because it is non-isolated global shared mutable state}}
5058
// expected-note@-1{{isolate 'mutable' to a global actor, or convert it to a 'let' constant and conform it to 'Sendable'}}
@@ -54,6 +62,11 @@ struct TestStatics {
5462
// expected-note@-1{{isolate 'wrapped' to a global actor, or convert it to a 'let' constant and conform it to 'Sendable'}}
5563
}
5664

65+
public actor TestPublicActor {
66+
nonisolated(unsafe) let immutableNonisolatedUnsafeSendable = TestSendable()
67+
// expected-warning@-1 {{'(unsafe)' is unnecessary for a constant public actor property with 'Sendable' type 'TestSendable', consider removing it}} {{14-22=}}
68+
}
69+
5770
@TestGlobalActor
5871
func f() {
5972
print(TestStatics.immutableExplicitSendable)
@@ -63,6 +76,9 @@ func f() {
6376
}
6477

6578
func testLocalNonisolatedUnsafe() async {
79+
nonisolated(unsafe) let immutable = 1
80+
// expected-warning@-1{{'nonisolated(unsafe)' is unnecessary for a constant with 'Sendable' type 'Int', consider removing it}} {{3-23=}}
81+
// expected-warning@-2{{initialization of immutable value 'immutable' was never used; consider replacing with assignment to '_' or removing it}}
6682
nonisolated(unsafe) var value = 1
6783
let task = Task {
6884
value = 2

0 commit comments

Comments
 (0)