Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions lib/IRGen/GenReflection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ getTypeRefByFunction(IRGenModule &IGM, CanGenericSignature sig, CanType t,
IRGenMangler mangler(IGM.Context);
std::string symbolName =
mangler.mangleSymbolNameForMangledMetadataAccessorString(
"get_type_metadata", sig, t);
"get_type_metadata", sig, t, role);
auto constant = IGM.getAddrOfStringForMetadataRef(symbolName, /*align*/2,
/*low bit*/false,
[&](ConstantInitBuilder &B) {
Expand Down Expand Up @@ -351,9 +351,22 @@ getTypeRefByFunction(IRGenModule &IGM, CanGenericSignature sig, CanType t,
? genericEnv->mapTypeIntoContext(t)->getCanonicalType()
: t;

// If a type is noncopyable, lie about the resolved type unless the
// runtime is sufficiently aware of noncopyable types.
if (substT->isNoncopyable()) {
// If a type is noncopyable, lie about the resolved type to reflection
// APIs unless the runtime is sufficiently aware of noncopyable types.
bool shouldHideNoncopyableTypeFromOldRuntimes;
switch (role) {
case MangledTypeRefRole::Metadata:
case MangledTypeRefRole::DefaultAssociatedTypeWitness:
case MangledTypeRefRole::FlatUnique:
shouldHideNoncopyableTypeFromOldRuntimes = false;
break;
case MangledTypeRefRole::FieldMetadata:
case MangledTypeRefRole::Reflection:
shouldHideNoncopyableTypeFromOldRuntimes = true;
break;
}
if (shouldHideNoncopyableTypeFromOldRuntimes
&& substT->isNoncopyable()) {
// Darwin-based platforms have ABI stability, and we want binaries
// that use noncopyable types nongenerically today to be forward
// compatible with a future OS runtime that supports noncopyable
Expand Down
37 changes: 34 additions & 3 deletions lib/IRGen/IRGenMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
#include "IRGenMangler.h"
#include "ExtendedExistential.h"
#include "GenClass.h"
#include "IRGenModule.h"
#include "swift/AST/ExistentialLayout.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/ProtocolAssociations.h"
#include "swift/AST/ProtocolConformance.h"
Expand Down Expand Up @@ -414,15 +416,44 @@ std::string IRGenMangler::mangleSymbolNameForAssociatedConformanceWitness(
std::string IRGenMangler::mangleSymbolNameForMangledMetadataAccessorString(
const char *kind,
CanGenericSignature genericSig,
CanType type) {
CanType type,
MangledTypeRefRole role) {
beginManglingWithoutPrefix();
Buffer << kind << " ";

if (genericSig)
if (genericSig) {
appendGenericSignature(genericSig);
}

if (type)
if (type) {
appendType(type, genericSig);
}

// Noncopyable types get additional runtime capability checks before we reveal
// their metadata to reflection APIs, while core metadata queries always provide
// the metadata. So we need a separate symbol mangling for the two variants in
// this case.
switch (role) {
case MangledTypeRefRole::DefaultAssociatedTypeWitness:
case MangledTypeRefRole::FlatUnique:
case MangledTypeRefRole::Metadata:
// Core metadata, never conditionalized.
break;

case MangledTypeRefRole::Reflection:
case MangledTypeRefRole::FieldMetadata: {
// Reflection metadata is conditionalized for noncopyable types.
CanType contextType = type;
if (genericSig) {
contextType = genericSig.getGenericEnvironment()->mapTypeIntoContext(contextType)
->getReducedType(genericSig);
}
if (contextType->isNoncopyable()) {
Buffer << " noncopyable";
}
}
}

return finalize();
}

Expand Down
3 changes: 2 additions & 1 deletion lib/IRGen/IRGenMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,8 @@ class IRGenMangler : public Mangle::ASTMangler {
std::string mangleSymbolNameForMangledMetadataAccessorString(
const char *kind,
CanGenericSignature genericSig,
CanType type);
CanType type,
MangledTypeRefRole role);

std::string mangleSymbolNameForMangledConformanceAccessorString(
const char *kind,
Expand Down
9 changes: 6 additions & 3 deletions lib/IRGen/TypeLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,8 @@ llvm::Function *createMetatypeAccessorFunction(IRGenModule &IGM, SILType ty,
std::string symbolName =
mangler.mangleSymbolNameForMangledMetadataAccessorString(
"get_type_metadata_for_layout_string", sig,
fieldType->mapTypeOutOfContext()->getCanonicalType());
fieldType->mapTypeOutOfContext()->getCanonicalType(),
MangledTypeRefRole::Metadata);

auto helperFn = IGM.getOrCreateHelperFunction(
symbolName, IGM.TypeMetadataPtrTy /*retTy*/,
Expand Down Expand Up @@ -1738,7 +1739,8 @@ AlignedGroupEntry::layoutString(IRGenModule &IGM,
std::string symbolName =
mangler.mangleSymbolNameForMangledMetadataAccessorString(
"type_layout_string", genericSig.getCanonicalSignature(),
ty.getASTType()->mapTypeOutOfContext()->getCanonicalType());
ty.getASTType()->mapTypeOutOfContext()->getCanonicalType(),
MangledTypeRefRole::Metadata);

auto *global = SB.finishAndCreateGlobal(symbolName, IGM.getPointerAlignment(),
/*constant*/ true);
Expand Down Expand Up @@ -2339,7 +2341,8 @@ EnumTypeLayoutEntry::layoutString(IRGenModule &IGM,
std::string symbolName =
mangler.mangleSymbolNameForMangledMetadataAccessorString(
"type_layout_string", genericSig.getCanonicalSignature(),
ty.getASTType()->mapTypeOutOfContext()->getCanonicalType());
ty.getASTType()->mapTypeOutOfContext()->getCanonicalType(),
MangledTypeRefRole::Metadata);

auto *global = SB.finishAndCreateGlobal(symbolName, IGM.getPointerAlignment(),
/*constant*/ true);
Expand Down
36 changes: 18 additions & 18 deletions test/IRGen/noncopyable_field_descriptors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ public struct NonCopyable: ~Copyable { }
// 'MF' constant as a separator that precedes each field descriptor.

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

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

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

// OLD: @"$s4test8NC_TestsCMF" =
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyxG.{{[0-9]+}}"
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyq_G.{{[0-9]+}}"
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyAA03NonC0VG.{{[0-9]+}}"
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOySSG.{{[0-9]+}}"
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyxG noncopyable
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyq_G noncopyable
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOyAA03NonC0VG noncopyable
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test13NeverCopyableOySSG noncopyable
public class NC_Tests<NCG: ~Copyable, T> {
var ncNCG: NeverCopyable<NCG> = .none
var ncT: NeverCopyable<T> = .none
Expand All @@ -83,7 +83,7 @@ public class NC_Tests<NCG: ~Copyable, T> {
// NEW: @"$s4test17StdlibTypes_TestsCMF" =
// NEW-SAME: @"symbolic xSg"
// NEW-SAME: @"symbolic q_Sg"
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableVSg.{{[0-9]+}}"
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableVSg noncopyable
// NEW-SAME: @"symbolic SSSg"
// NEW-SAME: @"symbolic SPyxG"
// NEW-SAME: @"symbolic SPyq_G"
Expand All @@ -93,7 +93,7 @@ public class NC_Tests<NCG: ~Copyable, T> {
// OLD: @"$s4test17StdlibTypes_TestsCMF" =
// OLD-SAME: @"symbolic xSg"
// OLD-SAME: @"symbolic q_Sg"
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableVSg.{{[0-9]+}}"
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableVSg noncopyable
// OLD-SAME: @"symbolic SSSg"
// OLD-SAME: @"symbolic SPyxG"
// OLD-SAME: @"symbolic SPyq_G"
Expand All @@ -115,13 +115,13 @@ public class StdlibTypes_Tests<NCG: ~Copyable, T> {
// NEW: @"$s4test19PlainlyStored_TestsCMF" =
// NEW-SAME: @"symbolic x"
// NEW-SAME: @"symbolic q_"
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableV.{{[0-9]+}}"
// NEW-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableV noncopyable
// NEW-SAME: @"symbolic SS"

// OLD: @"$s4test19PlainlyStored_TestsCMF" =
// OLD-SAME: @"symbolic x"
// OLD-SAME: @"symbolic q_"
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableV.{{[0-9]+}}"
// OLD-SAME: @"get_type_metadata Ri_zr0_l4test11NonCopyableV noncopyable
// OLD-SAME: @"symbolic SS"
public class PlainlyStored_Tests<NCG: ~Copyable, T> {
var ncg: NCG
Expand Down
42 changes: 42 additions & 0 deletions test/IRGen/noncopyable_runtime_back_compat.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// RUN: %target-run-simple-swift(-enable-experimental-feature SuppressedAssociatedTypes)
// REQUIRES: executable_test
// REQUIRES: swift_feature_SuppressedAssociatedTypes

// Noncopyable types are suppressed in field metadata in runtimes lacking
// reflection support for them (currently all runtimes). However, we want
// to ensure that noncopyable type metadata is still produced where it is
// "load-bearing" to the generics system, such as in associated types in
// protocol conformances.

protocol Barrable: ~Copyable {
}

struct Bar<T: ~Copyable>: Barrable & ~Copyable {
var x: Int = 0
}

protocol F: ~Copyable {
associatedtype B: Barrable & ~Copyable
}

struct Foo: F & ~Copyable {
typealias B = Bar<Int>
}

func test<T: F & ~Copyable>(_: T.Type) {
print("\(T.B.self)")
}

// CHECK: Bar<Int>
test(Foo.self)

class Mirrored {
var noncopyableField: Bar<Int>

init() {
self.noncopyableField = Bar()
}
}

// CHECK: noncopyableField (0 elements)
dump(Mirrored())