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