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