Fix a bug where we were generating an unnecessary vtable for a virtual base that's already a primary virtual base.

llvm-svn: 97303
This commit is contained in:
Anders Carlsson 2010-02-27 04:05:52 +00:00
parent e334bb1a66
commit b08aaa3e10
2 changed files with 67 additions and 9 deletions

View File

@ -1220,7 +1220,12 @@ private:
/// LayoutSecondaryVtables - Layout the secondary vtables for the given base
/// subobject.
void LayoutSecondaryVtables(BaseSubobject Base);
/// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this
/// class hierarchy.
void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
VisitedVirtualBasesSetTy &VBases);
/// LayoutVtablesForVirtualBases - Layout vtables for all virtual bases of the
/// given base (excluding any primary bases).
void LayoutVtablesForVirtualBases(const CXXRecordDecl *RD,
@ -1418,9 +1423,6 @@ VtableBuilder::AddMethods(BaseSubobject Base,
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!");
@ -1498,6 +1500,11 @@ void VtableBuilder::LayoutVtable() {
/*BaseIsVirtual=*/false);
VisitedVirtualBasesSetTy VBases;
// Determine the primary virtual bases.
DeterminePrimaryVirtualBases(MostDerivedClass, VBases);
VBases.clear();
LayoutVtablesForVirtualBases(MostDerivedClass, VBases);
}
@ -1591,6 +1598,31 @@ void VtableBuilder::LayoutSecondaryVtables(BaseSubobject Base) {
}
}
void
VtableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
VisitedVirtualBasesSetTy &VBases) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
// Check if this base has a primary base.
if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
// Check if it's virtual
if (Layout.getPrimaryBaseWasVirtual())
PrimaryVirtualBases.insert(PrimaryBase);
}
// Traverse bases, looking for more primary virtual bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
if (I->isVirtual() && !VBases.insert(BaseDecl))
continue;
DeterminePrimaryVirtualBases(BaseDecl, VBases);
}
}
void
VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD,
VisitedVirtualBasesSetTy &VBases) {
@ -1598,9 +1630,6 @@ VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD,
// Then come the virtual base virtual tables, also in inheritance graph
// order, and again excluding primary bases (which share virtual tables with
// the classes for which they are primary).
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
const CXXRecordDecl *BaseDecl =
@ -1609,8 +1638,7 @@ VtableBuilder::LayoutVtablesForVirtualBases(const CXXRecordDecl *RD,
// 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 && !PrimaryVirtualBases.count(BaseDecl) &&
VBases.insert(BaseDecl)) {
!PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) {
const ASTRecordLayout &MostDerivedClassLayout =
Context.getASTRecordLayout(MostDerivedClass);
uint64_t BaseOffset =

View File

@ -539,3 +539,33 @@ void D::f() { }
}
namespace Test15 {
// Test that we don't emit an extra vtable for B since it's a primary base of C.
struct A { virtual void a(); };
struct B { virtual void b(); };
struct C : virtual B { };
// CHECK: Vtable for 'Test15::D' (11 entries).
// CHECK-NEXT: 0 | vbase_offset (8)
// CHECK-NEXT: 1 | vbase_offset (8)
// CHECK-NEXT: 2 | offset_to_top (0)
// CHECK-NEXT: 3 | Test15::D RTTI
// CHECK-NEXT: -- (Test15::A, 0) vtable address --
// CHECK-NEXT: -- (Test15::D, 0) vtable address --
// CHECK-NEXT: 4 | void Test15::A::a()
// CHECK-NEXT: 5 | void Test15::D::f()
// CHECK-NEXT: 6 | vbase_offset (0)
// CHECK-NEXT: 7 | vcall_offset (0)
// CHECK-NEXT: 8 | offset_to_top (-8)
// CHECK-NEXT: 9 | Test15::D RTTI
// CHECK-NEXT: -- (Test15::B, 8) vtable address --
// CHECK-NEXT: -- (Test15::C, 8) vtable address --
// CHECK-NEXT: 10 | void Test15::B::b()
struct D : A, virtual B, virtual C {
virtual void f();
};
void D::f() { }
}