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

source code of libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/pointer_deleter.pass.cpp