Emit virtual/deleting destructors properly with -cxx-abi microsoft, PR15058
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@175045 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CodeGenCXX/microsoft-abi-structors.cpp b/test/CodeGenCXX/microsoft-abi-structors.cpp
index 12622f1..16763d5 100644
--- a/test/CodeGenCXX/microsoft-abi-structors.cpp
+++ b/test/CodeGenCXX/microsoft-abi-structors.cpp
@@ -1,4 +1,8 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 -fno-rtti > %t 2>&1
+// RUN: FileCheck %s < %t
+// Using a different check prefix as the inline destructors might be placed
+// anywhere in the output.
+// RUN: FileCheck --check-prefix=DTORS %s < %t
class A {
public:
@@ -23,13 +27,60 @@
}
struct B {
- virtual ~B();
+ virtual ~B() {
+// Complete destructor first:
+// DTORS: define {{.*}} x86_thiscallcc void @"\01??1B@@UAE@XZ"(%struct.B* %this)
+//
+// Then, the scalar deleting destructor (used in the vtable):
+// DTORS: define {{.*}} x86_thiscallcc void @"\01??_GB@@UAEPAXI@Z"(%struct.B* %this, i1 zeroext %should_call_delete)
+// DTORS: %0 = icmp eq i8 %should_call_delete{{.*}}, 0
+// DTORS-NEXT: br i1 %0, label %dtor.continue, label %dtor.call_delete
+// DTORS: dtor.call_delete:
+// DTORS-NEXT: %1 = bitcast %struct.B* %this1 to i8*
+// DTORS-NEXT: call void @"\01??3@YAXPAX@Z"(i8* %1) nounwind
+// DTORS-NEXT: br label %dtor.continue
+// DTORS: dtor.continue:
+// DTORS-NEXT: ret void
+ }
virtual void foo();
};
+// Emits the vftable in the output.
+void B::foo() {}
+
void check_vftable_offset() {
B b;
// The vftable pointer should point at the beginning of the vftable.
// CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %struct.B* {{.*}} to i8***
// CHECK: store i8** getelementptr inbounds ([2 x i8*]* @"\01??_7B@@6B@", i64 0, i64 0), i8*** [[THIS_PTR]]
}
+
+// FIXME: Enable the following block and add expectations when calls
+// to virtual complete dtor are supported.
+#if 0
+void call_complete_dtor(B *obj_ptr) {
+ obj_ptr->~B();
+}
+#endif
+
+void call_deleting_dtor(B *obj_ptr) {
+// FIXME: Add CHECKs when calls to virtual deleting dtor are generated properly.
+ delete obj_ptr;
+}
+
+struct C {
+ static int foo();
+
+ C() {
+ static int ctor_static = foo();
+ // CHECK that the static in the ctor gets mangled correctly:
+ // CHECK: @"\01?ctor_static@?1???0C@@QAE@XZ@4HA"
+ }
+ ~C() {
+ static int dtor_static = foo();
+ // CHECK that the static in the dtor gets mangled correctly:
+ // CHECK: @"\01?dtor_static@?1???1C@@QAE@XZ@4HA"
+ }
+};
+
+void use_C() { C c; }
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
index 176ecf1..5d430db 100644
--- a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
+++ b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
@@ -37,10 +37,10 @@
struct C {
// CHECK-C: Vtable for 'C' (2 entries)
- // CHECK-C-NEXT: 0 | C::~C()
+ // CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
// CHECK-C-NEXT: 1 | void C::f()
// CHECK-C: VTable indices for 'C' (2 entries).
- // CHECK-C-NEXT: 0 | C::~C()
+ // CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
// CHECK-C-NEXT: 1 | void C::f()
// Never used, so doesn't emit a vtable.
virtual ~C();
@@ -52,7 +52,7 @@
struct D {
// CHECK-D: Vtable for 'D' (2 entries)
// CHECK-D-NEXT: 0 | void D::f()
- // CHECK-D-NEXT: 1 | D::~D()
+ // CHECK-D-NEXT: 1 | D::~D() [scalar deleting]
// EMITS-VTABLE: @"\01??_7D@@6B@" = unnamed_addr constant [2 x i8*]
virtual void f();
@@ -65,10 +65,10 @@
// CHECK-E-NEXT: 0 | void A::f()
// CHECK-E-NEXT: 1 | void A::g()
// CHECK-E-NEXT: 2 | void A::h()
- // CHECK-E-NEXT: 3 | E::~E()
+ // CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
// CHECK-E-NEXT: 4 | void E::i()
// CHECK-E: VTable indices for 'E' (2 entries).
- // CHECK-E-NEXT: 3 | E::~E()
+ // CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
// CHECK-E-NEXT: 4 | void E::i()
// Never used, so doesn't emit a vtable.
@@ -83,10 +83,10 @@
// CHECK-F-NEXT: 1 | void A::g()
// CHECK-F-NEXT: 2 | void A::h()
// CHECK-F-NEXT: 3 | void F::i()
- // CHECK-F-NEXT: 4 | F::~F()
+ // CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
// CHECK-F: VTable indices for 'F' (2 entries).
// CHECK-F-NEXT: 3 | void F::i()
- // CHECK-F-NEXT: 4 | F::~F()
+ // CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
// EMITS-VTABLE: @"\01??_7F@@6B@" = unnamed_addr constant [5 x i8*]
virtual void i();
virtual ~F();
@@ -98,12 +98,12 @@
// CHECK-G-NEXT: 0 | void G::f()
// CHECK-G-NEXT: 1 | void A::g()
// CHECK-G-NEXT: 2 | void A::h()
- // CHECK-G-NEXT: 3 | G::~G()
+ // CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
// CHECK-G-NEXT: 4 | void E::i()
// CHECK-G-NEXT: 5 | void G::j()
// CHECK-G: VTable indices for 'G' (3 entries).
// CHECK-G-NEXT: 0 | void G::f()
- // CHECK-G-NEXT: 3 | G::~G()
+ // CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
// CHECK-G-NEXT: 5 | void G::j()
// Never used, so doesn't emit a vtable.
virtual void f(); // overrides A::f()