]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp
Vendor import of libc++ trunk r300422:
[FreeBSD/FreeBSD.git] / test / std / utilities / smartptr / unique.ptr / unique.ptr.class / unique.ptr.asgn / move_convert.pass.cpp
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 // UNSUPPORTED: c++98, c++03
11
12 // <memory>
13
14 // unique_ptr
15
16 // Test unique_ptr converting move ctor
17
18 #include <memory>
19 #include <cassert>
20
21 #include "test_macros.h"
22 #include "unique_ptr_test_helper.h"
23 #include "type_id.h"
24
25 template <int ID = 0>
26 struct GenericDeleter {
27   void operator()(void*) const {}
28 };
29
30 template <int ID = 0>
31 struct GenericConvertingDeleter {
32
33   template <int OID>
34   GenericConvertingDeleter(GenericConvertingDeleter<OID>) {}
35
36   template <int OID>
37   GenericConvertingDeleter& operator=(GenericConvertingDeleter<OID> const&) {
38     return *this;
39   }
40
41   void operator()(void*) const {}
42 };
43
44 template <class T, class U>
45 using EnableIfNotSame = typename std::enable_if<
46     !std::is_same<typename std::decay<T>::type, typename std::decay<U>::type>::value
47 >::type;
48
49 template <class Templ, class Other>
50 struct is_specialization;
51
52 template <template <int> class Templ, int ID1, class Other>
53 struct is_specialization<Templ<ID1>, Other> : std::false_type {};
54
55 template <template <int> class Templ, int ID1, int ID2>
56 struct is_specialization<Templ<ID1>, Templ<ID2> > : std::true_type {};
57
58 template <class Templ, class Other>
59 using EnableIfSpecialization = typename std::enable_if<
60     is_specialization<Templ, typename std::decay<Other>::type >::value
61   >::type;
62
63 template <int ID> struct TrackingDeleter;
64 template <int ID> struct ConstTrackingDeleter;
65
66 template <int ID>
67 struct TrackingDeleter {
68   TrackingDeleter() : arg_type(&makeArgumentID<>()) {}
69
70   TrackingDeleter(TrackingDeleter const&)
71       : arg_type(&makeArgumentID<TrackingDeleter const&>()) {}
72
73   TrackingDeleter(TrackingDeleter&&)
74       : arg_type(&makeArgumentID<TrackingDeleter &&>()) {}
75
76   template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
77   TrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
78
79   TrackingDeleter& operator=(TrackingDeleter const&) {
80     arg_type = &makeArgumentID<TrackingDeleter const&>();
81     return *this;
82   }
83
84   TrackingDeleter& operator=(TrackingDeleter &&) {
85     arg_type = &makeArgumentID<TrackingDeleter &&>();
86     return *this;
87   }
88
89   template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
90   TrackingDeleter& operator=(T&&) {
91     arg_type = &makeArgumentID<T&&>();
92     return *this;
93   }
94
95   void operator()(void*) const {}
96
97 public:
98   TypeID const* reset() const {
99     TypeID const* tmp = arg_type;
100     arg_type = nullptr;
101     return tmp;
102   }
103
104   mutable TypeID const* arg_type;
105 };
106
107 template <int ID>
108 struct ConstTrackingDeleter {
109   ConstTrackingDeleter() : arg_type(&makeArgumentID<>()) {}
110
111   ConstTrackingDeleter(ConstTrackingDeleter const&)
112       : arg_type(&makeArgumentID<ConstTrackingDeleter const&>()) {}
113
114   ConstTrackingDeleter(ConstTrackingDeleter&&)
115       : arg_type(&makeArgumentID<ConstTrackingDeleter &&>()) {}
116
117   template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> >
118   ConstTrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
119
120   const ConstTrackingDeleter& operator=(ConstTrackingDeleter const&) const {
121     arg_type = &makeArgumentID<ConstTrackingDeleter const&>();
122     return *this;
123   }
124
125   const ConstTrackingDeleter& operator=(ConstTrackingDeleter &&) const {
126     arg_type = &makeArgumentID<ConstTrackingDeleter &&>();
127     return *this;
128   }
129
130   template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> >
131   const ConstTrackingDeleter& operator=(T&&) const {
132     arg_type = &makeArgumentID<T&&>();
133     return *this;
134   }
135
136   void operator()(void*) const {}
137
138 public:
139   TypeID const* reset() const {
140     TypeID const* tmp = arg_type;
141     arg_type = nullptr;
142     return tmp;
143   }
144
145   mutable TypeID const* arg_type;
146 };
147
148 template <class ExpectT, int ID>
149 bool checkArg(TrackingDeleter<ID> const& d) {
150   return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>();
151 }
152
153 template <class ExpectT, int ID>
154 bool checkArg(ConstTrackingDeleter<ID> const& d) {
155   return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>();
156 }
157
158 template <class From, bool AssignIsConst = false>
159 struct AssignDeleter {
160   AssignDeleter() = default;
161   AssignDeleter(AssignDeleter const&) = default;
162   AssignDeleter(AssignDeleter&&) = default;
163
164   AssignDeleter& operator=(AssignDeleter const&) = delete;
165   AssignDeleter& operator=(AssignDeleter &&) = delete;
166
167   template <class T> AssignDeleter& operator=(T&&) && = delete;
168   template <class T> AssignDeleter& operator=(T&&) const && = delete;
169
170   template <class T, class = typename std::enable_if<
171       std::is_same<T&&, From>::value && !AssignIsConst
172     >::type>
173   AssignDeleter& operator=(T&&) & { return *this; }
174
175   template <class T, class = typename std::enable_if<
176       std::is_same<T&&, From>::value && AssignIsConst
177     >::type>
178   const AssignDeleter& operator=(T&&) const & { return *this; }
179
180   template <class T>
181   void operator()(T) const {}
182 };
183
184 template <class VT, class DDest, class DSource>
185   void doDeleterTest() {
186     using U1 = std::unique_ptr<VT, DDest>;
187     using U2 = std::unique_ptr<VT, DSource>;
188     static_assert(std::is_nothrow_assignable<U1, U2&&>::value, "");
189     typename std::decay<DDest>::type ddest;
190     typename std::decay<DSource>::type dsource;
191     U1 u1(nullptr, ddest);
192     U2 u2(nullptr, dsource);
193     u1 = std::move(u2);
194 }
195
196 template <bool IsArray>
197 void test_sfinae() {
198   typedef typename std::conditional<IsArray, A[], A>::type VT;
199
200   { // Test that different non-reference deleter types are allowed so long
201     // as they convert to each other.
202     using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
203     using U2 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
204     static_assert(std::is_assignable<U1, U2&&>::value, "");
205   }
206   { // Test that different non-reference deleter types are disallowed when
207     // they cannot convert.
208     using U1 = std::unique_ptr<VT, GenericDeleter<0> >;
209     using U2 = std::unique_ptr<VT, GenericDeleter<1> >;
210     static_assert(!std::is_assignable<U1, U2&&>::value, "");
211   }
212   { // Test that if the deleter assignment is not valid the assignment operator
213     // SFINAEs.
214     using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> const& >;
215     using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
216     using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>;
217     using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
218     using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>;
219     static_assert(!std::is_assignable<U1, U2&&>::value, "");
220     static_assert(!std::is_assignable<U1, U3&&>::value, "");
221     static_assert(!std::is_assignable<U1, U4&&>::value, "");
222     static_assert(!std::is_assignable<U1, U5&&>::value, "");
223
224     using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> const&>;
225     static_assert(std::is_nothrow_assignable<U1C, U1&&>::value, "");
226   }
227   { // Test that if the deleter assignment is not valid the assignment operator
228     // SFINAEs.
229     using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> & >;
230     using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
231     using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>;
232     using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
233     using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>;
234
235     static_assert(std::is_nothrow_assignable<U1, U2&&>::value, "");
236     static_assert(std::is_nothrow_assignable<U1, U3&&>::value, "");
237     static_assert(std::is_nothrow_assignable<U1, U4&&>::value, "");
238     static_assert(std::is_nothrow_assignable<U1, U5&&>::value, "");
239
240     using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> &>;
241     static_assert(std::is_nothrow_assignable<U1C, U1&&>::value, "");
242   }
243   { // Test that non-reference destination deleters can be assigned
244     // from any source deleter type with a sutible conversion. Including
245     // reference types.
246     using U1 = std::unique_ptr<VT, GenericConvertingDeleter<0> >;
247     using U2 = std::unique_ptr<VT, GenericConvertingDeleter<0> &>;
248     using U3 = std::unique_ptr<VT, GenericConvertingDeleter<0> const &>;
249     using U4 = std::unique_ptr<VT, GenericConvertingDeleter<1> >;
250     using U5 = std::unique_ptr<VT, GenericConvertingDeleter<1> &>;
251     using U6 = std::unique_ptr<VT, GenericConvertingDeleter<1> const&>;
252     static_assert(std::is_assignable<U1, U2&&>::value, "");
253     static_assert(std::is_assignable<U1, U3&&>::value, "");
254     static_assert(std::is_assignable<U1, U4&&>::value, "");
255     static_assert(std::is_assignable<U1, U5&&>::value, "");
256     static_assert(std::is_assignable<U1, U6&&>::value, "");
257   }
258   /////////////////////////////////////////////////////////////////////////////
259   {
260     using Del = GenericDeleter<0>;
261     using AD = AssignDeleter<Del&&>;
262     using ADC = AssignDeleter<Del&&, /*AllowConstAssign*/true>;
263     doDeleterTest<VT, AD, Del>();
264     doDeleterTest<VT, AD&, Del>();
265     doDeleterTest<VT, ADC const&, Del>();
266   }
267   {
268     using Del = GenericDeleter<0>;
269     using AD = AssignDeleter<Del&>;
270     using ADC = AssignDeleter<Del&, /*AllowConstAssign*/true>;
271     doDeleterTest<VT, AD, Del&>();
272     doDeleterTest<VT, AD&, Del&>();
273     doDeleterTest<VT, ADC const&, Del&>();
274   }
275   {
276     using Del = GenericDeleter<0>;
277     using AD = AssignDeleter<Del const&>;
278     using ADC = AssignDeleter<Del const&, /*AllowConstAssign*/true>;
279     doDeleterTest<VT, AD, Del const&>();
280     doDeleterTest<VT, AD&, Del const&>();
281     doDeleterTest<VT, ADC const&, Del const&>();
282   }
283 }
284
285
286 template <bool IsArray>
287 void test_noexcept() {
288   typedef typename std::conditional<IsArray, A[], A>::type VT;
289   {
290     typedef std::unique_ptr<const VT> APtr;
291     typedef std::unique_ptr<VT> BPtr;
292     static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, "");
293   }
294   {
295     typedef std::unique_ptr<const VT, CDeleter<const VT> > APtr;
296     typedef std::unique_ptr<VT, CDeleter<VT> > BPtr;
297     static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, "");
298   }
299   {
300     typedef std::unique_ptr<const VT, NCDeleter<const VT>&> APtr;
301     typedef std::unique_ptr<VT, NCDeleter<const VT>&> BPtr;
302     static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, "");
303   }
304   {
305     typedef std::unique_ptr<const VT, const NCConstDeleter<const VT>&> APtr;
306     typedef std::unique_ptr<VT, const NCConstDeleter<const VT>&> BPtr;
307     static_assert(std::is_nothrow_assignable<APtr, BPtr>::value, "");
308   }
309 }
310
311 template <bool IsArray>
312 void test_deleter_value_category() {
313   typedef typename std::conditional<IsArray, A[], A>::type VT;
314   using TD1 = TrackingDeleter<1>;
315   using TD2 = TrackingDeleter<2>;
316   TD1 d1;
317   TD2 d2;
318   using CD1 = ConstTrackingDeleter<1>;
319   using CD2 = ConstTrackingDeleter<2>;
320   CD1 cd1;
321   CD2 cd2;
322
323   { // Test non-reference deleter conversions
324     using U1 = std::unique_ptr<VT, TD1 >;
325     using U2 = std::unique_ptr<VT, TD2 >;
326     U1 u1;
327     U2 u2;
328     u1.get_deleter().reset();
329     u1 = std::move(u2);
330     assert(checkArg<TD2&&>(u1.get_deleter()));
331   }
332   { // Test assignment to non-const ref
333     using U1 = std::unique_ptr<VT, TD1& >;
334     using U2 = std::unique_ptr<VT, TD2 >;
335     U1 u1(nullptr, d1);
336     U2 u2;
337     u1.get_deleter().reset();
338     u1 = std::move(u2);
339     assert(checkArg<TD2&&>(u1.get_deleter()));
340   }
341   { // Test assignment to const&.
342     using U1 = std::unique_ptr<VT, CD1 const& >;
343     using U2 = std::unique_ptr<VT, CD2 >;
344     U1 u1(nullptr, cd1);
345     U2 u2;
346     u1.get_deleter().reset();
347     u1 = std::move(u2);
348     assert(checkArg<CD2&&>(u1.get_deleter()));
349   }
350
351   { // Test assignment from non-const ref
352     using U1 = std::unique_ptr<VT, TD1 >;
353     using U2 = std::unique_ptr<VT, TD2& >;
354     U1 u1;
355     U2 u2(nullptr, d2);
356     u1.get_deleter().reset();
357     u1 = std::move(u2);
358     assert(checkArg<TD2&>(u1.get_deleter()));
359   }
360   { // Test assignment from const ref
361     using U1 = std::unique_ptr<VT, TD1 >;
362     using U2 = std::unique_ptr<VT, TD2 const& >;
363     U1 u1;
364     U2 u2(nullptr, d2);
365     u1.get_deleter().reset();
366     u1 = std::move(u2);
367     assert(checkArg<TD2 const&>(u1.get_deleter()));
368   }
369
370   { // Test assignment from non-const ref
371     using U1 = std::unique_ptr<VT, TD1& >;
372     using U2 = std::unique_ptr<VT, TD2& >;
373     U1 u1(nullptr, d1);
374     U2 u2(nullptr, d2);
375     u1.get_deleter().reset();
376     u1 = std::move(u2);
377     assert(checkArg<TD2&>(u1.get_deleter()));
378   }
379   { // Test assignment from const ref
380     using U1 = std::unique_ptr<VT, TD1& >;
381     using U2 = std::unique_ptr<VT, TD2 const& >;
382     U1 u1(nullptr, d1);
383     U2 u2(nullptr, d2);
384     u1.get_deleter().reset();
385     u1 = std::move(u2);
386     assert(checkArg<TD2 const&>(u1.get_deleter()));
387   }
388
389   { // Test assignment from non-const ref
390     using U1 = std::unique_ptr<VT, CD1 const& >;
391     using U2 = std::unique_ptr<VT, CD2 & >;
392     U1 u1(nullptr, cd1);
393     U2 u2(nullptr, cd2);
394     u1.get_deleter().reset();
395     u1 = std::move(u2);
396     assert(checkArg<CD2 &>(u1.get_deleter()));
397   }
398   { // Test assignment from const ref
399     using U1 = std::unique_ptr<VT, CD1 const& >;
400     using U2 = std::unique_ptr<VT, CD2 const& >;
401     U1 u1(nullptr, cd1);
402     U2 u2(nullptr, cd2);
403     u1.get_deleter().reset();
404     u1 = std::move(u2);
405     assert(checkArg<CD2 const&>(u1.get_deleter()));
406   }
407 }
408
409 int main() {
410   {
411     test_sfinae</*IsArray*/false>();
412     test_noexcept<false>();
413     test_deleter_value_category<false>();
414   }
415   {
416     test_sfinae</*IsArray*/true>();
417     test_noexcept<true>();
418     test_deleter_value_category<true>();
419   }
420 }