From: Anders Carlsson Date: Wed, 24 Feb 2010 16:43:12 +0000 (+0000) Subject: Generate correct vcall offsets when we have a primary virtual base that is not a... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5edcc3752563ae0ed5b26f8c89a472ac84af9cf7;p=clang Generate correct vcall offsets when we have a primary virtual base that is not a primary base in the complete class hierarchy. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97039 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 93ed111955..61dd11e490 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -968,6 +968,7 @@ private: /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the /// given base subobject. void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, + uint64_t RealBaseOffset, VisitedVirtualBasesSetTy &VBases); /// AddVCallOffsets - Add vcall offsets for the given base subobject. @@ -1112,6 +1113,7 @@ VtableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, void VtableBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, + uint64_t RealBaseOffset, VisitedVirtualBasesSetTy &VBases) { const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); @@ -1126,8 +1128,28 @@ VtableBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, // emit them for the primary base first). if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { bool PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual(); - AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, Base.getBaseOffset()), - PrimaryBaseIsVirtual, VBases); + + uint64_t PrimaryBaseOffset; + + // Get the base offset of the primary base. + if (PrimaryBaseIsVirtual) { + assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 && + "Primary vbase should have a zero offset!"); + + const ASTRecordLayout &MostDerivedClassLayout = + Context.getASTRecordLayout(MostDerivedClass); + + PrimaryBaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); + } else { + assert(Layout.getBaseClassOffset(PrimaryBase) == 0 && + "Primary base should have a zero offset!"); + + PrimaryBaseOffset = Base.getBaseOffset(); + } + + AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), + PrimaryBaseIsVirtual, RealBaseOffset, VBases); } // FIXME: Don't use /8 here. @@ -1136,7 +1158,7 @@ VtableBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, // We only want to add vcall offsets for virtual bases. if (BaseIsVirtual) - AddVCallOffsets(Base, Base.getBaseOffset()); + AddVCallOffsets(Base, RealBaseOffset); } void VtableBuilder::AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset) { @@ -1434,7 +1456,7 @@ void VtableBuilder::LayoutPrimaryAndAndSecondaryVtables(BaseSubobject Base, // Add vcall and vbase offsets for this vtable. VisitedVirtualBasesSetTy VBases; - AddVCallAndVBaseOffsets(Base, BaseIsVirtual, VBases); + AddVCallAndVBaseOffsets(Base, BaseIsVirtual, Base.getBaseOffset(), VBases); // Reverse them and add them to the vtable components. std::reverse(VCallAndVBaseOffsets.begin(), VCallAndVBaseOffsets.end()); @@ -1470,11 +1492,11 @@ void VtableBuilder::LayoutPrimaryAndAndSecondaryVtables(BaseSubobject Base, AddressPoints.insert(std::make_pair(PrimaryBase, AddressPoint)); } - // Layout secondary vtables. - LayoutSecondaryVtables(Base); - // Clear the vcall offsets. VCallOffsets.clear(); + + // Layout secondary vtables. + LayoutSecondaryVtables(Base); } void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base) { diff --git a/test/CodeGenCXX/vtable-layout-abi-examples.cpp b/test/CodeGenCXX/vtable-layout-abi-examples.cpp index be5765f4f2..2c6b7a48cc 100644 --- a/test/CodeGenCXX/vtable-layout-abi-examples.cpp +++ b/test/CodeGenCXX/vtable-layout-abi-examples.cpp @@ -155,3 +155,35 @@ struct E : X, D { void E::f() { } } + +namespace Test2 { + +// From http://www.codesourcery.com/public/cxx-abi/abi.html#class-types. + +struct A { virtual void f(); }; +struct B : virtual public A { int i; }; +struct C : virtual public A { int j; }; + +// CHECK: Vtable for 'Test2::D' (11 entries). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vcall_offset (0) +// CHECK-NEXT: 2 | offset_to_top (0) +// CHECK-NEXT: 3 | Test2::D RTTI +// CHECK-NEXT: -- (Test2::A, 0) vtable address -- +// CHECK-NEXT: -- (Test2::B, 0) vtable address -- +// CHECK-NEXT: -- (Test2::D, 0) vtable address -- +// CHECK-NEXT: 4 | void Test2::A::f() +// CHECK-NEXT: 5 | void Test2::D::d() +// CHECK-NEXT: 6 | vbase_offset (-16) +// CHECK-NEXT: 7 | vcall_offset (-16) +// CHECK-NEXT: 8 | offset_to_top (-16) +// CHECK-NEXT: 9 | Test2::D RTTI +// CHECK-NEXT: -- (Test2::A, 16) vtable address -- +// CHECK-NEXT: -- (Test2::C, 16) vtable address -- +// CHECK-NEXT: 10 | [unused] void Test2::A::f() +struct D : public B, public C { + virtual void d(); +}; +void D::d() { } + +}