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 void operator()(void*) const {}
38 };
39 struct CopyOnlyDeleter : DeleterBase {
40 CopyOnlyDeleter() = default;
41 CopyOnlyDeleter(CopyOnlyDeleter const&) = default;
42 CopyOnlyDeleter(CopyOnlyDeleter&&) = delete;
43 };
44 struct MoveOnlyDeleter : DeleterBase {
45 MoveOnlyDeleter() = default;
46 MoveOnlyDeleter(MoveOnlyDeleter&&) = default;
47 };
48 struct NoCopyMoveDeleter : DeleterBase {
49 NoCopyMoveDeleter() = default;
50 NoCopyMoveDeleter(NoCopyMoveDeleter const&) = delete;
51 };
52 #endif
53
54 template <bool IsArray>
test_sfinae()55 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 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 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 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 assert(A::count == expect_alive);
213 std::unique_ptr<VT, Deleter<VT> > s(p, Deleter<VT>(5));
214 assert(s.get() == p);
215 assert(s.get_deleter().state() == 5);
216 }
217 assert(A::count == 0);
218 { // CopyConstructible deleter (C-2)
219 A* p = newValue<VT>(expect_alive);
220 assert(A::count == expect_alive);
221 CopyDeleter<VT> d(5);
222 std::unique_ptr<VT, CopyDeleter<VT> > s(p, d);
223 assert(s.get() == p);
224 assert(s.get_deleter().state() == 5);
225 d.set_state(6);
226 assert(s.get_deleter().state() == 5);
227 }
228 assert(A::count == 0);
229 { // Reference deleter (C-3)
230 A* p = newValue<VT>(expect_alive);
231 assert(A::count == expect_alive);
232 NCDeleter<VT> d(5);
233 std::unique_ptr<VT, NCDeleter<VT>&> s(p, d);
234 assert(s.get() == p);
235 assert(&s.get_deleter() == &d);
236 assert(s.get_deleter().state() == 5);
237 d.set_state(6);
238 assert(s.get_deleter().state() == 6);
239 }
240 assert(A::count == 0);
241 { // Const Reference deleter (C-4)
242 A* p = newValue<VT>(expect_alive);
243 assert(A::count == expect_alive);
244 NCConstDeleter<VT> d(5);
245 std::unique_ptr<VT, NCConstDeleter<VT> const&> s(p, d);
246 assert(s.get() == p);
247 assert(s.get_deleter().state() == 5);
248 assert(&s.get_deleter() == &d);
249 }
250 assert(A::count == 0);
251 { // Void and function pointers (C-6,7)
252 typedef typename std::conditional<IsArray, int[], int>::type VT2;
253 my_free_called = false;
254 {
255 int i = 0;
256 std::unique_ptr<VT2, void (*)(void*)> s(&i, my_free);
257 assert(s.get() == &i);
258 assert(s.get_deleter() == my_free);
259 assert(!my_free_called);
260 }
261 assert(my_free_called);
262 }
263 }
264
test_basic_single()265 void test_basic_single() {
266 assert(A::count == 0);
267 assert(B::count == 0);
268 { // Derived pointers (C-5)
269 B* p = new B;
270 assert(A::count == 1);
271 assert(B::count == 1);
272 std::unique_ptr<A, Deleter<A> > s(p, Deleter<A>(5));
273 assert(s.get() == p);
274 assert(s.get_deleter().state() == 5);
275 }
276 assert(A::count == 0);
277 assert(B::count == 0);
278 { // Void and function pointers (C-6,7)
279 my_free_called = false;
280 {
281 int i = 0;
282 std::unique_ptr<void, void (*)(void*)> s(&i, my_free);
283 assert(s.get() == &i);
284 assert(s.get_deleter() == my_free);
285 assert(!my_free_called);
286 }
287 assert(my_free_called);
288 }
289 }
290
291 template <bool IsArray>
test_nullptr()292 void test_nullptr() {
293 #if TEST_STD_VER >= 11
294 typedef typename std::conditional<!IsArray, A, A[]>::type VT;
295 {
296 std::unique_ptr<VT, Deleter<VT> > u(nullptr, Deleter<VT>{});
297 assert(u.get() == nullptr);
298 }
299 {
300 NCDeleter<VT> d;
301 std::unique_ptr<VT, NCDeleter<VT>& > u(nullptr, d);
302 assert(u.get() == nullptr);
303 }
304 {
305 NCConstDeleter<VT> d;
306 std::unique_ptr<VT, NCConstDeleter<VT> const& > u(nullptr, d);
307 assert(u.get() == nullptr);
308 }
309 #endif
310 }
311
main(int,char **)312 int main(int, char**) {
313 {
314 test_basic</*IsArray*/ false>();
315 test_nullptr<false>();
316 test_basic_single();
317 test_sfinae<false>();
318 test_noexcept<false>();
319 }
320 {
321 test_basic</*IsArray*/ true>();
322 test_nullptr<true>();
323 test_sfinae<true>();
324 test_sfinae_runtime();
325 test_noexcept<true>();
326 }
327
328 return 0;
329 }
330