Skip to content

Commit 564e63c

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 6cb3181 commit 564e63c

File tree

6 files changed

+120
-30
lines changed

6 files changed

+120
-30
lines changed

lib/IRGen/GenReflection.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -317,11 +317,12 @@ getRuntimeVersionThatSupportsDemanglingType(CanType type) {
317317
static std::pair<llvm::Constant *, unsigned>
318318
getTypeRefByFunction(IRGenModule &IGM,
319319
CanGenericSignature sig,
320-
CanType t) {
320+
CanType t,
321+
MangledTypeRefRole role) {
321322
IRGenMangler mangler(IGM.Context);
322323
std::string symbolName =
323324
mangler.mangleSymbolNameForMangledMetadataAccessorString(
324-
"get_type_metadata", sig, t);
325+
"get_type_metadata", sig, t, role);
325326
auto constant = IGM.getAddrOfStringForMetadataRef(symbolName, /*align*/2,
326327
/*low bit*/false,
327328
[&](ConstantInitBuilder &B) {
@@ -352,9 +353,22 @@ getTypeRefByFunction(IRGenModule &IGM,
352353
? genericEnv->mapTypeIntoContext(t)->getCanonicalType()
353354
: t;
354355

355-
// If a type is noncopyable, lie about the resolved type unless the
356-
// runtime is sufficiently aware of noncopyable types.
357-
if (substT->isNoncopyable()) {
356+
// If a type is noncopyable, lie about the resolved type to reflection
357+
// APIs unless the runtime is sufficiently aware of noncopyable types.
358+
bool shouldHideNoncopyableTypeFromOldRuntimes;
359+
switch (role) {
360+
case MangledTypeRefRole::Metadata:
361+
case MangledTypeRefRole::DefaultAssociatedTypeWitness:
362+
case MangledTypeRefRole::FlatUnique:
363+
shouldHideNoncopyableTypeFromOldRuntimes = false;
364+
break;
365+
case MangledTypeRefRole::FieldMetadata:
366+
case MangledTypeRefRole::Reflection:
367+
shouldHideNoncopyableTypeFromOldRuntimes = true;
368+
break;
369+
}
370+
if (shouldHideNoncopyableTypeFromOldRuntimes
371+
&& substT->isNoncopyable()) {
358372
// Darwin-based platforms have ABI stability, and we want binaries
359373
// that use noncopyable types nongenerically today to be forward
360374
// compatible with a future OS runtime that supports noncopyable
@@ -513,7 +527,7 @@ getTypeRefImpl(IRGenModule &IGM,
513527
// the field will be artificially hidden to reflectors.
514528
if (isAlwaysNoncopyable) {
515529
IGM.IRGen.noteUseOfTypeMetadata(type);
516-
return getTypeRefByFunction(IGM, sig, type);
530+
return getTypeRefByFunction(IGM, sig, type, role);
517531
}
518532
}
519533
LLVM_FALLTHROUGH;
@@ -529,7 +543,7 @@ getTypeRefImpl(IRGenModule &IGM,
529543
// this mangled name, then fall back to generating a "mangled name" with a
530544
// symbolic reference with a callback function.
531545
if (mangledNameIsUnknownToDeployTarget(IGM, type)) {
532-
return getTypeRefByFunction(IGM, sig, type);
546+
return getTypeRefByFunction(IGM, sig, type, role);
533547
}
534548

535549
break;

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: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ 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.3"
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.4"
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.3"
48+
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyxG noncopyable
4949
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyq_G.4"
50-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyAA03NonC0VG.5"
50+
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOyAA03NonC0VG noncopyable
5151
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test21ConditionallyCopyableOySSG.6"
5252
public class CC_Tests<NCG: ~Copyable, T> {
5353
var ccNCG: ConditionallyCopyable<NCG> = .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.5"
66-
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyq_G.6"
67-
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyAA03NonC0VG.7"
68-
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOySSG.8"
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.7"
72-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyq_G.8"
73-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyAA03NonC0VG.9"
74-
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOySSG.10"
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.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.11"
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.10"
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.12"
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)