[cfe-commits] r95965 - in /cfe/trunk: lib/CodeGen/CGVtable.cpp test/CodeGenCXX/vtable-layout.cpp
Anders Carlsson
andersca at mac.com
Thu Feb 11 21:25:37 PST 2010
Author: andersca
Date: Thu Feb 11 23:25:12 2010
New Revision: 95965
URL: http://llvm.org/viewvc/llvm-project?rev=95965&view=rev
Log:
More work on vtable layout. We can now layout vtables with primary bases.
Modified:
cfe/trunk/lib/CodeGen/CGVtable.cpp
cfe/trunk/test/CodeGenCXX/vtable-layout.cpp
Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=95965&r1=95964&r2=95965&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVtable.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVtable.cpp Thu Feb 11 23:25:12 2010
@@ -99,6 +99,17 @@
return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl);
}
+static bool
+ReturnTypeConversionRequiresAdjustment(ASTContext &Context,
+ const CXXMethodDecl *DerivedMD,
+ const CXXMethodDecl *BaseMD) {
+ const FunctionType *BaseFT = BaseMD->getType()->getAs<FunctionType>();
+ const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>();
+
+ return TypeConversionRequiresAdjustment(Context, DerivedFT->getResultType(),
+ BaseFT->getResultType());
+}
+
namespace {
/// FinalOverriders - Contains the final overrider member functions for all
@@ -248,6 +259,9 @@
OverriddenMD)];
assert(Overrider && "Did not find existing overrider!");
+ assert(!ReturnTypeConversionRequiresAdjustment(Context, NewMD,
+ OverriddenMD) &&
+ "FIXME: Covariant return types not handled yet!");
// Set the new overrider.
Overrider = NewMD;
@@ -470,12 +484,17 @@
/// VtableBuilder - Class for building vtable layout information.
class VtableBuilder {
+public:
+ /// PrimaryBasesSetTy - A set of direct and indirect primary bases.
+ typedef llvm::SmallPtrSet<const CXXRecordDecl *, 8> PrimaryBasesSetTy;
+
+private:
/// MostDerivedClass - The most derived class for which we're building this
/// vtable.
const CXXRecordDecl *MostDerivedClass;
/// Context - The ASTContext which we will use for layout information.
- const ASTContext &Context;
+ ASTContext &Context;
/// FinalOverriders - The final overriders of the most derived class.
FinalOverriders Overriders;
@@ -486,42 +505,85 @@
/// AddressPoints - Address points for the vtable being built.
CGVtableInfo::AddressPointsMapTy AddressPoints;
+ void layoutVirtualMemberFunctions(BaseSubobject Base,
+ PrimaryBasesSetTy &PrimaryBases);
+
/// layoutSimpleVtable - A test function that will layout very simple vtables
/// without any bases. Just used for testing for now.
- void layoutSimpleVtable(const CXXRecordDecl *RD);
+ void layoutSimpleVtable(BaseSubobject Base);
public:
VtableBuilder(const CXXRecordDecl *MostDerivedClass)
: MostDerivedClass(MostDerivedClass),
Context(MostDerivedClass->getASTContext()), Overriders(MostDerivedClass) {
- layoutSimpleVtable(MostDerivedClass);
+ layoutSimpleVtable(BaseSubobject(MostDerivedClass, 0));
}
/// dumpLayout - Dump the vtable layout.
void dumpLayout(llvm::raw_ostream&);
};
-void VtableBuilder::layoutSimpleVtable(const CXXRecordDecl *RD) {
- assert(!RD->getNumBases() &&
- "We don't support layout for vtables with bases right now!");
-
- // First, add the offset to top.
- Components.push_back(VtableComponent::MakeOffsetToTop(0));
-
- // Next, add the RTTI.
- Components.push_back(VtableComponent::MakeRTTI(RD));
-
- // Record the address point.
- AddressPoints.insert(std::make_pair(BaseSubobject(RD, 0), Components.size()));
+/// OverridesMethodInPrimaryBase - Checks whether whether this virtual member
+/// function overrides a member function in a direct or indirect primary base.
+/// Returns the overridden member function, or null if none was found.
+static const CXXMethodDecl *
+OverridesMethodInPrimaryBase(const CXXMethodDecl *MD,
+ VtableBuilder::PrimaryBasesSetTy &PrimaryBases) {
+ 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 (PrimaryBases.count(OverriddenRD))
+ return OverriddenMD;
+ }
+
+ return 0;
+}
+
+void
+VtableBuilder::layoutVirtualMemberFunctions(BaseSubobject Base,
+ PrimaryBasesSetTy &PrimaryBases) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
+ if (Layout.getPrimaryBaseWasVirtual())
+ assert(false && "FIXME: Handle vbases here.");
+ else
+ assert(Layout.getBaseClassOffset(PrimaryBase) == 0 &&
+ "Primary base should have a zero offset!");
+
+ layoutVirtualMemberFunctions(BaseSubobject(PrimaryBase, 0), PrimaryBases);
+
+ if (!PrimaryBases.insert(PrimaryBase))
+ assert(false && "Found a duplicate primary base!");
+ }
// Now go through all virtual member functions and add them.
for (CXXRecordDecl::method_iterator I = RD->method_begin(),
E = RD->method_end(); I != E; ++I) {
const CXXMethodDecl *MD = *I;
-
+
if (!MD->isVirtual())
continue;
+
+ // Get the final overrider.
+ const CXXMethodDecl *Overrider = Overriders.getOverrider(Base, MD);
+
+ // Check if this virtual member function overrides a method in a primary
+ // 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 (OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
+ assert(!ReturnTypeConversionRequiresAdjustment(Context, Overrider, MD) &&
+ "FIXME: Handle covariant thunks!");
+
+ continue;
+ }
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
// Add both the complete destructor and the deleting destructor.
@@ -534,6 +596,42 @@
}
}
+void VtableBuilder::layoutSimpleVtable(BaseSubobject Base) {
+ const CXXRecordDecl *RD = Base.getBase();
+
+ // First, add the offset to top.
+ Components.push_back(VtableComponent::MakeOffsetToTop(0));
+
+ // Next, add the RTTI.
+ Components.push_back(VtableComponent::MakeRTTI(RD));
+
+ // Record the address point.
+ // FIXME: Record the address point for all primary bases.
+ AddressPoints.insert(std::make_pair(Base, Components.size()));
+
+ // Now go through all virtual member functions and add them.
+ PrimaryBasesSetTy PrimaryBases;
+ layoutVirtualMemberFunctions(Base, PrimaryBases);
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ // Traverse 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());
+
+ // Ignore the primary base.
+ if (BaseDecl == PrimaryBase)
+ continue;
+
+ assert(!I->isVirtual() && "FIXME: Handle virtual bases");
+
+ assert(false && "FIXME: Handle secondary virtual tables!");
+ }
+}
+
/// dumpLayout - Dump the vtable layout.
void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
@@ -1726,7 +1824,7 @@
// Collect all the primary bases, so we can check whether methods override
// a method from the base.
- llvm::SmallPtrSet<const CXXRecordDecl *, 5> PrimaryBases;
+ VtableBuilder::PrimaryBasesSetTy PrimaryBases;
for (ASTRecordLayout::primary_base_info_iterator
I = Layout.primary_base_begin(), E = Layout.primary_base_end();
I != E; ++I)
@@ -1745,42 +1843,30 @@
bool ShouldAddEntryForMethod = true;
// Check if this method overrides a method in the primary base.
- 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 (PrimaryBases.count(OverriddenRD)) {
- // Check if converting from the return type of the method to the
- // return type of the overridden method requires conversion.
- QualType ReturnType =
- MD->getType()->getAs<FunctionType>()->getResultType();
- QualType OverriddenReturnType =
- OverriddenMD->getType()->getAs<FunctionType>()->getResultType();
-
- if (!TypeConversionRequiresAdjustment(CGM.getContext(),
- ReturnType, OverriddenReturnType)) {
- // This index is shared between the index in the vtable of the primary
- // base class.
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- const CXXDestructorDecl *OverriddenDD =
- cast<CXXDestructorDecl>(OverriddenMD);
-
- // Add both the complete and deleting entries.
- MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] =
- getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
- MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] =
- getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
- } else {
- MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD);
- }
+ if (const CXXMethodDecl *OverriddenMD =
+ OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
+ // Check if converting from the return type of the method to the
+ // return type of the overridden method requires conversion.
+ if (!ReturnTypeConversionRequiresAdjustment(CGM.getContext(),
+ MD, OverriddenMD)) {
+ // This index is shared between the index in the vtable of the primary
+ // base class.
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ const CXXDestructorDecl *OverriddenDD =
+ cast<CXXDestructorDecl>(OverriddenMD);
- // We don't need to add an entry for this method.
- ShouldAddEntryForMethod = false;
- break;
- }
+ // Add both the complete and deleting entries.
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] =
+ getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ } else {
+ MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD);
+ }
+
+ // We don't need to add an entry for this method.
+ ShouldAddEntryForMethod = false;
+ break;
}
}
Modified: cfe/trunk/test/CodeGenCXX/vtable-layout.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-layout.cpp?rev=95965&r1=95964&r2=95965&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/vtable-layout.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/vtable-layout.cpp Thu Feb 11 23:25:12 2010
@@ -9,8 +9,8 @@
struct A {
virtual void f();
};
-
void A::f() { }
+
}
namespace Test2 {
@@ -36,10 +36,10 @@
virtual void h();
virtual A& operator=(const A&);
};
-
void A::f() { }
// Another simple vtable dumper test.
+
// CHECK: Vtable for 'Test2::B' (6 entries).
// CHECK-NEXT: 0 | offset_to_top (0)
// CHECK-NEXT: 1 | Test2::B RTTI
@@ -48,13 +48,68 @@
// CHECK-NEXT: 3 | void Test2::B::g() [pure]
// CHECK-NEXT: 4 | Test2::B::~B() [complete] [pure]
// CHECK-NEXT: 5 | Test2::B::~B() [deleting] [pure]
-
struct B {
virtual void f();
virtual void g() = 0;
virtual ~B() = 0;
};
+void B::f() { }
+
+}
+
+namespace Test3 {
+// If a function in a derived class overrides a function in a primary base,
+// then the function should not have an entry in the derived class (unless the return
+// value requires adjusting).
+
+// CHECK: Vtable for 'Test3::A' (3 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test3::A RTTI
+// CHECK-NEXT: -- (Test3::A, 0) vtable address --
+// CHECK-NEXT: 2 | void Test3::A::f()
+struct A {
+ virtual void f();
+};
+void A::f() { }
+
+// CHECK: Vtable for 'Test3::B' (4 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test3::B RTTI
+// CHECK-NEXT: -- (Test3::B, 0) vtable address --
+// CHECK-NEXT: 2 | void Test3::A::f()
+// CHECK-NEXT: 3 | void Test3::B::g()
+struct B : A {
+ virtual void f();
+ virtual void g();
+};
void B::f() { }
+// CHECK: Vtable for 'Test3::C' (5 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test3::C RTTI
+// CHECK-NEXT: -- (Test3::C, 0) vtable address --
+// CHECK-NEXT: 2 | void Test3::A::f()
+// CHECK-NEXT: 3 | void Test3::C::g()
+// CHECK-NEXT: 4 | void Test3::C::h()
+struct C : A {
+ virtual void g();
+ virtual void h();
+};
+void C::g() { }
+
+// CHECK: Vtable for 'Test3::D' (5 entries).
+// CHECK-NEXT: 0 | offset_to_top (0)
+// CHECK-NEXT: 1 | Test3::D RTTI
+// CHECK-NEXT: -- (Test3::D, 0) vtable address --
+// CHECK-NEXT: 2 | void Test3::A::f()
+// CHECK-NEXT: 3 | void Test3::B::g()
+// CHECK-NEXT: 4 | void Test3::D::h()
+struct D : B {
+ virtual void f();
+ virtual void g();
+ virtual void h();
+};
+
+void D::f() { }
}
More information about the cfe-commits
mailing list