unsigned AS = cast<llvm::PointerType>(This->getType())->getAddressSpace();
llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS);
CharUnits StaticOffset = ML.VFPtrOffset;
+
+ // Base destructors expect 'this' to point to the beginning of the base
+ // subobject, not the first vfptr that happens to contain the virtual dtor.
+ // However, we still need to apply the virtual base adjustment.
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
+ StaticOffset = CharUnits::Zero();
+
if (ML.VBase) {
bool AvoidVirtualOffset = false;
if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) {
MicrosoftVTableContext::MethodVFTableLocation ML =
CGM.getMicrosoftVTableContext().getMethodVFTableLocation(LookupGD);
CharUnits Adjustment = ML.VFPtrOffset;
+
+ // Normal virtual instance methods need to adjust from the vfptr that first
+ // defined the virtual method to the virtual base subobject, but destructors
+ // do not. The vector deleting destructor thunk applies this adjustment for
+ // us if necessary.
+ if (isa<CXXDestructorDecl>(MD))
+ Adjustment = CharUnits::Zero();
+
if (ML.VBase) {
const ASTRecordLayout &DerivedLayout =
CGF.getContext().getASTRecordLayout(MD->getParent());
// vftables are emitted very late, so do another pass to try to keep the checks
// in source order.
// RUN: FileCheck --check-prefix DTORS %s < %t
+// RUN: FileCheck --check-prefix DTORS2 %s < %t
+// RUN: FileCheck --check-prefix DTORS3 %s < %t
//
// RUN: %clang_cc1 -emit-llvm %s -o - -mconstructor-aliases -triple=x86_64-pc-win32 -fno-rtti | FileCheck --check-prefix DTORS-X64 %s
} // end namespace basic
+namespace dtor_in_second_nvbase {
+
+struct A {
+ virtual void f(); // A needs vftable to be primary.
+};
+struct B {
+ virtual ~B();
+};
+struct C : A, B {
+ virtual ~C();
+};
+
+C::~C() {
+// CHECK-LABEL: define x86_thiscallcc void @"\01??1C@dtor_in_second_nvbase@@UAE@XZ"
+// CHECK: (%"struct.dtor_in_second_nvbase::C"* %this)
+// No this adjustment!
+// CHECK-NOT: getelementptr
+// CHECK: load %"struct.dtor_in_second_nvbase::C"** %{{.*}}
+// Now we this-adjust before calling ~B.
+// CHECK: bitcast %"struct.dtor_in_second_nvbase::C"* %{{.*}} to i8*
+// CHECK: getelementptr inbounds i8* %{{.*}}, i64 4
+// CHECK: bitcast i8* %{{.*}} to %"struct.dtor_in_second_nvbase::B"*
+// CHECK: call x86_thiscallcc void @"\01??1B@dtor_in_second_nvbase@@UAE@XZ"
+// CHECK: (%"struct.dtor_in_second_nvbase::B"* %{{.*}})
+// CHECK: ret void
+}
+
+void foo() {
+ C c;
+}
+// DTORS2-LABEL: define weak x86_thiscallcc void @"\01??_EC@dtor_in_second_nvbase@@W3AEPAXI@Z"
+// DTORS2: (%"struct.dtor_in_second_nvbase::C"* %this, i32 %should_call_delete)
+// Do an adjustment from B* to C*.
+// DTORS2: getelementptr i8* %{{.*}}, i32 -4
+// DTORS2: bitcast i8* %{{.*}} to %"struct.dtor_in_second_nvbase::C"*
+// DTORS2: call x86_thiscallcc void @"\01??_GC@dtor_in_second_nvbase@@UAEPAXI@Z"
+// DTORS2: ret void
+
+}
+
+namespace test2 {
+// Just like dtor_in_second_nvbase, except put that in a vbase of a diamond.
+
+// C's dtor is in the non-primary base.
+struct A { virtual void f(); };
+struct B { virtual ~B(); };
+struct C : A, B { virtual ~C(); int c; };
+
+// Diamond hierarchy, with C as the shared vbase.
+struct D : virtual C { int d; };
+struct E : virtual C { int e; };
+struct F : D, E { ~F(); int f; };
+
+F::~F() {
+// CHECK-LABEL: define x86_thiscallcc void @"\01??1F@test2@@UAE@XZ"(%"struct.test2::F"*)
+// Do an adjustment from C vbase subobject to F as though F was the
+// complete type.
+// CHECK: getelementptr inbounds i8* %{{.*}}, i32 -20
+// CHECK: bitcast i8* %{{.*}} to %"struct.test2::F"*
+// CHECK: store %"struct.test2::F"*
+}
+
+void foo() {
+ F f;
+}
+// DTORS3-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_DF@test2@@UAE@XZ"
+// Do an adjustment from C* to F*.
+// DTORS3: getelementptr i8* %{{.*}}, i32 20
+// DTORS3: bitcast i8* %{{.*}} to %"struct.test2::F"*
+// DTORS3: call x86_thiscallcc void @"\01??1F@test2@@UAE@XZ"
+// DTORS3: ret void
+
+}
namespace constructors {