зеркало из https://github.com/microsoft/clang-1.git
More work on vtable layout. We can now layout vtables with primary bases.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95965 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
27935ee59c
Коммит
57071e29bd
|
@ -99,6 +99,17 @@ TypeConversionRequiresAdjustment(ASTContext &Ctx,
|
|||
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 @@ void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD,
|
|||
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 @@ private:
|
|||
|
||||
/// 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 @@ class VtableBuilder {
|
|||
/// 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(const CXXRecordDecl *RD) {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
|
|||
|
||||
// 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 @@ void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ namespace Test1 {
|
|||
struct A {
|
||||
virtual void f();
|
||||
};
|
||||
|
||||
void A::f() { }
|
||||
|
||||
}
|
||||
|
||||
namespace Test2 {
|
||||
|
@ -36,10 +36,10 @@ struct A {
|
|||
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 @@ void A::f() { }
|
|||
// 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() { }
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче