Skip to content

Commit 075846d

Browse files
committed
Deployment-gate treatment of protocols without witness tables as never-dependent
Within Swift 6.0, we expanded an optimization for witness tables that that allowed direct access to the witness table for conformances to any protocol that can never have a witness table, rather than requiring access through `swift_getWitnessTable` that might need to instantiate the witness table. The previous optimization only covered Objective-C protocols, but Swift 6.0 expanded that to marker protocols (such as `Sendable`) as well. However, this constituted an API break when a Swift 6.0 compiler uses a witness table that comes from a library built with an earlier version of Swift, when the protocol inherits from Sendable but the conformance to that protocol otherwise does not require an instantiation function. In such cases, Swift 6.0 would generate code that directly accesses the uninstantiated witness table symbol, which will have NULL entries for any conformance in it that was considered "dependent" by the earlier Swift compiler. Introduce a deployment target check to guard the new optimization. Specifically, when building for a deployment target that predates Swift 6.0, treat conformances to marker protocols as if they might be dependent (so the access patterns go through `swift_getWitnessTable` for potential instantiation on older platforms). For newer deployment targets, use the more efficent direct access pattern. Fixes rdar://133157093.
1 parent 7de7134 commit 075846d

File tree

3 files changed

+61
-2
lines changed

3 files changed

+61
-2
lines changed

lib/IRGen/GenProto.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "swift/AST/PackConformance.h"
3939
#include "swift/AST/PrettyStackTrace.h"
4040
#include "swift/AST/SubstitutionMap.h"
41+
#include "swift/Basic/Platform.h"
4142
#include "swift/ClangImporter/ClangModule.h"
4243
#include "swift/IRGen/Linking.h"
4344
#include "swift/SIL/SILDeclRef.h"
@@ -1028,6 +1029,28 @@ static bool isSynthesizedNonUnique(const RootProtocolConformance *conformance) {
10281029
return false;
10291030
}
10301031

1032+
/// Determine whether a protocol can ever have a dependent conformance.
1033+
static bool protocolCanHaveDependentConformance(ProtocolDecl *proto) {
1034+
// Objective-C protocols have never been able to have a dependent conformance.
1035+
if (proto->isObjC())
1036+
return false;
1037+
1038+
// Prior to Swift 6.0, only Objective-C protocols were never able to have
1039+
// a dependent conformance. This is overly pessimistic when the protocol
1040+
// is a marker protocol (since they don't have requirements), but we must
1041+
// retain backward compatibility with binaries built for earlier deployment
1042+
// targets that concluded that these protocols might involve dependent
1043+
// conformances.
1044+
ASTContext &ctx = proto->getASTContext();
1045+
if (auto runtimeCompatVersion = getSwiftRuntimeCompatibilityVersionForTarget(
1046+
ctx.LangOpts.Target)) {
1047+
if (runtimeCompatVersion < llvm::VersionTuple(6, 0))
1048+
return true;
1049+
}
1050+
1051+
return Lowering::TypeConverter::protocolRequiresWitnessTable(proto);
1052+
}
1053+
10311054
static bool isDependentConformance(
10321055
IRGenModule &IGM,
10331056
const RootProtocolConformance *rootConformance,
@@ -1060,7 +1083,7 @@ static bool isDependentConformance(
10601083
continue;
10611084

10621085
auto assocProtocol = req.getProtocolDecl();
1063-
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(assocProtocol))
1086+
if (!protocolCanHaveDependentConformance(assocProtocol))
10641087
continue;
10651088

10661089
auto assocConformance =
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend -emit-module -enable-library-evolution -emit-module-path=%t/resilient_protocol.swiftmodule -module-name=resilient_protocol %S/../Inputs/resilient_protocol.swift
4+
5+
// RUN: %target-swift-frontend -I %t -emit-ir %s -target %target-cpu-apple-macos14.0 | %FileCheck %s -DINT=i%target-ptrsize -check-prefix=CHECK-USAGE -check-prefix=CHECK-USAGE-BEFORE
6+
// RUN: %target-swift-frontend -I %t -emit-ir %s -target %target-cpu-apple-macos15.0 | %FileCheck %s -DINT=i%target-ptrsize -check-prefix=CHECK-USAGE -check-prefix=CHECK-USAGE-AFTER
7+
8+
// REQUIRES: OS=macosx
9+
10+
import resilient_protocol
11+
12+
func acceptResilientSendableBase<T: ResilientSendableBase>(_: T.Type) { }
13+
14+
// CHECK-USAGE: define{{.*}}swiftcc void @"$s28protocol_resilience_sendable25passResilientSendableBaseyyF"()
15+
func passResilientSendableBase() {
16+
// CHECK-USAGE-NOT: ret
17+
// CHECK-USAGE: [[METATYPE:%.*]] = extractvalue
18+
// CHECK-USAGE-BEFORE: [[WITNESS_TABLE:%.*]] = call ptr @"$s18resilient_protocol27ConformsToResilientSendableVAcA0eF4BaseAAWl"()
19+
// CHECK-USAGE-BEFORE-NEXT: call swiftcc void @"$s28protocol_resilience_sendable27acceptResilientSendableBaseyyxm010resilient_A00efG0RzlF"(ptr [[METATYPE]], ptr [[METATYPE]], ptr [[WITNESS_TABLE]])
20+
// CHECK-USAGE-AFTER-NEXT: call swiftcc void @"$s28protocol_resilience_sendable27acceptResilientSendableBaseyyxm010resilient_A00efG0RzlF"(ptr [[METATYPE]], ptr [[METATYPE]], ptr @"$s18resilient_protocol27ConformsToResilientSendableVAA0eF4BaseAAWP")
21+
acceptResilientSendableBase(ConformsToResilientSendable.self)
22+
}

test/Inputs/resilient_protocol.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,18 @@ public protocol ResilientSelfDefault : ResilientBaseProtocol {
4343

4444
@_fixed_layout public protocol OtherFrozenProtocol {
4545
func protocolMethod()
46-
}
46+
}
47+
48+
public protocol ResilientSendableBase: Sendable {
49+
func f()
50+
}
51+
52+
public protocol ResilientSendable: ResilientSendableBase {
53+
func g()
54+
}
55+
56+
57+
public struct ConformsToResilientSendable: ResilientSendable {
58+
public func f() { }
59+
public func g() { }
60+
}

0 commit comments

Comments
 (0)