More fixes. Don't try to emit a virtual base vtable if the virtual base in question is a primary virtual base of some other base.

llvm-svn: 96881
This commit is contained in:
Anders Carlsson 2010-02-23 03:48:14 +00:00
parent bae46277fe
commit 0570f71255
2 changed files with 72 additions and 10 deletions

View File

@ -961,6 +961,10 @@ private:
typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy;
/// PrimaryVirtualBases - All known virtual bases who is a primary base of
/// some other base.
VisitedVirtualBasesSetTy PrimaryVirtualBases;
/// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the
/// given base subobject.
void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual,
@ -1107,7 +1111,7 @@ VtableBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base,
AddVBaseOffsets(Base.getBase(), OffsetToTop, VBases);
// We only want to add vcall offsets for virtual bases.
if (BaseIsVirtual && OffsetToTop != 0)
if (BaseIsVirtual)
AddVCallOffsets(Base, Base.getBaseOffset());
}
@ -1117,9 +1121,24 @@ void VtableBuilder::AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset) {
// Handle the primary base first.
if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
uint64_t PrimaryBaseOffset;
// Get the base offset of the primary base.
uint64_t PrimaryBaseOffset = Base.getBaseOffset() +
Layout.getBaseClassOffset(PrimaryBase);
if (Layout.getPrimaryBaseWasVirtual()) {
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();
}
AddVCallOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset),
VBaseOffset);
@ -1245,13 +1264,26 @@ VtableBuilder::AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
if (Layout.getPrimaryBaseWasVirtual())
assert(false && "FIXME: Handle vbases here.");
else
uint64_t BaseOffset;
if (Layout.getPrimaryBaseWasVirtual()) {
assert(Layout.getVBaseClassOffset(PrimaryBase) == 0 &&
"Primary vbase should have a zero offset!");
const ASTRecordLayout &MostDerivedClassLayout =
Context.getASTRecordLayout(MostDerivedClass);
BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase);
// Keep track of this primary virtual base.
PrimaryVirtualBases.insert(PrimaryBase);
} else {
assert(Layout.getBaseClassOffset(PrimaryBase) == 0 &&
"Primary base should have a zero offset!");
BaseOffset = Base.getBaseOffset();
}
AddMethods(BaseSubobject(PrimaryBase, Base.getBaseOffset()), PrimaryBases);
AddMethods(BaseSubobject(PrimaryBase, BaseOffset), PrimaryBases);
if (!PrimaryBases.insert(PrimaryBase))
assert(false && "Found a duplicate primary base!");
@ -1409,10 +1441,11 @@ VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
// Check if this base needs a vtable. (If it's virtual, and we haven't
// visited it before).
// Check if this base needs a vtable. (If it's virtual, not a primary base
// of some other class, and we haven't visited it before).
if (I->isVirtual() && BaseDecl->isDynamicClass() &&
BaseDecl != PrimaryBase && VBases.insert(BaseDecl)) {
BaseDecl != PrimaryBase && !PrimaryVirtualBases.count(BaseDecl) &&
VBases.insert(BaseDecl)) {
const ASTRecordLayout &MostDerivedClassLayout =
Context.getASTRecordLayout(MostDerivedClass);
uint64_t BaseOffset =

View File

@ -481,3 +481,32 @@ struct B : virtual A {
void B::f() { }
}
namespace Test13 {
// Test that we don't try to emit a vtable for 'A' twice.
struct A {
virtual void f();
};
struct B : virtual A {
virtual void f();
};
// CHECK: Vtable for 'Test13::C' (6 entries).
// CHECK-NEXT: 0 | vbase_offset (0)
// CHECK-NEXT: 1 | vbase_offset (0)
// CHECK-NEXT: 2 | vcall_offset (0)
// CHECK-NEXT: 3 | offset_to_top (0)
// CHECK-NEXT: 4 | Test13::C RTTI
// CHECK-NEXT: -- (Test13::A, 0) vtable address --
// CHECK-NEXT: -- (Test13::B, 0) vtable address --
// CHECK-NEXT: -- (Test13::C, 0) vtable address --
// CHECK-NEXT: 5 | void Test13::C::f()
struct C : virtual B, virtual A {
virtual void f();
};
void C::f() { }
}