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 { 26 void operator()(void*) const {} 27 }; 28 29 template <int ID = 0> 30 struct GenericConvertingDeleter { 31 32 template <int OID> 33 GenericConvertingDeleter(GenericConvertingDeleter<OID>) {} 34 35 template <int OID> 36 GenericConvertingDeleter& operator=(GenericConvertingDeleter<OID> const&) { 37 return *this; 38 } 39 40 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 { 67 TrackingDeleter() : arg_type(&makeArgumentID<>()) {} 68 69 TrackingDeleter(TrackingDeleter const&) 70 : arg_type(&makeArgumentID<TrackingDeleter const&>()) {} 71 72 TrackingDeleter(TrackingDeleter&&) 73 : arg_type(&makeArgumentID<TrackingDeleter &&>()) {} 74 75 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> > 76 TrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {} 77 78 TrackingDeleter& operator=(TrackingDeleter const&) { 79 arg_type = &makeArgumentID<TrackingDeleter const&>(); 80 return *this; 81 } 82 83 TrackingDeleter& operator=(TrackingDeleter &&) { 84 arg_type = &makeArgumentID<TrackingDeleter &&>(); 85 return *this; 86 } 87 88 template <class T, class = EnableIfSpecialization<TrackingDeleter, T> > 89 TrackingDeleter& operator=(T&&) { 90 arg_type = &makeArgumentID<T&&>(); 91 return *this; 92 } 93 94 void operator()(void*) const {} 95 96 public: 97 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 { 108 ConstTrackingDeleter() : arg_type(&makeArgumentID<>()) {} 109 110 ConstTrackingDeleter(ConstTrackingDeleter const&) 111 : arg_type(&makeArgumentID<ConstTrackingDeleter const&>()) {} 112 113 ConstTrackingDeleter(ConstTrackingDeleter&&) 114 : arg_type(&makeArgumentID<ConstTrackingDeleter &&>()) {} 115 116 template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> > 117 ConstTrackingDeleter(T&&) : arg_type(&makeArgumentID<T&&>()) {} 118 119 const ConstTrackingDeleter& operator=(ConstTrackingDeleter const&) const { 120 arg_type = &makeArgumentID<ConstTrackingDeleter const&>(); 121 return *this; 122 } 123 124 const ConstTrackingDeleter& operator=(ConstTrackingDeleter &&) const { 125 arg_type = &makeArgumentID<ConstTrackingDeleter &&>(); 126 return *this; 127 } 128 129 template <class T, class = EnableIfSpecialization<ConstTrackingDeleter, T> > 130 const ConstTrackingDeleter& operator=(T&&) const { 131 arg_type = &makeArgumentID<T&&>(); 132 return *this; 133 } 134 135 void operator()(void*) const {} 136 137 public: 138 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> 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> 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> 172 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> 177 const AssignDeleter& operator=(T&&) const & { return *this; } 178 179 template <class T> 180 void operator()(T) const {} 181 }; 182 183 template <class VT, class DDest, class DSource> 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> 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> 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> 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 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