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