forked from OSchip/llvm-project
More work on covariant return types. We now handle non-virtual adjustments fine.
llvm-svn: 96114
This commit is contained in:
parent
3dc137d8ed
commit
6a6cbfc55f
|
|
@ -225,14 +225,19 @@ public:
|
|||
|
||||
/// getOverrider - Get the final overrider for the given method declaration in
|
||||
/// the given base subobject.
|
||||
const OverriderInfo getOverrider(BaseSubobject Base,
|
||||
const CXXMethodDecl *MD) const {
|
||||
OverriderInfo getOverrider(BaseSubobject Base,
|
||||
const CXXMethodDecl *MD) const {
|
||||
assert(OverridersMap.count(std::make_pair(Base, MD)) &&
|
||||
"Did not find overrider!");
|
||||
|
||||
return OverridersMap.lookup(std::make_pair(Base, MD));
|
||||
}
|
||||
|
||||
BaseOffset getReturnAdjustmentOffset(BaseSubobject Base,
|
||||
const CXXMethodDecl *MD) const {
|
||||
return ReturnAdjustments.lookup(std::make_pair(Base, MD));
|
||||
}
|
||||
|
||||
/// dump - dump the final overriders.
|
||||
void dump() const {
|
||||
dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0));
|
||||
|
|
@ -469,7 +474,6 @@ void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base,
|
|||
}
|
||||
|
||||
void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base) const {
|
||||
|
||||
const CXXRecordDecl *RD = Base.getBase();
|
||||
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
|
||||
|
||||
|
|
@ -532,9 +536,6 @@ public:
|
|||
CK_DeletingDtorPointer
|
||||
};
|
||||
|
||||
/// dump - Dump the contents of this component to the given stream.
|
||||
void dump(llvm::raw_ostream &Out);
|
||||
|
||||
static VtableComponent MakeOffsetToTop(int64_t Offset) {
|
||||
return VtableComponent(CK_OffsetToTop, Offset);
|
||||
}
|
||||
|
|
@ -670,10 +671,27 @@ private:
|
|||
/// VBaseOffsetIndex - The index relative to the address point of the
|
||||
/// virtual base class offset.
|
||||
int64_t VBaseOffsetIndex;
|
||||
};
|
||||
|
||||
void layoutVirtualMemberFunctions(BaseSubobject Base,
|
||||
PrimaryBasesSetTy &PrimaryBases);
|
||||
ReturnAdjustment() : NonVirtual(0), VBaseOffsetIndex(0) { }
|
||||
|
||||
bool isEmpty() const { return !NonVirtual && !VBaseOffsetIndex; }
|
||||
};
|
||||
|
||||
/// ReturnAdjustments - The return adjustments needed in this vtable.
|
||||
llvm::SmallVector<std::pair<uint64_t, ReturnAdjustment>, 16>
|
||||
ReturnAdjustments;
|
||||
|
||||
/// ComputeReturnAdjustment - Compute the return adjustment given return
|
||||
/// adjustment base offset.
|
||||
ReturnAdjustment ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset);
|
||||
|
||||
/// AddMethod - Add a single virtual member function to the vtable
|
||||
/// components vector.
|
||||
void AddMethod(const CXXMethodDecl *MD, ReturnAdjustment ReturnAdjustment);
|
||||
|
||||
/// AddMethods - Add the methods of this base subobject and all its
|
||||
/// primary bases to the vtable components vector.
|
||||
void AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases);
|
||||
|
||||
/// layoutSimpleVtable - A test function that will layout very simple vtables
|
||||
/// without any bases. Just used for testing for now.
|
||||
|
|
@ -711,9 +729,41 @@ OverridesMethodInPrimaryBase(const CXXMethodDecl *MD,
|
|||
return 0;
|
||||
}
|
||||
|
||||
VtableBuilder::ReturnAdjustment
|
||||
VtableBuilder::ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset) {
|
||||
ReturnAdjustment Adjustment;
|
||||
|
||||
if (!Offset.isEmpty()) {
|
||||
assert(!Offset.VirtualBase && "FIXME: Handle virtual bases!");
|
||||
|
||||
Adjustment.NonVirtual = Offset.NonVirtualOffset;
|
||||
}
|
||||
|
||||
return Adjustment;
|
||||
}
|
||||
|
||||
void
|
||||
VtableBuilder::layoutVirtualMemberFunctions(BaseSubobject Base,
|
||||
PrimaryBasesSetTy &PrimaryBases) {
|
||||
VtableBuilder::AddMethod(const CXXMethodDecl *MD,
|
||||
ReturnAdjustment ReturnAdjustment) {
|
||||
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
|
||||
assert(ReturnAdjustment.isEmpty() &&
|
||||
"Destructor can't have return adjustment!");
|
||||
// Add both the complete destructor and the deleting destructor.
|
||||
Components.push_back(VtableComponent::MakeCompleteDtor(DD));
|
||||
Components.push_back(VtableComponent::MakeDeletingDtor(DD));
|
||||
} else {
|
||||
// Add the return adjustment if necessary.
|
||||
if (!ReturnAdjustment.isEmpty())
|
||||
ReturnAdjustments.push_back(std::make_pair(Components.size(),
|
||||
ReturnAdjustment));
|
||||
|
||||
// Add the function.
|
||||
Components.push_back(VtableComponent::MakeFunction(MD));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VtableBuilder::AddMethods(BaseSubobject Base, PrimaryBasesSetTy &PrimaryBases) {
|
||||
const CXXRecordDecl *RD = Base.getBase();
|
||||
|
||||
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
|
||||
|
|
@ -725,7 +775,7 @@ VtableBuilder::layoutVirtualMemberFunctions(BaseSubobject Base,
|
|||
assert(Layout.getBaseClassOffset(PrimaryBase) == 0 &&
|
||||
"Primary base should have a zero offset!");
|
||||
|
||||
layoutVirtualMemberFunctions(BaseSubobject(PrimaryBase, 0), PrimaryBases);
|
||||
AddMethods(BaseSubobject(PrimaryBase, 0), PrimaryBases);
|
||||
|
||||
if (!PrimaryBases.insert(PrimaryBase))
|
||||
assert(false && "Found a duplicate primary base!");
|
||||
|
|
@ -746,22 +796,20 @@ VtableBuilder::layoutVirtualMemberFunctions(BaseSubobject Base,
|
|||
// 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 (const CXXMethodDecl *OverriddenMD ATTRIBUTE_UNUSED =
|
||||
OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
|
||||
assert(!ReturnTypeConversionRequiresAdjustment(MD, OverriddenMD)
|
||||
&& "FIXME: Handle covariant thunks!");
|
||||
if (const CXXMethodDecl *OverriddenMD =
|
||||
OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
|
||||
if (!ReturnTypeConversionRequiresAdjustment(MD, OverriddenMD))
|
||||
continue;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
// Check if this overrider needs a return adjustment.
|
||||
FinalOverriders::BaseOffset ReturnAdjustmentOffset =
|
||||
Overriders.getReturnAdjustmentOffset(Base, MD);
|
||||
|
||||
ReturnAdjustment ReturnAdjustment =
|
||||
ComputeReturnAdjustment(ReturnAdjustmentOffset);
|
||||
|
||||
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
|
||||
// Add both the complete destructor and the deleting destructor.
|
||||
Components.push_back(VtableComponent::MakeCompleteDtor(DD));
|
||||
Components.push_back(VtableComponent::MakeDeletingDtor(DD));
|
||||
} else {
|
||||
// Add the function.
|
||||
Components.push_back(VtableComponent::MakeFunction(MD));
|
||||
}
|
||||
AddMethod(Overrider.Method, ReturnAdjustment);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -778,7 +826,7 @@ void VtableBuilder::layoutSimpleVtable(BaseSubobject Base) {
|
|||
|
||||
// Now go through all virtual member functions and add them.
|
||||
PrimaryBasesSetTy PrimaryBases;
|
||||
layoutVirtualMemberFunctions(Base, PrimaryBases);
|
||||
AddMethods(Base, PrimaryBases);
|
||||
|
||||
// Record the address point.
|
||||
AddressPoints.insert(std::make_pair(Base, AddressPoint));
|
||||
|
|
@ -832,6 +880,7 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
|
|||
AddressPointsByIndex.insert(std::make_pair(Index, Base));
|
||||
}
|
||||
|
||||
unsigned NextReturnAdjustmentIndex = 0;
|
||||
for (unsigned I = 0, E = Components.size(); I != E; ++I) {
|
||||
uint64_t Index = I;
|
||||
|
||||
|
|
@ -895,6 +944,20 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
|
|||
if (MD->isPure())
|
||||
Out << " [pure]";
|
||||
|
||||
// If this function pointer has a return adjustment thunk, dump it.
|
||||
if (NextReturnAdjustmentIndex < ReturnAdjustments.size() &&
|
||||
ReturnAdjustments[NextReturnAdjustmentIndex].first == I) {
|
||||
const ReturnAdjustment Adjustment =
|
||||
ReturnAdjustments[NextReturnAdjustmentIndex].second;
|
||||
|
||||
assert(!Adjustment.VBaseOffsetIndex && "FIXME: Handle virtual bases!");
|
||||
|
||||
Out << "\n [return adjustment: ";
|
||||
Out << Adjustment.NonVirtual << " non-virtual]";
|
||||
|
||||
NextReturnAdjustmentIndex++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -2186,6 +2249,12 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
|
|||
}
|
||||
|
||||
I = VirtualBaseClassIndicies.find(ClassPair);
|
||||
// FIXME: The assertion below assertion currently fails with the old vtable
|
||||
/// layout code if there is a non-virtual thunk adjustment in a vtable.
|
||||
// Once the new layout is in place, this return should be removed.
|
||||
if (I == VirtualBaseClassIndicies.end())
|
||||
return 0;
|
||||
|
||||
assert(I != VirtualBaseClassIndicies.end() && "Did not find index!");
|
||||
|
||||
return I->second;
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ void A::f() { }
|
|||
// CHECK-NEXT: 1 | Test3::B RTTI
|
||||
// CHECK-NEXT: -- (Test3::A, 0) vtable address --
|
||||
// CHECK-NEXT: -- (Test3::B, 0) vtable address --
|
||||
// CHECK-NEXT: 2 | void Test3::A::f()
|
||||
// CHECK-NEXT: 2 | void Test3::B::f()
|
||||
// CHECK-NEXT: 3 | void Test3::B::g()
|
||||
struct B : A {
|
||||
virtual void f();
|
||||
|
|
@ -106,8 +106,8 @@ void C::g() { }
|
|||
// CHECK-NEXT: -- (Test3::A, 0) vtable address --
|
||||
// CHECK-NEXT: -- (Test3::B, 0) vtable address --
|
||||
// CHECK-NEXT: -- (Test3::D, 0) vtable address --
|
||||
// CHECK-NEXT: 2 | void Test3::A::f()
|
||||
// CHECK-NEXT: 3 | void Test3::B::g()
|
||||
// CHECK-NEXT: 2 | void Test3::D::f()
|
||||
// CHECK-NEXT: 3 | void Test3::D::g()
|
||||
// CHECK-NEXT: 4 | void Test3::D::h()
|
||||
struct D : B {
|
||||
virtual void f();
|
||||
|
|
@ -118,6 +118,35 @@ struct D : B {
|
|||
void D::f() { }
|
||||
}
|
||||
|
||||
namespace Test4 {
|
||||
|
||||
// Test simple non-virtual result adjustments.
|
||||
|
||||
struct R1 { int r1; };
|
||||
struct R2 { int r2; };
|
||||
struct R3 : R1, R2 { int r3; };
|
||||
|
||||
struct A {
|
||||
virtual R2 *f();
|
||||
};
|
||||
|
||||
// CHECK: Vtable for 'Test4::B' (4 entries).
|
||||
// CHECK-NEXT: 0 | offset_to_top (0)
|
||||
// CHECK-NEXT: 1 | Test4::B RTTI
|
||||
// CHECK-NEXT: -- (Test4::A, 0) vtable address --
|
||||
// CHECK-NEXT: -- (Test4::B, 0) vtable address --
|
||||
// CHECK-NEXT: 2 | Test4::R3 *Test4::B::f()
|
||||
// CHECK-NEXT: [return adjustment: 4 non-virtual]
|
||||
// CHECK-NEXT: 3 | Test4::R3 *Test4::B::f()
|
||||
|
||||
struct B : A {
|
||||
virtual R3 *f();
|
||||
};
|
||||
|
||||
R3 *B::f() { return 0; }
|
||||
|
||||
}
|
||||
|
||||
// For now, just verify this doesn't crash.
|
||||
namespace test0 {
|
||||
struct Obj {};
|
||||
|
|
|
|||
Loading…
Reference in New Issue