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 {
operator ()GenericDeleter27 void operator()(void*) const {}
28 };
29
30 template <int ID = 0>
31 struct GenericConvertingDeleter {
32
33 template <int OID>
GenericConvertingDeleterGenericConvertingDeleter34 GenericConvertingDeleter(GenericConvertingDeleter<OID>) {}
35
36 template <int OID>
operator =GenericConvertingDeleter37 GenericConvertingDeleter& operator=(GenericConvertingDeleter<OID> const&) {
38 return *this;
39 }
40
operator ()GenericConvertingDeleter41 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 {
TrackingDeleterTrackingDeleter68 TrackingDeleter() : arg_type(&makeArgumentID<>()) {}
69
TrackingDeleterTrackingDeleter70 TrackingDeleter(TrackingDeleter const&)
71 : arg_type(&makeArgumentID<TrackingDeleter const&>()) {}
72
TrackingDeleterTrackingDeleter73 TrackingDeleter(TrackingDeleter&&)
74 : arg_type(&makeArgumentID<TrackingDeleter &&>()) {}
75
76 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
TrackingDeleterTrackingDeleter77 TrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
78
operator =TrackingDeleter79 TrackingDeleter& operator=(TrackingDeleter const&) {
80 arg_type = &makeArgumentID<TrackingDeleter const&>();
81 return *this;
82 }
83
operator =TrackingDeleter84 TrackingDeleter& operator=(TrackingDeleter &&) {
85 arg_type = &makeArgumentID<TrackingDeleter &&>();
86 return *this;
87 }
88
89 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
operator =TrackingDeleter90 TrackingDeleter& operator=(T&&) {
91 arg_type = &makeArgumentID<T&&>();
92 return *this;
93 }
94
operator ()TrackingDeleter95 void operator()(void*) const {}
96
97 public:
resetTrackingDeleter98 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 {
ConstTrackingDeleterConstTrackingDeleter109 ConstTrackingDeleter() : arg_type(&makeArgumentID<>()) {}
110
ConstTrackingDeleterConstTrackingDeleter111 ConstTrackingDeleter(ConstTrackingDeleter const&)
112 : arg_type(&makeArgumentID<ConstTrackingDeleter const&>()) {}
113
ConstTrackingDeleterConstTrackingDeleter114 ConstTrackingDeleter(ConstTrackingDeleter&&)
115 : arg_type(&makeArgumentID<ConstTrackingDeleter &&>()) {}
116
117 template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> >
ConstTrackingDeleterConstTrackingDeleter118 ConstTrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
119
operator =ConstTrackingDeleter120 const ConstTrackingDeleter& operator=(ConstTrackingDeleter const&) const {
121 arg_type = &makeArgumentID<ConstTrackingDeleter const&>();
122 return *this;
123 }
124
operator =ConstTrackingDeleter125 const ConstTrackingDeleter& operator=(ConstTrackingDeleter &&) const {
126 arg_type = &makeArgumentID<ConstTrackingDeleter &&>();
127 return *this;
128 }
129
130 template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> >
operator =ConstTrackingDeleter131 const ConstTrackingDeleter& operator=(T&&) const {
132 arg_type = &makeArgumentID<T&&>();
133 return *this;
134 }
135
operator ()ConstTrackingDeleter136 void operator()(void*) const {}
137
138 public:
resetConstTrackingDeleter139 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>
checkArg(TrackingDeleter<ID> const & d)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>
checkArg(ConstTrackingDeleter<ID> const & d)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>
operator =AssignDeleter173 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>
operator =AssignDeleter178 const AssignDeleter& operator=(T&&) const & { return *this; }
179
180 template <class T>
operator ()AssignDeleter181 void operator()(T) const {}
182 };
183
184 template <class VT, class DDest, class DSource>
doDeleterTest()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>
test_sfinae()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>
test_noexcept()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>
test_deleter_value_category()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
main()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 }
421