Skip to content

Commit c08bd56

Browse files
committed
Prohibit isolated conformances for checked casts to potentially-SendableMetatype types
This removes the IsolatedConformances feature gate from SILGen for dynamic casts, such that all dynamic casts that will not work with isolated conformances are marked as such. Isolated conformances can still only come into a program when part of it enables the feature flag.
1 parent 2f5c6d2 commit c08bd56

File tree

4 files changed

+76
-25
lines changed

4 files changed

+76
-25
lines changed

lib/SILGen/SILGenDynamicCast.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -308,16 +308,17 @@ namespace {
308308
if (!TargetType->isAnyExistentialType())
309309
return CastingIsolatedConformances::Allow;
310310

311-
// Only do this if isolated conformances are enabled.
311+
// If there is a conformance to SendableMetatype, then this existential
312+
// can leave the current isolation domain. Prohibit isolated conformances.
312313
ASTContext &ctx = TargetType->getASTContext();
313-
if (!ctx.LangOpts.hasFeature(Feature::IsolatedConformances))
314-
return CastingIsolatedConformances::Allow;
314+
Type checkType;
315+
if (auto existentialMetatype = TargetType->getAs<ExistentialMetatypeType>())
316+
checkType = existentialMetatype->getInstanceType();
317+
else
318+
checkType = TargetType;
315319

316320
auto proto = ctx.getProtocol(KnownProtocolKind::SendableMetatype);
317-
318-
// If there is a conformance to SendableMetatype, then this existential
319-
// can leave the current isolation domain. Prohibit isolated conformances.
320-
if (proto && lookupConformance(TargetType, proto, /*allowMissing=*/false))
321+
if (proto && lookupConformance(checkType, proto, /*allowMissing=*/false))
321322
return CastingIsolatedConformances::Prohibit;
322323

323324
return CastingIsolatedConformances::Allow;
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 6 -enable-experimental-feature IsolatedConformances -enable-experimental-feature InferIsolatedConformances %s
2+
3+
// REQUIRES: swift_feature_IsolatedConformances
4+
// REQUIRES: swift_feature_InferIsolatedConformances
5+
// REQUIRES: concurrency
6+
7+
protocol P {
8+
func f()
9+
}
10+
11+
@SomeGlobalActor
12+
protocol Q {
13+
func g()
14+
}
15+
16+
@globalActor
17+
actor SomeGlobalActor {
18+
static let shared = SomeGlobalActor()
19+
}
20+
21+
@SomeGlobalActor
22+
protocol R {
23+
func h()
24+
}
25+
26+
@SomeGlobalActor
27+
class CExplicit: P {
28+
func f() { } // okay! conformance above is isolated
29+
}
30+
31+
// If the protocol itself is isolated, don't do anything.
32+
extension CExplicit: Q {
33+
func g() { }
34+
}
35+
36+
// expected-error@+3{{conformance of 'CNonIsolated' to protocol 'P' crosses into global actor 'SomeGlobalActor'-isolated code and can cause data races}}
37+
// expected-note@+2{{turn data races into runtime errors with '@preconcurrency'}}
38+
// expected-note@+1{{isolate this conformance to the global actor 'SomeGlobalActor' with '@SomeGlobalActor'}}{{33-33=@SomeGlobalActor }}
39+
nonisolated class CNonIsolated: P {
40+
@SomeGlobalActor func f() { } // expected-note{{global actor 'SomeGlobalActor'-isolated instance method 'f()' cannot satisfy nonisolated requirement}}
41+
}
42+
43+
func acceptSendablePMeta<T: Sendable & P>(_: T.Type) { }
44+
func acceptSendableQMeta<T: Sendable & Q>(_: T.Type) { }
45+
46+
nonisolated func testConformancesFromNonisolated() {
47+
let _: any P = CExplicit() // expected-error{{global actor 'SomeGlobalActor'-isolated conformance of 'CExplicit' to 'P' cannot be used in nonisolated context}}
48+
49+
let _: any P = CNonIsolated()
50+
51+
// Okay, these are nonisolated conformances.
52+
let _: any Q = CExplicit()
53+
}

test/Concurrency/isolated_conformance_sil.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -Xllvm -sil-print-types -emit-silgen -enable-experimental-feature IsolatedConformances -verify %s | %FileCheck %s
2-
3-
// REQUIRES: swift_feature_IsolatedConformances
4-
// REQUIRES: concurrency
1+
// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -Xllvm -sil-print-types -emit-silgen -verify %s | %FileCheck %s
52

63
protocol P { }
74

test/SILGen/subclass_existentials.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -296,17 +296,17 @@ func downcasts(
296296
let _ = baseAndP as! Derived
297297

298298
// CHECK: [[COPIED:%.*]] = copy_value [[ARG0]] : $any Base<Int> & P
299-
// CHECK-NEXT: checked_cast_br any Base<Int> & P in [[COPIED]] : $any Base<Int> & P to any Derived & R
299+
// CHECK-NEXT: checked_cast_br [prohibit_isolated_conformances] any Base<Int> & P in [[COPIED]] : $any Base<Int> & P to any Derived & R
300300
let _ = baseAndP as? (Derived & R)
301301

302302
// CHECK: [[COPIED:%.*]] = copy_value [[ARG0]] : $any Base<Int> & P
303-
// CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $any Base<Int> & P to any Derived & R
303+
// CHECK-NEXT: unconditional_checked_cast [prohibit_isolated_conformances] [[COPIED]] : $any Base<Int> & P to any Derived & R
304304
let _ = baseAndP as! (Derived & R)
305305

306-
// CHECK: checked_cast_br Derived.Type in %3 : $@thick Derived.Type to any (Derived & R).Type
306+
// CHECK: checked_cast_br [prohibit_isolated_conformances] Derived.Type in %3 : $@thick Derived.Type to any (Derived & R).Type
307307
let _ = derivedType as? (Derived & R).Type
308308

309-
// CHECK: unconditional_checked_cast %3 : $@thick Derived.Type to any (Derived & R).Type
309+
// CHECK: unconditional_checked_cast [prohibit_isolated_conformances] %3 : $@thick Derived.Type to any (Derived & R).Type
310310
let _ = derivedType as! (Derived & R).Type
311311

312312
// CHECK: checked_cast_br any (Base<Int> & P).Type in %2 : $@thick any (Base<Int> & P).Type to Derived.Type
@@ -315,10 +315,10 @@ func downcasts(
315315
// CHECK: unconditional_checked_cast %2 : $@thick any (Base<Int> & P).Type to Derived.Type
316316
let _ = baseAndPType as! Derived.Type
317317

318-
// CHECK: checked_cast_br any (Base<Int> & P).Type in %2 : $@thick any (Base<Int> & P).Type to any (Derived & R).Type
318+
// CHECK: checked_cast_br [prohibit_isolated_conformances] any (Base<Int> & P).Type in %2 : $@thick any (Base<Int> & P).Type to any (Derived & R).Type
319319
let _ = baseAndPType as? (Derived & R).Type
320320

321-
// CHECK: unconditional_checked_cast %2 : $@thick any (Base<Int> & P).Type to any (Derived & R).Type
321+
// CHECK: unconditional_checked_cast [prohibit_isolated_conformances] %2 : $@thick any (Base<Int> & P).Type to any (Derived & R).Type
322322
let _ = baseAndPType as! (Derived & R).Type
323323

324324
// CHECK: return
@@ -378,33 +378,33 @@ func archetypeDowncasts<S,
378378
// CHECK: [[COPY:%.*]] = alloc_stack $S
379379
// CHECK-NEXT: copy_addr %0 to [init] [[COPY]] : $*S
380380
// CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $any Base<T> & P
381-
// CHECK-NEXT: checked_cast_addr_br take_always S in [[COPY]] : $*S to any Base<T> & P in [[RESULT]] : $*any Base<T> & P
381+
// CHECK-NEXT: checked_cast_addr_br [prohibit_isolated_conformances] take_always S in [[COPY]] : $*S to any Base<T> & P in [[RESULT]] : $*any Base<T> & P
382382
let _ = s as? (Base<T> & P)
383383

384384
// CHECK: [[COPY:%.*]] = alloc_stack $S
385385
// CHECK-NEXT: copy_addr [[ARG0]] to [init] [[COPY]] : $*S
386386
// CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $any Base<T> & P
387-
// CHECK-NEXT: unconditional_checked_cast_addr S in [[COPY]] : $*S to any Base<T> & P in [[RESULT]] : $*any Base<T> & P
387+
// CHECK-NEXT: unconditional_checked_cast_addr [prohibit_isolated_conformances] S in [[COPY]] : $*S to any Base<T> & P in [[RESULT]] : $*any Base<T> & P
388388
let _ = s as! (Base<T> & P)
389389

390390
// CHECK: [[COPY:%.*]] = alloc_stack $S
391391
// CHECK-NEXT: copy_addr [[ARG0]] to [init] [[COPY]] : $*S
392392
// CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $any Base<Int> & P
393-
// CHECK-NEXT: checked_cast_addr_br take_always S in [[COPY]] : $*S to any Base<Int> & P in [[RESULT]] : $*any Base<Int> & P
393+
// CHECK-NEXT: checked_cast_addr_br [prohibit_isolated_conformances] take_always S in [[COPY]] : $*S to any Base<Int> & P in [[RESULT]] : $*any Base<Int> & P
394394
let _ = s as? (Base<Int> & P)
395395

396396
// CHECK: [[COPY:%.*]] = alloc_stack $S
397397
// CHECK-NEXT: copy_addr [[ARG0]] to [init] [[COPY]] : $*S
398398
// CHECK-NEXT: [[RESULT:%.*]] = alloc_stack $any Base<Int> & P
399-
// CHECK-NEXT: unconditional_checked_cast_addr S in [[COPY]] : $*S to any Base<Int> & P in [[RESULT]] : $*any Base<Int> & P
399+
// CHECK-NEXT: unconditional_checked_cast_addr [prohibit_isolated_conformances] S in [[COPY]] : $*S to any Base<Int> & P in [[RESULT]] : $*any Base<Int> & P
400400
let _ = s as! (Base<Int> & P)
401401

402402
// CHECK: [[COPIED:%.*]] = copy_value [[ARG5]] : $BaseTAndP
403-
// CHECK-NEXT: checked_cast_br BaseTAndP in [[COPIED]] : $BaseTAndP to any Derived & R
403+
// CHECK-NEXT: checked_cast_br [prohibit_isolated_conformances] BaseTAndP in [[COPIED]] : $BaseTAndP to any Derived & R
404404
let _ = baseTAndP_archetype as? (Derived & R)
405405

406406
// CHECK: [[COPIED:%.*]] = copy_value [[ARG5]] : $BaseTAndP
407-
// CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $BaseTAndP to any Derived & R
407+
// CHECK-NEXT: unconditional_checked_cast [prohibit_isolated_conformances] [[COPIED]] : $BaseTAndP to any Derived & R
408408
let _ = baseTAndP_archetype as! (Derived & R)
409409

410410
// CHECK: [[COPIED:%.*]] = copy_value [[ARG9]] : $any Base<T> & P
@@ -447,11 +447,11 @@ func archetypeDowncasts<S,
447447
let _ = baseTAndP_concrete as! BaseTAndP
448448

449449
// CHECK: [[COPIED:%.*]] = copy_value [[ARG6]] : $BaseIntAndP
450-
// CHECK-NEXT: checked_cast_br BaseIntAndP in [[COPIED]] : $BaseIntAndP to any Derived & R
450+
// CHECK-NEXT: checked_cast_br [prohibit_isolated_conformances] BaseIntAndP in [[COPIED]] : $BaseIntAndP to any Derived & R
451451
let _ = baseIntAndP_archetype as? (Derived & R)
452452

453453
// CHECK: [[COPIED:%.*]] = copy_value [[ARG6]] : $BaseIntAndP
454-
// CHECK-NEXT: unconditional_checked_cast [[COPIED]] : $BaseIntAndP to any Derived & R
454+
// CHECK-NEXT: unconditional_checked_cast [prohibit_isolated_conformances] [[COPIED]] : $BaseIntAndP to any Derived & R
455455
let _ = baseIntAndP_archetype as! (Derived & R)
456456

457457
// CHECK: [[COPIED:%.*]] = copy_value [[ARG10]] : $any Base<Int> & P

0 commit comments

Comments
 (0)