summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorReid Kleckner <reid@kleckner.net>2014-02-18 22:51:52 +0000
committerReid Kleckner <reid@kleckner.net>2014-02-18 22:51:52 +0000
commit0c12b36ebb1d8a1f4785dd321431f8b5da3ac8c7 (patch)
treed99ff965e0b6e73a97a2202ab0270cace59805de
parent7b535d545332bf90bbf084b43419a35c0f628274 (diff)
downloadbcm5719-llvm-0c12b36ebb1d8a1f4785dd321431f8b5da3ac8c7.tar.gz
bcm5719-llvm-0c12b36ebb1d8a1f4785dd321431f8b5da3ac8c7.zip
MS ABI: Remove nv adjustment from direct vdtor calls and prologues
Summary: Generally the vector deleting dtor, which we model as a vtable thunk, takes care of non-virtual adjustment and delegates to the other destructor variants. The other non-complete destructor variants assume that 'this' on entry points to the virtual base subobject that first declared the virtual destructor. We need to change the adjustment in both the prologue and the vdtor call setup. Reviewers: timurrrr CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D2821 llvm-svn: 201612
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp15
-rw-r--r--clang/test/CodeGenCXX/microsoft-abi-structors.cpp75
2 files changed, 90 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index d8c7d6ee5ab..572bb098c93 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -601,6 +601,13 @@ llvm::Value *MicrosoftCXXABI::adjustThisArgumentForVirtualCall(
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) {
@@ -729,6 +736,14 @@ llvm::Value *MicrosoftCXXABI::adjustThisParameterInVirtualFunctionPrologue(
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());
diff --git a/clang/test/CodeGenCXX/microsoft-abi-structors.cpp b/clang/test/CodeGenCXX/microsoft-abi-structors.cpp
index 19fff5dd6a3..85b9a7df63c 100644
--- a/clang/test/CodeGenCXX/microsoft-abi-structors.cpp
+++ b/clang/test/CodeGenCXX/microsoft-abi-structors.cpp
@@ -3,6 +3,8 @@
// 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
@@ -121,6 +123,79 @@ void use_D() { D c; }
} // 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 {
OpenPOWER on IntegriCloud