From cf5a882da111d5aa006066180733b1bdef235fb4 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Sat, 13 Feb 2010 21:07:32 +0000 Subject: [PATCH] Handle virtual bases in return adjustment types. llvm-svn: 96119 --- clang/lib/CodeGen/CGVtable.cpp | 54 +++++++++++++++++-------- clang/test/CodeGenCXX/vtable-layout.cpp | 43 ++++++++++++++++++-- 2 files changed, 77 insertions(+), 20 deletions(-) diff --git a/clang/lib/CodeGen/CGVtable.cpp b/clang/lib/CodeGen/CGVtable.cpp index f7b8c53d0214..912f33c5d642 100644 --- a/clang/lib/CodeGen/CGVtable.cpp +++ b/clang/lib/CodeGen/CGVtable.cpp @@ -124,6 +124,9 @@ public: /// BaseOffset - Represents an offset from a derived class to a direct or /// indirect base class. struct BaseOffset { + /// DerivedClass - The derived class. + const CXXRecordDecl *DerivedClass; + /// VirtualBase - If the path from the derived class to the base class /// involves a virtual base class, this holds its declaration. const CXXRecordDecl *VirtualBase; @@ -133,9 +136,11 @@ public: /// from the derived class to the base class involves a virtual base class. uint64_t NonVirtualOffset; - BaseOffset() : VirtualBase(0), NonVirtualOffset(0) { } - BaseOffset(const CXXRecordDecl *VirtualBase, uint64_t NonVirtualOffset) - : VirtualBase(VirtualBase), NonVirtualOffset(NonVirtualOffset) { } + BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { } + BaseOffset(const CXXRecordDecl *DerivedClass, + const CXXRecordDecl *VirtualBase, uint64_t NonVirtualOffset) + : DerivedClass(DerivedClass), VirtualBase(VirtualBase), + NonVirtualOffset(NonVirtualOffset) { } bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; } }; @@ -333,7 +338,8 @@ ComputeBaseOffset(ASTContext &Context, // FIXME: This should probably use CharUnits or something. Maybe we should // even change the base offsets in ASTRecordLayout to be specified in // CharUnits. - return FinalOverriders::BaseOffset(VirtualBase, NonVirtualOffset / 8); + return FinalOverriders::BaseOffset(DerivedRD, VirtualBase, + NonVirtualOffset / 8); } static FinalOverriders::BaseOffset @@ -663,6 +669,9 @@ public: typedef llvm::SmallPtrSet PrimaryBasesSetTy; private: + /// VtableInfo - Global vtable information. + CGVtableInfo &VtableInfo; + /// MostDerivedClass - The most derived class for which we're building this /// vtable. const CXXRecordDecl *MostDerivedClass; @@ -685,20 +694,20 @@ private: /// nearest virtual base. int64_t NonVirtual; - /// VBaseOffsetIndex - The index relative to the address point of the - /// virtual base class offset. - int64_t VBaseOffsetIndex; + /// VBaseOffsetOffset - The offset, in bytes, relative to the address point + /// of the virtual base class offset. + int64_t VBaseOffsetOffset; - ReturnAdjustment() : NonVirtual(0), VBaseOffsetIndex(0) { } + ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { } - bool isEmpty() const { return !NonVirtual && !VBaseOffsetIndex; } + bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; } }; /// ReturnAdjustments - The return adjustments needed in this vtable. llvm::SmallVector, 16> ReturnAdjustments; - /// ComputeReturnAdjustment - Compute the return adjustment given return + /// ComputeReturnAdjustment - Compute the return adjustment given a return /// adjustment base offset. ReturnAdjustment ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset); @@ -715,8 +724,8 @@ private: void layoutSimpleVtable(BaseSubobject Base); public: - VtableBuilder(const CXXRecordDecl *MostDerivedClass) - : MostDerivedClass(MostDerivedClass), + VtableBuilder(CGVtableInfo &VtableInfo, const CXXRecordDecl *MostDerivedClass) + : VtableInfo(VtableInfo), MostDerivedClass(MostDerivedClass), Context(MostDerivedClass->getASTContext()), Overriders(MostDerivedClass) { layoutSimpleVtable(BaseSubobject(MostDerivedClass, 0)); @@ -751,7 +760,16 @@ VtableBuilder::ComputeReturnAdjustment(FinalOverriders::BaseOffset Offset) { ReturnAdjustment Adjustment; if (!Offset.isEmpty()) { - assert(!Offset.VirtualBase && "FIXME: Handle virtual bases!"); + if (Offset.VirtualBase) { + // Get the virtual base offset offset. + Adjustment.VBaseOffsetOffset = + VtableInfo.getVirtualBaseOffsetIndex(Offset.DerivedClass, + Offset.VirtualBase); + // FIXME: Once the assert in getVirtualBaseOffsetIndex is back again, + // we can get rid of this assert. + assert(Adjustment.VBaseOffsetOffset != 0 && + "Invalid base offset offset!"); + } Adjustment.NonVirtual = Offset.NonVirtualOffset; } @@ -967,10 +985,12 @@ void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) { const ReturnAdjustment Adjustment = ReturnAdjustments[NextReturnAdjustmentIndex].second; - assert(!Adjustment.VBaseOffsetIndex && "FIXME: Handle virtual bases!"); - Out << "\n [return adjustment: "; - Out << Adjustment.NonVirtual << " non-virtual]"; + Out << Adjustment.NonVirtual << " non-virtual"; + + if (Adjustment.VBaseOffsetOffset) + Out << ", " << Adjustment.VBaseOffsetOffset << " vbase offset offset"; + Out << ']'; NextReturnAdjustmentIndex++; } @@ -2291,7 +2311,7 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD, uint64_t Offset, AddressPointsMapTy& AddressPoints) { if (GenerateDefinition && CGM.getLangOptions().DumpVtableLayouts) { - VtableBuilder Builder(RD); + VtableBuilder Builder(*this, RD); Builder.dumpLayout(llvm::errs()); } diff --git a/clang/test/CodeGenCXX/vtable-layout.cpp b/clang/test/CodeGenCXX/vtable-layout.cpp index 8c839ef6a11d..19ce8da4cfab 100644 --- a/clang/test/CodeGenCXX/vtable-layout.cpp +++ b/clang/test/CodeGenCXX/vtable-layout.cpp @@ -120,7 +120,7 @@ void D::f() { } namespace Test4 { -// Test simple non-virtual result adjustments. +// Test non-virtual result adjustments. struct R1 { int r1; }; struct R2 { int r2; }; @@ -142,9 +142,46 @@ struct A { struct B : A { virtual R3 *f(); }; - R3 *B::f() { return 0; } - + +// Test virtual result adjustments. +struct V1 { int v1; }; +struct V2 : virtual V1 { int v1; }; + +struct C { + virtual V1 *f(); +}; + +// CHECK: Vtable for 'Test4::D' (4 entries). +// CHECK-NEXT: 0 | offset_to_top (0) +// CHECK-NEXT: 1 | Test4::D RTTI +// CHECK-NEXT: -- (Test4::C, 0) vtable address -- +// CHECK-NEXT: -- (Test4::D, 0) vtable address -- +// CHECK-NEXT: 2 | Test4::V2 *Test4::D::f() +// CHECK-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset] +// CHECK-NEXT: 3 | Test4::V2 *Test4::D::f() +struct D : C { + virtual V2 *f(); +}; +V2 *D::f() { return 0; }; + +// Virtual result adjustments with an additional non-virtual adjustment. +struct V3 : virtual R3 { int r3; }; + +// CHECK: Vtable for 'Test4::E' (4 entries). +// CHECK-NEXT: 0 | offset_to_top (0) +// CHECK-NEXT: 1 | Test4::E RTTI +// CHECK-NEXT: -- (Test4::A, 0) vtable address -- +// CHECK-NEXT: -- (Test4::E, 0) vtable address -- +// CHECK-NEXT: 2 | Test4::V3 *Test4::E::f() +// CHECK-NEXT: [return adjustment: 4 non-virtual, -24 vbase offset offset] +// CHECK-NEXT: 3 | Test4::V3 *Test4::E::f() + +struct E : A { + virtual V3 *f(); +}; +V3 *E::f() { return 0;} + } // For now, just verify this doesn't crash.