diff --git a/lib/IRGen/GenClangDecl.cpp b/lib/IRGen/GenClangDecl.cpp index 559facb9fa5e1..73e570bdcf761 100644 --- a/lib/IRGen/GenClangDecl.cpp +++ b/lib/IRGen/GenClangDecl.cpp @@ -390,8 +390,12 @@ irgen::getBasesAndOffsets(const clang::CXXRecordDecl *decl) { continue; auto offset = Size(layout.getBaseClassOffset(baseRecord).getQuantity()); - auto size = - Size(decl->getASTContext().getTypeSizeInChars(baseType).getQuantity()); + // A base type might have different size and data size (sizeof != dsize). + // Make sure we are using data size here, since fields of the derived type + // might be packed into the base's tail padding. + auto size = Size(decl->getASTContext() + .getTypeInfoDataSizeInChars(baseType) + .Width.getQuantity()); baseOffsetsAndSizes.push_back({baseRecord, offset, size}); } diff --git a/test/Interop/Cxx/foreign-reference/Inputs/inheritance.h b/test/Interop/Cxx/foreign-reference/Inputs/inheritance.h index 5192ef2dd4ec8..f993a65ab200c 100644 --- a/test/Interop/Cxx/foreign-reference/Inputs/inheritance.h +++ b/test/Interop/Cxx/foreign-reference/Inputs/inheritance.h @@ -71,6 +71,27 @@ DerivedOutOfOrder : public BaseT, public DerivedWithVirtualDestructor { } }; +struct +__attribute__((swift_attr("import_reference"))) +__attribute__((swift_attr("retain:immortal"))) +__attribute__((swift_attr("release:immortal"))) +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; + + static DerivedUsesBaseTailPadding& getInstance() { + static DerivedUsesBaseTailPadding singleton; + return singleton; + } +}; // sizeof=16, dsize=14, align=8 + SWIFT_BEGIN_NULLABILITY_ANNOTATIONS namespace ImmortalRefereceExample { diff --git a/test/Interop/Cxx/foreign-reference/inheritance-irgen.swift b/test/Interop/Cxx/foreign-reference/inheritance-irgen.swift index daa556156bbfa..aed4476f1ad10 100644 --- a/test/Interop/Cxx/foreign-reference/inheritance-irgen.swift +++ b/test/Interop/Cxx/foreign-reference/inheritance-irgen.swift @@ -13,6 +13,11 @@ blackHole(x.baseField) blackHole(x.derivedField) blackHole(x.leafField) +let y = DerivedUsesBaseTailPadding.getInstance() + +blackHole(y.field2) +blackHole(y.field4) + // CHECK: call ptr @{{.*}}returnValueType{{.*}} // CHECK-NOT: call void @{{.*}}RCRetain@{{.*}}ValueType(ptr @{{.*}}) var x1 = BasicInheritanceExample.returnValueType() diff --git a/test/Interop/Cxx/foreign-reference/inheritance.swift b/test/Interop/Cxx/foreign-reference/inheritance.swift index 1556f1c149f92..cb0a0e1b7a355 100644 --- a/test/Interop/Cxx/foreign-reference/inheritance.swift +++ b/test/Interop/Cxx/foreign-reference/inheritance.swift @@ -15,9 +15,9 @@ func cast(_ s: SubT) -> BaseT { return cxxCast(s) } -var TemplatingTestSuite = TestSuite("Foreign references work with templates") +var InheritanceTestSuite = TestSuite("Inheritance of foreign reference types") -TemplatingTestSuite.test("SubT") { +InheritanceTestSuite.test("Templated cast to base") { let s: SubT = SubT.getSubT() expectFalse(s.isBase) let sc: BaseT = cast(s) @@ -26,23 +26,28 @@ TemplatingTestSuite.test("SubT") { expectFalse(sc.isBase) } -TemplatingTestSuite.test("BaseT") { +InheritanceTestSuite.test("Templated cast to itself") { let b: BaseT = BaseT.getBaseT() expectTrue(b.isBase) let bc: BaseT = cxxCast(b) // should instantiate I and O both to BaseT expectTrue(bc.isBase) } -TemplatingTestSuite.test("DerivedOutOfOrder") { +InheritanceTestSuite.test("DerivedOutOfOrder") { let d = DerivedOutOfOrder.getInstance() expectEqual(123, d.baseField) expectEqual(456, d.derivedField) expectEqual(789, d.leafField) } -var FrtInheritanceTestSuite = TestSuite("Foreign references in C++ inheritance") +InheritanceTestSuite.test("DerivedUsesBaseTailPadding") { + let d = DerivedUsesBaseTailPadding.getInstance() + expectEqual(123, d.field8) + expectEqual(456, d.field4) + expectEqual(789, d.field2) +} -FrtInheritanceTestSuite.test("ParentChild") { +InheritanceTestSuite.test("ParentChild") { let immortalRefType = ImmortalRefereceExample.returnImmortalRefType() expectTrue( type(of: immortalRefType) is AnyObject.Type,