[-cxx-abi microsoft] Fix this argument/parameter offsets for virtual destructors in the presence of virtual bases
Reviewed at http://llvm-reviews.chandlerc.com/D1939
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192822 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 045b7f1..2da0891 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -2668,11 +2668,6 @@
VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
BaseSubobject Base,
FinalOverriders::OverriderInfo Overrider) {
- // Complete object virtual destructors are always emitted in the most derived
- // class, thus don't have this offset.
- if (isa<CXXDestructorDecl>(MD))
- return CharUnits();
-
InitialOverriddenDefinitionCollector Collector;
visitAllOverriddenMethods(MD, Collector);
@@ -2690,6 +2685,7 @@
I != E; ++I) {
const CXXBasePath &Path = (*I);
CharUnits ThisOffset = Base.getBaseOffset();
+ bool SeenVBase = false;
// For each path from the overrider to the parents of the overridden methods,
// traverse the path, calculating the this offset in the most derived class.
@@ -2701,6 +2697,7 @@
const ASTRecordLayout &Layout = Context.getASTRecordLayout(PrevRD);
if (Element.Base->isVirtual()) {
+ SeenVBase = true;
if (Overrider.Method->getParent() == PrevRD) {
// This one's interesting. If the final overrider is in a vbase B of the
// most derived class and it overrides a method of the B's own vbase A,
@@ -2713,11 +2710,22 @@
} else {
ThisOffset = MostDerivedClassLayout.getVBaseClassOffset(CurRD);
}
+
+ // A virtual destructor of a virtual base takes the address of the
+ // virtual base subobject as the "this" argument.
+ if (isa<CXXDestructorDecl>(MD))
+ break;
} else {
ThisOffset += Layout.getBaseClassOffset(CurRD);
}
}
+ // If a "Base" class has at least one non-virtual base with a virtual
+ // destructor, the "Base" virtual destructor will take the address of the
+ // "Base" subobject as the "this" argument.
+ if (!SeenVBase && isa<CXXDestructorDecl>(MD))
+ return Base.getBaseOffset();
+
if (Ret > ThisOffset || First) {
First = false;
Ret = ThisOffset;