Skip to content

Commit 23b4c6f

Browse files
committed
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
1 parent ecfa808 commit 23b4c6f

File tree

3 files changed

+106
-5
lines changed

3 files changed

+106
-5
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/GenericSpecialization.swift

+7-4
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,14 @@ func specializeWitnessTable(forConformance conformance: Conformance,
144144
case .associatedType(let requirement, let witness):
145145
let substType = witness.subst(with: conformance.specializedSubstitutions)
146146
return .associatedType(requirement: requirement, witness: substType)
147-
case .associatedConformance(let requirement, let proto, let witness):
148-
if witness.isSpecialized {
149-
specializeWitnessTable(forConformance: witness, errorLocation: errorLocation, context, notifyNewWitnessTable)
147+
case .associatedConformance(let requirement, let proto, _):
148+
let concreteAssociateConf = conformance.getAssociatedConformance(ofAssociatedType: requirement.type, to: proto)
149+
if concreteAssociateConf.isSpecialized {
150+
specializeWitnessTable(forConformance: concreteAssociateConf,
151+
errorLocation: errorLocation,
152+
context, notifyNewWitnessTable)
150153
}
151-
return .associatedConformance(requirement: requirement, protocol: proto, witness: witness)
154+
return .associatedConformance(requirement: requirement, protocol: proto, witness: concreteAssociateConf)
152155
}
153156
}
154157
let newWT = context.createWitnessTable(entries: newEntries,conformance: conformance,

lib/IRGen/GenProto.cpp

+19-1
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,13 @@ namespace {
959959
}
960960

961961
void addAssociatedConformance(const AssociatedConformance &req) {
962+
if (req.getAssociation()->getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
963+
!req.getAssociatedRequirement()->requiresClass()) {
964+
// If it's not a class protocol, the associated type can never be used to create
965+
// an existential. Therefore this witness entry is never used at runtime
966+
// in embedded swift.
967+
return;
968+
}
962969
Entries.push_back(WitnessTableEntry::forAssociatedConformance(req));
963970
}
964971

@@ -1748,6 +1755,14 @@ class AccessorConformanceInfo : public ConformanceInfo {
17481755
(void)entry;
17491756
SILEntries = SILEntries.slice(1);
17501757

1758+
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded) &&
1759+
!requirement.getAssociatedRequirement()->requiresClass()) {
1760+
// If it's not a class protocol, the associated type can never be used to create
1761+
// an existential. Therefore this witness entry is never used at runtime
1762+
// in embedded swift.
1763+
return;
1764+
}
1765+
17511766
auto associate =
17521767
ConformanceInContext.getAssociatedType(
17531768
requirement.getAssociation())->getCanonicalType();
@@ -1775,7 +1790,10 @@ class AccessorConformanceInfo : public ConformanceInfo {
17751790
if (IGM.Context.LangOpts.hasFeature(Feature::Embedded)) {
17761791
// In Embedded Swift associated-conformance entries simply point to the witness table
17771792
// of the associated conformance.
1778-
llvm::Constant *witnessEntry = IGM.getAddrOfWitnessTable(associatedConformance.getConcrete());
1793+
ProtocolConformanceRef assocConf =
1794+
SILWT->getConformance()->getAssociatedConformance(requirement.getAssociation(),
1795+
requirement.getAssociatedRequirement());
1796+
llvm::Constant *witnessEntry = IGM.getAddrOfWitnessTable(assocConf.getConcrete());
17791797
auto &schema = IGM.getOptions().PointerAuth
17801798
.ProtocolAssociatedTypeWitnessTableAccessFunctions;
17811799
Table.addSignedPointer(witnessEntry, schema, requirement);

test/embedded/existential-class-bound1.swift

+80
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,82 @@ struct S: P2 {
156156
}
157157
}
158158

159+
protocol Q3 {
160+
func bar()
161+
}
162+
163+
protocol P3<T>: AnyObject {
164+
associatedtype T: Q3
165+
166+
var t: T { get }
167+
168+
func foo()
169+
}
170+
171+
extension P3 {
172+
func foo() {
173+
t.bar()
174+
}
175+
}
176+
177+
final class C3<T: Q3>: P3 {
178+
var t: T
179+
180+
181+
init(t: T) { self.t = t }
182+
}
183+
184+
struct S3<I: BinaryInteger>: Q3 {
185+
var x: I
186+
187+
func bar() {
188+
print(x)
189+
}
190+
}
191+
192+
@inline(never)
193+
func testP3() -> any P3 {
194+
return C3(t: S3(x: 102))
195+
}
196+
197+
protocol P4<T>: AnyObject {
198+
associatedtype T: Q
199+
200+
var t: T { get }
201+
202+
func foo()
203+
}
204+
205+
extension P4 {
206+
func foo() {
207+
t.bar()
208+
}
209+
}
210+
211+
final class C4<T: Q>: P4 {
212+
var t: T
213+
214+
215+
init(t: T) { self.t = t }
216+
}
217+
218+
class K4<I: BinaryInteger>: Q {
219+
var x: I
220+
221+
init(x: I) { self.x = x }
222+
223+
func bar() {
224+
print(x)
225+
}
226+
}
227+
228+
@inline(never)
229+
func testP4() -> any P4 {
230+
return C4(t: K4(x: 437))
231+
}
232+
233+
234+
159235
@main
160236
struct Main {
161237
static func main() {
@@ -181,6 +257,10 @@ struct Main {
181257
// CHECK: Derived2.bar()
182258
testConditionalConformance(t: S(i: 27))
183259
// CHECK: 27
260+
testP3().foo()
261+
// CHECK: 102
262+
testP4().foo()
263+
// CHECK: 437
184264
}
185265
}
186266

0 commit comments

Comments
 (0)