diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index 9a768a9fd223d373961288dcb814da555dfc0c88..089520debffd328bcf00ea1c93cf8aa1b91f6f35 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -3442,6 +3442,15 @@ MicrosoftVTableContext::~MicrosoftVTableContext() { llvm::DeleteContainerSeconds(VBaseInfo); } +/// Find the full path of bases from the most derived class to the base class +/// containing the vptr described by Info. Use depth-first search for this, but +/// search non-virtual bases before virtual bases. This is important in cases +/// like this where we need to find the path to a vbase that goes through an +/// nvbase: +/// struct A { virtual void f(); } +/// struct B : virtual A { virtual void f(); }; +/// struct C : virtual A, B { virtual void f(); }; +/// The path to A's vftable in C should be 'C, B, A', not 'C, A'. static bool findPathForVPtr(ASTContext &Context, const ASTRecordLayout &MostDerivedLayout, const CXXRecordDecl *RD, CharUnits Offset, @@ -3454,9 +3463,9 @@ findPathForVPtr(ASTContext &Context, const ASTRecordLayout &MostDerivedLayout, const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - // Recurse with non-virtual bases first. - // FIXME: Does this need to be in layout order? Virtual bases will be in base - // specifier order, which isn't necessarily layout order. + // Sort direct bases into non-virtual bases followed by virtual bases. This + // approximates layout order with the exception of classes that do not contain + // vptrs, and those don't affect our results. SmallVector<CXXBaseSpecifier, 4> Bases(RD->bases_begin(), RD->bases_end()); std::stable_partition(Bases.begin(), Bases.end(), [](CXXBaseSpecifier bs) { return !bs.isVirtual(); }); @@ -3468,7 +3477,7 @@ findPathForVPtr(ASTContext &Context, const ASTRecordLayout &MostDerivedLayout, NewOffset = Offset + Layout.getBaseClassOffset(Base); else { if (!VBasesSeen.insert(Base).second) - return false; + continue; NewOffset = MostDerivedLayout.getVBaseClassOffset(Base); } FullPath.push_back(Base); diff --git a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp index 65d6a9d90e6d484a544f60788ea980ac6d626aef..83f8114bae9938ee4ad3dab8db39e3d056b037d0 100644 --- a/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp +++ b/test/CodeGenCXX/microsoft-abi-vtables-virtual-inheritance.cpp @@ -807,3 +807,41 @@ C::C() {} // MANGLING-DAG: @"\01??_7C@pr21031_2@@6BA@1@@" = {{.*}} constant [1 x i8*] // MANGLING-DAG: @"\01??_7C@pr21031_2@@6BB@1@@" = {{.*}} constant [1 x i8*] } + +namespace pr21062_1 { +struct A { virtual void f(); }; +struct B {}; +struct C : virtual B {}; +struct D : virtual C, virtual B, virtual A { D();}; +D::D() {} + +// CHECK-LABEL: VFTable for 'pr21062_1::A' in 'pr21062_1::D' (1 entry) +// CHECK-NEXT: 0 | void pr21062_1::A::f() + +// MANGLING-DAG: @"\01??_7D@pr21062_1@@6B@" = {{.*}} constant [1 x i8*] +} + +namespace pr21062_2 { +struct A { virtual void f(); }; +struct B {}; +struct C : virtual B {}; +struct D : C, virtual B, virtual A { D(); }; +D::D() {} + +// CHECK-LABEL: VFTable for 'pr21062_2::A' in 'pr21062_2::D' (1 entry) +// CHECK-NEXT: 0 | void pr21062_2::A::f() + +// MANGLING-DAG: @"\01??_7D@pr21062_2@@6B@" = {{.*}} constant [1 x i8*] +} + +namespace pr21064 { +struct A {}; +struct B { virtual void f(); }; +struct C : virtual A, virtual B {}; +struct D : virtual A, virtual C { D(); }; +D::D() {} +// CHECK-LABEL: VFTable for 'pr21064::B' in 'pr21064::C' in 'pr21064::D' (1 entry) +// CHECK-NEXT: 0 | void pr21064::B::f() + +// MANGLING-DAG: @"\01??_7D@pr21064@@6B@" = {{.*}} constant [1 x i8*] +}