Skip to content

Commit 6767f2e

Browse files
committed
NCGenerics: fix runtime demangling strategy
We generally should use the open-coded, metadata function "accessor" strategy when targeting older runtimes, but if the type is part of the stdlib, assume the runtime demangler will produce correct metadata, as the retrofitting of Optional, etc, was done Carefully. resolves rdar://131337585
1 parent 9d2af57 commit 6767f2e

File tree

2 files changed

+147
-0
lines changed

2 files changed

+147
-0
lines changed

lib/IRGen/GenReflection.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,25 @@ getRuntimeVersionThatSupportsDemanglingType(CanType type) {
226226
// involving them.
227227
}
228228

229+
/// Any nominal type that has an inverse requirement in its generic
230+
/// signature uses NoncopyableGenerics. Since inverses are mangled into
231+
/// symbols, a Swift 6.0+ runtime is generally needed to demangle them.
232+
///
233+
/// We make an exception for types in the stdlib, like Optional, since the
234+
/// runtime should still be able to demangle them, based on the availability
235+
/// of the type.
236+
if (auto nominalTy = dyn_cast<NominalOrBoundGenericNominalType>(t)) {
237+
auto *nom = nominalTy->getDecl();
238+
if (auto sig = nom->getGenericSignature()) {
239+
SmallVector<InverseRequirement, 2> inverses;
240+
SmallVector<Requirement, 2> reqs;
241+
sig->getRequirementsWithInverses(reqs, inverses);
242+
if (!inverses.empty() && !nom->getModuleContext()->isStdlibModule()) {
243+
return addRequirement(Swift_6_0);
244+
}
245+
}
246+
}
247+
229248
return false;
230249
});
231250

@@ -358,6 +377,7 @@ getTypeRefByFunction(IRGenModule &IGM,
358377
Address(bindingsBufPtr, IGM.Int8Ty, IGM.getPointerAlignment()),
359378
MetadataState::Complete, subs);
360379

