1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // <memory>
10
11 // unique_ptr
12
13 //=============================================================================
14 // TESTING unique_ptr(pointer, deleter)
15 //
16 // Concerns:
17 // 1 unique_ptr(pointer, deleter&&) only requires a MoveConstructible deleter.
18 // 2 unique_ptr(pointer, deleter&) requires a CopyConstructible deleter.
19 // 3 unique_ptr<T, D&>(pointer, deleter) does not require a CopyConstructible deleter.
20 // 4 unique_ptr<T, D const&>(pointer, deleter) does not require a CopyConstructible deleter.
21 // 5 unique_ptr(pointer, deleter) should work for derived pointers.
22 // 6 unique_ptr(pointer, deleter) should work with function pointers.
23 // 7 unique_ptr<void> should work.
24
25 #include <memory>
26 #include <cassert>
27
28 #include "test_macros.h"
29 #include "unique_ptr_test_helper.h"
30
31 bool my_free_called = false;
32
my_free(void *)33 void my_free(void*) { my_free_called = true; }
34
35 #if TEST_STD_VER >= 11
36 struct DeleterBase {
operator ()DeleterBase37 TEST_CONSTEXPR_CXX23 void operator()(void*) const {}
38 };
39 struct CopyOnlyDeleter : DeleterBase {
40 TEST_CONSTEXPR_CXX23 CopyOnlyDeleter() = default;
41 TEST_CONSTEXPR_CXX23 CopyOnlyDeleter(CopyOnlyDeleter const&) = default;
42 CopyOnlyDeleter(CopyOnlyDeleter&&) = delete;
43 };
44 struct MoveOnlyDeleter : DeleterBase {
45 TEST_CONSTEXPR_CXX23 MoveOnlyDeleter() = default;
46 TEST_CONSTEXPR_CXX23 MoveOnlyDeleter(MoveOnlyDeleter&&) = default;
47 };
48 struct NoCopyMoveDeleter : DeleterBase {
49 TEST_CONSTEXPR_CXX23 NoCopyMoveDeleter() = default;
50 NoCopyMoveDeleter(NoCopyMoveDeleter const&) = delete;
51 };
52 #endif
53
54 template <bool IsArray>
test_sfinae()55 TEST_CONSTEXPR_CXX23 void test_sfinae() {
56 #if TEST_STD_VER >= 11
57 typedef typename std::conditional<!IsArray, int, int[]>::type VT;
58 {
59 using D = CopyOnlyDeleter;
60 using U = std::unique_ptr<VT, D>;
61 static_assert(std::is_constructible<U, int*, D const&>::value, "");
62 static_assert(std::is_constructible<U, int*, D&>::value, "");
63 static_assert(std::is_constructible<U, int*, D&&>::value, "");
64 // FIXME: __libcpp_compressed_pair attempts to perform a move even though
65 // it should only copy.
66 //D d;
67 //U u(nullptr, std::move(d));
68 }
69 {
70 using D = MoveOnlyDeleter;
71 using U = std::unique_ptr<VT, D>;
72 static_assert(!std::is_constructible<U, int*, D const&>::value, "");
73 static_assert(!std::is_constructible<U, int*, D&>::value, "");
74 static_assert(std::is_constructible<U, int*, D&&>::value, "");
75 D d;
76 U u(nullptr, std::move(d));
77 }
78 {
79 using D = NoCopyMoveDeleter;
80 using U = std::unique_ptr<VT, D>;
81 static_assert(!std::is_constructible<U, int*, D const&>::value, "");
82 static_assert(!std::is_constructible<U, int*, D&>::value, "");
83 static_assert(!std::is_constructible<U, int*, D&&>::value, "");
84 }
85 {
86 using D = NoCopyMoveDeleter;
87 using U = std::unique_ptr<VT, D&>;
88 static_assert(!std::is_constructible<U, int*, D const&>::value, "");
89 static_assert(std::is_constructible<U, int*, D&>::value, "");
90 static_assert(!std::is_constructible<U, int*, D&&>::value, "");
91 static_assert(!std::is_constructible<U, int*, const D&&>::value, "");
92 }
93 {
94 using D = NoCopyMoveDeleter;
95 using U = std::unique_ptr<VT, const D&>;
96 static_assert(std::is_constructible<U, int*, D const&>::value, "");
97 static_assert(std::is_constructible<U, int*, D&>::value, "");
98 static_assert(!std::is_constructible<U, int*, D&&>::value, "");
99 static_assert(!std::is_constructible<U, int*, const D&&>::value, "");
100 }
101 #endif
102 }
103
104 template <bool IsArray>
test_noexcept()105 TEST_CONSTEXPR_CXX23 void test_noexcept() {
106 #if TEST_STD_VER >= 11
107 typedef typename std::conditional<!IsArray, int, int[]>::type VT;
108 {
109 using D = CopyOnlyDeleter;
110 using U = std::unique_ptr<VT, D>;
111 static_assert(std::is_nothrow_constructible<U, int*, D const&>::value, "");
112 static_assert(std::is_nothrow_constructible<U, int*, D&>::value, "");
113 static_assert(std::is_nothrow_constructible<U, int*, D&&>::value, "");
114 }
115 {
116 using D = MoveOnlyDeleter;
117 using U = std::unique_ptr<VT, D>;
118 static_assert(std::is_nothrow_constructible<U, int*, D&&>::value, "");
119 D d;
120 U u(nullptr, std::move(d));
121 }
122 {
123 using D = NoCopyMoveDeleter;
124 using U = std::unique_ptr<VT, D&>;
125 static_assert(std::is_nothrow_constructible<U, int*, D&>::value, "");
126 }
127 {
128 using D = NoCopyMoveDeleter;
129 using U = std::unique_ptr<VT, const D&>;
130 static_assert(std::is_nothrow_constructible<U, int*, D const&>::value, "");
131 static_assert(std::is_nothrow_constructible<U, int*, D&>::value, "");
132 }
133 #endif
134 }
135
test_sfinae_runtime()136 TEST_CONSTEXPR_CXX23 void test_sfinae_runtime() {
137 #if TEST_STD_VER >= 11
138 {
139 using D = CopyOnlyDeleter;
140 using U = std::unique_ptr<A[], D>;
141 static_assert(std::is_nothrow_constructible<U, A*, D const&>::value, "");
142 static_assert(std::is_nothrow_constructible<U, A*, D&>::value, "");
143 static_assert(std::is_nothrow_constructible<U, A*, D&&>::value, "");
144
145 static_assert(!std::is_constructible<U, B*, D const&>::value, "");
146 static_assert(!std::is_constructible<U, B*, D&>::value, "");
147 static_assert(!std::is_constructible<U, B*, D&&>::value, "");
148 // FIXME: __libcpp_compressed_pair attempts to perform a move even though
149 // it should only copy.
150 //D d;
151 //U u(nullptr, std::move(d));
152 }
153 {
154 using D = MoveOnlyDeleter;
155 using U = std::unique_ptr<A[], D>;
156 static_assert(!std::is_constructible<U, A*, D const&>::value, "");
157 static_assert(!std::is_constructible<U, A*, D&>::value, "");
158 static_assert(std::is_nothrow_constructible<U, A*, D&&>::value, "");
159
160 static_assert(!std::is_constructible<U, B*, D const&>::value, "");
161 static_assert(!std::is_constructible<U, B*, D&>::value, "");
162 static_assert(!std::is_constructible<U, B*, D&&>::value, "");
163 D d;
164 U u(nullptr, std::move(d));
165 }
166 {
167 using D = NoCopyMoveDeleter;
168 using U = std::unique_ptr<A[], D>;
169 static_assert(!std::is_constructible<U, A*, D const&>::value, "");
170 static_assert(!std::is_constructible<U, A*, D&>::value, "");
171 static_assert(!std::is_constructible<U, A*, D&&>::value, "");
172
173 static_assert(!std::is_constructible<U, B*, D const&>::value, "");
174 static_assert(!std::is_constructible<U, B*, D&>::value, "");
175 static_assert(!std::is_constructible<U, B*, D&&>::value, "");
176 }
177 {
178 using D = NoCopyMoveDeleter;
179 using U = std::unique_ptr<A[], D&>;
180 static_assert(!std::is_constructible<U, A*, D const&>::value, "");
181 static_assert(std::is_nothrow_constructible<U, A*, D&>::value, "");
182 static_assert(!std::is_constructible<U, A*, D&&>::value, "");
183 static_assert(!std::is_constructible<U, A*, const D&&>::value, "");
184
185 static_assert(!std::is_constructible<U, B*, D const&>::value, "");
186 static_assert(!std::is_constructible<U, B*, D&>::value, "");
187 static_assert(!std::is_constructible<U, B*, D&&>::value, "");
188 static_assert(!std::is_constructible<U, B*, const D&&>::value, "");
189 }
190 {
191 using D = NoCopyMoveDeleter;
192 using U = std::unique_ptr<A[], const D&>;
193 static_assert(std::is_nothrow_constructible<U, A*, D const&>::value, "");
194 static_assert(std::is_nothrow_constructible<U, A*, D&>::value, "");
195 static_assert(!std::is_constructible<U, A*, D&&>::value, "");
196 static_assert(!std::is_constructible<U, A*, const D&&>::value, "");
197
198 static_assert(!std::is_constructible<U, B*, D const&>::value, "");
199 static_assert(!std::is_constructible<U, B*, D&>::value, "");
200 static_assert(!std::is_constructible<U, B*, D&&>::value, "");
201 static_assert(!std::is_constructible<U, B*, const D&&>::value, "");
202 }
203 #endif
204 }
205
206 template <bool IsArray>
test_basic()207 TEST_CONSTEXPR_CXX23 void test_basic() {
208 typedef typename std::conditional<!IsArray, A, A[]>::type VT;
209 const int expect_alive = IsArray ? 5 : 1;
210 { // MoveConstructible deleter (C-1)
211 A* p = newValue<VT>(expect_alive);
212 if (!TEST_IS_CONSTANT_EVALUATED)
213 assert(A::count == expect_alive);
214 std::unique_ptr<VT, Deleter<VT> > s(p, Deleter<VT>(5));
215 assert(s.get() == p);
216 assert(s.get_deleter().state() == 5);
217 }
218 if (!TEST_IS_CONSTANT_EVALUATED)
219 assert(A::count == 0);
220 { // CopyConstructible deleter (C-2)
221 A* p = newValue<VT>(expect_alive);
222 if (!TEST_IS_CONSTANT_EVALUATED)
223 assert(A::count == expect_alive);
224 CopyDeleter<VT> d(5);
225 std::unique_ptr<VT, CopyDeleter<VT> > s(p, d);
226 assert(s.get() == p);
227 assert(s.get_deleter().state() == 5);
228 d.set_state(6);
229 assert(s.get_deleter().state() == 5);
230 }
231 if (!TEST_IS_CONSTANT_EVALUATED)
232 assert(A::count == 0);
233 { // Reference deleter (C-3)
234 A* p = newValue<VT>(expect_alive);
235 if (!TEST_IS_CONSTANT_EVALUATED)
236 assert(A::count == expect_alive);
237 NCDeleter<VT> d(5);
238 std::unique_ptr<VT, NCDeleter<VT>&> s(p, d);
239 assert(s.get() == p);
240 assert(&s.get_deleter() == &d);
241 assert(s.get_deleter().state() == 5);
242 d.set_state(6);
243 assert(s.get_deleter().state() == 6);
244 }
245 if (!TEST_IS_CONSTANT_EVALUATED)
246 assert(A::count == 0);
247 { // Const Reference deleter (C-4)
248 A* p = newValue<VT>(expect_alive);
249 if (!TEST_IS_CONSTANT_EVALUATED)
250 assert(A::count == expect_alive);
251 NCConstDeleter<VT> d(5);
252 std::unique_ptr<VT, NCConstDeleter<VT> const&> s(p, d);
253 assert(s.get() == p);
254 assert(s.get_deleter().state() == 5);
255 assert(&s.get_deleter() == &d);
256 }
257 if (!TEST_IS_CONSTANT_EVALUATED) {
258 assert(A::count == 0);
259 { // Void and function pointers (C-6,7)
260 typedef typename std::conditional<IsArray, int[], int>::type VT2;
261 my_free_called = false;
262 {
263 int i = 0;
264 std::unique_ptr<VT2, void (*)(void*)> s(&i, my_free);
265 assert(s.get() == &i);
266 assert(s.get_deleter() == my_free);
267 assert(!my_free_called);
268 }
269 assert(my_free_called);
270 }
271 }
272 }
273
test_basic_single()274 TEST_CONSTEXPR_CXX23 void test_basic_single() {
275 if (!TEST_IS_CONSTANT_EVALUATED) {
276 assert(A::count == 0);
277 assert(B::count == 0);
278 }
279 { // Derived pointers (C-5)
280 B* p = new B;
281 if (!TEST_IS_CONSTANT_EVALUATED) {
282 assert(A::count == 1);
283 assert(B::count == 1);
284 }
285 std::unique_ptr<A, Deleter<A> > s(p, Deleter<A>(5));
286 assert(s.get() == p);
287 assert(s.get_deleter().state() == 5);
288 }
289 if (!TEST_IS_CONSTANT_EVALUATED) {
290 assert(A::count == 0);
291 assert(B::count == 0);
292
293 { // Void and function pointers (C-6,7)
294 my_free_called = false;
295 {
296 int i = 0;
297 std::unique_ptr<void, void (*)(void*)> s(&i, my_free);
298 assert(s.get() == &i);
299 assert(s.get_deleter() == my_free);
300 assert(!my_free_called);
301 }
302 assert(my_free_called);
303 }
304 }
305 }
306
307 template <bool IsArray>
test_nullptr()308 TEST_CONSTEXPR_CXX23 void test_nullptr() {
309 #if TEST_STD_VER >= 11
310 typedef typename std::conditional<!IsArray, A, A[]>::type VT;
311 {
312 std::unique_ptr<VT, Deleter<VT> > u(nullptr, Deleter<VT>{});
313 assert(u.get() == nullptr);
314 }
315 {
316 NCDeleter<VT> d;
317 std::unique_ptr<VT, NCDeleter<VT>& > u(nullptr, d);
318 assert(u.get() == nullptr);
319 }
320 {
321 NCConstDeleter<VT> d;
322 std::unique_ptr<VT, NCConstDeleter<VT> const& > u(nullptr, d);
323 assert(u.get() == nullptr);
324 }
325 #endif
326 }
327
test()328 TEST_CONSTEXPR_CXX23 bool test() {
329 {
330 test_basic</*IsArray*/ false>();
331 test_nullptr<false>();
332 test_basic_single();
333 test_sfinae<false>();
334 test_noexcept<false>();
335 }
336 {
337 test_basic</*IsArray*/ true>();
338 test_nullptr<true>();
339 test_sfinae<true>();
340 test_sfinae_runtime();
341 test_noexcept<true>();
342 }
343
344 return true;
345 }
346
main(int,char **)347 int main(int, char**) {
348 test();
349 #if TEST_STD_VER >= 23
350 static_assert(test());
351 #endif
352
353 return 0;
354 }
355