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