1 // RUN: %clang_cc1 -std=c++20 -verify %s 2 3 using size_t = decltype(sizeof(0)); 4 namespace std { 5 enum class align_val_t : size_t {}; 6 struct destroying_delete_t { 7 explicit destroying_delete_t() = default; 8 }; 9 10 inline constexpr destroying_delete_t destroying_delete{}; 11 } 12 13 // Aligned version is preferred over unaligned version, 14 // unsized version is preferred over sized version. 15 template<unsigned Align> 16 struct alignas(Align) A { 17 void operator delete(void*); 18 void operator delete(void*, std::align_val_t) = delete; // expected-note {{here}} 19 20 void operator delete(void*, size_t) = delete; 21 void operator delete(void*, size_t, std::align_val_t) = delete; 22 }; 23 void f(A<__STDCPP_DEFAULT_NEW_ALIGNMENT__> *p) { delete p; } 24 void f(A<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2> *p) { delete p; } // expected-error {{deleted}} 25 26 template<unsigned Align> 27 struct alignas(Align) B { 28 void operator delete(void*, size_t); 29 void operator delete(void*, size_t, std::align_val_t) = delete; // expected-note {{here}} 30 }; 31 void f(B<__STDCPP_DEFAULT_NEW_ALIGNMENT__> *p) { delete p; } 32 void f(B<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2> *p) { delete p; } // expected-error {{deleted}} 33 34 // Ensure that a deleted destructor is acceptable when the selected overload 35 // for operator delete is a destroying delete. See the comments in GH118660. 36 struct S { 37 ~S() = delete; 38 void operator delete(S *, std::destroying_delete_t) noexcept {} 39 }; 40 41 struct T { 42 void operator delete(T *, std::destroying_delete_t) noexcept {} 43 private: 44 ~T(); 45 }; 46 47 void foo(S *s, T *t) { 48 delete s; // Was rejected, is intended to be accepted. 49 delete t; // Was rejected, is intended to be accepted. 50 } 51 52 // However, if the destructor is virtual, then it has to be accessible because 53 // the behavior depends on which operator delete is selected and that is based 54 // on the dynamic type of the pointer. 55 struct U { 56 virtual ~U() = delete; // expected-note {{here}} 57 void operator delete(U *, std::destroying_delete_t) noexcept {} 58 }; 59 60 struct V { 61 void operator delete(V *, std::destroying_delete_t) noexcept {} 62 private: 63 virtual ~V(); // expected-note {{here}} 64 }; 65 66 void bar(U *u, V *v) { 67 // Both should be rejected because they have virtual destructors. 68 delete u; // expected-error {{attempt to use a deleted function}} 69 delete v; // expected-error {{calling a private destructor of class 'V'}} 70 } 71