Index: lib/AST/RecordLayoutBuilder.cpp =================================================================== --- lib/AST/RecordLayoutBuilder.cpp +++ lib/AST/RecordLayoutBuilder.cpp @@ -2692,7 +2692,8 @@ auto FieldBitOffset = External.getExternalFieldOffset(FD); placeFieldAtBitOffset(FieldBitOffset); auto NewSize = Context.toCharUnitsFromBits( - llvm::alignTo(FieldBitOffset + Width, Context.getCharWidth())); + llvm::alignDown(FieldBitOffset, Context.toBits(Info.Alignment)) + + Context.toBits(Info.Size)); Size = std::max(Size, NewSize); Alignment = std::max(Alignment, Info.Alignment); } else if (IsUnion) { @@ -2741,12 +2742,17 @@ CharUnits InjectionSite = VBPtrOffset; // But before we do, make sure it's properly aligned. VBPtrOffset = VBPtrOffset.alignTo(PointerInfo.Alignment); + // Determine where the first field should be laid out after the vbptr. + CharUnits FieldStart = VBPtrOffset + PointerInfo.Size; // Shift everything after the vbptr down, unless we're using an external // layout. - if (UseExternalLayout) + if (UseExternalLayout) { + // It is possible that there were no fields or bases located after vbptr, + // so the size was not adjusted before. + if (Size < FieldStart) + Size = FieldStart; return; - // Determine where the first field should be laid out after the vbptr. - CharUnits FieldStart = VBPtrOffset + PointerInfo.Size; + } // Make sure that the amount we push the fields back by is a multiple of the // alignment. CharUnits Offset = (FieldStart - InjectionSite) @@ -2771,8 +2777,14 @@ if (HasVBPtr) VBPtrOffset += Offset; - if (UseExternalLayout) + if (UseExternalLayout) { + // The class may have no bases or fields, but still have a vfptr + // (e.g. it's an interface class). The size was not correctly set before + // in this case. + if (FieldOffsets.empty() && Bases.empty()) + Size += Offset; return; + } Size += Offset; Index: test/CodeGenCXX/Inputs/override-bit-field-layout.layout =================================================================== --- test/CodeGenCXX/Inputs/override-bit-field-layout.layout +++ test/CodeGenCXX/Inputs/override-bit-field-layout.layout @@ -14,3 +14,11 @@ Size:128 Alignment:64 FieldOffsets: [64]> + +*** Dumping AST Record Layout +Type: struct S3 + +Layout: Index: test/CodeGenCXX/Inputs/override-layout-virtual-base.layout =================================================================== --- /dev/null +++ test/CodeGenCXX/Inputs/override-layout-virtual-base.layout @@ -0,0 +1,8 @@ + +*** Dumping AST Record Layout +Type: struct S2 + +Layout: Index: test/CodeGenCXX/override-bit-field-layout.cpp =================================================================== --- test/CodeGenCXX/override-bit-field-layout.cpp +++ test/CodeGenCXX/override-bit-field-layout.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -w -fdump-record-layouts-simple -foverride-record-layout=%S/Inputs/override-bit-field-layout.layout %s | FileCheck %s +// RUN: %clang_cc1 -w -triple=x86_64-pc-win32 -fms-compatibility -fdump-record-layouts-simple -foverride-record-layout=%S/Inputs/override-bit-field-layout.layout %s | FileCheck %s // CHECK: Type: struct S1 // CHECK: FieldOffsets: [0, 11] @@ -14,7 +14,23 @@ short a : 3; }; +// CHECK: Type: struct S3 +// CHECK: Size:32 +// CHECK: FieldOffsets: [0, 1] +struct S3 { + int a : 1; + int b : 2; +}; + +// CHECK: Type: struct S4 +// CHECK: FieldOffsets: [32] +struct S4 : S3 { + char c; +}; + void use_structs() { S1 s1s[sizeof(S1)]; S2 s2s[sizeof(S2)]; + S3 s3s[sizeof(S3)]; + S4 s4s[sizeof(S4)]; } Index: test/CodeGenCXX/override-layout-virtual-base.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/override-layout-virtual-base.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -w -triple=x86_64-pc-win32 -fms-compatibility -fdump-record-layouts-simple -foverride-record-layout=%S/Inputs/override-layout-virtual-base.layout %s | FileCheck %s + +struct S1 { + int a; +}; + +struct S2 : virtual S1 { + virtual void foo() {} +}; + +// CHECK: Type: struct S3 +// CHECK: FieldOffsets: [128] +struct S3 : S2 { + char b; +}; + +void use_structs() { + S1 s1s[sizeof(S1)]; + S2 s2s[sizeof(S2)]; + S3 s3s[sizeof(S3)]; +}