mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
IRGen: We cannot call destroy through metadata of private types of non-copyable fields
So call the destroy on the closing type instead. Amends the concepts areFieldsABIAccessible/isABIAccessible to take metadata accessibility of non-copyable types into account. rdar://133990500
This commit is contained in:
@@ -46,8 +46,9 @@ protected:
|
||||
IsBitwiseTakable_t bt,
|
||||
IsCopyable_t copy,
|
||||
IsFixedSize_t alwaysFixedSize,
|
||||
IsABIAccessible_t isABIAccessible,
|
||||
SpecialTypeInfoKind stik = SpecialTypeInfoKind::Fixed)
|
||||
: TypeInfo(type, align, pod, bt, copy, alwaysFixedSize, IsABIAccessible, stik),
|
||||
: TypeInfo(type, align, pod, bt, copy, alwaysFixedSize, isABIAccessible, stik),
|
||||
SpareBits(spareBits) {
|
||||
assert(SpareBits.size() == size.getValueInBits());
|
||||
assert(isFixedSize());
|
||||
@@ -61,8 +62,9 @@ protected:
|
||||
IsBitwiseTakable_t bt,
|
||||
IsCopyable_t copy,
|
||||
IsFixedSize_t alwaysFixedSize,
|
||||
IsABIAccessible_t isABIAccessible,
|
||||
SpecialTypeInfoKind stik = SpecialTypeInfoKind::Fixed)
|
||||
: TypeInfo(type, align, pod, bt, copy, alwaysFixedSize, IsABIAccessible, stik),
|
||||
: TypeInfo(type, align, pod, bt, copy, alwaysFixedSize, isABIAccessible, stik),
|
||||
SpareBits(std::move(spareBits)) {
|
||||
assert(SpareBits.size() == size.getValueInBits());
|
||||
assert(isFixedSize());
|
||||
@@ -73,7 +75,6 @@ protected:
|
||||
public:
|
||||
// This is useful for metaprogramming.
|
||||
static bool isFixed() { return true; }
|
||||
static IsABIAccessible_t isABIAccessible() { return IsABIAccessible; }
|
||||
|
||||
/// Whether this type is known to be empty.
|
||||
bool isKnownEmpty(ResilienceExpansion expansion) const {
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
Size size, Alignment align, SpareBitVector &&spareBits)
|
||||
: TrivialScalarPairTypeInfo(storageType, size, std::move(spareBits),
|
||||
align, IsTriviallyDestroyable,
|
||||
IsCopyable, IsFixedSize) {}
|
||||
IsCopyable, IsFixedSize, IsABIAccessible) {}
|
||||
|
||||
static Size getFirstElementSize(IRGenModule &IGM) {
|
||||
return IGM.getPointerSize();
|
||||
|
||||
@@ -96,8 +96,8 @@ public:
|
||||
unsigned explosionSize, llvm::Type *ty, Size size,
|
||||
SpareBitVector &&spareBits, Alignment align,
|
||||
IsTriviallyDestroyable_t isTriviallyDestroyable, IsFixedSize_t alwaysFixedSize)
|
||||
: super(fields, explosionSize, ty, size, std::move(spareBits), align,
|
||||
isTriviallyDestroyable, IsCopyable, alwaysFixedSize) {}
|
||||
: super(fields, explosionSize, FieldsAreABIAccessible, ty, size, std::move(spareBits), align,
|
||||
isTriviallyDestroyable, IsCopyable, alwaysFixedSize, IsABIAccessible) {}
|
||||
|
||||
Address projectFieldAddress(IRGenFunction &IGF, Address addr, SILType T,
|
||||
const DifferentiableFuncFieldInfo &field) const {
|
||||
@@ -174,12 +174,14 @@ public:
|
||||
}
|
||||
|
||||
TypeInfo *createFixed(ArrayRef<DifferentiableFuncFieldInfo> fields,
|
||||
FieldsAreABIAccessible_t unused,
|
||||
StructLayout &&layout) {
|
||||
llvm_unreachable("@differentiable functions are always loadable");
|
||||
}
|
||||
|
||||
DifferentiableFuncTypeInfo *
|
||||
createLoadable(ArrayRef<DifferentiableFuncFieldInfo> fields,
|
||||
FieldsAreABIAccessible_t unused,
|
||||
StructLayout &&layout, unsigned explosionSize) {
|
||||
return DifferentiableFuncTypeInfo::create(
|
||||
fields, explosionSize, layout.getType(), layout.getSize(),
|
||||
@@ -273,8 +275,8 @@ public:
|
||||
unsigned explosionSize, llvm::Type *ty, Size size,
|
||||
SpareBitVector &&spareBits, Alignment align, IsTriviallyDestroyable_t isTriviallyDestroyable,
|
||||
IsFixedSize_t alwaysFixedSize)
|
||||
: super(fields, explosionSize, ty, size, std::move(spareBits), align,
|
||||
isTriviallyDestroyable, IsCopyable, alwaysFixedSize) {}
|
||||
: super(fields, explosionSize, FieldsAreABIAccessible, ty, size, std::move(spareBits), align,
|
||||
isTriviallyDestroyable, IsCopyable, alwaysFixedSize, IsABIAccessible) {}
|
||||
|
||||
Address projectFieldAddress(IRGenFunction &IGF, Address addr, SILType T,
|
||||
const LinearFuncFieldInfo &field) const {
|
||||
@@ -345,11 +347,13 @@ public:
|
||||
}
|
||||
|
||||
TypeInfo *createFixed(ArrayRef<LinearFuncFieldInfo> fields,
|
||||
FieldsAreABIAccessible_t areFieldsABIAccessible,
|
||||
StructLayout &&layout) {
|
||||
llvm_unreachable("@differentiable functions are always loadable");
|
||||
}
|
||||
|
||||
LinearFuncTypeInfo *createLoadable(ArrayRef<LinearFuncFieldInfo> fields,
|
||||
FieldsAreABIAccessible_t unused,
|
||||
StructLayout &&layout,
|
||||
unsigned explosionSize) {
|
||||
return LinearFuncTypeInfo::create(
|
||||
|
||||
@@ -659,7 +659,15 @@ namespace {
|
||||
void consume(IRGenFunction &IGF, Explosion &src,
|
||||
Atomicity atomicity,
|
||||
SILType T) const override {
|
||||
if (tryEmitConsumeUsingDeinit(IGF, src, T)) {
|
||||
if (ElementsAreABIAccessible &&
|
||||
tryEmitConsumeUsingDeinit(IGF, src, T)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ElementsAreABIAccessible) {
|
||||
auto temporary = TI->allocateStack(IGF, T, "deinit.arg").getAddress();
|
||||
cast<LoadableTypeInfo>(TI)->initialize(IGF, src, temporary, /*outlined*/false);
|
||||
emitDestroyCall(IGF, T, temporary);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -674,10 +682,11 @@ namespace {
|
||||
|
||||
void destroy(IRGenFunction &IGF, Address addr, SILType T,
|
||||
bool isOutlined) const override {
|
||||
if (tryEmitDestroyUsingDeinit(IGF, addr, T)) {
|
||||
if (ElementsAreABIAccessible &&
|
||||
tryEmitDestroyUsingDeinit(IGF, addr, T)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (getSingleton() &&
|
||||
!getSingleton()->isTriviallyDestroyable(ResilienceExpansion::Maximal)) {
|
||||
if (!ElementsAreABIAccessible) {
|
||||
@@ -1986,6 +1995,7 @@ namespace {
|
||||
|
||||
// If the payload is TriviallyDestroyable, then we can use TriviallyDestroyable value semantics.
|
||||
auto &payloadTI = *ElementsWithPayload[0].ti;
|
||||
|
||||
if (!payloadTI.isABIAccessible()) {
|
||||
CopyDestroyKind = ABIInaccessible;
|
||||
} else if (payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal)) {
|
||||
@@ -2848,9 +2858,18 @@ namespace {
|
||||
|
||||
void consume(IRGenFunction &IGF, Explosion &src,
|
||||
Atomicity atomicity, SILType T) const override {
|
||||
if (tryEmitConsumeUsingDeinit(IGF, src, T)) {
|
||||
if (ElementsAreABIAccessible &&
|
||||
tryEmitConsumeUsingDeinit(IGF, src, T)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ElementsAreABIAccessible) {
|
||||
auto temporary = TI->allocateStack(IGF, T, "deinit.arg").getAddress();
|
||||
cast<LoadableTypeInfo>(TI)->initialize(IGF, src, temporary, /*outlined*/false);
|
||||
emitDestroyCall(IGF, T, temporary);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(TIK >= Loadable);
|
||||
|
||||
switch (CopyDestroyKind) {
|
||||
@@ -2968,7 +2987,8 @@ namespace {
|
||||
|
||||
void destroy(IRGenFunction &IGF, Address addr, SILType T,
|
||||
bool isOutlined) const override {
|
||||
if (tryEmitDestroyUsingDeinit(IGF, addr, T)) {
|
||||
if (ElementsAreABIAccessible &&
|
||||
tryEmitDestroyUsingDeinit(IGF, addr, T)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4879,9 +4899,18 @@ namespace {
|
||||
|
||||
void consume(IRGenFunction &IGF, Explosion &src,
|
||||
Atomicity atomicity, SILType T) const override {
|
||||
if (tryEmitConsumeUsingDeinit(IGF, src, T)) {
|
||||
if (ElementsAreABIAccessible &&
|
||||
tryEmitConsumeUsingDeinit(IGF, src, T)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ElementsAreABIAccessible) {
|
||||
auto temporary = TI->allocateStack(IGF, T, "deinit.arg").getAddress();
|
||||
cast<LoadableTypeInfo>(TI)->initialize(IGF, src, temporary, /*outlined*/false);
|
||||
emitDestroyCall(IGF, T, temporary);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(TIK >= Loadable);
|
||||
switch (CopyDestroyKind) {
|
||||
case TriviallyDestroyable:
|
||||
@@ -5230,7 +5259,8 @@ namespace {
|
||||
|
||||
void destroy(IRGenFunction &IGF, Address addr, SILType T,
|
||||
bool isOutlined) const override {
|
||||
if (tryEmitDestroyUsingDeinit(IGF, addr, T)) {
|
||||
if (ElementsAreABIAccessible &&
|
||||
tryEmitDestroyUsingDeinit(IGF, addr, T)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6407,7 +6437,6 @@ EnumImplStrategy::get(TypeConverter &TC, SILType type, EnumDecl *theEnum) {
|
||||
// fixed-size from this resilience scope.
|
||||
ResilienceExpansion layoutScope =
|
||||
TC.IGM.getResilienceExpansionForLayout(theEnum);
|
||||
|
||||
for (auto elt : theEnum->getAllElements()) {
|
||||
++numElements;
|
||||
|
||||
@@ -6652,8 +6681,6 @@ namespace {
|
||||
public:
|
||||
using EnumTypeInfoBase<Base>::Strategy;
|
||||
|
||||
/// \group Methods delegated to the EnumImplStrategy
|
||||
|
||||
unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
|
||||
return Strategy.getFixedExtraInhabitantCount(IGM);
|
||||
}
|
||||
@@ -6693,10 +6720,11 @@ namespace {
|
||||
IsTriviallyDestroyable_t isTriviallyDestroyable,
|
||||
IsBitwiseTakable_t isBT,
|
||||
IsCopyable_t copyable,
|
||||
IsFixedSize_t alwaysFixedSize)
|
||||
IsFixedSize_t alwaysFixedSize,
|
||||
IsABIAccessible_t isABIAccessible)
|
||||
: FixedEnumTypeInfoBase(strategy, T, S, std::move(SB), A,
|
||||
isTriviallyDestroyable, isBT, copyable,
|
||||
alwaysFixedSize) {}
|
||||
alwaysFixedSize, isABIAccessible) {}
|
||||
};
|
||||
|
||||
/// TypeInfo for loadable enum types.
|
||||
@@ -6708,10 +6736,11 @@ namespace {
|
||||
Alignment A,
|
||||
IsTriviallyDestroyable_t isTriviallyDestroyable,
|
||||
IsCopyable_t copyable,
|
||||
IsFixedSize_t alwaysFixedSize)
|
||||
IsFixedSize_t alwaysFixedSize,
|
||||
IsABIAccessible_t isABIAccessible)
|
||||
: FixedEnumTypeInfoBase(strategy, T, S, std::move(SB), A,
|
||||
isTriviallyDestroyable, copyable,
|
||||
alwaysFixedSize) {}
|
||||
alwaysFixedSize, isABIAccessible) {}
|
||||
|
||||
void addToAggLowering(IRGenModule &IGM, SwiftAggLowering &lowering,
|
||||
Size offset) const override {
|
||||
@@ -6821,7 +6850,8 @@ EnumImplStrategy::getFixedEnumTypeInfo(llvm::StructType *T, Size S,
|
||||
Alignment A,
|
||||
IsTriviallyDestroyable_t isTriviallyDestroyable,
|
||||
IsBitwiseTakable_t isBT,
|
||||
IsCopyable_t isCopyable) {
|
||||
IsCopyable_t isCopyable,
|
||||
IsABIAccessible_t abiAccessible) {
|
||||
TypeInfo *mutableTI;
|
||||
switch (TIK) {
|
||||
case Opaque:
|
||||
@@ -6831,14 +6861,16 @@ EnumImplStrategy::getFixedEnumTypeInfo(llvm::StructType *T, Size S,
|
||||
isTriviallyDestroyable,
|
||||
isBT,
|
||||
isCopyable,
|
||||
AlwaysFixedSize);
|
||||
AlwaysFixedSize,
|
||||
abiAccessible);
|
||||
break;
|
||||
case Loadable:
|
||||
assert(isBT && "loadable enum not bitwise takable?!");
|
||||
mutableTI = new LoadableEnumTypeInfo(*this, T, S, std::move(SB), A,
|
||||
isTriviallyDestroyable,
|
||||
isCopyable,
|
||||
AlwaysFixedSize);
|
||||
AlwaysFixedSize,
|
||||
abiAccessible);
|
||||
break;
|
||||
}
|
||||
TI = mutableTI;
|
||||
@@ -6859,7 +6891,8 @@ SingletonEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC,
|
||||
alignment,
|
||||
TriviallyDestroyable,
|
||||
Copyable,
|
||||
AlwaysFixedSize));
|
||||
AlwaysFixedSize,
|
||||
IsABIAccessible));
|
||||
} else {
|
||||
const TypeInfo &eltTI = *getSingleton();
|
||||
|
||||
@@ -6886,13 +6919,19 @@ SingletonEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC,
|
||||
auto alignment = fixedEltTI.getFixedAlignment();
|
||||
applyLayoutAttributes(TC.IGM, theEnum, /*fixed*/true, alignment);
|
||||
|
||||
IsABIAccessible_t isABIAccessible = IsABIAccessible;
|
||||
if (Type.getASTType()->isNoncopyable() &&
|
||||
!IGM.getSILModule().isTypeMetadataAccessible(Type.getASTType()))
|
||||
isABIAccessible = IsNotABIAccessible;
|
||||
|
||||
return getFixedEnumTypeInfo(enumTy,
|
||||
fixedEltTI.getFixedSize(),
|
||||
fixedEltTI.getSpareBits(),
|
||||
alignment,
|
||||
TriviallyDestroyable,
|
||||
BitwiseTakable,
|
||||
Copyable);
|
||||
Copyable,
|
||||
isABIAccessible);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6927,7 +6966,8 @@ NoPayloadEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC,
|
||||
alignment,
|
||||
TriviallyDestroyable,
|
||||
Copyable,
|
||||
AlwaysFixedSize));
|
||||
AlwaysFixedSize,
|
||||
IsABIAccessible));
|
||||
}
|
||||
|
||||
TypeInfo *
|
||||
@@ -6976,7 +7016,8 @@ CCompatibleEnumImplStrategy::completeEnumTypeLayout(TypeConverter &TC,
|
||||
alignment,
|
||||
IsTriviallyDestroyable,
|
||||
IsCopyable,
|
||||
IsFixedSize));
|
||||
IsFixedSize,
|
||||
IsABIAccessible));
|
||||
}
|
||||
|
||||
TypeInfo *SinglePayloadEnumImplStrategy::completeFixedLayout(
|
||||
@@ -7044,11 +7085,18 @@ TypeInfo *SinglePayloadEnumImplStrategy::completeFixedLayout(
|
||||
? IsNotTriviallyDestroyable : IsTriviallyDestroyable;
|
||||
auto copyable = !theEnum->canBeCopyable()
|
||||
? IsNotCopyable : IsCopyable;
|
||||
|
||||
IsABIAccessible_t isABIAccessible = IsABIAccessible;
|
||||
if (Type.getASTType()->isNoncopyable() &&
|
||||
!IGM.getSILModule().isTypeMetadataAccessible(Type.getASTType()))
|
||||
isABIAccessible = IsNotABIAccessible;
|
||||
|
||||
getFixedEnumTypeInfo(
|
||||
enumTy, Size(sizeWithTag), spareBits.build(), alignment,
|
||||
deinit & payloadTI.isTriviallyDestroyable(ResilienceExpansion::Maximal),
|
||||
payloadTI.isBitwiseTakable(ResilienceExpansion::Maximal),
|
||||
copyable);
|
||||
copyable, isABIAccessible);
|
||||
|
||||
if (TIK >= Loadable && CopyDestroyKind == Normal) {
|
||||
computePayloadTypesAndTagType(TC.IGM, *TI, PayloadTypesAndTagType);
|
||||
loweredType = Type;
|
||||
@@ -7255,9 +7303,15 @@ MultiPayloadEnumImplStrategy::completeFixedLayout(TypeConverter &TC,
|
||||
|
||||
applyLayoutAttributes(TC.IGM, theEnum, /*fixed*/ true, worstAlignment);
|
||||
|
||||
IsABIAccessible_t isABIAccessible = IsABIAccessible;
|
||||
if (Type.getASTType()->isNoncopyable() &&
|
||||
!IGM.getSILModule().isTypeMetadataAccessible(Type.getASTType()))
|
||||
isABIAccessible = IsNotABIAccessible;
|
||||
|
||||
getFixedEnumTypeInfo(enumTy, Size(sizeWithTag), std::move(spareBits),
|
||||
worstAlignment, isTriviallyDestroyable, isBT,
|
||||
isCopyable);
|
||||
isCopyable, isABIAccessible);
|
||||
|
||||
if (TIK >= Loadable &&
|
||||
(CopyDestroyKind == Normal || CopyDestroyKind == BitwiseTakable)) {
|
||||
computePayloadTypesAndTagType(TC.IGM, *TI, PayloadTypesAndTagType);
|
||||
|
||||
@@ -180,7 +180,8 @@ protected:
|
||||
Alignment A,
|
||||
IsTriviallyDestroyable_t isTriviallyDestroyable,
|
||||
IsBitwiseTakable_t isBT,
|
||||
IsCopyable_t isCopyable);
|
||||
IsCopyable_t isCopyable,
|
||||
IsABIAccessible_t abiAccessible);
|
||||
|
||||
public:
|
||||
virtual ~EnumImplStrategy() { }
|
||||
|
||||
@@ -689,7 +689,8 @@ namespace {
|
||||
align, IsNotTriviallyDestroyable, \
|
||||
IsNotBitwiseTakable, \
|
||||
IsCopyable, \
|
||||
IsFixedSize), \
|
||||
IsFixedSize, \
|
||||
IsABIAccessible), \
|
||||
IsOptional(isOptional) {} \
|
||||
TypeLayoutEntry \
|
||||
*buildTypeLayoutEntry(IRGenModule &IGM, \
|
||||
@@ -747,7 +748,7 @@ namespace {
|
||||
spareBits, align, \
|
||||
IsNotTriviallyDestroyable, \
|
||||
IsCopyable, \
|
||||
IsFixedSize), \
|
||||
IsFixedSize, IsABIAccessible), \
|
||||
Refcounting(refcounting), ValueType(valueTy), IsOptional(isOptional) { \
|
||||
assert(refcounting == ReferenceCounting::Native || \
|
||||
refcounting == ReferenceCounting::Unknown); \
|
||||
@@ -816,7 +817,7 @@ namespace {
|
||||
bool isOptional) \
|
||||
: ScalarExistentialTypeInfoBase(storedProtocols, ty, size, \
|
||||
spareBits, align, IsTriviallyDestroyable,\
|
||||
IsCopyable, IsFixedSize), \
|
||||
IsCopyable, IsFixedSize, IsABIAccessible), \
|
||||
IsOptional(isOptional) {} \
|
||||
TypeLayoutEntry \
|
||||
*buildTypeLayoutEntry(IRGenModule &IGM, \
|
||||
@@ -904,7 +905,7 @@ class OpaqueExistentialTypeInfo final :
|
||||
: super(protocols, ty, size,
|
||||
std::move(spareBits), align,
|
||||
IsNotTriviallyDestroyable, IsBitwiseTakable, IsCopyable,
|
||||
IsFixedSize) {}
|
||||
IsFixedSize, IsABIAccessible) {}
|
||||
|
||||
public:
|
||||
OpaqueExistentialLayout getLayout() const {
|
||||
@@ -1402,7 +1403,7 @@ class ExistentialMetatypeTypeInfo final
|
||||
std::move(spareBits), align,
|
||||
IsTriviallyDestroyable,
|
||||
IsCopyable,
|
||||
IsFixedSize),
|
||||
IsFixedSize, IsABIAccessible),
|
||||
MetatypeTI(metatypeTI) {}
|
||||
|
||||
public:
|
||||
|
||||
@@ -504,7 +504,7 @@ namespace {
|
||||
IsTriviallyDestroyable_t pod, IsBitwiseTakable_t bt, Size captureOffset)
|
||||
: IndirectTypeInfo(type, size, std::move(spareBits), align, pod, bt,
|
||||
IsCopyable,
|
||||
IsFixedSize),
|
||||
IsFixedSize, IsABIAccessible),
|
||||
CaptureOffset(captureOffset)
|
||||
{}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace {
|
||||
SpareBitVector &&spareBits, \
|
||||
bool isOptional) \
|
||||
: IndirectTypeInfo(type, size, std::move(spareBits), alignment, \
|
||||
IsNotTriviallyDestroyable, IsNotBitwiseTakable, IsCopyable, IsFixedSize), \
|
||||
IsNotTriviallyDestroyable, IsNotBitwiseTakable, IsCopyable, IsFixedSize, IsABIAccessible), \
|
||||
ValueTypeAndIsOptional(valueType, isOptional) {} \
|
||||
void initializeWithCopy(IRGenFunction &IGF, Address destAddr, \
|
||||
Address srcAddr, SILType T, \
|
||||
@@ -151,7 +151,7 @@ namespace {
|
||||
: SingleScalarTypeInfo(type, size, std::move(spareBits), \
|
||||
alignment, IsNotTriviallyDestroyable, \
|
||||
IsCopyable, \
|
||||
IsFixedSize), \
|
||||
IsFixedSize, IsABIAccessible), \
|
||||
ValueTypeAndIsOptional(valueType, isOptional) {} \
|
||||
enum { IsScalarTriviallyDestroyable = false }; \
|
||||
TypeLayoutEntry \
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
IntegerLiteralTypeInfo(llvm::StructType *storageType,
|
||||
Size size, Alignment align, SpareBitVector &&spareBits)
|
||||
: TrivialScalarPairTypeInfo(storageType, size, std::move(spareBits), align,
|
||||
IsTriviallyDestroyable, IsCopyable, IsFixedSize) {}
|
||||
IsTriviallyDestroyable, IsCopyable, IsFixedSize, IsABIAccessible) {}
|
||||
|
||||
static Size getFirstElementSize(IRGenModule &IGM) {
|
||||
return IGM.getPointerSize();
|
||||
|
||||
@@ -683,7 +683,7 @@ class RecordTypeInfo<Impl, Base, FieldImpl,
|
||||
protected:
|
||||
template <class... As>
|
||||
RecordTypeInfo(ArrayRef<FieldImpl> fields, As &&...args)
|
||||
: super(fields, FieldsAreABIAccessible, std::forward<As>(args)...) {}
|
||||
: super(fields, std::forward<As>(args)...) {}
|
||||
|
||||
using super::asImpl;
|
||||
|
||||
@@ -965,12 +965,12 @@ public:
|
||||
fieldTypesForLayout.reserve(astFields.size());
|
||||
|
||||
auto fieldsABIAccessible = FieldsAreABIAccessible;
|
||||
|
||||
unsigned explosionSize = 0;
|
||||
for (unsigned i : indices(astFields)) {
|
||||
auto &astField = astFields[i];
|
||||
// Compute the field's type info.
|
||||
auto &fieldTI = IGM.getTypeInfo(asImpl()->getType(astField));
|
||||
auto fieldTy = asImpl()->getType(astField);
|
||||
auto &fieldTI = IGM.getTypeInfo(fieldTy);
|
||||
fieldTypesForLayout.push_back(&fieldTI);
|
||||
|
||||
if (!fieldTI.isABIAccessible())
|
||||
@@ -1003,11 +1003,10 @@ public:
|
||||
// Create the type info.
|
||||
if (layout.isLoadable()) {
|
||||
assert(layout.isFixedLayout());
|
||||
assert(fieldsABIAccessible);
|
||||
return asImpl()->createLoadable(fields, std::move(layout), explosionSize);
|
||||
return asImpl()->createLoadable(fields, fieldsABIAccessible, std::move(layout), explosionSize
|
||||
);
|
||||
} else if (layout.isFixedLayout()) {
|
||||
assert(fieldsABIAccessible);
|
||||
return asImpl()->createFixed(fields, std::move(layout));
|
||||
return asImpl()->createFixed(fields, fieldsABIAccessible, std::move(layout));
|
||||
} else {
|
||||
return asImpl()->createNonFixed(fields, fieldsABIAccessible,
|
||||
std::move(layout));
|
||||
|
||||
@@ -155,6 +155,7 @@ namespace {
|
||||
using super::asImpl;
|
||||
|
||||
public:
|
||||
|
||||
const FieldInfoType &getFieldInfo(VarDecl *field) const {
|
||||
// FIXME: cache the physical field index in the VarDecl.
|
||||
for (auto &fieldInfo : asImpl().getFields()) {
|
||||
@@ -275,6 +276,12 @@ namespace {
|
||||
|
||||
void destroy(IRGenFunction &IGF, Address address, SILType T,
|
||||
bool isOutlined) const override {
|
||||
|
||||
if (!asImpl().areFieldsABIAccessible()) {
|
||||
emitDestroyCall(IGF, T, address);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the struct has a deinit declared, then call it to destroy the
|
||||
// value.
|
||||
if (!tryEmitDestroyUsingDeinit(IGF, address, T)) {
|
||||
@@ -390,11 +397,11 @@ namespace {
|
||||
Alignment align,
|
||||
const clang::RecordDecl *clangDecl)
|
||||
: StructTypeInfoBase(StructTypeInfoKind::LoadableClangRecordTypeInfo,
|
||||
fields, explosionSize, storageType, size,
|
||||
std::move(spareBits), align,
|
||||
fields, explosionSize, FieldsAreABIAccessible,
|
||||
storageType, size, std::move(spareBits), align,
|
||||
IsTriviallyDestroyable,
|
||||
IsCopyable,
|
||||
IsFixedSize),
|
||||
IsFixedSize, IsABIAccessible),
|
||||
ClangDecl(clangDecl) {}
|
||||
|
||||
TypeLayoutEntry
|
||||
@@ -484,13 +491,14 @@ namespace {
|
||||
Alignment align,
|
||||
const clang::RecordDecl *clangDecl)
|
||||
: StructTypeInfoBase(StructTypeInfoKind::AddressOnlyClangRecordTypeInfo,
|
||||
fields, storageType, size,
|
||||
fields, FieldsAreABIAccessible, storageType, size,
|
||||
// We can't assume any spare bits in a C++ type
|
||||
// with user-defined special member functions.
|
||||
SpareBitVector(std::optional<APInt>{
|
||||
llvm::APInt(size.getValueInBits(), 0)}),
|
||||
align, IsNotTriviallyDestroyable,
|
||||
IsNotBitwiseTakable, IsCopyable, IsFixedSize),
|
||||
IsNotBitwiseTakable, IsCopyable, IsFixedSize,
|
||||
IsABIAccessible),
|
||||
clangDecl(clangDecl) {
|
||||
(void)clangDecl;
|
||||
}
|
||||
@@ -666,7 +674,7 @@ namespace {
|
||||
Alignment align,
|
||||
const clang::RecordDecl *clangDecl)
|
||||
: StructTypeInfoBase(StructTypeInfoKind::AddressOnlyClangRecordTypeInfo,
|
||||
fields, storageType, size,
|
||||
fields, FieldsAreABIAccessible, storageType, size,
|
||||
// We can't assume any spare bits in a C++ type
|
||||
// with user-defined special member functions.
|
||||
SpareBitVector(std::optional<APInt>{
|
||||
@@ -675,7 +683,7 @@ namespace {
|
||||
IsNotBitwiseTakable,
|
||||
// TODO: Set this appropriately for the type's
|
||||
// C++ import behavior.
|
||||
IsCopyable, IsFixedSize),
|
||||
IsCopyable, IsFixedSize, IsABIAccessible),
|
||||
ClangDecl(clangDecl) {
|
||||
(void)ClangDecl;
|
||||
}
|
||||
@@ -865,21 +873,24 @@ namespace {
|
||||
class LoadableStructTypeInfo final
|
||||
: public StructTypeInfoBase<LoadableStructTypeInfo, LoadableTypeInfo> {
|
||||
using super = StructTypeInfoBase<LoadableStructTypeInfo, LoadableTypeInfo>;
|
||||
|
||||
public:
|
||||
LoadableStructTypeInfo(ArrayRef<StructFieldInfo> fields,
|
||||
FieldsAreABIAccessible_t areFieldsABIAccessible,
|
||||
unsigned explosionSize,
|
||||
llvm::Type *storageType, Size size,
|
||||
SpareBitVector &&spareBits,
|
||||
Alignment align,
|
||||
IsTriviallyDestroyable_t isTriviallyDestroyable,
|
||||
IsCopyable_t isCopyable,
|
||||
IsFixedSize_t alwaysFixedSize)
|
||||
IsFixedSize_t alwaysFixedSize,
|
||||
IsABIAccessible_t isABIAccessible)
|
||||
: StructTypeInfoBase(StructTypeInfoKind::LoadableStructTypeInfo,
|
||||
fields, explosionSize,
|
||||
fields, explosionSize, areFieldsABIAccessible,
|
||||
storageType, size, std::move(spareBits),
|
||||
align, isTriviallyDestroyable,
|
||||
isCopyable,
|
||||
alwaysFixedSize)
|
||||
alwaysFixedSize, isABIAccessible)
|
||||
{}
|
||||
|
||||
void addToAggLowering(IRGenModule &IGM, SwiftAggLowering &lowering,
|
||||
@@ -942,6 +953,13 @@ namespace {
|
||||
|
||||
void consume(IRGenFunction &IGF, Explosion &explosion,
|
||||
Atomicity atomicity, SILType T) const override {
|
||||
if (!areFieldsABIAccessible()) {
|
||||
auto temporary = allocateStack(IGF, T, "deinit.arg").getAddress();
|
||||
initialize(IGF, explosion, temporary, /*outlined*/false);
|
||||
emitDestroyCall(IGF, T, temporary);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the struct has a deinit declared, then call it to consume the
|
||||
// value.
|
||||
if (tryEmitConsumeUsingDeinit(IGF, explosion, T)) {
|
||||
@@ -960,17 +978,21 @@ namespace {
|
||||
FixedTypeInfo>> {
|
||||
public:
|
||||
// FIXME: Spare bits between struct members.
|
||||
FixedStructTypeInfo(ArrayRef<StructFieldInfo> fields, llvm::Type *T,
|
||||
FixedStructTypeInfo(ArrayRef<StructFieldInfo> fields,
|
||||
FieldsAreABIAccessible_t areFieldsABIAccessible,
|
||||
llvm::Type *T,
|
||||
Size size, SpareBitVector &&spareBits,
|
||||
Alignment align,
|
||||
IsTriviallyDestroyable_t isTriviallyDestroyable,
|
||||
IsBitwiseTakable_t isBT,
|
||||
IsCopyable_t isCopyable,
|
||||
IsFixedSize_t alwaysFixedSize)
|
||||
IsFixedSize_t alwaysFixedSize,
|
||||
IsABIAccessible_t isABIAccessible)
|
||||
: StructTypeInfoBase(StructTypeInfoKind::FixedStructTypeInfo,
|
||||
fields, T, size, std::move(spareBits), align,
|
||||
fields, areFieldsABIAccessible,
|
||||
T, size, std::move(spareBits), align,
|
||||
isTriviallyDestroyable, isBT, isCopyable,
|
||||
alwaysFixedSize)
|
||||
alwaysFixedSize, isABIAccessible)
|
||||
{}
|
||||
|
||||
TypeLayoutEntry
|
||||
@@ -1242,9 +1264,15 @@ namespace {
|
||||
}
|
||||
|
||||
LoadableStructTypeInfo *createLoadable(ArrayRef<StructFieldInfo> fields,
|
||||
FieldsAreABIAccessible_t areFieldsABIAccessible,
|
||||
StructLayout &&layout,
|
||||
unsigned explosionSize) {
|
||||
IsABIAccessible_t isABIAccessible = IsABIAccessible;
|
||||
if (TheStruct->isNoncopyable() &&
|
||||
!IGM.getSILModule().isTypeMetadataAccessible(TheStruct))
|
||||
isABIAccessible = IsNotABIAccessible;
|
||||
return LoadableStructTypeInfo::create(fields,
|
||||
areFieldsABIAccessible,
|
||||
explosionSize,
|
||||
layout.getType(),
|
||||
layout.getSize(),
|
||||
@@ -1252,23 +1280,31 @@ namespace {
|
||||
layout.getAlignment(),
|
||||
layout.isTriviallyDestroyable(),
|
||||
layout.isCopyable(),
|
||||
layout.isAlwaysFixedSize());
|
||||
layout.isAlwaysFixedSize(),
|
||||
isABIAccessible);
|
||||
}
|
||||
|
||||
FixedStructTypeInfo *createFixed(ArrayRef<StructFieldInfo> fields,
|
||||
FieldsAreABIAccessible_t areFieldsABIAccessible,
|
||||
StructLayout &&layout) {
|
||||
return FixedStructTypeInfo::create(fields, layout.getType(),
|
||||
IsABIAccessible_t isABIAccessible = IsABIAccessible;
|
||||
if (TheStruct->isNoncopyable() &&
|
||||
!IGM.getSILModule().isTypeMetadataAccessible(TheStruct))
|
||||
isABIAccessible = IsNotABIAccessible;
|
||||
return FixedStructTypeInfo::create(fields, areFieldsABIAccessible,
|
||||
layout.getType(),
|
||||
layout.getSize(),
|
||||
std::move(layout.getSpareBits()),
|
||||
layout.getAlignment(),
|
||||
layout.isTriviallyDestroyable(),
|
||||
layout.isBitwiseTakable(),
|
||||
layout.isCopyable(),
|
||||
layout.isAlwaysFixedSize());
|
||||
layout.isAlwaysFixedSize(),
|
||||
isABIAccessible);
|
||||
}
|
||||
|
||||
NonFixedStructTypeInfo *createNonFixed(ArrayRef<StructFieldInfo> fields,
|
||||
FieldsAreABIAccessible_t fieldsAccessible,
|
||||
FieldsAreABIAccessible_t fieldsAccessible,
|
||||
StructLayout &&layout) {
|
||||
auto structAccessible = IsABIAccessible_t(
|
||||
IGM.getSILModule().isTypeMetadataAccessible(TheStruct));
|
||||
|
||||
@@ -256,18 +256,20 @@ namespace {
|
||||
public:
|
||||
// FIXME: Spare bits between tuple elements.
|
||||
LoadableTupleTypeInfo(ArrayRef<TupleFieldInfo> fields,
|
||||
FieldsAreABIAccessible_t areFieldsABIAccessible,
|
||||
unsigned explosionSize,
|
||||
llvm::Type *ty,
|
||||
Size size, SpareBitVector &&spareBits,
|
||||
Alignment align,
|
||||
IsTriviallyDestroyable_t isTriviallyDestroyable,
|
||||
IsCopyable_t isCopyable,
|
||||
IsFixedSize_t alwaysFixedSize)
|
||||
: TupleTypeInfoBase(fields, explosionSize,
|
||||
IsFixedSize_t alwaysFixedSize,
|
||||
IsABIAccessible_t isABIAccessible)
|
||||
: TupleTypeInfoBase(fields, explosionSize, areFieldsABIAccessible,
|
||||
ty, size, std::move(spareBits), align,
|
||||
isTriviallyDestroyable,
|
||||
isCopyable,
|
||||
alwaysFixedSize)
|
||||
alwaysFixedSize, isABIAccessible)
|
||||
{}
|
||||
|
||||
void addToAggLowering(IRGenModule &IGM, SwiftAggLowering &lowering,
|
||||
@@ -319,15 +321,18 @@ namespace {
|
||||
{
|
||||
public:
|
||||
// FIXME: Spare bits between tuple elements.
|
||||
FixedTupleTypeInfo(ArrayRef<TupleFieldInfo> fields, llvm::Type *ty,
|
||||
FixedTupleTypeInfo(ArrayRef<TupleFieldInfo> fields,
|
||||
FieldsAreABIAccessible_t areFieldsABIAccessible,
|
||||
llvm::Type *ty,
|
||||
Size size, SpareBitVector &&spareBits, Alignment align,
|
||||
IsTriviallyDestroyable_t isTriviallyDestroyable,
|
||||
IsBitwiseTakable_t isBT,
|
||||
IsCopyable_t isCopyable,
|
||||
IsFixedSize_t alwaysFixedSize)
|
||||
: TupleTypeInfoBase(fields, ty, size, std::move(spareBits), align,
|
||||
IsFixedSize_t alwaysFixedSize,
|
||||
IsABIAccessible_t isABIAccessible)
|
||||
: TupleTypeInfoBase(fields, areFieldsABIAccessible, ty, size, std::move(spareBits), align,
|
||||
isTriviallyDestroyable, isBT, isCopyable,
|
||||
alwaysFixedSize)
|
||||
alwaysFixedSize, isABIAccessible)
|
||||
{}
|
||||
|
||||
TypeLayoutEntry
|
||||
@@ -464,27 +469,35 @@ namespace {
|
||||
: RecordTypeBuilder(IGM), TheTuple(theTuple) {}
|
||||
|
||||
FixedTupleTypeInfo *createFixed(ArrayRef<TupleFieldInfo> fields,
|
||||
FieldsAreABIAccessible_t areFieldsABIAccessible,
|
||||
StructLayout &&layout) {
|
||||
return FixedTupleTypeInfo::create(fields, layout.getType(),
|
||||
IsABIAccessible_t isABIAccessible = IsABIAccessible_t(areFieldsABIAccessible);
|
||||
return FixedTupleTypeInfo::create(fields, areFieldsABIAccessible,
|
||||
layout.getType(),
|
||||
layout.getSize(),
|
||||
std::move(layout.getSpareBits()),
|
||||
layout.getAlignment(),
|
||||
layout.isTriviallyDestroyable(),
|
||||
layout.isBitwiseTakable(),
|
||||
layout.isCopyable(),
|
||||
layout.isAlwaysFixedSize());
|
||||
layout.isAlwaysFixedSize(),
|
||||
isABIAccessible);
|
||||
}
|
||||
|
||||
LoadableTupleTypeInfo *createLoadable(ArrayRef<TupleFieldInfo> fields,
|
||||
FieldsAreABIAccessible_t areFieldsABIAccessible,
|
||||
StructLayout &&layout,
|
||||
unsigned explosionSize) {
|
||||
return LoadableTupleTypeInfo::create(fields, explosionSize,
|
||||
IsABIAccessible_t isABIAccessible = IsABIAccessible_t(areFieldsABIAccessible);
|
||||
return LoadableTupleTypeInfo::create(fields, areFieldsABIAccessible,
|
||||
explosionSize,
|
||||
layout.getType(), layout.getSize(),
|
||||
std::move(layout.getSpareBits()),
|
||||
layout.getAlignment(),
|
||||
layout.isTriviallyDestroyable(),
|
||||
layout.isCopyable(),
|
||||
layout.isAlwaysFixedSize());
|
||||
layout.isAlwaysFixedSize(),
|
||||
isABIAccessible);
|
||||
}
|
||||
|
||||
NonFixedTupleTypeInfo *createNonFixed(ArrayRef<TupleFieldInfo> fields,
|
||||
|
||||
@@ -970,7 +970,7 @@ namespace {
|
||||
: ScalarTypeInfo(ty, Size(0), SpareBitVector{}, Alignment(1),
|
||||
IsTriviallyDestroyable,
|
||||
IsCopyable,
|
||||
IsFixedSize) {}
|
||||
IsFixedSize, IsABIAccessible) {}
|
||||
unsigned getExplosionSize() const override { return 0; }
|
||||
void getSchema(ExplosionSchema &schema) const override {}
|
||||
void addToAggLowering(IRGenModule &IGM, SwiftAggLowering &lowering,
|
||||
@@ -1138,7 +1138,8 @@ namespace {
|
||||
: ScalarTypeInfo(storage, size, std::move(spareBits), align,
|
||||
IsTriviallyDestroyable,
|
||||
IsCopyable,
|
||||
IsFixedSize),
|
||||
IsFixedSize,
|
||||
IsABIAccessible),
|
||||
ScalarTypes(std::move(scalarTypes))
|
||||
{}
|
||||
|
||||
@@ -1329,7 +1330,7 @@ namespace {
|
||||
IsNotTriviallyDestroyable,
|
||||
IsNotBitwiseTakable,
|
||||
IsNotCopyable,
|
||||
IsFixedSize) {}
|
||||
IsFixedSize, IsABIAccessible) {}
|
||||
};
|
||||
|
||||
/// A TypeInfo implementation for address-only types which can never
|
||||
@@ -2541,7 +2542,8 @@ public:
|
||||
IsNotTriviallyDestroyable, /* irrelevant */
|
||||
IsNotBitwiseTakable, /* irrelevant */
|
||||
IsCopyable, /* irrelevant */
|
||||
IsFixedSize /* irrelevant */),
|
||||
IsFixedSize /* irrelevant */,
|
||||
IsABIAccessible),
|
||||
NumExtraInhabitants(node.NumExtraInhabitants) {}
|
||||
|
||||
TypeLayoutEntry
|
||||
|
||||
@@ -62,11 +62,12 @@ protected:
|
||||
IsTriviallyDestroyable_t pod,
|
||||
IsCopyable_t copy,
|
||||
IsFixedSize_t alwaysFixedSize,
|
||||
IsABIAccessible_t isABIAccessible,
|
||||
SpecialTypeInfoKind stik = SpecialTypeInfoKind::Loadable)
|
||||
: FixedTypeInfo(type, size, spareBits, align, pod,
|
||||
// All currently implemented loadable types are bitwise-takable.
|
||||
IsBitwiseTakable,
|
||||
copy, alwaysFixedSize, stik) {
|
||||
copy, alwaysFixedSize, isABIAccessible, stik) {
|
||||
assert(isLoadable());
|
||||
}
|
||||
|
||||
@@ -76,11 +77,12 @@ protected:
|
||||
IsTriviallyDestroyable_t pod,
|
||||
IsCopyable_t copy,
|
||||
IsFixedSize_t alwaysFixedSize,
|
||||
IsABIAccessible_t isABIAccessible,
|
||||
SpecialTypeInfoKind stik = SpecialTypeInfoKind::Loadable)
|
||||
: FixedTypeInfo(type, size, std::move(spareBits), align, pod,
|
||||
// All currently implemented loadable types are bitwise-takable.
|
||||
IsBitwiseTakable,
|
||||
copy, alwaysFixedSize, stik) {
|
||||
copy, alwaysFixedSize, isABIAccessible, stik) {
|
||||
assert(isLoadable());
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ protected:
|
||||
ReferenceTypeInfo(llvm::Type *type, Size size, SpareBitVector spareBits,
|
||||
Alignment align, IsTriviallyDestroyable_t pod = IsNotTriviallyDestroyable)
|
||||
: LoadableTypeInfo(type, size, spareBits, align, pod, IsCopyable,
|
||||
IsFixedSize, SpecialTypeInfoKind::Reference)
|
||||
IsFixedSize, IsABIAccessible, SpecialTypeInfoKind::Reference)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
||||
@@ -280,6 +280,7 @@ protected:
|
||||
IsTriviallyDestroyable,
|
||||
IsCopyable,
|
||||
IsFixedSize,
|
||||
IsABIAccessible,
|
||||
::std::forward<T>(args)...) {}
|
||||
|
||||
const Derived &asDerived() const {
|
||||
|
||||
@@ -208,9 +208,12 @@ public:
|
||||
/// actually possible to do ABI operations on it from this current SILModule.
|
||||
/// See SILModule::isTypeABIAccessible.
|
||||
///
|
||||
/// All fixed-size types are currently ABI-accessible, although this would
|
||||
/// Almost all fixed-size types are currently ABI-accessible, although this would
|
||||
/// not be difficult to change (e.g. if we had an archetype size constraint
|
||||
/// that didn't say anything about triviality).
|
||||
/// The exception to this is non-copyable types, non-copyable types need to be
|
||||
/// able to call the metadata to get to the deinit and so their type metadata
|
||||
/// needs to be accessible.
|
||||
IsABIAccessible_t isABIAccessible() const {
|
||||
return IsABIAccessible_t(Bits.TypeInfo.ABIAccessible);
|
||||
}
|
||||
|
||||
24
test/IRGen/Inputs/noncopyable_private_other.swift
Normal file
24
test/IRGen/Inputs/noncopyable_private_other.swift
Normal file
@@ -0,0 +1,24 @@
|
||||
fileprivate struct PrivateType : ~Copyable {
|
||||
let x = 5
|
||||
|
||||
deinit {
|
||||
print("deinit")
|
||||
}
|
||||
}
|
||||
|
||||
public struct PublicType : ~Copyable {
|
||||
fileprivate let p = PrivateType()
|
||||
|
||||
public init() {}
|
||||
}
|
||||
|
||||
public enum PublicSinglePayloadEnum : ~Copyable {
|
||||
case empty
|
||||
case some(PrivateType)
|
||||
}
|
||||
|
||||
public enum PublicMultiPayloadEnum : ~Copyable {
|
||||
case empty
|
||||
case some(PrivateType)
|
||||
case someOther(PrivateType)
|
||||
}
|
||||
42
test/IRGen/noncopyable_private.swift
Normal file
42
test/IRGen/noncopyable_private.swift
Normal file
@@ -0,0 +1,42 @@
|
||||
// RUN: %swift-frontend -primary-file %s %S/Inputs/noncopyable_private_other.swift -emit-ir -o - | %FileCheck %s
|
||||
|
||||
public struct SomeStruct : ~Copyable {
|
||||
// PublicType is a struct without a deinit but a non-copyable field with a
|
||||
// deinit of private type. So we can't access the private type's metadata.
|
||||
// Instead we have to call destroy on PublicType's metadata.
|
||||
public let x = PublicType()
|
||||
}
|
||||
|
||||
// Call the destroy on the `PublicType` metadata instead of its private typed
|
||||
// subfield.
|
||||
// CHECK: define{{.*}} internal void @"$s19noncopyable_private10SomeStructVwxx"(
|
||||
// CHECK: entry
|
||||
// CHECK-NOT: define
|
||||
// CHECK: call void %Destroy(ptr {{.*}}, ptr @"$s19noncopyable_private10PublicTypeVN"
|
||||
// CHECK: ret void
|
||||
// CHECK: }
|
||||
|
||||
// Similar issue with enums.
|
||||
|
||||
public struct SomeStructWithSPE : ~Copyable {
|
||||
public let x = PublicSinglePayloadEnum.empty
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}} internal void @"$s19noncopyable_private17SomeStructWithSPEVwxx"(
|
||||
// CHECK: entry:
|
||||
// CHECK-NOT: define
|
||||
// CHECK: call void %Destroy(ptr {{.*}}, ptr @"$s19noncopyable_private23PublicSinglePayloadEnumON"
|
||||
// CHECK: ret void
|
||||
// CHECK: }
|
||||
|
||||
public struct SomeStructWithMPE : ~Copyable {
|
||||
public let x = PublicMultiPayloadEnum.empty
|
||||
}
|
||||
|
||||
|
||||
// CHECK: define{{.*}} internal void @"$s19noncopyable_private17SomeStructWithMPEVwxx"(
|
||||
// CHECK: entry:
|
||||
// CHECK-NOT: define
|
||||
// CHECK: call void %Destroy(ptr {{.*}}, ptr @"$s19noncopyable_private22PublicMultiPayloadEnumON"
|
||||
// CHECK: ret void
|
||||
// CHECK: }
|
||||
Reference in New Issue
Block a user