Simplify the virtual base layout code and fix a bug where we wouldn't store the offset for a virtual base.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100940 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Anders Carlsson 2010-04-10 18:42:27 +00:00
Родитель c24b9c4655
Коммит bdda6c1788
2 изменённых файлов: 47 добавлений и 23 удалений

Просмотреть файл

@ -170,6 +170,9 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
// We have a virtual primary base, insert it as an indirect primary base. // We have a virtual primary base, insert it as an indirect primary base.
IndirectPrimaryBases.insert(Base); IndirectPrimaryBases.insert(Base);
assert(!VisitedVirtualBases.count(Base) && "vbase already visited!");
VisitedVirtualBases.insert(Base);
LayoutVirtualBase(Base); LayoutVirtualBase(Base);
} else } else
LayoutNonVirtualBase(Base); LayoutNonVirtualBase(Base);
@ -209,12 +212,23 @@ ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
uint64_t Offset, uint64_t Offset,
const CXXRecordDecl *MostDerivedClass) { const CXXRecordDecl *MostDerivedClass) {
const CXXRecordDecl *PrimaryBase; const CXXRecordDecl *PrimaryBase;
bool PrimaryBaseIsVirtual;
if (MostDerivedClass == RD) if (MostDerivedClass == RD) {
PrimaryBase = this->PrimaryBase.getBase(); PrimaryBase = this->PrimaryBase.getBase();
else { PrimaryBaseIsVirtual = this->PrimaryBase.isVirtual();
} else {
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
PrimaryBase = Layout.getPrimaryBase(); PrimaryBase = Layout.getPrimaryBase();
PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual();
}
// Check the primary base first.
if (PrimaryBase && PrimaryBaseIsVirtual &&
VisitedVirtualBases.insert(PrimaryBase)) {
assert(!VBases.count(PrimaryBase) && "vbase offset already exists!");
VBases.insert(std::make_pair(PrimaryBase, Offset));
} }
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
@ -226,28 +240,15 @@ ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
if (I->isVirtual()) { if (I->isVirtual()) {
if (PrimaryBase != Base || !PrimaryBaseIsVirtual) {
bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base); bool IndirectPrimaryBase = IndirectPrimaryBases.count(Base);
// We only want to visit this virtual base if it's either a primary base, // Only lay out the virtual base if it's not an indirect primary base.
// or not an indirect primary base. if (!IndirectPrimaryBase) {
if (Base == PrimaryBase || !IndirectPrimaryBase) { // Only visit virtual bases once.
// Only lay things out once.
if (!VisitedVirtualBases.insert(Base)) if (!VisitedVirtualBases.insert(Base))
continue; continue;
if (Base == PrimaryBase) {
assert(IndirectPrimaryBase &&
"Base is supposed to be an indirect primary base!");
// We only want to add a vbase offset if this primary base is not the
// primary base of the most derived class.
if (PrimaryBase != this->PrimaryBase.getBase() ||
!this->PrimaryBase.isVirtual()) {
if (!VBases.insert(std::make_pair(Base, Offset)).second)
assert(false && "Added same vbase offset more than once!");
}
} else {
// We actually do want to lay out this base.
LayoutVirtualBase(Base); LayoutVirtualBase(Base);
} }
} }

Просмотреть файл

@ -1303,3 +1303,26 @@ struct B : virtual A {
V2 *B::f() { return 0; } V2 *B::f() { return 0; }
} }
namespace Test30 {
// Test that we don't assert when generating a vtable for F.
struct A { };
struct B : virtual A {
int i;
};
struct C {
virtual void f();
};
struct D : virtual C, B { };
struct E : virtual D { };
struct F : E {
virtual void f();
};
void F::f() { }
}