380+
substT = substT.getReferenceStorageReferent();
361381
auto ret = IGF.emitTypeMetadataRef(substT);
362382
IGF.Builder.CreateRet(ret);
363383
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %swift-frontend %s -swift-version 6 -module-name main -emit-ir -o %t/new.ir
3+
// RUN: %FileCheck %s --check-prefix=NEW < %t/new.ir
4+
// RUN: %target-swift-frontend %s -target %target-cpu-apple-macosx11 -module-name main -emit-ir -o %t/old.ir
5+
// RUN: %FileCheck %s --check-prefix=OLD < %t/old.ir
6+
7+
// Check that we add extra type metadata accessors for types with generic
8+
// parameters that have an inverse. These are used instead of using demangling
9+
// cache variables since old runtimes cannot synthesize type metadata based on
10+
// the new mangling.
11+
12+
// RUN: %target-build-swift -target %target-cpu-apple-macosx11 %s -o %t/test_mangling
13+
// RUN: %target-run %t/test_mangling | %FileCheck %s
14+
15+
// REQUIRES: OS=macosx
16+
// REQUIRES: executable_test
17+
18+
19+
// This type's generic parameter is noncopyable, so older runtimes can't
20+
// demangle the type's name to build the metadata.
21+
struct Foo<T: ~Copyable>: ~Copyable {
22+
mutating func bar(_ i: Int) { print("Foo.bar(\(i))") }
23+
}
24+
25+
func test() {
26+
var foo = Foo<Int>()
27+
foo.bar(1)
28+
}
29+
test()
30+
// CHECK: Foo.bar(1)
31+
32+
// NEW: define hidden swiftcc void @"$s4main4testyyF"()
33+
// NEW: call ptr @__swift_instantiateConcreteTypeFromMangledName(ptr @"$s4main3FooVySiGMD")
34+
// NEW: }
35+
36+
// OLD: define hidden swiftcc void @"$s4main4testyyF"()
37+
// OLD: call swiftcc %swift.metadata_response @"$s4main3FooVySiGMa"(i64 0)
38+
// OLD: }
39+
40+
struct NC: ~Copyable {}
41+
42+
// NEW: define hidden swiftcc void @"$s4main10testWithNCyyF"()
43+
// NEW: call ptr @__swift_instantiateConcreteTypeFromMangledName(ptr @"$s4main3FooVyAA2NCVGMD")
44+
// NEW: }
45+
46+
// OLD: define hidden swiftcc void @"$s4main10testWithNCyyF"()
47+
// OLD: call swiftcc %swift.metadata_response @"$s4main3FooVyAA2NCVGMa"
48+
// OLD: }
49+
func testWithNC() {
50+
var foo = Foo<NC>()
51+
foo.bar(2)
52+
}
53+
testWithNC()
54+
// CHECK: Foo.bar(2)
55+
56+
57+
// NEW: define hidden swiftcc void @"$s4main17testWithNCGenericyyxnRi_zlF"
58+
// NEW: call swiftcc %swift.metadata_response @"$s4main3FooVMa"
59+
// NEW: }
60+
61+
// OLD: define hidden swiftcc void @"$s4main17testWithNCGenericyyxnRi_zlF"
62+
// OLD: call swiftcc %swift.metadata_response @"$s4main3FooVMa"
63+
// OLD: }
64+
func testWithNCGeneric<T: ~Copyable>(_ t: consuming T) {
65+
var foo = Foo<T>()
66+
foo.bar(3)
67+
}
68+
testWithNCGeneric(Foo<NC>())
69+
// CHECK: Foo.bar(3)
70+
71+
72+
// This type does not need a Swift 6.0 runtime, despite being noncopyable,
73+
// because it doesn't have a noncopyable generic parameter.
74+
struct JustNoncopyable<T>: ~Copyable {
75+
mutating func bar() { print("JustNoncopyable.bar") }
76+
}
77+
78+
func testNonGeneric() {
79+
var ng = JustNoncopyable<Int>()
80+
ng.bar()
81+
}
82+
testNonGeneric()
83+
// CHECK: JustNoncopyable.bar
84+
85+
// NEW: define hidden swiftcc void @"$s4main14testNonGenericyyF"()
86+
// NEW: call ptr @__swift_instantiateConcreteTypeFromMangledName(ptr @"$s4main15JustNoncopyableVySiGMD")
87+
// NEW: }
88+
89+
// OLD: define hidden swiftcc void @"$s4main14testNonGenericyyF"()
90+
// OLD: call ptr @__swift_instantiateConcreteTypeFromMangledName(ptr @"$s4main15JustNoncopyableVySiGMD")
91+
// OLD: }
92+
93+
94+
/// Check that Optional still uses `__swift_instantiateConcreteTypeFromMangledName`
95+
/// even when calling a method available to a noncopyable Optional.
96+
extension Optional where Wrapped: ~Copyable {
97+
mutating func bar(_ i: Int) { print("Optional.bar(\(i))") }
98+
}
99+
100+
// NEW: define hidden swiftcc void @"$s4main20testCopyableOptionalyyF"()
101+
// NEW: call ptr @__swift_instantiateConcreteTypeFromMangledName(ptr @"$sSiSgMD")
102+
// NEW: }
103+
104+
// OLD: define hidden swiftcc void @"$s4main20testCopyableOptionalyyF"()
105+
// OLD: call ptr @__swift_instantiateConcreteTypeFromMangledName(ptr @"$sSiSgMD")
106+
// OLD: }
107+
func testCopyableOptional() {
108+
var opt = Optional<Int>(94103)
109+
opt.bar(1)
110+
}
111+
testCopyableOptional()
112+
// CHECK: Optional.bar(1)
113+
114+
115+
// NEW: define hidden swiftcc void @"$s4main23testNOTCopyableOptionalyyF"()
116+
// NEW: call ptr @__swift_instantiateConcreteTypeFromMangledName(ptr @"$s4main2NCVSgMD")
117+
// NEW: }
118+
119+
// OLD: define hidden swiftcc void @"$s4main23testNOTCopyableOptionalyyF"()
120+
// OLD: call ptr @__swift_instantiateConcreteTypeFromMangledName(ptr @"$s4main2NCVSgMD")
121+
// OLD: }
122+
func testNOTCopyableOptional() {
123+
var opt = Optional<NC>(NC())
124+
opt.bar(2)
125+
}
126+
testNOTCopyableOptional()
127+
// CHECK: Optional.bar(2)

0 commit comments

Comments
 (0)