diff options
author | Anders Carlsson <andersca@mac.com> | 2010-02-27 06:38:03 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2010-02-27 06:38:03 +0000 |
commit | c784ba21ba14f4cf65fc6fa2e3548c4775819921 (patch) | |
tree | 508995b5ffb94de71ae06b153f3f530b63c28e15 | |
parent | 5560969d73e3e72747972d0f0f37ca4e3b042186 (diff) |
Fix another vtable layout bug; we weren't looking hard enough for overriden functions when determining if an overrider will ever be used.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97306 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CGVtable.cpp | 48 | ||||
-rw-r--r-- | test/CodeGenCXX/vtable-layout.cpp | 36 |
2 files changed, 76 insertions, 8 deletions
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 89676d4343..a12e80cc47 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -1247,12 +1247,12 @@ public: void dumpLayout(llvm::raw_ostream&); }; -/// OverridesMethodInPrimaryBase - Checks whether whether this virtual member -/// function overrides a member function in a direct or indirect primary base. +/// OverridesMethodInBases - Checks whether whether this virtual member +/// function overrides a member function in any of the given bases. /// Returns the overridden member function, or null if none was found. static const CXXMethodDecl * -OverridesMethodInPrimaryBase(const CXXMethodDecl *MD, - VtableBuilder::PrimaryBasesSetTy &PrimaryBases) { +OverridesMethodInBases(const CXXMethodDecl *MD, + VtableBuilder::PrimaryBasesSetTy &Bases) { for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I != E; ++I) { const CXXMethodDecl *OverriddenMD = *I; @@ -1260,7 +1260,7 @@ OverridesMethodInPrimaryBase(const CXXMethodDecl *MD, assert(OverriddenMD->isCanonicalDecl() && "Should have the canonical decl of the overridden RD!"); - if (PrimaryBases.count(OverriddenRD)) + if (Bases.count(OverriddenRD)) return OverriddenMD; } @@ -1352,6 +1352,38 @@ VtableBuilder::AddMethod(const CXXMethodDecl *MD, } } +/// OverridesIndirectMethodInBase - Return whether the given member function +/// overrides any methods in the set of given bases. +/// Unlike OverridesMethodInBase, this checks "overriders of overriders". +/// For example, if we have: +/// +/// struct A { virtual void f(); } +/// struct B : A { virtual void f(); } +/// struct C : B { virtual void f(); } +/// +/// OverridesIndirectMethodInBase will return true if given C::f as the method +/// and { A } as the set of bases. +static bool +OverridesIndirectMethodInBases(const CXXMethodDecl *MD, + VtableBuilder::PrimaryBasesSetTy &Bases) { + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); I != E; ++I) { + const CXXMethodDecl *OverriddenMD = *I; + const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent(); + assert(OverriddenMD->isCanonicalDecl() && + "Should have the canonical decl of the overridden RD!"); + + if (Bases.count(OverriddenRD)) + return true; + + // Check "indirect overriders". + if (OverridesIndirectMethodInBases(OverriddenMD, Bases)) + return true; + } + + return false; +} + bool VtableBuilder::IsOverriderUsed(BaseSubobject Base, BaseSubobject FirstBaseInPrimaryBaseChain, @@ -1406,7 +1438,7 @@ VtableBuilder::IsOverriderUsed(BaseSubobject Base, // If the final overrider is an override of one of the primary bases, // then we know that it will be used. - return OverridesMethodInPrimaryBase(Overrider.Method, PrimaryBases); + return OverridesIndirectMethodInBases(Overrider.Method, PrimaryBases); } void @@ -1457,7 +1489,7 @@ VtableBuilder::AddMethods(BaseSubobject Base, // base. If this is the case, and the return type doesn't require adjustment // then we can just use the member function from the primary base. if (const CXXMethodDecl *OverriddenMD = - OverridesMethodInPrimaryBase(MD, PrimaryBases)) { + OverridesMethodInBases(MD, PrimaryBases)) { if (ComputeReturnAdjustmentBaseOffset(Context, MD, OverriddenMD).isEmpty()) continue; @@ -2959,7 +2991,7 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) { // Check if this method overrides a method in the primary base. if (const CXXMethodDecl *OverriddenMD = - OverridesMethodInPrimaryBase(MD, PrimaryBases)) { + OverridesMethodInBases(MD, PrimaryBases)) { // Check if converting from the return type of the method to the // return type of the overridden method requires conversion. if (ComputeReturnAdjustmentBaseOffset(CGM.getContext(), MD, diff --git a/test/CodeGenCXX/vtable-layout.cpp b/test/CodeGenCXX/vtable-layout.cpp index e3a0e8aaac..84f0132a13 100644 --- a/test/CodeGenCXX/vtable-layout.cpp +++ b/test/CodeGenCXX/vtable-layout.cpp @@ -609,3 +609,39 @@ struct D : virtual C { void D::f() { } } + +namespace Test17 { + +// Test that we don't mark E::f in the C-in-E vtable as unused. +struct A { virtual void f(); }; +struct B : virtual A { virtual void f(); }; +struct C : virtual A { virtual void f(); }; +struct D : virtual B, virtual C { virtual void f(); }; + +// CHECK: Vtable for 'Test17::E' (13 entries). +// CHECK-NEXT: 0 | vbase_offset (0) +// CHECK-NEXT: 1 | vbase_offset (8) +// CHECK-NEXT: 2 | vbase_offset (0) +// CHECK-NEXT: 3 | vbase_offset (0) +// CHECK-NEXT: 4 | vcall_offset (0) +// CHECK-NEXT: 5 | offset_to_top (0) +// CHECK-NEXT: 6 | Test17::E RTTI +// CHECK-NEXT: -- (Test17::A, 0) vtable address -- +// CHECK-NEXT: -- (Test17::B, 0) vtable address -- +// CHECK-NEXT: -- (Test17::D, 0) vtable address -- +// CHECK-NEXT: -- (Test17::E, 0) vtable address -- +// CHECK-NEXT: 7 | void Test17::E::f() +// CHECK-NEXT: 8 | vbase_offset (-8) +// CHECK-NEXT: 9 | vcall_offset (-8) +// CHECK-NEXT: 10 | offset_to_top (-8) +// CHECK-NEXT: 11 | Test17::E RTTI +// CHECK-NEXT: -- (Test17::A, 8) vtable address -- +// CHECK-NEXT: -- (Test17::C, 8) vtable address -- +// CHECK-NEXT: 12 | void Test17::E::f() +// CHECK-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +class E : virtual D { + virtual void f(); +}; +void E::f() {} + +} |