Skip to content

Commit 0e33fe1

Browse files
committed
IRGen: Don't hide noncopyable metadata from access functions in load-bearing mangled names.
There is a compatibility hack where fallback metadata access functions used in field type metadata lie and say a field's type is the empty tuple when it's noncopyable and the runtime doesn't advertise compatibility with noncopyable types. Unfortunately, this hack applied to *all* fallback metadata access functions, causing us to return wrong metadata in situations we really need the correct metadata, such as in associated type substitutions. Constrain the hack to only apply to reflection metadata. Fixes rdar://161562839.
1 parent d3214de commit 0e33fe1

File tree

6 files changed

+118
-29
lines changed

6 files changed

+118
-29
lines changed

lib/IRGen/GenReflection.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ getTypeRefByFunction(IRGenModule &IGM, CanGenericSignature sig, CanType t,
320320
IRGenMangler mangler(IGM.Context);
321321
std::string symbolName =
322322
mangler.mangleSymbolNameForMangledMetadataAccessorString(
323-
"get_type_metadata", sig, t);
323+
"get_type_metadata", sig, t, role);
324324
auto constant = IGM.getAddrOfStringForMetadataRef(symbolName, /*align*/2,
325325
/*low bit*/false,
326326
[&](ConstantInitBuilder &B) {
@@ -351,9 +351,22 @@ getTypeRefByFunction(IRGenModule &IGM, CanGenericSignature sig, CanType t,
351351
? genericEnv->mapTypeIntoContext(t)->getCanonicalType()
352352
: t;
353353

354-
// If a type is noncopyable, lie about the resolved type unless the
355-
// runtime is sufficiently aware of noncopyable types.
356-
if (substT->isNoncopyable()) {
354+
// If a type is noncopyable, lie about the resolved type to reflection
355+
// APIs unless the runtime is sufficiently aware of noncopyable types.
356+
bool shouldHideNoncopyableTypeFromOldRuntimes;
357+
switch (role) {
358+
case MangledTypeRefRole::Metadata:
359+
case MangledTypeRefRole::DefaultAssociatedTypeWitness:
360+
case MangledTypeRefRole::FlatUnique:
361+
shouldHideNoncopyableTypeFromOldRuntimes = false;
362+
break;
363+
case MangledTypeRefRole::FieldMetadata:
364+
case MangledTypeRefRole::Reflection:
365+
shouldHideNoncopyableTypeFromOldRuntimes = true;
366+
break;
367+
}
368+
if (shouldHideNoncopyableTypeFromOldRuntimes
369+
&& substT->isNoncopyable()) {
357370
// Darwin-based platforms have ABI stability, and we want binaries
358371
// that use noncopyable types nongenerically today to be forward
359372
// compatible with a future OS runtime that supports noncopyable

lib/IRGen/IRGenMangler.cpp

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
#include "IRGenMangler.h"
1414
#include "ExtendedExistential.h"
1515
#include "GenClass.h"
16+
#include "IRGenModule.h"
1617
#include "swift/AST/ExistentialLayout.h"
18+
#include "swift/AST/GenericEnvironment.h"
1719
#include "swift/AST/IRGenOptions.h"
1820
#include "swift/AST/ProtocolAssociations.h"
1921
#include "swift/AST/ProtocolConformance.h"
@@ -414,15 +416,44 @@ std::string IRGenMangler::mangleSymbolNameForAssociatedConformanceWitness(
414416
std::string IRGenMangler::mangleSymbolNameForMangledMetadataAccessorString(
415417
const char *kind,
416418
CanGenericSignature genericSig,
417-
CanType type) {
419+
CanType type,
420+
MangledTypeRefRole role) {
418421
beginManglingWithoutPrefix();
419422
Buffer << kind << " ";
420423

421-
if (genericSig)
424+
if (genericSig) {
422425
appendGenericSignature(genericSig);
426+
}
423427

424-
if (type)
428+
if (type) {
425429
appendType(type, genericSig);
430+
}
431+
432+
// Noncopyable types get additional runtime capability checks before we reveal
433+
// their metadata to reflection APIs, while core metadata queries always provide
434+
// the metadata. So we need a separate symbol mangling for the two variants in
435+
// this case.
436+
switch (role) {
437+
case MangledTypeRefRole::DefaultAssociatedTypeWitness:
438+
case MangledTypeRefRole::FlatUnique:
439+
case MangledTypeRefRole::Metadata:
440+
// Core metadata, never conditionalized.
441+
break;
442+
443+
case MangledTypeRefRole::Reflection:
444+
case MangledTypeRefRole::FieldMetadata: {
445+
// Reflection metadata is conditionalized for noncopyable types.
446+
CanType contextType = type;
447+
if (genericSig) {
448+
contextType = genericSig.getGenericEnvironment()->mapTypeIntoContext(contextType)
449+
->getReducedType(genericSig);
450+
}
451+
if (contextType->isNoncopyable()) {
452+
Buffer << " noncopyable";
453+
}
454+
}
455+
}
456+
426457
return finalize();
427458
}
428459

lib/IRGen/IRGenMangler.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,8 @@ class IRGenMangler : public Mangle::ASTMangler {
685685
std::string mangleSymbolNameForMangledMetadataAccessorString(
686686
const char *kind,
687687
CanGenericSignature genericSig,
688-
CanType type);
688+
CanType type,
689+
MangledTypeRefRole role);
689690

690691
std::string mangleSymbolNameForMangledConformanceAccessorString(
691692
const char *kind,

lib/IRGen/TypeLayout.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,8 @@ llvm::Function *createMetatypeAccessorFunction(IRGenModule &IGM, SILType ty,
472472
std::string symbolName =
473473
mangler.mangleSymbolNameForMangledMetadataAccessorString(
474474
"get_type_metadata_for_layout_string", sig,
475-
fieldType->mapTypeOutOfContext()->getCanonicalType());
475+
fieldType->mapTypeOutOfContext()->getCanonicalType(),
476+
MangledTypeRefRole::Metadata);
476477

477478
auto helperFn = IGM.getOrCreateHelperFunction(
478479
symbolName, IGM.TypeMetadataPtrTy /*retTy*/,
@@ -1738,7 +1739,8 @@ AlignedGroupEntry::layoutString(IRGenModule &IGM,
17381739
std::string symbolName =
17391740
mangler.mangleSymbolNameForMangledMetadataAccessorString(
17401741
"type_layout_string", genericSig.getCanonicalSignature(),
1741-
ty.getASTType()->mapTypeOutOfContext()->getCanonicalType());
1742+
ty.getASTType()->mapTypeOutOfContext()->getCanonicalType(),
1743+
MangledTypeRefRole::Metadata);
17421744

17431745
auto *global = SB.finishAndCreateGlobal(symbolName, IGM.getPointerAlignment(),
17441746
/*constant*/ true);
@@ -2339,7 +2341,8 @@ EnumTypeLayoutEntry::layoutString(IRGenModule &IGM,
23392341
std::string symbolName =
23402342
mangler.mangleSymbolNameForMangledMetadataAccessorString(
23412343
"type_layout_string", genericSig.getCanonicalSignature(),
2342-
ty.getASTType()->mapTypeOutOfContext()->getCanonicalType());
2344+
ty.getASTType()->mapTypeOutOfContext()->getCanonicalType(),
2345+
MangledTypeRefRole::Metadata);
23432346

23442347
auto *global = SB.finishAndCreateGlobal(symbolName, IGM.getPointerAlignment(),
23452348
/*constant*/ true);

test/IRGen/noncopyable_field_descriptors.swift

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@ public struct NonCopyable: ~Copyable { }
3939
// 'MF' constant as a separator that precedes each field descriptor.
4040

4141
// NEW: @"$s4test8CC_TestsCMF" =
42-
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyxG.{{[0-9]+}}"
42+
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyxG noncopyable
4343
// NEW-SAME: @"symbolic _____yq_G 4test21ConditionallyCopyableOAARi_zrlE"
44-
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyAA03NonC0VG.{{[0-9]+}}"
44+
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyAA03NonC0VG noncopyable
4545
// NEW-SAME: @"symbolic _____ySSG 4test21ConditionallyCopyableOAARi_zrlE"
4646

4747
// OLD: @"$s4test8CC_TestsCMF" =
48-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyxG.{{[0-9]+}}"
49-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyq_G.{{[0-9]+}}"
50-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyAA03NonC0VG.{{[0-9]+}}"
51-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOySSG.{{[0-9]+}}"
48+
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyxG noncopyable
49+
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyq_G
50+
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyAA03NonC0VG noncopyable
51+
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOySSG
5252
public class CC_Tests<NCG: ~Copyable, T> {
5353
var ccNCG: ConditionallyCopyable<NCG> = .none
5454
var ccT: ConditionallyCopyable<T> = .none
@@ -62,16 +62,16 @@ public class CC_Tests<NCG: ~Copyable, T> {
6262
/// fields until a future runtime says they're safe to reflect.
6363

6464
// NEW: @"$s4test8NC_TestsCMF" =
65-
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyxG.{{[0-9]+}}"
66-
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyq_G.{{[0-9]+}}"
67-
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyAA03NonC0VG.{{[0-9]+}}"
68-
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOySSG.{{[0-9]+}}"
65+
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyxG noncopyable
66+
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyq_G noncopyable
67+
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyAA03NonC0VG noncopyable
68+
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOySSG noncopyable
6969

7070
// OLD: @"$s4test8NC_TestsCMF" =
71-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyxG.{{[0-9]+}}"
72-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyq_G.{{[0-9]+}}"
73-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyAA03NonC0VG.{{[0-9]+}}"
74-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOySSG.{{[0-9]+}}"
71+
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyxG noncopyable
72+
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyq_G noncopyable
73+
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyAA03NonC0VG noncopyable
74+
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOySSG noncopyable
7575
public class NC_Tests<NCG: ~Copyable, T> {
7676
var ncNCG: NeverCopyable<NCG> = .none
7777
var ncT: NeverCopyable<T> = .none
@@ -83,7 +83,7 @@ public class NC_Tests<NCG: ~Copyable, T> {
8383
// NEW: @"$s4test17StdlibTypes_TestsCMF" =
8484
// NEW-SAME: @"symbolic xSg"
8585
// NEW-SAME: @"symbolic q_Sg"
86-
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableVSg.{{[0-9]+}}"
86+
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableVSg noncopyable
8787
// NEW-SAME: @"symbolic SSSg"
8888
// NEW-SAME: @"symbolic SPyxG"
8989
// NEW-SAME: @"symbolic SPyq_G"
@@ -93,7 +93,7 @@ public class NC_Tests<NCG: ~Copyable, T> {
9393
// OLD: @"$s4test17StdlibTypes_TestsCMF" =
9494
// OLD-SAME: @"symbolic xSg"
9595
// OLD-SAME: @"symbolic q_Sg"
96-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableVSg.{{[0-9]+}}"
96+
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableVSg noncopyable
9797
// OLD-SAME: @"symbolic SSSg"
9898
// OLD-SAME: @"symbolic SPyxG"
9999
// OLD-SAME: @"symbolic SPyq_G"
@@ -115,13 +115,13 @@ public class StdlibTypes_Tests<NCG: ~Copyable, T> {
115115
// NEW: @"$s4test19PlainlyStored_TestsCMF" =
116116
// NEW-SAME: @"symbolic x"
117117
// NEW-SAME: @"symbolic q_"
118-
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableV.{{[0-9]+}}"
118+
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableV noncopyable
119119
// NEW-SAME: @"symbolic SS"
120120

121121
// OLD: @"$s4test19PlainlyStored_TestsCMF" =
122122
// OLD-SAME: @"symbolic x"
123123
// OLD-SAME: @"symbolic q_"
124-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableV.{{[0-9]+}}"
124+
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableV noncopyable
125125
// OLD-SAME: @"symbolic SS"
126126
public class PlainlyStored_Tests<NCG: ~Copyable, T> {
127127
var ncg: NCG
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %target-run-simple-swift(-enable-experimental-feature SuppressedAssociatedTypes)
2+
// REQUIRES: executable_test
3+
4+
// Noncopyable types are suppressed in field metadata in runtimes lacking
5+
// reflection support for them (currently all runtimes). However, we want
6+
// to ensure that noncopyable type metadata is still produced where it is
7+
// "load-bearing" to the generics system, such as in associated types in
8+
// protocol conformances.
9+
10+
protocol Barrable: ~Copyable {
11+
}
12+
13+
struct Bar<T: ~Copyable>: Barrable & ~Copyable {
14+
var x: Int = 0
15+
}
16+
17+
protocol F: ~Copyable {
18+
associatedtype B: Barrable & ~Copyable
19+
}
20+
21+
struct Foo: F & ~Copyable {
22+
typealias B = Bar<Int>
23+
}
24+
25+
func test<T: F & ~Copyable>(_: T.Type) {
26+
print("\(T.B.self)")
27+
}
28+
29+
// CHECK: Bar<Int>
30+
test(Foo.self)
31+
32+
class Mirrored {
33+
var noncopyableField: Bar<Int>
34+
35+
init() {
36+
self.noncopyableField = Bar()
37+
}
38+
}
39+
40+
// CHECK: noncopyableField (0 elements)
41+
dump(Mirrored())

0 commit comments

Comments
 (0)