summaryrefslogtreecommitdiff
path: root/test/CodeGenCXX/cxx2a-destroying-delete.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/CodeGenCXX/cxx2a-destroying-delete.cpp')
-rw-r--r--test/CodeGenCXX/cxx2a-destroying-delete.cpp161
1 files changed, 161 insertions, 0 deletions
diff --git a/test/CodeGenCXX/cxx2a-destroying-delete.cpp b/test/CodeGenCXX/cxx2a-destroying-delete.cpp
new file mode 100644
index 0000000000000..2e4d40715e153
--- /dev/null
+++ b/test/CodeGenCXX/cxx2a-destroying-delete.cpp
@@ -0,0 +1,161 @@
+// RUN: %clang_cc1 -std=c++2a -emit-llvm %s -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ITANIUM
+// RUN: %clang_cc1 -std=c++2a -emit-llvm %s -triple x86_64-windows -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-MSABI
+
+namespace std {
+ using size_t = decltype(sizeof(0));
+ enum class align_val_t : size_t;
+ struct destroying_delete_t {};
+}
+
+struct A {
+ void *data;
+ ~A();
+ void operator delete(A*, std::destroying_delete_t);
+};
+void delete_A(A *a) { delete a; }
+// CHECK-LABEL: define {{.*}}delete_A
+// CHECK: %[[a:.*]] = load
+// CHECK: icmp eq %{{.*}} %[[a]], null
+// CHECK: br i1
+//
+// Ensure that we call the destroying delete and not the destructor.
+// CHECK-NOT: call
+// CHECK-ITANIUM: call void @_ZN1AdlEPS_St19destroying_delete_t(%{{.*}}* %[[a]])
+// CHECK-MSABI: call void @"\01??3A@@SAXPEAU0@Udestroying_delete_t@std@@@Z"(%{{.*}}* %[[a]], i8
+// CHECK-NOT: call
+// CHECK: }
+
+struct B {
+ virtual ~B();
+ void operator delete(B*, std::destroying_delete_t);
+};
+void delete_B(B *b) { delete b; }
+// CHECK-LABEL: define {{.*}}delete_B
+// CHECK: %[[b:.*]] = load
+// CHECK: icmp eq %{{.*}} %[[b]], null
+// CHECK: br i1
+//
+// Ensure that we call the virtual destructor and not the operator delete.
+// CHECK-NOT: call
+// CHECK: %[[VTABLE:.*]] = load
+// CHECK: %[[DTOR:.*]] = load
+// CHECK: call {{void|i8\*}} %[[DTOR]](%{{.*}}* %[[b]]
+// CHECK-MSABI-SAME: , i32 1)
+// CHECK-NOT: call
+// CHECK: }
+
+struct Padding {
+ virtual void f();
+};
+
+struct C : Padding, A {};
+void delete_C(C *c) { delete c; }
+// Check that we perform a derived-to-base conversion on the parameter to 'operator delete'.
+// CHECK-LABEL: define {{.*}}delete_C
+// CHECK: %[[c:.*]] = load
+// CHECK: icmp eq %{{.*}} %[[c]], null
+// CHECK: br i1
+//
+// CHECK: %[[base:.*]] = getelementptr {{.*}}, i64 8
+// CHECK: %[[castbase:.*]] = bitcast {{.*}} %[[base]]
+//
+// CHECK: %[[a:.*]] = phi {{.*}} %[[castbase]]
+// CHECK: icmp eq %{{.*}} %[[a]], null
+// CHECK: br i1
+//
+// CHECK-NOT: call
+// CHECK-ITANIUM: call void @_ZN1AdlEPS_St19destroying_delete_t(%{{.*}}* %[[a]])
+// CHECK-MSABI: call void @"\01??3A@@SAXPEAU0@Udestroying_delete_t@std@@@Z"(%{{.*}}* %[[a]], i8
+// CHECK-NOT: call
+// CHECK: }
+
+struct VDel { virtual ~VDel(); };
+struct D : Padding, VDel, B {};
+void delete_D(D *d) { delete d; }
+// CHECK-LABEL: define {{.*}}delete_D
+// CHECK: %[[d:.*]] = load
+// CHECK: icmp eq %{{.*}} %[[d]], null
+// CHECK: br i1
+//
+// CHECK-NOT: call
+// CHECK: %[[VTABLE:.*]] = load
+// CHECK: %[[DTOR:.*]] = load
+//
+// For MS, we don't add a new vtable slot to the primary vtable for the virtual
+// destructor. Instead we cast to the VDel base class.
+// CHECK-MSABI: bitcast {{.*}} %[[d]]
+// CHECK-MSABI-NEXT: getelementptr {{.*}}, i64 8
+// CHECK-MSABI-NEXT: %[[d:.*]] = bitcast i8*
+//
+// CHECK: call {{void|i8\*}} %[[DTOR]](%{{.*}}* %[[d]]
+// CHECK-MSABI-SAME: , i32 1)
+// CHECK-NOT: call
+// CHECK: }
+
+struct E { void *data; };
+struct F { void operator delete(F *, std::destroying_delete_t, std::size_t, std::align_val_t); void *data; };
+struct alignas(16) G : E, F { void *data; };
+
+void delete_G(G *g) { delete g; }
+// CHECK-LABEL: define {{.*}}delete_G
+// CHECK-NOT: call
+// CHECK-ITANIUM: call void @_ZN1FdlEPS_St19destroying_delete_tmSt11align_val_t(%{{.*}}* %[[a]], i64 32, i64 16)
+// CHECK-MSABI: call void @"\01??3F@@SAXPEAU0@Udestroying_delete_t@std@@_KW4align_val_t@2@@Z"(%{{.*}}* %[[a]], i8 {{[^,]*}}, i64 32, i64 16)
+// CHECK-NOT: call
+// CHECK: }
+
+void call_in_dtor();
+
+struct H : G { virtual ~H(); } h;
+H::~H() { call_in_dtor(); }
+// CHECK-ITANIUM-LABEL: define void @_ZN1HD0Ev(
+// CHECK-ITANIUM-NOT: call
+// CHECK-ITANIUM: getelementptr {{.*}}, i64 24
+// CHECK-ITANIUM-NOT: call
+// CHECK-ITANIUM: call void @_ZN1FdlEPS_St19destroying_delete_tmSt11align_val_t({{.*}}, i64 48, i64 16)
+// CHECK-ITANIUM-NOT: call
+// CHECK-ITANIUM: }
+
+// CHECK-MSABI: define {{.*}} @"\01??_GH@@UEAAPEAXI@Z"(
+// CHECK-MSABI-NOT: call{{ }}
+// CHECK-MSABI: load i32
+// CHECK-MSABI: icmp eq i32 {{.*}}, 0
+// CHECK-MSABI: br i1
+//
+// CHECK-MSABI-NOT: call{{ }}
+// CHECK-MSABI: getelementptr {{.*}}, i64 24
+// CHECK-MSABI-NOT: call{{ }}
+// CHECK-MSABI: call void @"\01??3F@@SAXPEAU0@Udestroying_delete_t@std@@_KW4align_val_t@2@@Z"({{.*}}, i64 48, i64 16)
+// CHECK-MSABI: br label %[[RETURN:.*]]
+//
+// CHECK-MSABI: call void @"\01??_DH@@QEAAXXZ"(
+// CHECK-MSABI: br label %[[RETURN]]
+//
+// CHECK-MSABI: }
+
+struct I : H { virtual ~I(); alignas(32) char buffer[32]; } i;
+I::~I() { call_in_dtor(); }
+// CHECK-ITANIUM-LABEL: define void @_ZN1ID0Ev(
+// CHECK-ITANIUM-NOT: call
+// CHECK-ITANIUM: getelementptr {{.*}}, i64 24
+// CHECK-ITANIUM-NOT: call
+// CHECK-ITANIUM: call void @_ZN1FdlEPS_St19destroying_delete_tmSt11align_val_t({{.*}}, i64 96, i64 32)
+// CHECK-ITANIUM-NOT: call
+// CHECK-ITANIUM: }
+
+// CHECK-MSABI: define {{.*}} @"\01??_GI@@UEAAPEAXI@Z"(
+// CHECK-MSABI-NOT: call{{ }}
+// CHECK-MSABI: load i32
+// CHECK-MSABI: icmp eq i32 {{.*}}, 0
+// CHECK-MSABI: br i1
+//
+// CHECK-MSABI-NOT: call{{ }}
+// CHECK-MSABI: getelementptr {{.*}}, i64 24
+// CHECK-MSABI-NOT: call{{ }}
+// CHECK-MSABI: call void @"\01??3F@@SAXPEAU0@Udestroying_delete_t@std@@_KW4align_val_t@2@@Z"({{.*}}, i64 96, i64 32)
+// CHECK-MSABI: br label %[[RETURN:.*]]
+//
+// CHECK-MSABI: call void @"\01??_DI@@QEAAXXZ"(
+// CHECK-MSABI: br label %[[RETURN]]
+//
+// CHECK-MSABI: }