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.
|
/// 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.
|
// Objective-C protocols have never been able to have a dependent conformance.
|
||||||
if (proto->isObjC())
|
if (proto->isObjC())
|
||||||
return false;
|
return false;
|
||||||
@@ -1047,13 +1050,14 @@ static bool protocolCanHaveDependentConformance(ProtocolDecl *proto) {
|
|||||||
// is a marker protocol (since they don't have requirements), but we must
|
// is a marker protocol (since they don't have requirements), but we must
|
||||||
// retain backward compatibility with binaries built for earlier deployment
|
// retain backward compatibility with binaries built for earlier deployment
|
||||||
// targets that concluded that these protocols might involve dependent
|
// targets that concluded that these protocols might involve dependent
|
||||||
// conformances.
|
// conformances. Only do this for resilient protocols.
|
||||||
ASTContext &ctx = proto->getASTContext();
|
if (isResilient && proto->isSpecificProtocol(KnownProtocolKind::Sendable)) {
|
||||||
if (auto runtimeCompatVersion = getSwiftRuntimeCompatibilityVersionForTarget(
|
ASTContext &ctx = proto->getASTContext();
|
||||||
ctx.LangOpts.Target)) {
|
if (auto runtimeCompatVersion = getSwiftRuntimeCompatibilityVersionForTarget(
|
||||||
if (runtimeCompatVersion < llvm::VersionTuple(6, 0) &&
|
ctx.LangOpts.Target)) {
|
||||||
proto->isSpecificProtocol(KnownProtocolKind::Sendable))
|
if (runtimeCompatVersion < llvm::VersionTuple(6, 0))
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Lowering::TypeConverter::protocolRequiresWitnessTable(proto);
|
return Lowering::TypeConverter::protocolRequiresWitnessTable(proto);
|
||||||
@@ -1062,6 +1066,7 @@ static bool protocolCanHaveDependentConformance(ProtocolDecl *proto) {
|
|||||||
static bool isDependentConformance(
|
static bool isDependentConformance(
|
||||||
IRGenModule &IGM,
|
IRGenModule &IGM,
|
||||||
const RootProtocolConformance *rootConformance,
|
const RootProtocolConformance *rootConformance,
|
||||||
|
bool isResilient,
|
||||||
llvm::SmallPtrSet<const NormalProtocolConformance *, 4> &visited){
|
llvm::SmallPtrSet<const NormalProtocolConformance *, 4> &visited){
|
||||||
// Self-conformances are never dependent.
|
// Self-conformances are never dependent.
|
||||||
auto conformance = dyn_cast<NormalProtocolConformance>(rootConformance);
|
auto conformance = dyn_cast<NormalProtocolConformance>(rootConformance);
|
||||||
@@ -1091,7 +1096,8 @@ static bool isDependentConformance(
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto assocProtocol = req.getProtocolDecl();
|
auto assocProtocol = req.getProtocolDecl();
|
||||||
if (!protocolCanHaveDependentConformance(assocProtocol))
|
if (!protocolCanHaveDependentConformance(
|
||||||
|
assocProtocol, isResilient))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto assocConformance =
|
auto assocConformance =
|
||||||
@@ -1105,6 +1111,7 @@ static bool isDependentConformance(
|
|||||||
isDependentConformance(IGM,
|
isDependentConformance(IGM,
|
||||||
assocConformance.getConcrete()
|
assocConformance.getConcrete()
|
||||||
->getRootConformance(),
|
->getRootConformance(),
|
||||||
|
isResilient,
|
||||||
visited))
|
visited))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1173,7 +1180,8 @@ static bool hasConditionalConformances(IRGenModule &IGM,
|
|||||||
bool IRGenModule::isDependentConformance(
|
bool IRGenModule::isDependentConformance(
|
||||||
const RootProtocolConformance *conformance) {
|
const RootProtocolConformance *conformance) {
|
||||||
llvm::SmallPtrSet<const NormalProtocolConformance *, 4> visited;
|
llvm::SmallPtrSet<const NormalProtocolConformance *, 4> visited;
|
||||||
return ::isDependentConformance(*this, conformance, visited);
|
return ::isDependentConformance(
|
||||||
|
*this, conformance, conformance->getProtocol()->isResilient(), visited);
|
||||||
}
|
}
|
||||||
|
|
||||||
static llvm::Value *
|
static llvm::Value *
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// RUN: %empty-directory(%t)
|
// 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 -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-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
|
// 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
|
// REQUIRES: OS=macosx
|
||||||
|
|
||||||
import resilient_protocol
|
import resilient_protocol
|
||||||
|
import non_resilient_protocol
|
||||||
|
|
||||||
func acceptResilientSendableBase<T: ResilientSendableBase>(_: T.Type) { }
|
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")
|
// CHECK-USAGE-AFTER-NEXT: call swiftcc void @"$s28protocol_resilience_sendable27acceptResilientSendableBaseyyxm010resilient_A00efG0RzlF"(ptr [[METATYPE]], ptr [[METATYPE]], ptr @"$s18resilient_protocol27ConformsToResilientSendableVAA0eF4BaseAAWP")
|
||||||
acceptResilientSendableBase(ConformsToResilientSendable.self)
|
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