mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Fix ABI mismatch involving Sendable-refining protocols and deployment targets
A change to the way we determined whether a protocol conformance is "dependent" for marker protocols caused an ABI break for Sendable-refining protocols built with pre-6.0 Swift compilers. The fix for this issue (https://github.com/swiftlang/swift/pull/75769) gated the change on deployment target. The deployment target change fixed the original problem, then caused a related issue when a project mixes deployment targets (pre-6.0 and 6.0+) with non-resilient protocols. Exempt non-resilient protocols from this change so we get consistent behavior. Fixes rdar://134953989.
This commit is contained in:
@@ -1037,7 +1037,10 @@ static bool isSynthesizedNonUnique(const RootProtocolConformance *conformance) {
|
||||
}
|
||||
|
||||
/// Determine whether a protocol can ever have a dependent conformance.
|
||||
static bool protocolCanHaveDependentConformance(ProtocolDecl *proto) {
|
||||
static bool protocolCanHaveDependentConformance(
|
||||
ProtocolDecl *proto,
|
||||
bool isResilient
|
||||
) {
|
||||
// Objective-C protocols have never been able to have a dependent conformance.
|
||||
if (proto->isObjC())
|
||||
return false;
|
||||
@@ -1047,13 +1050,14 @@ static bool protocolCanHaveDependentConformance(ProtocolDecl *proto) {
|
||||
// is a marker protocol (since they don't have requirements), but we must
|
||||
// retain backward compatibility with binaries built for earlier deployment
|
||||
// targets that concluded that these protocols might involve dependent
|
||||
// conformances.
|
||||
ASTContext &ctx = proto->getASTContext();
|
||||
if (auto runtimeCompatVersion = getSwiftRuntimeCompatibilityVersionForTarget(
|
||||
ctx.LangOpts.Target)) {
|
||||
if (runtimeCompatVersion < llvm::VersionTuple(6, 0) &&
|
||||
proto->isSpecificProtocol(KnownProtocolKind::Sendable))
|
||||
return true;
|
||||
// conformances. Only do this for resilient protocols.
|
||||
if (isResilient && proto->isSpecificProtocol(KnownProtocolKind::Sendable)) {
|
||||
ASTContext &ctx = proto->getASTContext();
|
||||
if (auto runtimeCompatVersion = getSwiftRuntimeCompatibilityVersionForTarget(
|
||||
ctx.LangOpts.Target)) {
|
||||
if (runtimeCompatVersion < llvm::VersionTuple(6, 0))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return Lowering::TypeConverter::protocolRequiresWitnessTable(proto);
|
||||
@@ -1062,6 +1066,7 @@ static bool protocolCanHaveDependentConformance(ProtocolDecl *proto) {
|
||||
static bool isDependentConformance(
|
||||
IRGenModule &IGM,
|
||||
const RootProtocolConformance *rootConformance,
|
||||
bool isResilient,
|
||||
llvm::SmallPtrSet<const NormalProtocolConformance *, 4> &visited){
|
||||
// Self-conformances are never dependent.
|
||||
auto conformance = dyn_cast<NormalProtocolConformance>(rootConformance);
|
||||
@@ -1091,7 +1096,8 @@ static bool isDependentConformance(
|
||||
continue;
|
||||
|
||||
auto assocProtocol = req.getProtocolDecl();
|
||||
if (!protocolCanHaveDependentConformance(assocProtocol))
|
||||
if (!protocolCanHaveDependentConformance(
|
||||
assocProtocol, isResilient))
|
||||
continue;
|
||||
|
||||
auto assocConformance =
|
||||
@@ -1105,6 +1111,7 @@ static bool isDependentConformance(
|
||||
isDependentConformance(IGM,
|
||||
assocConformance.getConcrete()
|
||||
->getRootConformance(),
|
||||
isResilient,
|
||||
visited))
|
||||
return true;
|
||||
}
|
||||
@@ -1173,7 +1180,8 @@ static bool hasConditionalConformances(IRGenModule &IGM,
|
||||
bool IRGenModule::isDependentConformance(
|
||||
const RootProtocolConformance *conformance) {
|
||||
llvm::SmallPtrSet<const NormalProtocolConformance *, 4> visited;
|
||||
return ::isDependentConformance(*this, conformance, visited);
|
||||
return ::isDependentConformance(
|
||||
*this, conformance, conformance->getProtocol()->isResilient(), visited);
|
||||
}
|
||||
|
||||
static llvm::Value *
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// RUN: %empty-directory(%t)
|
||||
|
||||
// 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
|
||||
// RUN: %target-swift-frontend -emit-module -emit-module-path=%t/non_resilient_protocol.swiftmodule -module-name=non_resilient_protocol %S/../Inputs/non_resilient_protocol.swift
|
||||
|
||||
// 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
|
||||
// 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
|
||||
@@ -8,6 +9,7 @@
|
||||
// REQUIRES: OS=macosx
|
||||
|
||||
import resilient_protocol
|
||||
import non_resilient_protocol
|
||||
|
||||
func acceptResilientSendableBase<T: ResilientSendableBase>(_: T.Type) { }
|
||||
|
||||
@@ -20,3 +22,12 @@ func passResilientSendableBase() {
|
||||
// CHECK-USAGE-AFTER-NEXT: call swiftcc void @"$s28protocol_resilience_sendable27acceptResilientSendableBaseyyxm010resilient_A00efG0RzlF"(ptr [[METATYPE]], ptr [[METATYPE]], ptr @"$s18resilient_protocol27ConformsToResilientSendableVAA0eF4BaseAAWP")
|
||||
acceptResilientSendableBase(ConformsToResilientSendable.self)
|
||||
}
|
||||
|
||||
func acceptNonResilientSendableBase<T: NonResilientSendableBase>(_: T.Type) { }
|
||||
|
||||
// CHECK-USAGE: define{{.*}}swiftcc void @"$s28protocol_resilience_sendable28passNonResilientSendableBaseyyF"()
|
||||
func passNonResilientSendableBase() {
|
||||
// CHECK-USAGE-NOT: ret
|
||||
// CHECK-USAGE: call swiftcc void @"$s28protocol_resilience_sendable30acceptNonResilientSendableBaseyyxm014non_resilient_A00efgH0RzlF"(ptr @"$s22non_resilient_protocol30ConformsToNonResilientSendableVN", ptr @"$s22non_resilient_protocol30ConformsToNonResilientSendableVN", ptr @"$s22non_resilient_protocol30ConformsToNonResilientSendableVAA0fgH4BaseAAWP")
|
||||
acceptNonResilientSendableBase(ConformsToNonResilientSendable.self)
|
||||
}
|
||||
|
||||
12
test/Inputs/non_resilient_protocol.swift
Normal file
12
test/Inputs/non_resilient_protocol.swift
Normal file
@@ -0,0 +1,12 @@
|
||||
public protocol NonResilientSendableBase: Sendable {
|
||||
func f()
|
||||
}
|
||||
|
||||
public protocol NonResilientSendable: NonResilientSendableBase {
|
||||
func g()
|
||||
}
|
||||
|
||||
public struct ConformsToNonResilientSendable: NonResilientSendable {
|
||||
public func f() { }
|
||||
public func g() { }
|
||||
}
|
||||
Reference in New Issue
Block a user