1 //===----------------------------------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // UNSUPPORTED: c++98, c++03
16 // Test unique_ptr converting move ctor
21 #include "test_macros.h"
22 #include "unique_ptr_test_helper.h"
26 struct GenericDeleter {
27 void operator()(void*) const {}
31 struct GenericConvertingDeleter {
34 GenericConvertingDeleter(GenericConvertingDeleter<OID>) {}
37 GenericConvertingDeleter& operator=(GenericConvertingDeleter<OID> const&) {
41 void operator()(void*) const {}
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
49 template <class Templ, class Other>
50 struct is_specialization;
52 template <template <int> class Templ, int ID1, class Other>
53 struct is_specialization<Templ<ID1>, Other> : std::false_type {};
55 template <template <int> class Templ, int ID1, int ID2>
56 struct is_specialization<Templ<ID1>, Templ<ID2> > : std::true_type {};
58 template <class Templ, class Other>
59 using EnableIfSpecialization = typename std::enable_if<
60 is_specialization<Templ, typename std::decay<Other>::type >::value
63 template <int ID> struct TrackingDeleter;
64 template <int ID> struct ConstTrackingDeleter;
67 struct TrackingDeleter {
68 TrackingDeleter() : arg_type(&makeArgumentID<>()) {}
70 TrackingDeleter(TrackingDeleter const&)
71 : arg_type(&makeArgumentID<TrackingDeleter const&>()) {}
73 TrackingDeleter(TrackingDeleter&&)
74 : arg_type(&makeArgumentID<TrackingDeleter &&>()) {}
76 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
77 TrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
79 TrackingDeleter& operator=(TrackingDeleter const&) {
80 arg_type = &makeArgumentID<TrackingDeleter const&>();
84 TrackingDeleter& operator=(TrackingDeleter &&) {
85 arg_type = &makeArgumentID<TrackingDeleter &&>();
89 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> >
90 TrackingDeleter& operator=(T&&) {
91 arg_type = &makeArgumentID<T&&>();
95 void operator()(void*) const {}
98 TypeID const* reset() const {
99 TypeID const* tmp = arg_type;
104 mutable TypeID const* arg_type;
108 struct ConstTrackingDeleter {
109 ConstTrackingDeleter() : arg_type(&makeArgumentID<>()) {}
111 ConstTrackingDeleter(ConstTrackingDeleter const&)
112 : arg_type(&makeArgumentID<ConstTrackingDeleter const&>()) {}
114 ConstTrackingDeleter(ConstTrackingDeleter&&)
115 : arg_type(&makeArgumentID<ConstTrackingDeleter &&>()) {}
117 template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> >
118 ConstTrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {}
120 const ConstTrackingDeleter& operator=(ConstTrackingDeleter const&) const {
121 arg_type = &makeArgumentID<ConstTrackingDeleter const&>();
125 const ConstTrackingDeleter& operator=(ConstTrackingDeleter &&) const {
126 arg_type = &makeArgumentID<ConstTrackingDeleter &&>();
130 template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> >
131 const ConstTrackingDeleter& operator=(T&&) const {
132 arg_type = &makeArgumentID<T&&>();
136 void operator()(void*) const {}
139 TypeID const* reset() const {
140 TypeID const* tmp = arg_type;
145 mutable TypeID const* arg_type;
148 template <class ExpectT, int ID>
149 bool checkArg(TrackingDeleter<ID> const& d) {
150 return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>();
153 template <class ExpectT, int ID>
154 bool checkArg(ConstTrackingDeleter<ID> const& d) {
155 return d.arg_type && *d.arg_type == makeArgumentID<ExpectT>();
158 template <class From, bool AssignIsConst = false>
159 struct AssignDeleter {
160 AssignDeleter() = default;
161 AssignDeleter(AssignDeleter const&) = default;
162 AssignDeleter(AssignDeleter&&) = default;
164 AssignDeleter& operator=(AssignDeleter const&) = delete;
165 AssignDeleter& operator=(AssignDeleter &&) = delete;
167 template <class T> AssignDeleter& operator=(T&&) && = delete;
168 template <class T> AssignDeleter& operator=(T&&) const && = delete;
170 template <class T, class = typename std::enable_if<
171 std::is_same<T&&, From>::value && !AssignIsConst
173 AssignDeleter& operator=(T&&) & { return *this; }
175 template <class T, class = typename std::enable_if<
176 std::is_same<T&&, From>::value && AssignIsConst
178 const AssignDeleter& operator=(T&&) const & { return *this; }
181 void operator()(T) const {}
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);
196 template <bool IsArray>
198 typedef typename std::conditional<IsArray, A[], A>::type VT;
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, "");
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, "");
212 { // Test that if the deleter assignment is not valid the assignment operator
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, "");
224 using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> const&>;
225 static_assert(std::is_nothrow_assignable<U1C, U1&&>::value, "");
227 { // Test that if the deleter assignment is not valid the assignment operator
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&>;
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, "");
240 using U1C = std::unique_ptr<const VT, GenericConvertingDeleter<0> &>;
241 static_assert(std::is_nothrow_assignable<U1C, U1&&>::value, "");
243 { // Test that non-reference destination deleters can be assigned
244 // from any source deleter type with a sutible conversion. Including
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, "");
258 /////////////////////////////////////////////////////////////////////////////
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>();
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&>();
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&>();
286 template <bool IsArray>
287 void test_noexcept() {
288 typedef typename std::conditional<IsArray, A[], A>::type VT;
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, "");
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, "");
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, "");
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, "");
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>;
318 using CD1 = ConstTrackingDeleter<1>;
319 using CD2 = ConstTrackingDeleter<2>;
323 { // Test non-reference deleter conversions
324 using U1 = std::unique_ptr<VT, TD1 >;
325 using U2 = std::unique_ptr<VT, TD2 >;
328 u1.get_deleter().reset();
330 assert(checkArg<TD2&&>(u1.get_deleter()));
332 { // Test assignment to non-const ref
333 using U1 = std::unique_ptr<VT, TD1& >;
334 using U2 = std::unique_ptr<VT, TD2 >;
337 u1.get_deleter().reset();
339 assert(checkArg<TD2&&>(u1.get_deleter()));
341 { // Test assignment to const&.
342 using U1 = std::unique_ptr<VT, CD1 const& >;
343 using U2 = std::unique_ptr<VT, CD2 >;
346 u1.get_deleter().reset();
348 assert(checkArg<CD2&&>(u1.get_deleter()));
351 { // Test assignment from non-const ref
352 using U1 = std::unique_ptr<VT, TD1 >;
353 using U2 = std::unique_ptr<VT, TD2& >;
356 u1.get_deleter().reset();
358 assert(checkArg<TD2&>(u1.get_deleter()));
360 { // Test assignment from const ref
361 using U1 = std::unique_ptr<VT, TD1 >;
362 using U2 = std::unique_ptr<VT, TD2 const& >;
365 u1.get_deleter().reset();
367 assert(checkArg<TD2 const&>(u1.get_deleter()));
370 { // Test assignment from non-const ref
371 using U1 = std::unique_ptr<VT, TD1& >;
372 using U2 = std::unique_ptr<VT, TD2& >;
375 u1.get_deleter().reset();
377 assert(checkArg<TD2&>(u1.get_deleter()));
379 { // Test assignment from const ref
380 using U1 = std::unique_ptr<VT, TD1& >;
381 using U2 = std::unique_ptr<VT, TD2 const& >;
384 u1.get_deleter().reset();
386 assert(checkArg<TD2 const&>(u1.get_deleter()));
389 { // Test assignment from non-const ref
390 using U1 = std::unique_ptr<VT, CD1 const& >;
391 using U2 = std::unique_ptr<VT, CD2 & >;
394 u1.get_deleter().reset();
396 assert(checkArg<CD2 &>(u1.get_deleter()));
398 { // Test assignment from const ref
399 using U1 = std::unique_ptr<VT, CD1 const& >;
400 using U2 = std::unique_ptr<VT, CD2 const& >;
403 u1.get_deleter().reset();
405 assert(checkArg<CD2 const&>(u1.get_deleter()));
411 test_sfinae</*IsArray*/false>();
412 test_noexcept<false>();
413 test_deleter_value_category<false>();
416 test_sfinae</*IsArray*/true>();
417 test_noexcept<true>();
418 test_deleter_value_category<true>();