Skip to content

Commit 75a0cc0

Browse files
committed
CastOptimizer: handle isolated conformances
Check the isolation of conformances to avoid wrong folding of dynamic casts rdar://147417762
1 parent e18beda commit 75a0cc0

File tree

4 files changed

+108
-3
lines changed

4 files changed

+108
-3
lines changed

lib/SIL/Utils/DynamicCasts.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,12 @@ classifyDynamicCastToProtocol(SILFunction *function, CanType source, CanType tar
115115

116116
// If checkConformance() returns a valid conformance, then all conditional
117117
// requirements were satisfied.
118-
if (checkConformance(source, TargetProtocol))
118+
if (auto conformance = checkConformance(source, TargetProtocol)) {
119+
if (!matchesActorIsolation(conformance, function))
120+
return DynamicCastFeasibility::MaySucceed;
121+
119122
return DynamicCastFeasibility::WillSucceed;
123+
}
120124

121125
auto *SourceNominalTy = source.getAnyNominal();
122126
if (!SourceNominalTy)

lib/SILOptimizer/Utils/CastOptimizer.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,6 +1481,9 @@ static bool optimizeStaticallyKnownProtocolConformance(
14811481
if (Conformance.isInvalid())
14821482
return false;
14831483

1484+
if (!matchesActorIsolation(Conformance, Inst->getFunction()))
1485+
return false;
1486+
14841487
auto layout = TargetType->getExistentialLayout();
14851488
if (layout.getProtocols().size() != 1)
14861489
return false;

test/SILOptimizer/constant_propagation_casts_ossa.sil

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
// RUN: %target-sil-opt -enable-sil-verify-all %s -diagnostic-constant-propagation | %FileCheck %s
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -diagnostic-constant-propagation -enable-experimental-feature IsolatedConformances | %FileCheck %s
2+
3+
// REQUIRES: swift_feature_IsolatedConformances
4+
// REQUIRES: concurrency
5+
26
sil_stage canonical
37

4-
//import Swift
8+
import Builtin
9+
import Swift
10+
import _Concurrency
11+
import SwiftShims
512

613
class Klass {
714
}
@@ -12,6 +19,15 @@ class SubKlass : Klass {
1219
class NoSubKlass {
1320
}
1421

22+
protocol P {
23+
func f() -> Int
24+
}
25+
26+
struct X : @MainActor P {
27+
func f() -> Int
28+
init()
29+
}
30+
1531
sil [noinline] @blackhole1 : $@convention(thin) (@guaranteed SubKlass) -> ()
1632
sil [noinline] @blackhole2 : $@convention(thin) (@guaranteed NoSubKlass) -> ()
1733

@@ -94,3 +110,26 @@ bb3:
94110
return %r : $()
95111
}
96112

113+
// CHECK-LABEL: sil [ossa] @isolated_conf_ucca :
114+
// CHECK: unconditional_checked_cast_addr
115+
// CHECK-LABEL: } // end sil function 'isolated_conf_ucca'
116+
sil [ossa] @isolated_conf_ucca : $@convention(thin) (@in X) -> @out P {
117+
bb0(%0 : $*P, %1 : $*X):
118+
unconditional_checked_cast_addr X in %1 to any P in %0
119+
%2 = tuple ()
120+
return %2
121+
}
122+
123+
// CHECK-LABEL: sil [ossa] @isolated_conf_ccab :
124+
// CHECK: checked_cast_addr_br
125+
// CHECK-LABEL: } // end sil function 'isolated_conf_ccab'
126+
sil [ossa] @isolated_conf_ccab : $@convention(thin) (@in X) -> @out P {
127+
bb0(%0 : $*P, %1 : $*X):
128+
checked_cast_addr_br take_always X in %1 to any P in %0, bb1, bb2
129+
bb1:
130+
%2 = tuple ()
131+
return %2
132+
bb2:
133+
unreachable
134+
}
135+
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -parse-as-library -O %s -enable-experimental-feature IsolatedConformances -o %t/a.out
3+
// RUN: %target-codesign %t/a.out
4+
// RUN: %target-run %t/a.out | %FileCheck %s --check-prefix=CHECK-OUTPUT
5+
6+
// RUN: %target-build-swift -parse-as-library -O %s -enable-experimental-feature IsolatedConformances -Xllvm -sil-disable-pass=function-signature-opts -emit-sil | %FileCheck %s
7+
8+
// REQUIRES: concurrency
9+
// REQUIRES: executable_test
10+
// REQUIRES: concurrency_runtime
11+
// REQUIRES: swift_feature_IsolatedConformances
12+
13+
// UNSUPPORTED: back_deployment_runtime
14+
// UNSUPPORTED: back_deploy_concurrency
15+
16+
protocol P {
17+
func f() -> Int
18+
}
19+
20+
struct X: @MainActor P {
21+
func f() -> Int { 17 }
22+
}
23+
24+
// CHECK-LABEL: sil hidden [noinline] @$s21isolated_conformances12castAnywhereySiSgAA1XVF :
25+
// CHECK: checked_cast_addr_br take_always X in %{{[0-9]+}} to any P in %{{[0-9]+}}, bb1, bb2
26+
// CHECK: } // end sil function '$s21isolated_conformances12castAnywhereySiSgAA1XVF'
27+
@inline(never)
28+
nonisolated func castAnywhere(_ value: X) -> Int? {
29+
if let value = value as? P {
30+
return value.f()
31+
}
32+
return nil
33+
}
34+
35+
// CHECK-LABEL: sil hidden [noinline] @$s21isolated_conformances15castOnMainActorySiSgAA1XVF :
36+
// CHECK: [[L:%.*]] = integer_literal {{.*}} 17
37+
// CHECK: [[I:%.*]] = struct $Int ([[L]])
38+
// CHECK: [[O:%.*]] = enum $Optional<Int>, #Optional.some!enumelt, [[I]]
39+
// CHECK: return [[O]]
40+
// CHECK: } // end sil function '$s21isolated_conformances15castOnMainActorySiSgAA1XVF'
41+
@MainActor
42+
@inline(never)
43+
func castOnMainActor(_ value: X) -> Int? {
44+
if let value = value as? P {
45+
return value.f()
46+
}
47+
return nil
48+
}
49+
50+
51+
@main
52+
struct Main {
53+
static func main() async {
54+
await Task.detached {
55+
// CHECK-OUTPUT: nil
56+
print(castAnywhere(X()))
57+
}.value
58+
}
59+
}

0 commit comments

Comments
 (0)