mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
embedded: fix specialization of associated conformance entries in witness tables
When creating a specialized witness table, we need to get the right specialized conformance. In IRGen don't emit associated conformance witness table entries if the protocol is not a class protocol. In this case the associated type can never be used to create an existential. Therefore such a witness table entry is never used at runtime in embedded swift. Fixes a compiler crash rdar://146448091
This commit is contained in:
@@ -144,11 +144,14 @@ func specializeWitnessTable(forConformance conformance: Conformance,
|
||||
case .associatedType(let requirement, let witness):
|
||||
let substType = witness.subst(with: conformance.specializedSubstitutions)
|
||||
return .associatedType(requirement: requirement, witness: substType)
|
||||
case .associatedConformance(let requirement, let proto, let witness):
|
||||
if witness.isSpecialized {
|
||||
specializeWitnessTable(forConformance: witness, errorLocation: errorLocation, context, notifyNewWitnessTable)
|
||||
case .associatedConformance(let requirement, let proto, _):
|
||||
let concreteAssociateConf = conformance.getAssociatedConformance(ofAssociatedType: requirement.type, to: proto)
|
||||
if concreteAssociateConf.isSpecialized {
|
||||
specializeWitnessTable(forConformance: concreteAssociateConf,
|
||||
errorLocation: errorLocation,
|
||||
context, notifyNewWitnessTable)
|
||||
}
|
||||
return .associatedConformance(requirement: requirement, protocol: proto, witness: witness)
|
||||
return .associatedConformance(requirement: requirement, protocol: proto, witness: concreteAssociateConf)
|
||||
}
|
||||
}
|
||||
let newWT = context.createWitnessTable(entries: newEntries,conformance: conformance,
|
||||
|
||||
@@ -959,6 +959,13 @@ namespace {
|
||||
}
|
||||
|
||||
void addAssociatedConformance(const AssociatedConformance &req) {
|
||||
if (req.getAssociation()->getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
|
||||
!req.getAssociatedRequirement()->requiresClass()) {
|
||||
// If it's not a class protocol, the associated type can never be used to create
|
||||
// an existential. Therefore this witness entry is never used at runtime
|
||||
// in embedded swift.
|
||||
return;
|
||||
}
|
||||
Entries.push_back(WitnessTableEntry::forAssociatedConformance(req));
|
||||
}
|
||||
|
||||
@@ -1748,6 +1755,14 @@ public:
|
||||
(void)entry;
|
||||
SILEntries = SILEntries.slice(1);
|
||||
|
||||
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded) &&
|
||||
!requirement.getAssociatedRequirement()->requiresClass()) {
|
||||
// If it's not a class protocol, the associated type can never be used to create
|
||||
// an existential. Therefore this witness entry is never used at runtime
|
||||
// in embedded swift.
|
||||
return;
|
||||
}
|
||||
|
||||
auto associate =
|
||||
ConformanceInContext.getAssociatedType(
|
||||
requirement.getAssociation())->getCanonicalType();
|
||||
@@ -1775,7 +1790,10 @@ public:
|
||||
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
|
||||
// In Embedded Swift associated-conformance entries simply point to the witness table
|
||||
// of the associated conformance.
|
||||
llvm::Constant *witnessEntry = IGM.getAddrOfWitnessTable(associatedConformance.getConcrete());
|
||||
ProtocolConformanceRef assocConf =
|
||||
SILWT->getConformance()->getAssociatedConformance(requirement.getAssociation(),
|
||||
requirement.getAssociatedRequirement());
|
||||
llvm::Constant *witnessEntry = IGM.getAddrOfWitnessTable(assocConf.getConcrete());
|
||||
auto &schema = IGM.getOptions().PointerAuth
|
||||
.ProtocolAssociatedTypeWitnessTableAccessFunctions;
|
||||
Table.addSignedPointer(witnessEntry, schema, requirement);
|
||||
|
||||
@@ -156,6 +156,82 @@ struct S: P2 {
|
||||
}
|
||||
}
|
||||
|
||||
protocol Q3 {
|
||||
func bar()
|
||||
}
|
||||
|
||||
protocol P3<T>: AnyObject {
|
||||
associatedtype T: Q3
|
||||
|
||||
var t: T { get }
|
||||
|
||||
func foo()
|
||||
}
|
||||
|
||||
extension P3 {
|
||||
func foo() {
|
||||
t.bar()
|
||||
}
|
||||
}
|
||||
|
||||
final class C3<T: Q3>: P3 {
|
||||
var t: T
|
||||
|
||||
|
||||
init(t: T) { self.t = t }
|
||||
}
|
||||
|
||||
struct S3<I: BinaryInteger>: Q3 {
|
||||
var x: I
|
||||
|
||||
func bar() {
|
||||
print(x)
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func testP3() -> any P3 {
|
||||
return C3(t: S3(x: 102))
|
||||
}
|
||||
|
||||
protocol P4<T>: AnyObject {
|
||||
associatedtype T: Q
|
||||
|
||||
var t: T { get }
|
||||
|
||||
func foo()
|
||||
}
|
||||
|
||||
extension P4 {
|
||||
func foo() {
|
||||
t.bar()
|
||||
}
|
||||
}
|
||||
|
||||
final class C4<T: Q>: P4 {
|
||||
var t: T
|
||||
|
||||
|
||||
init(t: T) { self.t = t }
|
||||
}
|
||||
|
||||
class K4<I: BinaryInteger>: Q {
|
||||
var x: I
|
||||
|
||||
init(x: I) { self.x = x }
|
||||
|
||||
func bar() {
|
||||
print(x)
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func testP4() -> any P4 {
|
||||
return C4(t: K4(x: 437))
|
||||
}
|
||||
|
||||
|
||||
|
||||
@main
|
||||
struct Main {
|
||||
static func main() {
|
||||
@@ -181,6 +257,10 @@ struct Main {
|
||||
// CHECK: Derived2.bar()
|
||||
testConditionalConformance(t: S(i: 27))
|
||||
// CHECK: 27
|
||||
testP3().foo()
|
||||
// CHECK: 102
|
||||
testP4().foo()
|
||||
// CHECK: 437
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user