| // RUN: %clang_cc1 -emit-llvm -fms-extensions %s -triple=x86_64-pc-windows-msvc -o - | FileCheck %s | |
| // Scalar `operator delete` and array `operator delete[]` use DISTINCT global | |
| // delete wrappers even though their mangled signatures are otherwise identical | |
| // (both YAXPEAX_K@Z): __global_delete for scalar, __global_array_delete for | |
| // array. Conflating them would forward one path to the wrong global operator | |
| // delete. This matches MSVC (validated against cl.exe 19.44), which likewise | |
| // uses __global_delete vs __global_array_delete and shares one empty fallback. | |
| using sz = decltype(sizeof(0)); | |
| // Member scalar operator delete -> its deleting destructor's global path uses | |
| // __global_delete. | |
| struct Scalar { | |
| void *operator new(sz); | |
| void operator delete(void *, sz); | |
| virtual ~Scalar(); | |
| }; | |
| struct ScalarD : Scalar { | |
| virtual ~ScalarD(); | |
| }; | |
| Scalar::~Scalar() {} | |
| ScalarD::~ScalarD() {} | |
| // Member array operator delete[] -> its vector deleting destructor's global | |
| // path uses __global_array_delete. | |
| struct Array { | |
| void *operator new[](sz); | |
| void operator delete[](void *, sz); | |
| virtual ~Array(); | |
| }; | |
| struct ArrayD : Array { | |
| virtual ~ArrayD(); | |
| }; | |
| Array::~Array() {} | |
| ArrayD::~ArrayD() {} | |
| // ::delete on class types with non-trivial destructors triggers the forwarding | |
| // bodies for both wrappers. | |
| void test() { | |
| ::delete new ScalarD(); | |
| ArrayD *a = new ArrayD[2]; | |
| ::delete[] a; | |
| } | |
| // The shared __empty_global_delete fallback is emitted with a trapping body | |
| // (kept alive via llvm.used) even though both wrappers have real forwarding | |
| // bodies here. | |
| // CHECK: define linkonce_odr void @"?__empty_global_delete@@YAXPEAX_K@Z"(ptr noundef %0, i64 noundef %1) | |
| // CHECK-NEXT: call void @llvm.trap() | |
| // The scalar deleting destructor's global path calls __global_delete. | |
| // CHECK: call void @"?__global_delete@@YAXPEAX_K@Z"( | |
| // The vector deleting destructor's global array path calls __global_array_delete. | |
| // CHECK: call void @"?__global_array_delete@@YAXPEAX_K@Z"( | |
| // The forwarding bodies are emitted at end-of-module. Each wrapper forwards to | |
| // its OWN global operator delete: __global_delete to the scalar ??3@, | |
| // __global_array_delete to the array ??_V@. | |
| // CHECK: define linkonce_odr void @"?__global_delete@@YAXPEAX_K@Z"(ptr noundef %0, i64 noundef %1) | |
| // CHECK-NEXT: call void @"??3@YAXPEAX_K@Z"(ptr %0, i64 %1) | |
| // CHECK: define linkonce_odr void @"?__global_array_delete@@YAXPEAX_K@Z"(ptr noundef %0, i64 noundef %1) | |
| // CHECK-NEXT: call void @"??_V@YAXPEAX_K@Z"(ptr %0, i64 %1) |