libcxx

libcxx mirror with random patches
git clone https://git.neptards.moe/neptards/libcxx.git
Log | Files | Refs

copy.pass.cpp (17469B)


      1 // -*- C++ -*-
      2 //===----------------------------------------------------------------------===//
      3 //
      4 //                     The LLVM Compiler Infrastructure
      5 //
      6 // This file is dual licensed under the MIT and the University of Illinois Open
      7 // Source Licenses. See LICENSE.TXT for details.
      8 //
      9 //===----------------------------------------------------------------------===//
     10 
     11 // UNSUPPORTED: c++98, c++03, c++11, c++14
     12 
     13 // The following compilers don't generate constexpr special members correctly.
     14 // XFAIL: clang-3.5, clang-3.6, clang-3.7, clang-3.8
     15 // XFAIL: apple-clang-6, apple-clang-7, apple-clang-8.0
     16 
     17 // XFAIL: availability=macosx10.13
     18 // XFAIL: availability=macosx10.12
     19 // XFAIL: availability=macosx10.11
     20 // XFAIL: availability=macosx10.10
     21 // XFAIL: availability=macosx10.9
     22 // XFAIL: availability=macosx10.8
     23 // XFAIL: availability=macosx10.7
     24 
     25 // <variant>
     26 
     27 // template <class ...Types> class variant;
     28 
     29 // variant& operator=(variant const&); // constexpr in C++20
     30 
     31 #include <cassert>
     32 #include <string>
     33 #include <type_traits>
     34 #include <variant>
     35 
     36 #include "test_macros.h"
     37 
     38 struct NoCopy {
     39   NoCopy(const NoCopy &) = delete;
     40   NoCopy &operator=(const NoCopy &) = default;
     41 };
     42 
     43 struct CopyOnly {
     44   CopyOnly(const CopyOnly &) = default;
     45   CopyOnly(CopyOnly &&) = delete;
     46   CopyOnly &operator=(const CopyOnly &) = default;
     47   CopyOnly &operator=(CopyOnly &&) = delete;
     48 };
     49 
     50 struct MoveOnly {
     51   MoveOnly(const MoveOnly &) = delete;
     52   MoveOnly(MoveOnly &&) = default;
     53   MoveOnly &operator=(const MoveOnly &) = default;
     54 };
     55 
     56 struct MoveOnlyNT {
     57   MoveOnlyNT(const MoveOnlyNT &) = delete;
     58   MoveOnlyNT(MoveOnlyNT &&) {}
     59   MoveOnlyNT &operator=(const MoveOnlyNT &) = default;
     60 };
     61 
     62 struct CopyAssign {
     63   static int alive;
     64   static int copy_construct;
     65   static int copy_assign;
     66   static int move_construct;
     67   static int move_assign;
     68   static void reset() {
     69     copy_construct = copy_assign = move_construct = move_assign = alive = 0;
     70   }
     71   CopyAssign(int v) : value(v) { ++alive; }
     72   CopyAssign(const CopyAssign &o) : value(o.value) {
     73     ++alive;
     74     ++copy_construct;
     75   }
     76   CopyAssign(CopyAssign &&o) noexcept : value(o.value) {
     77     o.value = -1;
     78     ++alive;
     79     ++move_construct;
     80   }
     81   CopyAssign &operator=(const CopyAssign &o) {
     82     value = o.value;
     83     ++copy_assign;
     84     return *this;
     85   }
     86   CopyAssign &operator=(CopyAssign &&o) noexcept {
     87     value = o.value;
     88     o.value = -1;
     89     ++move_assign;
     90     return *this;
     91   }
     92   ~CopyAssign() { --alive; }
     93   int value;
     94 };
     95 
     96 int CopyAssign::alive = 0;
     97 int CopyAssign::copy_construct = 0;
     98 int CopyAssign::copy_assign = 0;
     99 int CopyAssign::move_construct = 0;
    100 int CopyAssign::move_assign = 0;
    101 
    102 struct CopyMaybeThrows {
    103   CopyMaybeThrows(const CopyMaybeThrows &);
    104   CopyMaybeThrows &operator=(const CopyMaybeThrows &);
    105 };
    106 struct CopyDoesThrow {
    107   CopyDoesThrow(const CopyDoesThrow &) noexcept(false);
    108   CopyDoesThrow &operator=(const CopyDoesThrow &) noexcept(false);
    109 };
    110 
    111 
    112 struct NTCopyAssign {
    113   constexpr NTCopyAssign(int v) : value(v) {}
    114   NTCopyAssign(const NTCopyAssign &) = default;
    115   NTCopyAssign(NTCopyAssign &&) = default;
    116   NTCopyAssign &operator=(const NTCopyAssign &that) {
    117     value = that.value;
    118     return *this;
    119   };
    120   NTCopyAssign &operator=(NTCopyAssign &&) = delete;
    121   int value;
    122 };
    123 
    124 static_assert(!std::is_trivially_copy_assignable<NTCopyAssign>::value, "");
    125 static_assert(std::is_copy_assignable<NTCopyAssign>::value, "");
    126 
    127 struct TCopyAssign {
    128   constexpr TCopyAssign(int v) : value(v) {}
    129   TCopyAssign(const TCopyAssign &) = default;
    130   TCopyAssign(TCopyAssign &&) = default;
    131   TCopyAssign &operator=(const TCopyAssign &) = default;
    132   TCopyAssign &operator=(TCopyAssign &&) = delete;
    133   int value;
    134 };
    135 
    136 static_assert(std::is_trivially_copy_assignable<TCopyAssign>::value, "");
    137 
    138 struct TCopyAssignNTMoveAssign {
    139   constexpr TCopyAssignNTMoveAssign(int v) : value(v) {}
    140   TCopyAssignNTMoveAssign(const TCopyAssignNTMoveAssign &) = default;
    141   TCopyAssignNTMoveAssign(TCopyAssignNTMoveAssign &&) = default;
    142   TCopyAssignNTMoveAssign &operator=(const TCopyAssignNTMoveAssign &) = default;
    143   TCopyAssignNTMoveAssign &operator=(TCopyAssignNTMoveAssign &&that) {
    144     value = that.value;
    145     that.value = -1;
    146     return *this;
    147   }
    148   int value;
    149 };
    150 
    151 static_assert(std::is_trivially_copy_assignable_v<TCopyAssignNTMoveAssign>, "");
    152 
    153 #ifndef TEST_HAS_NO_EXCEPTIONS
    154 struct CopyThrows {
    155   CopyThrows() = default;
    156   CopyThrows(const CopyThrows &) { throw 42; }
    157   CopyThrows &operator=(const CopyThrows &) { throw 42; }
    158 };
    159 
    160 struct CopyCannotThrow {
    161   static int alive;
    162   CopyCannotThrow() { ++alive; }
    163   CopyCannotThrow(const CopyCannotThrow &) noexcept { ++alive; }
    164   CopyCannotThrow(CopyCannotThrow &&) noexcept { assert(false); }
    165   CopyCannotThrow &operator=(const CopyCannotThrow &) noexcept = default;
    166   CopyCannotThrow &operator=(CopyCannotThrow &&) noexcept { assert(false); return *this; }
    167 };
    168 
    169 int CopyCannotThrow::alive = 0;
    170 
    171 struct MoveThrows {
    172   static int alive;
    173   MoveThrows() { ++alive; }
    174   MoveThrows(const MoveThrows &) { ++alive; }
    175   MoveThrows(MoveThrows &&) { throw 42; }
    176   MoveThrows &operator=(const MoveThrows &) { return *this; }
    177   MoveThrows &operator=(MoveThrows &&) { throw 42; }
    178   ~MoveThrows() { --alive; }
    179 };
    180 
    181 int MoveThrows::alive = 0;
    182 
    183 struct MakeEmptyT {
    184   static int alive;
    185   MakeEmptyT() { ++alive; }
    186   MakeEmptyT(const MakeEmptyT &) {
    187     ++alive;
    188     // Don't throw from the copy constructor since variant's assignment
    189     // operator performs a copy before committing to the assignment.
    190   }
    191   MakeEmptyT(MakeEmptyT &&) { throw 42; }
    192   MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; }
    193   MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
    194   ~MakeEmptyT() { --alive; }
    195 };
    196 
    197 int MakeEmptyT::alive = 0;
    198 
    199 template <class Variant> void makeEmpty(Variant &v) {
    200   Variant v2(std::in_place_type<MakeEmptyT>);
    201   try {
    202     v = std::move(v2);
    203     assert(false);
    204   } catch (...) {
    205     assert(v.valueless_by_exception());
    206   }
    207 }
    208 #endif // TEST_HAS_NO_EXCEPTIONS
    209 
    210 void test_copy_assignment_not_noexcept() {
    211   {
    212     using V = std::variant<CopyMaybeThrows>;
    213     static_assert(!std::is_nothrow_copy_assignable<V>::value, "");
    214   }
    215   {
    216     using V = std::variant<int, CopyDoesThrow>;
    217     static_assert(!std::is_nothrow_copy_assignable<V>::value, "");
    218   }
    219 }
    220 
    221 void test_copy_assignment_sfinae() {
    222   {
    223     using V = std::variant<int, long>;
    224     static_assert(std::is_copy_assignable<V>::value, "");
    225   }
    226   {
    227     using V = std::variant<int, CopyOnly>;
    228     static_assert(std::is_copy_assignable<V>::value, "");
    229   }
    230   {
    231     using V = std::variant<int, NoCopy>;
    232     static_assert(!std::is_copy_assignable<V>::value, "");
    233   }
    234   {
    235     using V = std::variant<int, MoveOnly>;
    236     static_assert(!std::is_copy_assignable<V>::value, "");
    237   }
    238   {
    239     using V = std::variant<int, MoveOnlyNT>;
    240     static_assert(!std::is_copy_assignable<V>::value, "");
    241   }
    242 
    243   // Make sure we properly propagate triviality (see P0602R4).
    244 #if TEST_STD_VER > 17
    245   {
    246     using V = std::variant<int, long>;
    247     static_assert(std::is_trivially_copy_assignable<V>::value, "");
    248   }
    249   {
    250     using V = std::variant<int, NTCopyAssign>;
    251     static_assert(!std::is_trivially_copy_assignable<V>::value, "");
    252     static_assert(std::is_copy_assignable<V>::value, "");
    253   }
    254   {
    255     using V = std::variant<int, TCopyAssign>;
    256     static_assert(std::is_trivially_copy_assignable<V>::value, "");
    257   }
    258   {
    259     using V = std::variant<int, TCopyAssignNTMoveAssign>;
    260     static_assert(std::is_trivially_copy_assignable<V>::value, "");
    261   }
    262   {
    263     using V = std::variant<int, CopyOnly>;
    264     static_assert(std::is_trivially_copy_assignable<V>::value, "");
    265   }
    266 #endif // > C++17
    267 }
    268 
    269 void test_copy_assignment_empty_empty() {
    270 #ifndef TEST_HAS_NO_EXCEPTIONS
    271   using MET = MakeEmptyT;
    272   {
    273     using V = std::variant<int, long, MET>;
    274     V v1(std::in_place_index<0>);
    275     makeEmpty(v1);
    276     V v2(std::in_place_index<0>);
    277     makeEmpty(v2);
    278     V &vref = (v1 = v2);
    279     assert(&vref == &v1);
    280     assert(v1.valueless_by_exception());
    281     assert(v1.index() == std::variant_npos);
    282   }
    283 #endif // TEST_HAS_NO_EXCEPTIONS
    284 }
    285 
    286 void test_copy_assignment_non_empty_empty() {
    287 #ifndef TEST_HAS_NO_EXCEPTIONS
    288   using MET = MakeEmptyT;
    289   {
    290     using V = std::variant<int, MET>;
    291     V v1(std::in_place_index<0>, 42);
    292     V v2(std::in_place_index<0>);
    293     makeEmpty(v2);
    294     V &vref = (v1 = v2);
    295     assert(&vref == &v1);
    296     assert(v1.valueless_by_exception());
    297     assert(v1.index() == std::variant_npos);
    298   }
    299   {
    300     using V = std::variant<int, MET, std::string>;
    301     V v1(std::in_place_index<2>, "hello");
    302     V v2(std::in_place_index<0>);
    303     makeEmpty(v2);
    304     V &vref = (v1 = v2);
    305     assert(&vref == &v1);
    306     assert(v1.valueless_by_exception());
    307     assert(v1.index() == std::variant_npos);
    308   }
    309 #endif // TEST_HAS_NO_EXCEPTIONS
    310 }
    311 
    312 void test_copy_assignment_empty_non_empty() {
    313 #ifndef TEST_HAS_NO_EXCEPTIONS
    314   using MET = MakeEmptyT;
    315   {
    316     using V = std::variant<int, MET>;
    317     V v1(std::in_place_index<0>);
    318     makeEmpty(v1);
    319     V v2(std::in_place_index<0>, 42);
    320     V &vref = (v1 = v2);
    321     assert(&vref == &v1);
    322     assert(v1.index() == 0);
    323     assert(std::get<0>(v1) == 42);
    324   }
    325   {
    326     using V = std::variant<int, MET, std::string>;
    327     V v1(std::in_place_index<0>);
    328     makeEmpty(v1);
    329     V v2(std::in_place_type<std::string>, "hello");
    330     V &vref = (v1 = v2);
    331     assert(&vref == &v1);
    332     assert(v1.index() == 2);
    333     assert(std::get<2>(v1) == "hello");
    334   }
    335 #endif // TEST_HAS_NO_EXCEPTIONS
    336 }
    337 
    338 template <typename T> struct Result { size_t index; T value; };
    339 
    340 void test_copy_assignment_same_index() {
    341   {
    342     using V = std::variant<int>;
    343     V v1(43);
    344     V v2(42);
    345     V &vref = (v1 = v2);
    346     assert(&vref == &v1);
    347     assert(v1.index() == 0);
    348     assert(std::get<0>(v1) == 42);
    349   }
    350   {
    351     using V = std::variant<int, long, unsigned>;
    352     V v1(43l);
    353     V v2(42l);
    354     V &vref = (v1 = v2);
    355     assert(&vref == &v1);
    356     assert(v1.index() == 1);
    357     assert(std::get<1>(v1) == 42);
    358   }
    359   {
    360     using V = std::variant<int, CopyAssign, unsigned>;
    361     V v1(std::in_place_type<CopyAssign>, 43);
    362     V v2(std::in_place_type<CopyAssign>, 42);
    363     CopyAssign::reset();
    364     V &vref = (v1 = v2);
    365     assert(&vref == &v1);
    366     assert(v1.index() == 1);
    367     assert(std::get<1>(v1).value == 42);
    368     assert(CopyAssign::copy_construct == 0);
    369     assert(CopyAssign::move_construct == 0);
    370     assert(CopyAssign::copy_assign == 1);
    371   }
    372 #ifndef TEST_HAS_NO_EXCEPTIONS
    373   using MET = MakeEmptyT;
    374   {
    375     using V = std::variant<int, MET, std::string>;
    376     V v1(std::in_place_type<MET>);
    377     MET &mref = std::get<1>(v1);
    378     V v2(std::in_place_type<MET>);
    379     try {
    380       v1 = v2;
    381       assert(false);
    382     } catch (...) {
    383     }
    384     assert(v1.index() == 1);
    385     assert(&std::get<1>(v1) == &mref);
    386   }
    387 #endif // TEST_HAS_NO_EXCEPTIONS
    388 
    389   // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
    390 #if TEST_STD_VER > 17
    391   {
    392     struct {
    393       constexpr Result<int> operator()() const {
    394         using V = std::variant<int>;
    395         V v(43);
    396         V v2(42);
    397         v = v2;
    398         return {v.index(), std::get<0>(v)};
    399       }
    400     } test;
    401     constexpr auto result = test();
    402     static_assert(result.index == 0, "");
    403     static_assert(result.value == 42, "");
    404   }
    405   {
    406     struct {
    407       constexpr Result<long> operator()() const {
    408         using V = std::variant<int, long, unsigned>;
    409         V v(43l);
    410         V v2(42l);
    411         v = v2;
    412         return {v.index(), std::get<1>(v)};
    413       }
    414     } test;
    415     constexpr auto result = test();
    416     static_assert(result.index == 1, "");
    417     static_assert(result.value == 42l, "");
    418   }
    419   {
    420     struct {
    421       constexpr Result<int> operator()() const {
    422         using V = std::variant<int, TCopyAssign, unsigned>;
    423         V v(std::in_place_type<TCopyAssign>, 43);
    424         V v2(std::in_place_type<TCopyAssign>, 42);
    425         v = v2;
    426         return {v.index(), std::get<1>(v).value};
    427       }
    428     } test;
    429     constexpr auto result = test();
    430     static_assert(result.index == 1, "");
    431     static_assert(result.value == 42, "");
    432   }
    433   {
    434     struct {
    435       constexpr Result<int> operator()() const {
    436         using V = std::variant<int, TCopyAssignNTMoveAssign, unsigned>;
    437         V v(std::in_place_type<TCopyAssignNTMoveAssign>, 43);
    438         V v2(std::in_place_type<TCopyAssignNTMoveAssign>, 42);
    439         v = v2;
    440         return {v.index(), std::get<1>(v).value};
    441       }
    442     } test;
    443     constexpr auto result = test();
    444     static_assert(result.index == 1, "");
    445     static_assert(result.value == 42, "");
    446   }
    447 #endif // > C++17
    448 }
    449 
    450 void test_copy_assignment_different_index() {
    451   {
    452     using V = std::variant<int, long, unsigned>;
    453     V v1(43);
    454     V v2(42l);
    455     V &vref = (v1 = v2);
    456     assert(&vref == &v1);
    457     assert(v1.index() == 1);
    458     assert(std::get<1>(v1) == 42);
    459   }
    460   {
    461     using V = std::variant<int, CopyAssign, unsigned>;
    462     CopyAssign::reset();
    463     V v1(std::in_place_type<unsigned>, 43);
    464     V v2(std::in_place_type<CopyAssign>, 42);
    465     assert(CopyAssign::copy_construct == 0);
    466     assert(CopyAssign::move_construct == 0);
    467     assert(CopyAssign::alive == 1);
    468     V &vref = (v1 = v2);
    469     assert(&vref == &v1);
    470     assert(v1.index() == 1);
    471     assert(std::get<1>(v1).value == 42);
    472     assert(CopyAssign::alive == 2);
    473     assert(CopyAssign::copy_construct == 1);
    474     assert(CopyAssign::move_construct == 1);
    475     assert(CopyAssign::copy_assign == 0);
    476   }
    477 #ifndef TEST_HAS_NO_EXCEPTIONS
    478   {
    479     using V = std::variant<int, CopyThrows, std::string>;
    480     V v1(std::in_place_type<std::string>, "hello");
    481     V v2(std::in_place_type<CopyThrows>);
    482     try {
    483       v1 = v2;
    484       assert(false);
    485     } catch (...) { /* ... */
    486     }
    487     // Test that copy construction is used directly if move construction may throw,
    488     // resulting in a valueless variant if copy throws.
    489     assert(v1.valueless_by_exception());
    490   }
    491   {
    492     using V = std::variant<int, MoveThrows, std::string>;
    493     V v1(std::in_place_type<std::string>, "hello");
    494     V v2(std::in_place_type<MoveThrows>);
    495     assert(MoveThrows::alive == 1);
    496     // Test that copy construction is used directly if move construction may throw.
    497     v1 = v2;
    498     assert(v1.index() == 1);
    499     assert(v2.index() == 1);
    500     assert(MoveThrows::alive == 2);
    501   }
    502   {
    503     // Test that direct copy construction is preferred when it cannot throw.
    504     using V = std::variant<int, CopyCannotThrow, std::string>;
    505     V v1(std::in_place_type<std::string>, "hello");
    506     V v2(std::in_place_type<CopyCannotThrow>);
    507     assert(CopyCannotThrow::alive == 1);
    508     v1 = v2;
    509     assert(v1.index() == 1);
    510     assert(v2.index() == 1);
    511     assert(CopyCannotThrow::alive == 2);
    512   }
    513   {
    514     using V = std::variant<int, CopyThrows, std::string>;
    515     V v1(std::in_place_type<CopyThrows>);
    516     V v2(std::in_place_type<std::string>, "hello");
    517     V &vref = (v1 = v2);
    518     assert(&vref == &v1);
    519     assert(v1.index() == 2);
    520     assert(std::get<2>(v1) == "hello");
    521     assert(v2.index() == 2);
    522     assert(std::get<2>(v2) == "hello");
    523   }
    524   {
    525     using V = std::variant<int, MoveThrows, std::string>;
    526     V v1(std::in_place_type<MoveThrows>);
    527     V v2(std::in_place_type<std::string>, "hello");
    528     V &vref = (v1 = v2);
    529     assert(&vref == &v1);
    530     assert(v1.index() == 2);
    531     assert(std::get<2>(v1) == "hello");
    532     assert(v2.index() == 2);
    533     assert(std::get<2>(v2) == "hello");
    534   }
    535 #endif // TEST_HAS_NO_EXCEPTIONS
    536 
    537   // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
    538 #if TEST_STD_VER > 17
    539   {
    540     struct {
    541       constexpr Result<long> operator()() const {
    542         using V = std::variant<int, long, unsigned>;
    543         V v(43);
    544         V v2(42l);
    545         v = v2;
    546         return {v.index(), std::get<1>(v)};
    547       }
    548     } test;
    549     constexpr auto result = test();
    550     static_assert(result.index == 1, "");
    551     static_assert(result.value == 42l, "");
    552   }
    553   {
    554     struct {
    555       constexpr Result<int> operator()() const {
    556         using V = std::variant<int, TCopyAssign, unsigned>;
    557         V v(std::in_place_type<unsigned>, 43);
    558         V v2(std::in_place_type<TCopyAssign>, 42);
    559         v = v2;
    560         return {v.index(), std::get<1>(v).value};
    561       }
    562     } test;
    563     constexpr auto result = test();
    564     static_assert(result.index == 1, "");
    565     static_assert(result.value == 42, "");
    566   }
    567 #endif // > C++17
    568 }
    569 
    570 template <size_t NewIdx, class ValueType>
    571 constexpr bool test_constexpr_assign_imp(
    572     std::variant<long, void*, int>&& v, ValueType&& new_value)
    573 {
    574   const std::variant<long, void*, int> cp(
    575       std::forward<ValueType>(new_value));
    576   v = cp;
    577   return v.index() == NewIdx &&
    578         std::get<NewIdx>(v) == std::get<NewIdx>(cp);
    579 }
    580 
    581 void test_constexpr_copy_assignment() {
    582   // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
    583 #if TEST_STD_VER > 17
    584   using V = std::variant<long, void*, int>;
    585   static_assert(std::is_trivially_copyable<V>::value, "");
    586   static_assert(std::is_trivially_copy_assignable<V>::value, "");
    587   static_assert(test_constexpr_assign_imp<0>(V(42l), 101l), "");
    588   static_assert(test_constexpr_assign_imp<0>(V(nullptr), 101l), "");
    589   static_assert(test_constexpr_assign_imp<1>(V(42l), nullptr), "");
    590   static_assert(test_constexpr_assign_imp<2>(V(42l), 101), "");
    591 #endif // > C++17
    592 }
    593 
    594 int main() {
    595   test_copy_assignment_empty_empty();
    596   test_copy_assignment_non_empty_empty();
    597   test_copy_assignment_empty_non_empty();
    598   test_copy_assignment_same_index();
    599   test_copy_assignment_different_index();
    600   test_copy_assignment_sfinae();
    601   test_copy_assignment_not_noexcept();
    602   test_constexpr_copy_assignment();
    603 }