Skip to content

Commit 3925323

Browse files
committed
[Concurrency] Don't allow initializing global actor isolated stored
properties with non-Sendable type from across isolation boundaries. (cherry picked from commit 0b1e2fe)
1 parent ec16d2c commit 3925323

File tree

3 files changed

+35
-8
lines changed

3 files changed

+35
-8
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5871,6 +5871,23 @@ ActorReferenceResult ActorReferenceResult::forReference(
58715871
return forSameConcurrencyDomain(declIsolation);
58725872
}
58735873

5874+
// Initializing a global actor isolated stored property with a value
5875+
// effectively passes that value from the init context into the global
5876+
// actor context. This is only okay to do if the property type is Sendable.
5877+
if (declIsolation.isGlobalActor() && isStoredProperty(declRef.getDecl())) {
5878+
auto *init = dyn_cast<ConstructorDecl>(fromDC);
5879+
if (init && init->isDesignatedInit()) {
5880+
auto type =
5881+
fromDC->mapTypeIntoContext(declRef.getDecl()->getInterfaceType());
5882+
if (!isSendableType(fromDC->getParentModule(), type)) {
5883+
// Treat the decl isolation as 'preconcurrency' to downgrade violations
5884+
// to warnings, because violating Sendable here is accepted by the
5885+
// Swift 5.9 compiler.
5886+
return forEntersActor(declIsolation, Flags::Preconcurrency);
5887+
}
5888+
}
5889+
}
5890+
58745891
// If there is an instance and it is checked by flow isolation, treat it
58755892
// as being in the same concurrency domain.
58765893
if (actorInstance &&
@@ -5889,13 +5906,8 @@ ActorReferenceResult ActorReferenceResult::forReference(
58895906

58905907
// If there is an instance that corresponds to 'self',
58915908
// we are in a constructor or destructor, and we have a stored property of
5892-
// global-actor-qualified type, pretend we are in the same concurrency
5893-
// domain.
5894-
// FIXME: This is an odd carve-out that probably shouldn't have been allowed.
5895-
// It should at the very least be diagnosed, and either subsumed by flow
5896-
// isolation or banned outright.
5897-
// FIXME: At the very least, we should consistently use
5898-
// isActorInitOrDeInitContext here, but it only wants to think about actors.
5909+
// global-actor-qualified type, then we have problems if the stored property
5910+
// type is non-Sendable. Note that if we get here, the type must be Sendable.
58995911
if (actorInstance && actorInstance->isSelf() &&
59005912
isNonInheritedStorage(declRef.getDecl(), fromDC) &&
59015913
declIsolation.isGlobalActor() &&

test/Concurrency/global_actor_inference.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,17 +324,30 @@ struct WrapperOnActor<Wrapped: Sendable> {
324324
public struct WrapperOnMainActor<Wrapped> {
325325
// Make sure inference of @MainActor on wrappedValue doesn't crash.
326326

327+
// expected-note@+1 {{mutation of this property is only permitted within the actor}}
327328
public var wrappedValue: Wrapped
328329

329330
public var accessCount: Int
330331

331332
nonisolated public init(wrappedValue: Wrapped) {
333+
// expected-warning@+1 {{main actor-isolated property 'wrappedValue' can not be mutated from a non-isolated context; this is an error in Swift 6}}
332334
self.wrappedValue = wrappedValue
333335
}
334336
}
335337

336338
@propertyWrapper
337-
public struct WrapperOnMainActor2<Wrapped> {
339+
public struct WrapperOnMainActorNonSendable<Wrapped> {
340+
// expected-note@+1 {{mutation of this property is only permitted within the actor}}
341+
@MainActor public var wrappedValue: Wrapped
342+
343+
public init(wrappedValue: Wrapped) {
344+
// expected-warning@+1 {{main actor-isolated property 'wrappedValue' can not be mutated from a non-isolated context; this is an error in Swift 6}}
345+
self.wrappedValue = wrappedValue
346+
}
347+
}
348+
349+
@propertyWrapper
350+
public struct WrapperOnMainActorSendable<Wrapped: Sendable> {
338351
@MainActor public var wrappedValue: Wrapped
339352

340353
public init(wrappedValue: Wrapped) {

test/Concurrency/global_actor_inference_swift6.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,13 @@ struct WrapperOnActor<Wrapped: Sendable> {
6969
public struct WrapperOnMainActor<Wrapped> {
7070
// Make sure inference of @MainActor on wrappedValue doesn't crash.
7171

72+
// expected-note@+1 {{mutation of this property is only permitted within the actor}}
7273
public var wrappedValue: Wrapped // expected-note {{property declared here}}
7374

7475
public var accessCount: Int
7576

7677
nonisolated public init(wrappedValue: Wrapped) {
78+
// expected-error@+1 {{main actor-isolated property 'wrappedValue' can not be mutated from a non-isolated context}}
7779
self.wrappedValue = wrappedValue
7880
}
7981
}

0 commit comments

Comments
 (0)