blob: 1703b81c7f7f7673290aa10aec46413fa1368284 [file] [edit]
// RUN: %clang_cc1 -emit-llvm -fms-extensions %s -triple=x86_64-pc-windows-msvc -o - | FileCheck %s
// Verify that a plain delete (no `::`) does NOT trigger __global_delete
// forwarding body emission, but the VDD still uses the __global_delete wrapper.
// This matches MSVC (validated against cl.exe): a plain delete that resolves to
// a global operator delete never emits a forwarding body; only an explicit
// `::delete` on a class type does.
struct Base {
void* operator new(__SIZE_TYPE__);
void operator delete(void*);
void operator delete[](void*);
virtual ~Base();
};
struct Derived : Base {
virtual ~Derived();
};
Base::~Base() {}
Derived::~Derived() {}
// new[] forces VDD emission; regular delete[], not ::delete[].
void test() {
Base *p = new Derived[2];
delete[] p;
}
// Each wrapper defaults to a weak alias to the trapping __empty_global_delete
// (matching MSVC's weak-external-with-default; this also works under Arm64EC,
// unlike an /alternatename directive). These aliases are emitted before the
// function definitions.
// CHECK-DAG: @"?__global_delete@@YAXPEAX_K@Z" = weak alias void (ptr, i64), ptr @"?__empty_global_delete@@YAXPEAX_K@Z"
// CHECK-DAG: @"?__global_array_delete@@YAXPEAX_K@Z" = weak alias void (ptr, i64), ptr @"?__empty_global_delete@@YAXPEAX_K@Z"
// The VDD dispatches between class and global delete: the array path uses the
// __global_array_delete wrapper, the scalar path uses __global_delete.
// CHECK-LABEL: define weak dso_local noundef ptr @"??_EDerived@@UEAAPEAXI@Z"
// CHECK: dtor.call_glob_delete_after_array_destroy:
// CHECK: call void @"?__global_array_delete@@YAXPEAX_K@Z"(ptr noundef %{{.*}}, i64 noundef %{{.*}})
// CHECK: dtor.call_glob_delete:
// CHECK-NEXT: call void @"?__global_delete@@YAXPEAX_K@Z"(ptr noundef %{{.*}}, i64 noundef 8)
// CHECK: dtor.call_class_delete:
// CHECK-NEXT: call void @"??3Base@@SAXPEAX@Z"(ptr noundef %{{.*}})
// __empty_global_delete should be emitted with a trap.
// CHECK: define linkonce_odr void @"?__empty_global_delete@@YAXPEAX_K@Z"(ptr noundef %0, i64 noundef %1)
// CHECK-NEXT: call void @llvm.trap()
// CHECK-NEXT: unreachable
// Neither wrapper should have a forwarding body (no `::delete` on a class
// type in this TU, and no dllexport class).
// CHECK-NOT: define {{.*}}void @"?__global_delete@@YAXPEAX_K@Z"
// CHECK-NOT: define {{.*}}void @"?__global_array_delete@@YAXPEAX_K@Z"