From: Timur Iskhodzhanov Date: Tue, 22 Apr 2014 17:32:02 +0000 (+0000) Subject: Fix PR19487, PR19505 and PR19506 -- redundant vtordisp thunks when the final override... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1b710a8d225a503a9c44cfd15de18794403e6a83;p=clang Fix PR19487, PR19505 and PR19506 -- redundant vtordisp thunks when the final overrider is present in both a vbase and nvbase Reviewed at http://reviews.llvm.org/D3449 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206908 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index c606450e1e..c018f1b303 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -64,10 +64,14 @@ public: /// Method - The method decl of the overrider. const CXXMethodDecl *Method; + /// VirtualBase - The virtual base class subobject of this overridder. + /// Note that this records the closest derived virtual base class subobject. + const CXXRecordDecl *VirtualBase; + /// Offset - the base offset of the overrider's parent in the layout class. CharUnits Offset; - OverriderInfo() : Method(0), Offset(CharUnits::Zero()) { } + OverriderInfo() : Method(0), VirtualBase(0), Offset(CharUnits::Zero()) { } }; private: @@ -201,6 +205,7 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, Overrider.Offset = OverriderOffset; Overrider.Method = Method.Method; + Overrider.VirtualBase = Method.InVirtualSubobject; } } @@ -2716,20 +2721,10 @@ void VFTableBuilder::CalculateVtordispAdjustment( VBaseMap.find(WhichVFPtr.getVBaseWithVPtr()); assert(VBaseMapEntry != VBaseMap.end()); - // If there's no vtordisp, we don't need any vtordisp adjustment. - if (!VBaseMapEntry->second.hasVtorDisp()) - return; - - const CXXRecordDecl *OverriderRD = Overrider.Method->getParent(); - const CXXRecordDecl *OverriderVBase = 0; - if (OverriderRD != MostDerivedClass) { - OverriderVBase = - ComputeBaseOffset(Context, OverriderRD, MostDerivedClass).VirtualBase; - } - - // If the final overrider is defined in the same vbase as the initial - // declaration, we don't need a vtordisp thunk at all. - if (OverriderVBase == WhichVFPtr.getVBaseWithVPtr()) + // If there's no vtordisp or the final overrider is defined in the same vbase + // as the initial declaration, we don't need any vtordisp adjustment. + if (!VBaseMapEntry->second.hasVtorDisp() || + Overrider.VirtualBase == WhichVFPtr.getVBaseWithVPtr()) return; // OK, now we know we need to use a vtordisp thunk. @@ -2740,7 +2735,8 @@ void VFTableBuilder::CalculateVtordispAdjustment( // A simple vtordisp thunk will suffice if the final overrider is defined // in either the most derived class or its non-virtual base. - if (OverriderRD == MostDerivedClass || !OverriderVBase) + if (Overrider.Method->getParent() == MostDerivedClass || + !Overrider.VirtualBase) return; // Otherwise, we need to do use the dynamic offset of the final overrider @@ -2750,7 +2746,7 @@ void VFTableBuilder::CalculateVtordispAdjustment( MostDerivedClassLayout.getVBPtrOffset()).getQuantity(); TA.Virtual.Microsoft.VBOffsetOffset = Context.getTypeSizeInChars(Context.IntTy).getQuantity() * - VTables.getVBTableIndex(MostDerivedClass, OverriderVBase); + VTables.getVBTableIndex(MostDerivedClass, Overrider.VirtualBase); TA.NonVirtual = (ThisOffset - Overrider.Offset).getQuantity(); } diff --git a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp index ecafb72f0d..066c8912fd 100644 --- a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp +++ b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp @@ -480,3 +480,58 @@ struct C : virtual B { C c; } + +namespace pr19505 { +struct A { + virtual void f(); + virtual void z(); +}; + +struct B : A { + virtual void f(); +}; + +struct C : A, B { + virtual void g(); +}; + +struct X : B, virtual C { + X() {} + virtual void g(); + + // CHECK-LABEL: VFTable for 'pr19505::A' in 'pr19505::B' in 'pr19505::C' in 'pr19505::X' (2 entries). + // CHECK-NEXT: 0 | void pr19505::B::f() + // CHECK-NEXT: 1 | void pr19505::A::z() + + // MANGLING-DAG: @"\01??_7X@pr19505@@6BB@1@@" = {{.*}}@"\01?f@B@pr19505@@UAEXXZ" +} x; + +void build_vftable(X *obj) { obj->g(); } +} + +namespace pr19506 { +struct A { + virtual void f(); + virtual void g(); +}; + +struct B : A { + virtual void f(); +}; + +struct C : B {}; + +struct X : C, virtual B { + virtual void g(); + X() {} + + // CHECK-LABEL: VFTable for 'pr19506::A' in 'pr19506::B' in 'pr19506::X' (2 entries). + // CHECK-NEXT: 0 | void pr19506::B::f() + // CHECK-NEXT: 1 | void pr19506::X::g() + // CHECK-NEXT: [this adjustment: vtordisp at -4, -12 non-virtual] + + // MANGLING-DAG: @"\01??_7X@pr19506@@6BB@1@@" = {{.*}}@"\01?f@B@pr19506@@UAEXXZ" +} x; + +void build_vftable(X *obj) { obj->g(); } +}