Skip to content

Commit ba8ba57

Browse files
committed
[cxx-interop] Layout reference types that use tail padding of their bases correctly
This is a follow-up to d3e43bb which resolved the issue for value types, but not for foreign reference types. This change teaches IRGen that a base type of a C++ type might occupy less memory than its `sizeof`, specifically, it might only use `dsize` amount of memory. rdar://147527755
1 parent 2abed96 commit ba8ba57

File tree

4 files changed

+39
-2
lines changed

4 files changed

+39
-2
lines changed

lib/IRGen/GenClangDecl.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,12 @@ irgen::getBasesAndOffsets(const clang::CXXRecordDecl *decl) {
390390
continue;
391391

392392
auto offset = Size(layout.getBaseClassOffset(baseRecord).getQuantity());
393-
auto size =
394-
Size(decl->getASTContext().getTypeSizeInChars(baseType).getQuantity());
393+
// A base type might have different size and data size (sizeof != dsize).
394+
// Make sure we are using data size here, since fields of the derived type
395+
// might be packed into the base's tail padding.
396+
auto size = Size(decl->getASTContext()
397+
.getTypeInfoDataSizeInChars(baseType)
398+
.Width.getQuantity());
395399

396400
baseOffsetsAndSizes.push_back({baseRecord, offset, size});
397401
}

test/Interop/Cxx/foreign-reference/Inputs/inheritance.h

+21
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,27 @@ DerivedOutOfOrder : public BaseT, public DerivedWithVirtualDestructor {
7171
}
7272
};
7373

74+
struct
75+
__attribute__((swift_attr("import_reference")))
76+
__attribute__((swift_attr("retain:immortal")))
77+
__attribute__((swift_attr("release:immortal")))
78+
BaseAlign8 {
79+
long long field8 = 123;
80+
}; // sizeof=8, dsize=8, align=8
81+
82+
struct DerivedHasTailPadding : public BaseAlign8 {
83+
int field4 = 456;
84+
}; // sizeof=16, dsize=12, align=8
85+
86+
struct DerivedUsesBaseTailPadding : public DerivedHasTailPadding {
87+
short field2 = 789;
88+
89+
static DerivedUsesBaseTailPadding& getInstance() {
90+
static DerivedUsesBaseTailPadding singleton;
91+
return singleton;
92+
}
93+
}; // sizeof=16, dsize=14, align=8
94+
7495
SWIFT_BEGIN_NULLABILITY_ANNOTATIONS
7596

7697
namespace ImmortalRefereceExample {

test/Interop/Cxx/foreign-reference/inheritance-irgen.swift

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ blackHole(x.baseField)
1313
blackHole(x.derivedField)
1414
blackHole(x.leafField)
1515

16+
let y = DerivedUsesBaseTailPadding.getInstance()
17+
18+
blackHole(y.field2)
19+
blackHole(y.field4)
20+
1621
// CHECK: call ptr @{{.*}}returnValueType{{.*}}
1722
// CHECK-NOT: call void @{{.*}}RCRetain@{{.*}}ValueType(ptr @{{.*}})
1823
var x1 = BasicInheritanceExample.returnValueType()

test/Interop/Cxx/foreign-reference/inheritance.swift

+7
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ InheritanceTestSuite.test("DerivedOutOfOrder") {
4040
expectEqual(789, d.leafField)
4141
}
4242

43+
InheritanceTestSuite.test("DerivedUsesBaseTailPadding") {
44+
let d = DerivedUsesBaseTailPadding.getInstance()
45+
expectEqual(123, d.field8)
46+
expectEqual(456, d.field4)
47+
expectEqual(789, d.field2)
48+
}
49+
4350
InheritanceTestSuite.test("ParentChild") {
4451
let immortalRefType = ImmortalRefereceExample.returnImmortalRefType()
4552
expectTrue(

0 commit comments

Comments
 (0)