mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[cxx-interop] Fix IRGen for C++ types that use tail padding of their bases
In C++, a field of a derived class might be placed into the tail padding of a base class. Swift was not handling this case correctly, causing an asserts-disabled compiler to run out of RAM, and an asserts-enabled compiler to fail with an assertion. Fixes this IRGen assertion: ``` Assertion failed: (offset >= NextOffset && "adding fields out of order"), function addField, file GenStruct.cpp, line 1509. ``` rdar://138764929
This commit is contained in:
@@ -1423,7 +1423,8 @@ private:
|
|||||||
auto sfi = swiftProperties.begin(), sfe = swiftProperties.end();
|
auto sfi = swiftProperties.begin(), sfe = swiftProperties.end();
|
||||||
// When collecting fields from the base subobjects, we do not have corresponding swift
|
// When collecting fields from the base subobjects, we do not have corresponding swift
|
||||||
// stored properties.
|
// stored properties.
|
||||||
if (decl != ClangDecl)
|
bool isBaseSubobject = decl != ClangDecl;
|
||||||
|
if (isBaseSubobject)
|
||||||
sfi = swiftProperties.end();
|
sfi = swiftProperties.end();
|
||||||
|
|
||||||
while (cfi != cfe) {
|
while (cfi != cfe) {
|
||||||
@@ -1475,10 +1476,14 @@ private:
|
|||||||
|
|
||||||
assert(sfi == sfe && "more Swift fields than there were Clang fields?");
|
assert(sfi == sfe && "more Swift fields than there were Clang fields?");
|
||||||
|
|
||||||
Size objectTotalStride = Size(layout.getSize().getQuantity());
|
auto objectSize = isBaseSubobject ? layout.getDataSize() : layout.getSize();
|
||||||
// We never take advantage of tail padding, because that would prevent
|
Size objectTotalStride = Size(objectSize.getQuantity());
|
||||||
// us from passing the address of the object off to C, which is a pretty
|
// Unless this is a base subobject of a C++ type, we do not take advantage
|
||||||
// likely scenario for imported C types.
|
// of tail padding, because that would prevent us from passing the address
|
||||||
|
// of the object off to C, which is a pretty likely scenario for imported C
|
||||||
|
// types.
|
||||||
|
// In C++, fields of a derived class might get placed into tail padding of a
|
||||||
|
// base class, in which case we should not add extra padding here.
|
||||||
assert(NextOffset <= SubobjectAdjustment + objectTotalStride);
|
assert(NextOffset <= SubobjectAdjustment + objectTotalStride);
|
||||||
assert(SpareBits.size() <= SubobjectAdjustment.getValueInBits() +
|
assert(SpareBits.size() <= SubobjectAdjustment.getValueInBits() +
|
||||||
objectTotalStride.getValueInBits());
|
objectTotalStride.getValueInBits());
|
||||||
|
|||||||
@@ -118,3 +118,17 @@ struct InheritFromStructsWithVirtualMethod: HasOneFieldWithVirtualMethod, HasTwo
|
|||||||
int d;
|
int d;
|
||||||
virtual ~InheritFromStructsWithVirtualMethod() = default;
|
virtual ~InheritFromStructsWithVirtualMethod() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// MARK: Types that pack their fields into tail padding of a base class.
|
||||||
|
|
||||||
|
struct BaseAlign8 {
|
||||||
|
long long field8 = 123;
|
||||||
|
}; // sizeof=8, dsize=8, align=8
|
||||||
|
|
||||||
|
struct DerivedHasTailPadding : public BaseAlign8 {
|
||||||
|
int field4 = 456;
|
||||||
|
}; // sizeof=16, dsize=12, align=8
|
||||||
|
|
||||||
|
struct DerivedUsesBaseTailPadding : public DerivedHasTailPadding {
|
||||||
|
short field2 = 789;
|
||||||
|
}; // sizeof=16, dsize=14, align=8
|
||||||
|
|||||||
@@ -117,4 +117,11 @@ FieldsTestSuite.test("Structs with virtual methods") {
|
|||||||
expectEqual(derived.d, 42)
|
expectEqual(derived.d, 42)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FieldsTestSuite.test("Field in tail padding of base class") {
|
||||||
|
let usesBaseTailPadding = DerivedUsesBaseTailPadding()
|
||||||
|
expectEqual(usesBaseTailPadding.field2, 789)
|
||||||
|
expectEqual(usesBaseTailPadding.field4, 456)
|
||||||
|
expectEqual(usesBaseTailPadding.field8, 123)
|
||||||
|
}
|
||||||
|
|
||||||
runAllTests()
|
runAllTests()
|
||||||
|
|||||||
Reference in New Issue
Block a user