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