Index: lib/AST/VTableBuilder.cpp =================================================================== --- lib/AST/VTableBuilder.cpp +++ lib/AST/VTableBuilder.cpp @@ -2734,9 +2734,22 @@ const CXXRecordDecl *OverriderVBase = ComputeBaseOffset(Context, OverriderRD, MostDerivedClass).VirtualBase; - if (!OverriderVBase || OverriderVBase == WhichVFPtr.getVBaseWithVPtr()) + if (OverriderVBase == WhichVFPtr.getVBaseWithVPtr()) return; + if (!OverriderVBase) { + MethodVFTableLocation ML = VTables.getMethodVFTableLocation(Overrider.Method); + assert(ML.VBase && "why would we need a vtordisp if we can call the method " + "without a vfptr of a vbase?"); + // We need to offset the this parameter if the offset of the vbase is + // different between the overrider class and the most derived class. + const ASTRecordLayout &OverriderRDLayout = + Context.getASTRecordLayout(OverriderRD); + TA.NonVirtual = (OverriderRDLayout.getVBaseClassOffset(ML.VBase) + + ML.VFPtrOffset - ThisOffset).getQuantity(); + return; + } + // Otherwise, we need to do use the dynamic offset of the final overrider // in order to get "this" adjustment right. TA.Virtual.Microsoft.VBPtrOffset = Index: test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp =================================================================== --- test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp +++ test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance-vtordisps.cpp @@ -355,6 +355,40 @@ void use(A *obj) { delete obj; } } +namespace pr19408 { +// In this test, the vptr used to vcall D::f() is located in the A vbase. +// The offset of A in different in C and D, so the D vtordisp thunk should +// adjust "this" so C::f gets the right value. +struct A { + A(); + virtual void f(); + int a; +}; + +struct B : virtual A { + B(); + int b; +}; + +struct C : B { + C(); + virtual void f(); + int c; +}; + +struct D : C { + // CHECK-LABEL: VFTable for 'pr19408::A' in 'pr19408::B' in 'pr19408::C' in 'pr19408::D' (1 entry). + // CHECK-NEXT: 0 | void pr19408::C::f() + // CHECK-NEXT: [this adjustment: vtordisp at -4, -4 non-virtual] + + // MANGLING-DAG: @"\01?f@C@pr19408@@$4PPPPPPPM@3AEXXZ" + D(); + int d; +}; + +D::D() {} +} + namespace access { struct A { virtual ~A();