brintos

brintos / llvm-project-archived public Read only

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