Skip to content

Commit 2c007d8

Browse files
authored
IRGen: use the accessor conformance on Windows (#40264)
When building with lazy initialization of the root conformance, we need to ensure that we are invoking the accessor to initialize the conformance record. We would previously generate a direct reference to the conformance, which was uninitialized, resulting in a crash at runtime. The non-windows test changes here are to use/imply static linking for the support modules. This should have no difference on the non-Windows targets, but makes a difference on Windows where this implies that everything will be built into a single module, which permits the non-indirect access to types. Unfortunately, this does somewhat regress the test coverage on Windows as we do not exercise as much of the shared linkage paths which do change some of the code-generation to deal with the moral equivalent of the GOT - the IAT. Special thanks to @slavapestov for the pointer to `isDependentConformance`. This should eliminate the last known issue with cross-module protocol conformances. Fixes: SR-14807 The 5.5-only test changes are due to the lack of support for static linking which means that all the support modules are treated as though they are behind a resiliency boundary on Windows. We relax the tests to accept both though on main we do not do so.
1 parent 9026b6e commit 2c007d8

8 files changed

+96
-11
lines changed

lib/IRGen/GenProto.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,12 @@ static bool isDependentConformance(
910910
if (!conformance)
911911
return false;
912912

913+
if (IGM.getOptions().LazyInitializeProtocolConformances) {
914+
const auto *MD = rootConformance->getDeclContext()->getParentModule();
915+
if (MD != IGM.getSwiftModule())
916+
return true;
917+
}
918+
913919
// Check whether we've visited this conformance already. If so,
914920
// optimistically assume it's fine --- we want the maximal fixed point.
915921
if (!visited.insert(conformance).second)

test/IRGen/conformance_resilience.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public func getConformance<T>(_ w: Wrapper<T>) {
2222
public func getConformance(_ w: ConcreteWrapper) {
2323
// CHECK: [[RESPONSE:%.*]] = call swiftcc %swift.metadata_response @"$s18resilient_protocol15ConcreteWrapperVMa"([[INT]] 0)
2424
// CHECK: [[META:%.*]] = extractvalue %swift.metadata_response [[RESPONSE]], 0
25-
// CHECK: call swiftcc void @"$s22conformance_resilience14useConformanceyyx18resilient_protocol22OtherResilientProtocolRzlF"(%swift.opaque* noalias nocapture %0, %swift.type* [[META]], i8** @"$s18resilient_protocol15ConcreteWrapperVAA22OtherResilientProtocolAAWP")
25+
// CHECK: call swiftcc void @"$s22conformance_resilience14useConformanceyyx18resilient_protocol22OtherResilientProtocolRzlF"(%swift.opaque* noalias nocapture %0, %swift.type* [[META]], i8** {{%[0-9]+|@"\$s18resilient_protocol15ConcreteWrapperVAA22OtherResilientProtocolAAWP"}})
2626
// CHECK: ret void
2727
useConformance(w)
2828
}

test/IRGen/lazy-root-conformance.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ extension E : Q {
2121
#endif
2222

2323
// CHECK-DIRECT: @"$s1A1EO1B1QADWP" ={{( dllexport)?}}{{( protected)?}} constant [2 x i8*] [i8* bitcast (%swift.protocol_conformance_descriptor* @"$s1A1EO1B1QADMc" to i8*), i8* bitcast (i8** @"$s1A1EOAA1PAAWP" to i8*)]
24-
// CHECK-INDIRECT: @"$s1A1EO1B1QADWP" ={{( dllexport)?}}{{( protected)?}} constant [2 x i8*] [i8* bitcast (%swift.protocol_conformance_descriptor* @"$s1A1EO1B1QADMc" to i8*), i8* null]
24+
// CHECK-INDIRECT: @"$s1A1EO1B1QADWP" ={{( dllexport)?}}{{( protected)?}} constant [2 x i8*] [i8* bitcast ({{.*}}* @"$s1A1EO1B1QADMc" to i8*), i8* null]
2525

test/IRGen/opaque_result_type_metadata_peephole.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,25 @@ dynamic var replaceable_opaque_var: some P {
4242
// CHECK-LABEL: define {{.*}} @"$s36opaque_result_type_metadata_peephole26testOpaqueMetadataAccessesyyF"
4343
public func testOpaqueMetadataAccesses() {
4444
// We can look through, since it's internal
45-
// DEFAULT: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* @"$sSiN", i8** @"$sSi36opaque_result_type_metadata_external1PAAWP")
45+
// DEFAULT: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* @"$sSiN", i8** {{%[0-9]+|@"\$sSi36opaque_result_type_metadata_external1PAAWP"}})
4646
// IMPLICIT-DYNAMIC: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* %{{.*}}, i8** %{{.*}})
4747
bar(x: foo())
4848
// We can look through, since it's internal
49-
// DEFAULT: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* @"$sSiN", i8** @"$sSi36opaque_result_type_metadata_external1PAAWP")
49+
// DEFAULT: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* @"$sSiN", i8** {{%[0-9]+|@"\$sSi36opaque_result_type_metadata_external1PAAWP"}})
5050
// IMPLICIT-DYNAMIC: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* %{{.*}}, i8** %{{.*}})
5151
bar(x: foo2())
5252
// We can't look through, since it's resilient
5353
// CHECK: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* %[[EXTERNAL_OPAQUE_METADATA:.*]], i8** %[[EXTERNAL_OPAQUE_PROTO:.*]])
5454
bar(x: external_opaque())
5555
// We can look through, since it's inlinable
56-
// CHECK: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* @"$sSiN", i8** @"$sSi36opaque_result_type_metadata_external1PAAWP")
56+
// CHECK: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* @"$sSiN", i8** {{%[0-9]+|@"\$sSi36opaque_result_type_metadata_external1PAAWP"}})
5757
bar(x: external_inlinable())
5858
// We can look through to the wrapped resilient opaque type
5959
// DEFAULT: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* %[[EXTERNAL_OPAQUE_METADATA]], i8** %[[EXTERNAL_OPAQUE_PROTO]])
6060
// IMPLICIT-DYNAMIC: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* %{{.*}}, i8** %{{.*}})
6161
bar(x: external_opaque_wrap())
6262
// We can look all the way through to the inlinable underlying type
63-
// DEFAULT: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* @"$sSiN", i8** @"$sSi36opaque_result_type_metadata_external1PAAWP")
63+
// DEFAULT: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* @"$sSiN", i8** {{%[0-9]+|@"\$sSi36opaque_result_type_metadata_external1PAAWP"}})
6464
// IMPLICIT-DYNAMIC: call {{.*}}3bar{{.*}}(%swift.opaque* {{.*}}, %swift.type* %{{.*}}, i8** %{{.*}})
6565
bar(x: external_inlinable_wrap())
6666

test/IRGen/sil_witness_tables.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %target-swift-frontend -emit-module -o %t %S/sil_witness_tables_external_conformance.swift
3-
// RUN: %target-swift-frontend -I %t -primary-file %s -emit-ir | %FileCheck %s
3+
// RUN: %target-swift-frontend -I %t -primary-file %s -emit-ir | %FileCheck %s -check-prefix CHECK -check-prefix CHECK-%target-import-type
44

55
// REQUIRES: CPU=x86_64
66

@@ -36,7 +36,7 @@ struct Conformer: Q, QQ {
3636
func qMethod() {}
3737
}
3838

39-
// CHECK: [[EXTERNAL_CONFORMER_EXTERNAL_P_WITNESS_TABLE:@"\$s39sil_witness_tables_external_conformance17ExternalConformerVAA0F1PAAWP"]] = external{{( dllimport)?}} global i8*, align 8
39+
// CHECK-DIRECT: [[EXTERNAL_CONFORMER_EXTERNAL_P_WITNESS_TABLE:@"\$s39sil_witness_tables_external_conformance17ExternalConformerVAA0F1PAAWP"]] = external{{( dllimport)?}} global i8*, align 8
4040
// CHECK: [[CONFORMER_Q_WITNESS_TABLE:@"\$s18sil_witness_tables9ConformerVAA1QAAWP"]] = hidden constant [3 x i8*] [
4141
// CHECK: i8* bitcast ([5 x i8*]* [[CONFORMER_P_WITNESS_TABLE:@"\$s18sil_witness_tables9ConformerVAA1PAAWP"]] to i8*),
4242
// CHECK: i8* bitcast (void (%T18sil_witness_tables9ConformerV*, %swift.type*, i8**)* @"$s18sil_witness_tables9ConformerVAA1QA2aDP7qMethod{{[_0-9a-zA-Z]*}}FTW" to i8*)
@@ -66,7 +66,8 @@ func erasure(c: Conformer) -> QQ {
6666

6767
// CHECK-LABEL: define hidden swiftcc void @"$s18sil_witness_tables15externalErasure1c0a1_b1_c1_D12_conformance9ExternalP_pAD0G9ConformerV_tF"(%T39sil_witness_tables_external_conformance9ExternalPP* noalias nocapture sret({{.*}}) %0)
6868
// CHECK: [[WITNESS_TABLE_ADDR:%.*]] = getelementptr inbounds %T39sil_witness_tables_external_conformance9ExternalPP, %T39sil_witness_tables_external_conformance9ExternalPP* %0, i32 0, i32 2
69-
// CHECK-NEXT: store i8** [[EXTERNAL_CONFORMER_EXTERNAL_P_WITNESS_TABLE]], i8*** %2, align 8
69+
// CHECK-DIRECT-NEXT: store i8** [[EXTERNAL_CONFORMER_EXTERNAL_P_WITNESS_TABLE]], i8*** %2, align 8
70+
// CHECK-INDIRECT-NEXT: store i8** %2, i8*** %3, align 8
7071
func externalErasure(c: ExternalConformer) -> ExternalP {
7172
return c
7273
}

test/IRGen/sil_witness_tables_external_witnesstable.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %target-swift-frontend -emit-module %S/Inputs/sil_witness_tables_external_input.swift -o %t/Swift.swiftmodule -parse-stdlib -parse-as-library -module-name Swift -module-link-name swiftCore
3-
// RUN: %target-swift-frontend -I %t -primary-file %s -emit-ir | %FileCheck %s
3+
// RUN: %target-swift-frontend -I %t -primary-file %s -emit-ir | %FileCheck %s -check-prefix CHECK -check-prefix CHECK-%target-import-type
44

55
import Swift
66

77
// CHECK: @"$ss1XVN" = external {{(dllimport )?}}global %swift.type
8-
// CHECK: @"$ss1XVs1PsWP" = external {{(dllimport )?}}global i8*
8+
// CHECK-DIRECT: @"$ss1XVs1PsWP" = external {{(dllimport )?}}global i8*
9+
// CHECK-INDIRECT-NOT: @"$ss1XVs1PsWP" = external {{(dllimport )?}}global i8*
910

1011
func doSomething<T : P>(_ t : T) -> Y {
1112
return t.doSomething()
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %target-swift-frontend -S -emit-ir %s -o - | %FileCheck %s
2+
// REQUIRES: OS=windows-msvc
3+
4+
class C {
5+
static func encode(_ c: Encodable) throws {}
6+
}
7+
8+
public protocol P: Codable {}
9+
10+
extension String: P {}
11+
12+
public enum E {
13+
case associated(P)
14+
}
15+
16+
extension E: Encodable {
17+
public func encode(to encoder: Encoder) throws {
18+
switch self {
19+
case .associated(let p):
20+
try p.encode(to: encoder)
21+
}
22+
}
23+
}
24+
25+
try? print(C.encode(E.associated("string")))
26+
27+
// CHECK-NOT: store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @"$sSS4main1PAAWP", i32 0, i32 0), i8***

test/IRGen/windows-linking.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -target x86_64-unknown-windows-msvc -parse-as-library -parse-stdlib -emit-module -emit-module-path %t/module.swiftmodule -module-name module -DMODULE %s
3+
// RUN: %target-swift-frontend -target x86_64-unknown-windows-msvc -parse-as-library -parse-stdlib -S -emit-ir %s -module-name main -o - -I%t | %FileCheck %s -check-prefix CHECK-SHARED
4+
5+
#if MODULE
6+
7+
public struct S {}
8+
public var value: S {
9+
S()
10+
}
11+
12+
public func f(_ s: S) {}
13+
14+
public protocol P {
15+
}
16+
17+
public enum E: P {
18+
}
19+
20+
#else
21+
22+
import module
23+
24+
protocol Q: P {
25+
}
26+
27+
extension E: Q {
28+
}
29+
30+
@main
31+
struct Entry {
32+
public static func main() {
33+
f(value)
34+
}
35+
}
36+
37+
#endif
38+
39+
40+
// Ensure that shared linking does mark the functions as being indirected
41+
// through the IAT.
42+
43+
// CHECK-SHARED: @"$s6module1EO4main1QADWP" = hidden constant [2 x i8*] [
44+
// CHECK-SHARED-SAME: i8* bitcast ({ i32, i32, i32, i32, i16, i16, i32, i32 }* @"$s6module1EO4main1QADMc" to i8*),
45+
// CHECK-SHARED-SAME: i8* null
46+
// CHECK-SHARED-SAME: ]
47+
48+
// CHECK-SHARED: declare dllimport swiftcc void @"$s6module5valueAA1SVvg"()
49+
50+
// CHECK-SHARED: declare dllimport swiftcc void @"$s6module1fyyAA1SVF"()

0 commit comments

Comments
 (0)