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 
10 // <memory>
11 
12 // unique_ptr
13 
14 // Test unique_ptr converting move ctor
15 
16 // NOTE: unique_ptr does not provide converting constructors in C++03
17 // UNSUPPORTED: c++03
18 
19 #include <memory>
20 #include <type_traits>
21 #include <utility>
22 #include <cassert>
23 
24 #include "test_macros.h"
25 #include "unique_ptr_test_helper.h"
26 
27 // test converting move ctor.  Should only require a MoveConstructible deleter, or if
28 //    deleter is a reference, not even that.
29 // Explicit version
30 
31 template <class LHS, class RHS>
checkReferenceDeleter(LHS & lhs,RHS & rhs)32 void checkReferenceDeleter(LHS& lhs, RHS& rhs) {
33   typedef typename LHS::deleter_type NewDel;
34   static_assert(std::is_reference<NewDel>::value, "");
35   rhs.get_deleter().set_state(42);
36   assert(rhs.get_deleter().state() == 42);
37   assert(lhs.get_deleter().state() == 42);
38   lhs.get_deleter().set_state(99);
39   assert(lhs.get_deleter().state() == 99);
40   assert(rhs.get_deleter().state() == 99);
41 }
42 
43 template <class LHS, class RHS>
checkDeleter(LHS & lhs,RHS & rhs,int LHSVal,int RHSVal)44 void checkDeleter(LHS& lhs, RHS& rhs, int LHSVal, int RHSVal) {
45   assert(lhs.get_deleter().state() == LHSVal);
46   assert(rhs.get_deleter().state() == RHSVal);
47 }
48 
49 template <class LHS, class RHS>
checkCtor(LHS & lhs,RHS & rhs,A * RHSVal)50 void checkCtor(LHS& lhs, RHS& rhs, A* RHSVal) {
51   assert(lhs.get() == RHSVal);
52   assert(rhs.get() == nullptr);
53   assert(A::count == 1);
54   assert(B::count == 1);
55 }
56 
checkNoneAlive()57 void checkNoneAlive() {
58   assert(A::count == 0);
59   assert(B::count == 0);
60 }
61 
62 template <class T>
63 struct NCConvertingDeleter {
64   NCConvertingDeleter() = default;
65   NCConvertingDeleter(NCConvertingDeleter const&) = delete;
66   NCConvertingDeleter(NCConvertingDeleter&&) = default;
67 
68   template <class U>
NCConvertingDeleterNCConvertingDeleter69   NCConvertingDeleter(NCConvertingDeleter<U>&&) {}
70 
operator ()NCConvertingDeleter71   void operator()(T*) const {}
72 };
73 
74 template <class T>
75 struct NCConvertingDeleter<T[]> {
76   NCConvertingDeleter() = default;
77   NCConvertingDeleter(NCConvertingDeleter const&) = delete;
78   NCConvertingDeleter(NCConvertingDeleter&&) = default;
79 
80   template <class U>
NCConvertingDeleterNCConvertingDeleter81   NCConvertingDeleter(NCConvertingDeleter<U>&&) {}
82 
operator ()NCConvertingDeleter83   void operator()(T*) const {}
84 };
85 
86 struct NCGenericDeleter {
87   NCGenericDeleter() = default;
88   NCGenericDeleter(NCGenericDeleter const&) = delete;
89   NCGenericDeleter(NCGenericDeleter&&) = default;
90 
operator ()NCGenericDeleter91   void operator()(void*) const {}
92 };
93 
test_sfinae()94 void test_sfinae() {
95   using DA = NCConvertingDeleter<A>; // non-copyable deleters
96   using DB = NCConvertingDeleter<B>;
97   using UA = std::unique_ptr<A>;
98   using UB = std::unique_ptr<B>;
99   using UAD = std::unique_ptr<A, DA>;
100   using UBD = std::unique_ptr<B, DB>;
101   { // cannot move from an lvalue
102     static_assert(std::is_constructible<UA, UB&&>::value, "");
103     static_assert(!std::is_constructible<UA, UB&>::value, "");
104     static_assert(!std::is_constructible<UA, const UB&>::value, "");
105   }
106   { // cannot move if the deleter-types cannot convert
107     static_assert(std::is_constructible<UAD, UBD&&>::value, "");
108     static_assert(!std::is_constructible<UAD, UB&&>::value, "");
109     static_assert(!std::is_constructible<UA, UBD&&>::value, "");
110   }
111   { // cannot move-convert with reference deleters of different types
112     using UA1 = std::unique_ptr<A, DA&>;
113     using UB1 = std::unique_ptr<B, DB&>;
114     static_assert(!std::is_constructible<UA1, UB1&&>::value, "");
115   }
116   { // cannot move-convert with reference deleters of different types
117     using UA1 = std::unique_ptr<A, const DA&>;
118     using UB1 = std::unique_ptr<B, const DB&>;
119     static_assert(!std::is_constructible<UA1, UB1&&>::value, "");
120   }
121   { // cannot move-convert from unique_ptr<Array[]>
122     using UA1 = std::unique_ptr<A>;
123     using UA2 = std::unique_ptr<A[]>;
124     using UB1 = std::unique_ptr<B[]>;
125     static_assert(!std::is_constructible<UA1, UA2&&>::value, "");
126     static_assert(!std::is_constructible<UA1, UB1&&>::value, "");
127   }
128   { // cannot move-convert from unique_ptr<Array[]>
129     using UA1 = std::unique_ptr<A, NCGenericDeleter>;
130     using UA2 = std::unique_ptr<A[], NCGenericDeleter>;
131     using UB1 = std::unique_ptr<B[], NCGenericDeleter>;
132     static_assert(!std::is_constructible<UA1, UA2&&>::value, "");
133     static_assert(!std::is_constructible<UA1, UB1&&>::value, "");
134   }
135 }
136 
test_noexcept()137 void test_noexcept() {
138   {
139     typedef std::unique_ptr<A> APtr;
140     typedef std::unique_ptr<B> BPtr;
141     static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
142   }
143   {
144     typedef std::unique_ptr<A, Deleter<A> > APtr;
145     typedef std::unique_ptr<B, Deleter<B> > BPtr;
146     static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
147   }
148   {
149     typedef std::unique_ptr<A, NCDeleter<A>&> APtr;
150     typedef std::unique_ptr<B, NCDeleter<A>&> BPtr;
151     static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
152   }
153   {
154     typedef std::unique_ptr<A, const NCConstDeleter<A>&> APtr;
155     typedef std::unique_ptr<B, const NCConstDeleter<A>&> BPtr;
156     static_assert(std::is_nothrow_constructible<APtr, BPtr>::value, "");
157   }
158 }
159 
main(int,char **)160 int main(int, char**) {
161   {
162     test_sfinae();
163     test_noexcept();
164   }
165   {
166     typedef std::unique_ptr<A> APtr;
167     typedef std::unique_ptr<B> BPtr;
168     { // explicit
169       BPtr b(new B);
170       A* p = b.get();
171       APtr a(std::move(b));
172       checkCtor(a, b, p);
173     }
174     checkNoneAlive();
175     { // implicit
176       BPtr b(new B);
177       A* p = b.get();
178       APtr a = std::move(b);
179       checkCtor(a, b, p);
180     }
181     checkNoneAlive();
182   }
183   { // test with moveable deleters
184     typedef std::unique_ptr<A, Deleter<A> > APtr;
185     typedef std::unique_ptr<B, Deleter<B> > BPtr;
186     {
187       Deleter<B> del(5);
188       BPtr b(new B, std::move(del));
189       A* p = b.get();
190       APtr a(std::move(b));
191       checkCtor(a, b, p);
192       checkDeleter(a, b, 5, 0);
193     }
194     checkNoneAlive();
195     {
196       Deleter<B> del(5);
197       BPtr b(new B, std::move(del));
198       A* p = b.get();
199       APtr a = std::move(b);
200       checkCtor(a, b, p);
201       checkDeleter(a, b, 5, 0);
202     }
203     checkNoneAlive();
204   }
205   { // test with reference deleters
206     typedef std::unique_ptr<A, NCDeleter<A>&> APtr;
207     typedef std::unique_ptr<B, NCDeleter<A>&> BPtr;
208     NCDeleter<A> del(5);
209     {
210       BPtr b(new B, del);
211       A* p = b.get();
212       APtr a(std::move(b));
213       checkCtor(a, b, p);
214       checkReferenceDeleter(a, b);
215     }
216     checkNoneAlive();
217     {
218       BPtr b(new B, del);
219       A* p = b.get();
220       APtr a = std::move(b);
221       checkCtor(a, b, p);
222       checkReferenceDeleter(a, b);
223     }
224     checkNoneAlive();
225   }
226   {
227     typedef std::unique_ptr<A, CDeleter<A> > APtr;
228     typedef std::unique_ptr<B, CDeleter<B>&> BPtr;
229     CDeleter<B> del(5);
230     {
231       BPtr b(new B, del);
232       A* p = b.get();
233       APtr a(std::move(b));
234       checkCtor(a, b, p);
235       checkDeleter(a, b, 5, 5);
236     }
237     checkNoneAlive();
238     {
239       BPtr b(new B, del);
240       A* p = b.get();
241       APtr a = std::move(b);
242       checkCtor(a, b, p);
243       checkDeleter(a, b, 5, 5);
244     }
245     checkNoneAlive();
246   }
247 
248   return 0;
249 }
250