Skip to content

Commit 1e2992f

Browse files
committed
SIL: Pick default ARC convention for enum case witness thunks based on the kind of the original decl.
Enum constructors take their arguments +1 by default, but they can now be used to satisfy protocol static member requirements, which take arguments +0 by default. Type lowering would accidentally use the kind of the witness to determine the conventions for the witness thunk, leading to a miscompile when the requirement is called through the protocol. This differs from the fix on main in that the behavior change is contained to only cases where the witness is an enum constructor, to minimize behavior change. rdar://73855052
1 parent 6e52b9a commit 1e2992f

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2485,7 +2485,22 @@ static CanSILFunctionType getNativeSILFunctionType(
24852485
case SILFunctionType::Representation::Method:
24862486
case SILFunctionType::Representation::Closure:
24872487
case SILFunctionType::Representation::WitnessMethod: {
2488-
switch (constant ? constant->kind : SILDeclRef::Kind::Func) {
2488+
// FIXME: We should use origConstant unconditionally here, since in the
2489+
// case of protocol witness thunk type lowering, we want to lower the
2490+
// witness's calling convention according to the convention of the protocol
2491+
// requirement, even if the witness has a different kind. Previously we
2492+
// would base this on the witness `constant`, and this worked because
2493+
// witnesses had always been the same decl kind as the requirement, but
2494+
// enum cases as static witnesses broke this invariant.
2495+
//
2496+
// To minimize the change in behavior for Swift 5.4, we only consider
2497+
// origConstant when constant is an EnumElement, to avoid affecting other
2498+
// potential corner cases I'm not thinking of in the moment.
2499+
auto constantToTest = constant;
2500+
if (constant && constant->kind == SILDeclRef::Kind::EnumElement) {
2501+
constantToTest = origConstant;
2502+
}
2503+
switch (constantToTest ? constantToTest->kind : SILDeclRef::Kind::Func) {
24892504
case SILDeclRef::Kind::Initializer:
24902505
case SILDeclRef::Kind::EnumElement:
24912506
return getSILFunctionTypeForConventions(DefaultInitializerConventions());

test/SILGen/enum_witness_thunks.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: %target-swift-emit-silgen %s | %FileCheck %s
2+
3+
class C {}
4+
5+
protocol P {
6+
static func c(_: C) -> Self
7+
}
8+
9+
enum E: P {
10+
case c(C)
11+
}
12+
13+
// CHECK-LABEL: sil {{.*}} @$s19enum_witness_thunks1EOAA1PA2aDP1cyxAA1CCFZTW : $@convention(witness_method: P) (@guaranteed C, @thick E.Type) -> @out E
14+
// CHECK: [[COPY:%.*]] = copy_value
15+
// CHECK: apply {{.*}}([[COPY]]

0 commit comments

Comments
 (0)