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