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):
|
case .associatedType(let requirement, let witness):
|
||||||
let substType = witness.subst(with: conformance.specializedSubstitutions)
|
let substType = witness.subst(with: conformance.specializedSubstitutions)
|
||||||
return .associatedType(requirement: requirement, witness: substType)
|
return .associatedType(requirement: requirement, witness: substType)
|
||||||
case .associatedConformance(let requirement, let proto, let witness):
|
case .associatedConformance(let requirement, let proto, _):
|
||||||
if witness.isSpecialized {
|
let concreteAssociateConf = conformance.getAssociatedConformance(ofAssociatedType: requirement.type, to: proto)
|
||||||
specializeWitnessTable(forConformance: witness, errorLocation: errorLocation, context, notifyNewWitnessTable)
|
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,
|
let newWT = context.createWitnessTable(entries: newEntries,conformance: conformance,
|
||||||
|
|||||||
@@ -959,6 +959,13 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void addAssociatedConformance(const AssociatedConformance &req) {
|
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));
|
Entries.push_back(WitnessTableEntry::forAssociatedConformance(req));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1748,6 +1755,14 @@ public:
|
|||||||
(void)entry;
|
(void)entry;
|
||||||
SILEntries = SILEntries.slice(1);
|
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 =
|
auto associate =
|
||||||
ConformanceInContext.getAssociatedType(
|
ConformanceInContext.getAssociatedType(
|
||||||
requirement.getAssociation())->getCanonicalType();
|
requirement.getAssociation())->getCanonicalType();
|
||||||
@@ -1775,7 +1790,10 @@ public:
|
|||||||
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
|
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
|
||||||
// In Embedded Swift associated-conformance entries simply point to the witness table
|
// In Embedded Swift associated-conformance entries simply point to the witness table
|
||||||
// of the associated conformance.
|
// 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
|
auto &schema = IGM.getOptions().PointerAuth
|
||||||
.ProtocolAssociatedTypeWitnessTableAccessFunctions;
|
.ProtocolAssociatedTypeWitnessTableAccessFunctions;
|
||||||
Table.addSignedPointer(witnessEntry, schema, requirement);
|
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
|
@main
|
||||||
struct Main {
|
struct Main {
|
||||||
static func main() {
|
static func main() {
|
||||||
@@ -181,6 +257,10 @@ struct Main {
|
|||||||
// CHECK: Derived2.bar()
|
// CHECK: Derived2.bar()
|
||||||
testConditionalConformance(t: S(i: 27))
|
testConditionalConformance(t: S(i: 27))
|
||||||
// CHECK: 27
|
// CHECK: 27
|
||||||
|
testP3().foo()
|
||||||
|
// CHECK: 102
|
||||||
|
testP4().foo()
|
||||||
|
// CHECK: 437
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user