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:
Arnold Schwaighofer
2024-08-19 09:08:52 -07:00
parent ebe17694d4
commit ad6f6dec6e
19 changed files with 268 additions and 85 deletions

View File

@@ -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 {

View File

@@ -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();

View File

@@ -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(

View File

@@ -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);

View File

@@ -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() { }

View File

@@ -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:

View File

@@ -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)
{}

View File

@@ -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 \

View File

@@ -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();

View File

@@ -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));

View File

@@ -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));

View File

@@ -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,

View File

@@ -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

View File

@@ -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());
}

View File

@@ -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:

View File

@@ -280,6 +280,7 @@ protected:
IsTriviallyDestroyable,
IsCopyable,
IsFixedSize,
IsABIAccessible,
::std::forward<T>(args)...) {}
const Derived &asDerived() const {

View File

@@ -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);
}

View 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)
}

View 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: }