1 // RUN: %clang_cc1 -std=c++2a -fexceptions -verify %s
2 // RUN: %clang_cc1 -std=c++2a  -verify %s
3 
4 namespace std {
5   using size_t = decltype(sizeof(0));
6   enum class align_val_t : size_t;
7 
8   struct destroying_delete_t {
9     struct __construct { explicit __construct() = default; };
destroying_delete_tstd::destroying_delete_t10     explicit destroying_delete_t(__construct) {}
11   };
12 
13   inline constexpr destroying_delete_t destroying_delete(destroying_delete_t::__construct());
14 }
15 
16 void operator delete(void*, std::destroying_delete_t); // ok, just a placement delete
17 
18 struct A;
19 void operator delete(A*, std::destroying_delete_t); // expected-error {{first parameter of 'operator delete' must have type 'void *'}}
20 
21 struct A {
22   void operator delete(A*, std::destroying_delete_t);
23   void operator delete(A*, std::destroying_delete_t, std::size_t);
24   void operator delete(A*, std::destroying_delete_t, std::align_val_t);
25   void operator delete(A*, std::destroying_delete_t, std::size_t, std::align_val_t);
26   void operator delete(A*, std::destroying_delete_t, int); // expected-error {{destroying operator delete can have only an optional size and optional alignment parameter}}
27   // FIXME: It's probably a language defect that we permit usual operator delete to be variadic.
28   void operator delete(A*, std::destroying_delete_t, std::size_t, ...);
29 
30   void operator delete(struct X*, std::destroying_delete_t, std::size_t, ...); // expected-error {{first parameter of 'operator delete' must have type 'A *'}}
31 
32   void operator delete(void*, std::size_t);
33 };
34 
delete_A(A * a)35 void delete_A(A *a) { delete a; }
36 
37 namespace convert_param {
38   struct A {
39     void operator delete(
40         A*,
41         std::destroying_delete_t);
42   };
43   struct B : private A { using A::operator delete; }; // expected-note 2{{declared private here}}
44   struct C : B {};
delete_C(C * c)45   void delete_C(C *c) { delete c; } // expected-error {{cannot cast 'convert_param::C' to its private base class 'convert_param::A'}}
46 
47   // expected-error@-7 {{cannot cast 'convert_param::D' to its private base class 'convert_param::A'}}
~Dconvert_param::D48   struct D : B { virtual ~D() {} }; // expected-note {{while checking implicit 'delete this' for virtual destructor}}
49 }
50 
51 namespace delete_selection {
52   struct B {
53     void operator delete(void*) = delete;
54     void operator delete(B *, std::destroying_delete_t) = delete; // expected-note {{deleted}}
55   };
delete_B(B * b)56   void delete_B(B *b) { delete b; } // expected-error {{deleted}}
57 
58   struct C {
59     C();
60     void *operator new(std::size_t);
61     void operator delete(void*) = delete; // expected-note 0-1 {{deleted here}}
62     void operator delete(C *, std::destroying_delete_t) = delete;
63   };
64   // TODO: We only diagnose the use of a deleted operator delete when exceptions
65   // are enabled. Otherwise we don't bother doing the lookup.
66 #ifdef __EXCEPTIONS
67   // expected-error@+2 {{attempt to use a deleted function}}
68 #endif
new_C()69   C *new_C() { return new C; }
70 
71   struct D {
72     void operator delete(D *, std::destroying_delete_t) = delete; // expected-note {{deleted}}
73     void operator delete(D *, std::destroying_delete_t, std::align_val_t) = delete;
74   };
delete_D(D * d)75   void delete_D(D *d) { delete d; } // expected-error {{deleted}}
76 
77   struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2) E {
78     void operator delete(E *, std::destroying_delete_t) = delete;
79     void operator delete(E *, std::destroying_delete_t, std::align_val_t) = delete; // expected-note {{deleted}}
80   };
delete_E(E * e)81   void delete_E(E *e) { delete e; } // expected-error {{deleted}}
82 
83   struct F {
84     void operator delete(F *, std::destroying_delete_t) = delete; // expected-note {{deleted}}
85     void operator delete(F *, std::destroying_delete_t, std::size_t) = delete;
86   };
delete_F(F * f)87   void delete_F(F *f) { delete f; } // expected-error {{deleted}}
88 
89   struct G {
90     void operator delete(G *, std::destroying_delete_t, std::align_val_t) = delete;
91     void operator delete(G *, std::destroying_delete_t, std::size_t) = delete; // expected-note {{deleted}}
92   };
delete_G(G * g)93   void delete_G(G *g) { delete g; } // expected-error {{deleted}}
94 
95   struct H {
96     void operator delete(H *, std::destroying_delete_t, std::align_val_t) = delete; // expected-note {{deleted}}
97     void operator delete(H *, std::destroying_delete_t, std::size_t, std::align_val_t) = delete;
98   };
delete_H(H * h)99   void delete_H(H *h) { delete h; } // expected-error {{deleted}}
100 
101   struct alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2) I {
102     void operator delete(I *, std::destroying_delete_t, std::size_t) = delete;
103     void operator delete(I *, std::destroying_delete_t, std::size_t, std::align_val_t) = delete; // expected-note {{deleted}}
104   };
delete_I(I * i)105   void delete_I(I *i) { delete i; } // expected-error {{deleted}}
106 }
107 
108 namespace first_param_conversion {
109   struct A {
110     void operator delete(A *, std::destroying_delete_t);
111   };
f(const volatile A * a)112   void f(const volatile A *a) {
113     delete a; // ok
114   }
115 
116   struct B {
117     void operator delete(B *, std::destroying_delete_t);
118   };
119   struct C : B {};
120   struct D : B {};
121   struct E : C, D {};
g(E * e)122   void g(E *e) {
123     delete e; // expected-error {{ambiguous conversion from derived class 'first_param_conversion::E' to base class 'first_param_conversion::B':}}
124   }
125 }
126 
127 namespace templated {
128   template<typename T> using id_alias = T;
129   template<typename T> struct id_struct { using type = T; };
130 
131   template<typename T> struct A {
132     void operator delete(A *, std::destroying_delete_t);
133   };
134   template<typename T> struct B {
135     void operator delete(B<T> *, std::destroying_delete_t);
136   };
137   template<typename T> struct C {
138     void operator delete(id_alias<C> *, std::destroying_delete_t);
139   };
140   template<typename T> struct D {
141     void operator delete(typename id_struct<D>::type *, std::destroying_delete_t); // expected-error {{use 'D<T> *'}}
142   };
143 }
144 
145 namespace dtor_access {
146   struct S {
147     void operator delete(S *p, std::destroying_delete_t);
148   private:
149     ~S(); // expected-note {{here}}
150   };
151 
152   // FIXME: PR47474: GCC accepts this, and it seems somewhat reasonable to
153   // allow, even though [expr.delete]p12 says this is ill-formed.
f()154   void f() { delete new S; } // expected-error {{calling a private destructor}}
155 
156   struct T {
157     void operator delete(T *, std::destroying_delete_t);
158   protected:
159     virtual ~T(); // expected-note {{here}}
160   };
161 
162   struct U : T {
163     void operator delete(void *);
164   private:
165     ~U() override;
166   };
167 
g()168   void g() { delete (T *)new U; } // expected-error {{calling a protected destructor}}
169 }
170 
171 namespace delete_from_new {
172   struct A {
173     A(); // might throw
174     void operator delete(A *, std::destroying_delete_t) = delete;
175   };
176   struct B {
177     B(); // might throw
178     void operator delete(void *) = delete; // #member-delete-from-new
179     void operator delete(B *, std::destroying_delete_t) = delete;
180   };
f()181   void f() {
182     new A; // calls ::operator delete
183     new B; // calls B::operator delete
184 #ifdef __EXCEPTIONS
185   // expected-error@-2 {{attempt to use a deleted function}}
186   // expected-note@#member-delete-from-new {{deleted here}}
187 #endif
188   }
189 }
190