diff options
author | Eli Friedman <eli.friedman@gmail.com> | 2011-10-21 22:49:56 +0000 |
---|---|---|
committer | Eli Friedman <eli.friedman@gmail.com> | 2011-10-21 22:49:56 +0000 |
commit | 227e483cb1f77ea6dcd38c2ca9fb490894a5f887 (patch) | |
tree | 0e9d9dbc284db15b3fde014cf8760e0cf1db4493 | |
parent | 13c7fcceb9fd96f5be03af038ce16b05bb5e9598 (diff) |
More ASTRecordLayout changes for MS ABI; based on patch by r4start.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142694 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/RecordLayout.h | 20 | ||||
-rw-r--r-- | lib/AST/RecordLayout.cpp | 4 | ||||
-rw-r--r-- | lib/AST/RecordLayoutBuilder.cpp | 56 | ||||
-rw-r--r-- | test/Sema/ms_class_layout.cpp | 53 |
4 files changed, 86 insertions, 47 deletions
diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index b0186cea29..ec07267d66 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -62,8 +62,11 @@ class ASTRecordLayout { /// (either a base or a member). Will be zero if the class doesn't contain /// any empty subobjects. CharUnits SizeOfLargestEmptySubobject; - - /// VBPtrOffset - Virtual base table offset. + + /// VFPtrOffset - Virtual function table offset (Microsoft-only). + CharUnits VFPtrOffset; + + /// VBPtrOffset - Virtual base table offset (Microsoft-only). CharUnits VBPtrOffset; /// PrimaryBase - The primary base info for this record. @@ -92,7 +95,8 @@ class ASTRecordLayout { // Constructor for C++ records. typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy; ASTRecordLayout(const ASTContext &Ctx, - CharUnits size, CharUnits alignment, CharUnits vbptroffset, + CharUnits size, CharUnits alignment, + CharUnits vfptroffset, CharUnits vbptroffset, CharUnits datasize, const uint64_t *fieldoffsets, unsigned fieldcount, CharUnits nonvirtualsize, CharUnits nonvirtualalign, @@ -204,7 +208,17 @@ public: return CXXInfo->SizeOfLargestEmptySubobject; } + /// getVFPtrOffset - Get the offset for virtual function table pointer. + /// This is only meaningful with the Microsoft ABI. + CharUnits getVFPtrOffset() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return CXXInfo->VFPtrOffset; + } + + /// getVBPtrOffset - Get the offset for virtual base table pointer. + /// This is only meaningful with the Microsoft ABI. CharUnits getVBPtrOffset() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); return CXXInfo->VBPtrOffset; } }; diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp index ccc591a28f..0114eba06d 100644 --- a/lib/AST/RecordLayout.cpp +++ b/lib/AST/RecordLayout.cpp @@ -43,7 +43,8 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size, // Constructor for C++ records. ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment, - CharUnits vbptroffset, CharUnits datasize, + CharUnits vfptroffset, CharUnits vbptroffset, + CharUnits datasize, const uint64_t *fieldoffsets, unsigned fieldcount, CharUnits nonvirtualsize, @@ -68,6 +69,7 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject; CXXInfo->BaseOffsets = BaseOffsets; CXXInfo->VBaseOffsets = VBaseOffsets; + CXXInfo->VFPtrOffset = vfptroffset; CXXInfo->VBPtrOffset = vbptroffset; #ifndef NDEBUG diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 827c7efa66..e8820d002c 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -592,6 +592,9 @@ protected: /// out is virtual. bool PrimaryBaseIsVirtual; + /// VFPtrOffset - Virtual function table offset. Only for MS layout. + CharUnits VFPtrOffset; + /// VBPtrOffset - Virtual base table offset. Only for MS layout. CharUnits VBPtrOffset; @@ -625,7 +628,9 @@ protected: DataSize(0), NonVirtualSize(CharUnits::Zero()), NonVirtualAlignment(CharUnits::One()), ZeroLengthBitfield(0), PrimaryBase(0), - PrimaryBaseIsVirtual(false), VBPtrOffset(CharUnits::fromQuantity(-1)), + PrimaryBaseIsVirtual(false), + VFPtrOffset(CharUnits::fromQuantity(-1)), + VBPtrOffset(CharUnits::fromQuantity(-1)), FirstNearlyEmptyVBase(0) { } void Layout(const RecordDecl *D); @@ -669,7 +674,7 @@ protected: void SelectPrimaryVBase(const CXXRecordDecl *RD); - void EnsureVTablePointerAlignment(); + void EnsureVTablePointerAlignment(CharUnits UnpackedBaseAlign); /// LayoutNonVirtualBases - Determines the primary base class (if any) and /// lays it out. Will then proceed to lay out all non-virtual base clasess. @@ -739,8 +744,6 @@ public: static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD); virtual ~RecordLayoutBuilder() { } - - CharUnits GetVBPtrOffset() const { return VBPtrOffset; } }; } // end anonymous namespace @@ -937,9 +940,7 @@ void RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD) { } void -RecordLayoutBuilder::EnsureVTablePointerAlignment() { - CharUnits UnpackedBaseAlign = - Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0)); +RecordLayoutBuilder::EnsureVTablePointerAlignment(CharUnits UnpackedBaseAlign) { CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign; // The maximum field alignment overrides base align. @@ -949,7 +950,8 @@ RecordLayoutBuilder::EnsureVTablePointerAlignment() { } // Round up the current record size to pointer alignment. - setDataSize(getDataSize().RoundUpToAlignment(BaseAlign)); + setSize(getSize().RoundUpToAlignment(BaseAlign)); + setDataSize(getSize()); // Update the alignment. UpdateAlignment(BaseAlign, UnpackedBaseAlign); @@ -994,9 +996,11 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { // Under the Itanium ABI, a dynamic class without a primary base has a // vtable pointer. It is placed at offset 0. assert(DataSize == 0 && "Vtable pointer must be at offset zero!"); - EnsureVTablePointerAlignment(); CharUnits PtrWidth = Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); + CharUnits PtrAlign = + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0)); + EnsureVTablePointerAlignment(PtrAlign); setSize(getSize() + PtrWidth); setDataSize(getSize()); } @@ -1032,15 +1036,19 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { // after any base classes. CharUnits PtrWidth = Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); + CharUnits PtrAlign = + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0)); + PtrAlign = std::max(PtrAlign, Alignment); if (HasNewVirtualFunction(RD) && (!PrimaryBase || !BaseHasVFPtr(PrimaryBase))) { - EnsureVTablePointerAlignment(); + EnsureVTablePointerAlignment(PtrAlign); + VFPtrOffset = getSize(); setSize(getSize() + PtrWidth); setDataSize(getSize()); } if (RD->getNumVBases() && (!PrimaryBase || !PrimaryBase->getNumVBases())) { - EnsureVTablePointerAlignment(); + EnsureVTablePointerAlignment(PtrAlign); VBPtrOffset = getSize(); setSize(getSize() + PtrWidth); setDataSize(getSize()); @@ -2030,7 +2038,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { Builder->Layout(RD); - TargetAlign = Builder->getAligment(); + TargetAlign = Builder->NonVirtualAlignment; if (getTargetInfo().getCXXABI() == CXXABI_Microsoft && TargetAlign.getQuantity() > 4) { @@ -2053,7 +2061,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout. // This does not affect the calculations of MSVC layouts bool IsPODForThePurposeOfLayout = - (getTargetInfo().getCXXABI() == CXXABI_Microsoft) || + (getTargetInfo().getCXXABI() != CXXABI_Microsoft) && cast<CXXRecordDecl>(D)->isPOD(); // FIXME: This should be done in FinalizeLayout. @@ -2065,7 +2073,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { NewEntry = new (*this) ASTRecordLayout(*this, Builder->getSize(), Builder->Alignment, - Builder->GetVBPtrOffset(), + Builder->VFPtrOffset, + Builder->VBPtrOffset, DataSize, Builder->FieldOffsets.data(), Builder->FieldOffsets.size(), @@ -2175,22 +2184,16 @@ static void DumpCXXRecordLayout(raw_ostream &OS, IndentLevel++; const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + bool HasVfptr = Layout.getVFPtrOffset() != CharUnits::fromQuantity(-1); bool HasVbptr = Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1); // Vtable pointer. - if (RD->isDynamicClass() && !PrimaryBase) { + if (RD->isDynamicClass() && !PrimaryBase && + C.getTargetInfo().getCXXABI() != CXXABI_Microsoft) { PrintOffset(OS, Offset, IndentLevel); OS << '(' << *RD << " vtable pointer)\n"; } - if (HasVbptr && !PrimaryBase) { - PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel); - OS << '(' << *RD << " vbtable pointer)\n"; - - // one vbtable per class - HasVbptr = false; - } - // Dump (non-virtual) bases for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) { @@ -2208,7 +2211,12 @@ static void DumpCXXRecordLayout(raw_ostream &OS, Base == PrimaryBase ? "(primary base)" : "(base)", /*IncludeVirtualBases=*/false); } - // vbptr + + // vfptr and vbptr (for Microsoft C++ ABI) + if (HasVfptr) { + PrintOffset(OS, Offset + Layout.getVFPtrOffset(), IndentLevel); + OS << '(' << *RD << " vftable pointer)\n"; + } if (HasVbptr) { PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel); OS << '(' << *RD << " vbtable pointer)\n"; diff --git a/test/Sema/ms_class_layout.cpp b/test/Sema/ms_class_layout.cpp index f516aa5df8..9a0cd459a3 100644 --- a/test/Sema/ms_class_layout.cpp +++ b/test/Sema/ms_class_layout.cpp @@ -61,6 +61,12 @@ struct H : public G, { }; +struct I : public virtual D +{ + virtual ~I(){} + double q; +}; + #pragma pack(pop) // This needs only for building layouts. @@ -72,18 +78,19 @@ int main() { DerivedStruct* v; H* g; BaseStruct* u; + I* i; return 0; } // CHECK: 0 | class D -// CHECK-NEXT: 0 | (D vtable pointer) +// CHECK-NEXT: 0 | (D vftable pointer) // CHECK-NEXT: 8 | double a // CHECK-NEXT: sizeof=16, dsize=16, align=8 // CHECK-NEXT: nvsize=16, nvalign=8 // CHECK: 0 | class B -// CHECK-NEXT: 0 | (B vtable pointer) +// CHECK-NEXT: 0 | (B vftable pointer) // CHECK-NEXT: 4 | int b_field // CHECK-NEXT: sizeof=8, dsize=8, align=4 @@ -91,7 +98,7 @@ int main() { // CHECK: 0 | class A // CHECK-NEXT: 0 | class B (primary base) -// CHECK-NEXT: 0 | (B vtable pointer) +// CHECK-NEXT: 0 | (B vftable pointer) // CHECK-NEXT: 4 | int b_field // CHECK-NEXT: 8 | int a_field // CHECK-NEXT: 12 | char one @@ -101,10 +108,10 @@ int main() { // CHECK: 0 | class C // CHECK-NEXT: 0 | class D (primary base) -// CHECK-NEXT: 0 | (D vtable pointer) +// CHECK-NEXT: 0 | (D vftable pointer) // CHECK-NEXT: 8 | double a // CHECK-NEXT: 16 | class B (base) -// CHECK-NEXT: 16 | (B vtable pointer) +// CHECK-NEXT: 16 | (B vftable pointer) // CHECK-NEXT: 20 | int b_field // CHECK-NEXT: 24 | (C vbtable pointer) // CHECK-NEXT: 32 | double c1_field @@ -113,23 +120,23 @@ int main() { // CHECK-NEXT: 56 | int c4_field // CHECK-NEXT: 64 | class A (virtual base) // CHECK-NEXT: 64 | class B (primary base) -// CHECK-NEXT: 64 | (B vtable pointer) +// CHECK-NEXT: 64 | (B vftable pointer) // CHECK-NEXT: 68 | int b_field // CHECK-NEXT: 72 | int a_field // CHECK-NEXT: 76 | char one // CHECK-NEXT: sizeof=80, dsize=80, align=8 -// CHECK-NEXT: nvsize=80, nvalign=8 +// CHECK-NEXT: nvsize=64, nvalign=8 // CHECK: 0 | struct BaseStruct // CHECK-NEXT: 0 | double v0 // CHECK-NEXT: 8 | float v1 // CHECK-NEXT: 16 | class C fg // CHECK-NEXT: 16 | class D (primary base) -// CHECK-NEXT: 16 | (D vtable pointer) +// CHECK-NEXT: 16 | (D vftable pointer) // CHECK-NEXT: 24 | double a // CHECK-NEXT: 32 | class B (base) -// CHECK-NEXT: 32 | (B vtable pointer) +// CHECK-NEXT: 32 | (B vftable pointer) // CHECK-NEXT: 36 | int b_field // CHECK-NEXT: 40 | (C vbtable pointer) // CHECK-NEXT: 48 | double c1_field @@ -138,13 +145,13 @@ int main() { // CHECK-NEXT: 72 | int c4_field // CHECK-NEXT: 80 | class A (virtual base) // CHECK-NEXT: 80 | class B (primary base) -// CHECK-NEXT: 80 | (B vtable pointer) +// CHECK-NEXT: 80 | (B vftable pointer) // CHECK-NEXT: 84 | int b_field // CHECK-NEXT: 88 | int a_field // CHECK-NEXT: 92 | char one // CHECK-NEXT: sizeof=80, dsize=80, align=8 -// CHECK-NEXT: nvsize=80, nvalign=8 +// CHECK-NEXT: nvsize=64, nvalign=8 // CHECK: sizeof=96, dsize=96, align=8 // CHECK-NEXT: nvsize=96, nvalign=8 @@ -155,10 +162,10 @@ int main() { // CHECK-NEXT: 8 | float v1 // CHECK-NEXT: 16 | class C fg // CHECK-NEXT: 16 | class D (primary base) -// CHECK-NEXT: 16 | (D vtable pointer) +// CHECK-NEXT: 16 | (D vftable pointer) // CHECK-NEXT: 24 | double a // CHECK-NEXT: 32 | class B (base) -// CHECK-NEXT: 32 | (B vtable pointer) +// CHECK-NEXT: 32 | (B vftable pointer) // CHECK-NEXT: 36 | int b_field // CHECK-NEXT: 40 | (C vbtable pointer) // CHECK-NEXT: 48 | double c1_field @@ -167,12 +174,12 @@ int main() { // CHECK-NEXT: 72 | int c4_field // CHECK-NEXT: 80 | class A (virtual base) // CHECK-NEXT: 80 | class B (primary base) -// CHECK-NEXT: 80 | (B vtable pointer) +// CHECK-NEXT: 80 | (B vftable pointer) // CHECK-NEXT: 84 | int b_field // CHECK-NEXT: 88 | int a_field // CHECK-NEXT: 92 | char one // CHECK-NEXT: sizeof=80, dsize=80, align=8 -// CHECK-NEXT: nvsize=80, nvalign=8 +// CHECK-NEXT: nvsize=64, nvalign=8 // CHECK: 96 | int x // CHECK-NEXT: sizeof=104, dsize=104, align=8 @@ -183,14 +190,22 @@ int main() { // CHECK-NEXT: sizeof=4, dsize=4, align=4 // CHECK-NEXT: nvsize=4, nvalign=4 -// FIXME: Dump should not be showing vfptr, and vbptr is in the wrong order. // CHECK: 0 | struct H -// CHECK-NEXT: 0 | (H vtable pointer) -// CHECK-NEXT: 4 | (H vbtable pointer) // CHECK-NEXT: 0 | struct G (base) // CHECK-NEXT: 0 | int g_field +// CHECK-NEXT: 4 | (H vbtable pointer) // CHECK-NEXT: 8 | class D (virtual base) -// CHECK-NEXT: 8 | (D vtable pointer) +// CHECK-NEXT: 8 | (D vftable pointer) // CHECK-NEXT: 16 | double a // CHECK-NEXT: sizeof=24, dsize=24, align=8 +// CHECK-NEXT: nvsize=8, nvalign=4 + +// CHECK: 0 | struct I +// CHECK-NEXT: 0 | (I vftable pointer) +// CHECK-NEXT: 8 | (I vbtable pointer) +// CHECK-NEXT: 16 | double q +// CHECK-NEXT: 24 | class D (virtual base) +// CHECK-NEXT: 24 | (D vftable pointer) +// CHECK-NEXT: 32 | double a +// CHECK-NEXT: sizeof=40, dsize=40, align=8 // CHECK-NEXT: nvsize=24, nvalign=8 |