diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index 7d2e40db88fc7..848731fe1088e 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -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) { @@ -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 diff --git a/lib/IRGen/IRGenMangler.cpp b/lib/IRGen/IRGenMangler.cpp index 6ae760fbabe2d..a8a68b585c229 100644 --- a/lib/IRGen/IRGenMangler.cpp +++ b/lib/IRGen/IRGenMangler.cpp @@ -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" @@ -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(); } diff --git a/lib/IRGen/IRGenMangler.h b/lib/IRGen/IRGenMangler.h index 60d20a40d8ff9..d3121c56a7e1c 100644 --- a/lib/IRGen/IRGenMangler.h +++ b/lib/IRGen/IRGenMangler.h @@ -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, diff --git a/lib/IRGen/TypeLayout.cpp b/lib/IRGen/TypeLayout.cpp index b88fa9939f1a9..61de9e4fb9251 100644 --- a/lib/IRGen/TypeLayout.cpp +++ b/lib/IRGen/TypeLayout.cpp @@ -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*/, @@ -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); @@ -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); diff --git a/test/IRGen/noncopyable_field_descriptors.swift b/test/IRGen/noncopyable_field_descriptors.swift index bdfc8b36f5c09..eb62fbf590419 100644 --- a/test/IRGen/noncopyable_field_descriptors.swift +++ b/test/IRGen/noncopyable_field_descriptors.swift @@ -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 { var ccNCG: ConditionallyCopyable = .none var ccT: ConditionallyCopyable = .none @@ -62,16 +62,16 @@ public class CC_Tests { /// 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 { var ncNCG: NeverCopyable = .none var ncT: NeverCopyable = .none @@ -83,7 +83,7 @@ public class NC_Tests { // 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" @@ -93,7 +93,7 @@ public class NC_Tests { // 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" @@ -115,13 +115,13 @@ public class StdlibTypes_Tests { // 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 { var ncg: NCG diff --git a/test/IRGen/noncopyable_runtime_back_compat.swift b/test/IRGen/noncopyable_runtime_back_compat.swift new file mode 100644 index 0000000000000..c99f631bac202 --- /dev/null +++ b/test/IRGen/noncopyable_runtime_back_compat.swift @@ -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: Barrable & ~Copyable { + var x: Int = 0 +} + +protocol F: ~Copyable { + associatedtype B: Barrable & ~Copyable +} + +struct Foo: F & ~Copyable { + typealias B = Bar +} + +func test(_: T.Type) { + print("\(T.B.self)") +} + +// CHECK: Bar +test(Foo.self) + +class Mirrored { + var noncopyableField: Bar + + init() { + self.noncopyableField = Bar() + } +} + +// CHECK: noncopyableField (0 elements) +dump(Mirrored())