move_convert.pass.cpp (13633B)
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 }