libcxx

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

move.pass.cpp (15145B)


      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 
     26 // <variant>
     27 
     28 // template <class ...Types> class variant;
     29 
     30 // variant& operator=(variant&&) noexcept(see below); // constexpr in C++20
     31 
     32 #include <cassert>
     33 #include <string>
     34 #include <type_traits>
     35 #include <utility>
     36 #include <variant>
     37 
     38 #include "test_macros.h"
     39 #include "variant_test_helpers.hpp"
     40 
     41 struct NoCopy {
     42   NoCopy(const NoCopy &) = delete;
     43   NoCopy &operator=(const NoCopy &) = default;
     44 };
     45 
     46 struct CopyOnly {
     47   CopyOnly(const CopyOnly &) = default;
     48   CopyOnly(CopyOnly &&) = delete;
     49   CopyOnly &operator=(const CopyOnly &) = default;
     50   CopyOnly &operator=(CopyOnly &&) = delete;
     51 };
     52 
     53 struct MoveOnly {
     54   MoveOnly(const MoveOnly &) = delete;
     55   MoveOnly(MoveOnly &&) = default;
     56   MoveOnly &operator=(const MoveOnly &) = delete;
     57   MoveOnly &operator=(MoveOnly &&) = default;
     58 };
     59 
     60 struct MoveOnlyNT {
     61   MoveOnlyNT(const MoveOnlyNT &) = delete;
     62   MoveOnlyNT(MoveOnlyNT &&) {}
     63   MoveOnlyNT &operator=(const MoveOnlyNT &) = delete;
     64   MoveOnlyNT &operator=(MoveOnlyNT &&) = default;
     65 };
     66 
     67 struct MoveOnlyOddNothrow {
     68   MoveOnlyOddNothrow(MoveOnlyOddNothrow &&) noexcept(false) {}
     69   MoveOnlyOddNothrow(const MoveOnlyOddNothrow &) = delete;
     70   MoveOnlyOddNothrow &operator=(MoveOnlyOddNothrow &&) noexcept = default;
     71   MoveOnlyOddNothrow &operator=(const MoveOnlyOddNothrow &) = delete;
     72 };
     73 
     74 struct MoveAssignOnly {
     75   MoveAssignOnly(MoveAssignOnly &&) = delete;
     76   MoveAssignOnly &operator=(MoveAssignOnly &&) = default;
     77 };
     78 
     79 struct MoveAssign {
     80   static int move_construct;
     81   static int move_assign;
     82   static void reset() { move_construct = move_assign = 0; }
     83   MoveAssign(int v) : value(v) {}
     84   MoveAssign(MoveAssign &&o) : value(o.value) {
     85     ++move_construct;
     86     o.value = -1;
     87   }
     88   MoveAssign &operator=(MoveAssign &&o) {
     89     value = o.value;
     90     ++move_assign;
     91     o.value = -1;
     92     return *this;
     93   }
     94   int value;
     95 };
     96 
     97 int MoveAssign::move_construct = 0;
     98 int MoveAssign::move_assign = 0;
     99 
    100 struct NTMoveAssign {
    101   constexpr NTMoveAssign(int v) : value(v) {}
    102   NTMoveAssign(const NTMoveAssign &) = default;
    103   NTMoveAssign(NTMoveAssign &&) = default;
    104   NTMoveAssign &operator=(const NTMoveAssign &that) = default;
    105   NTMoveAssign &operator=(NTMoveAssign &&that) {
    106     value = that.value;
    107     that.value = -1;
    108     return *this;
    109   };
    110   int value;
    111 };
    112 
    113 static_assert(!std::is_trivially_move_assignable<NTMoveAssign>::value, "");
    114 static_assert(std::is_move_assignable<NTMoveAssign>::value, "");
    115 
    116 struct TMoveAssign {
    117   constexpr TMoveAssign(int v) : value(v) {}
    118   TMoveAssign(const TMoveAssign &) = delete;
    119   TMoveAssign(TMoveAssign &&) = default;
    120   TMoveAssign &operator=(const TMoveAssign &) = delete;
    121   TMoveAssign &operator=(TMoveAssign &&) = default;
    122   int value;
    123 };
    124 
    125 static_assert(std::is_trivially_move_assignable<TMoveAssign>::value, "");
    126 
    127 struct TMoveAssignNTCopyAssign {
    128   constexpr TMoveAssignNTCopyAssign(int v) : value(v) {}
    129   TMoveAssignNTCopyAssign(const TMoveAssignNTCopyAssign &) = default;
    130   TMoveAssignNTCopyAssign(TMoveAssignNTCopyAssign &&) = default;
    131   TMoveAssignNTCopyAssign &operator=(const TMoveAssignNTCopyAssign &that) {
    132     value = that.value;
    133     return *this;
    134   }
    135   TMoveAssignNTCopyAssign &operator=(TMoveAssignNTCopyAssign &&) = default;
    136   int value;
    137 };
    138 
    139 static_assert(std::is_trivially_move_assignable_v<TMoveAssignNTCopyAssign>, "");
    140 
    141 struct TrivialCopyNontrivialMove {
    142   TrivialCopyNontrivialMove(TrivialCopyNontrivialMove const&) = default;
    143   TrivialCopyNontrivialMove(TrivialCopyNontrivialMove&&) noexcept {}
    144   TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove const&) = default;
    145   TrivialCopyNontrivialMove& operator=(TrivialCopyNontrivialMove&&) noexcept {
    146     return *this;
    147   }
    148 };
    149 
    150 static_assert(std::is_trivially_copy_assignable_v<TrivialCopyNontrivialMove>, "");
    151 static_assert(!std::is_trivially_move_assignable_v<TrivialCopyNontrivialMove>, "");
    152 
    153 
    154 void test_move_assignment_noexcept() {
    155   {
    156     using V = std::variant<int>;
    157     static_assert(std::is_nothrow_move_assignable<V>::value, "");
    158   }
    159   {
    160     using V = std::variant<MoveOnly>;
    161     static_assert(std::is_nothrow_move_assignable<V>::value, "");
    162   }
    163   {
    164     using V = std::variant<int, long>;
    165     static_assert(std::is_nothrow_move_assignable<V>::value, "");
    166   }
    167   {
    168     using V = std::variant<int, MoveOnly>;
    169     static_assert(std::is_nothrow_move_assignable<V>::value, "");
    170   }
    171   {
    172     using V = std::variant<MoveOnlyNT>;
    173     static_assert(!std::is_nothrow_move_assignable<V>::value, "");
    174   }
    175   {
    176     using V = std::variant<MoveOnlyOddNothrow>;
    177     static_assert(!std::is_nothrow_move_assignable<V>::value, "");
    178   }
    179 }
    180 
    181 void test_move_assignment_sfinae() {
    182   {
    183     using V = std::variant<int, long>;
    184     static_assert(std::is_move_assignable<V>::value, "");
    185   }
    186   {
    187     using V = std::variant<int, CopyOnly>;
    188     static_assert(std::is_move_assignable<V>::value, "");
    189   }
    190   {
    191     using V = std::variant<int, NoCopy>;
    192     static_assert(!std::is_move_assignable<V>::value, "");
    193   }
    194   {
    195     using V = std::variant<int, MoveOnly>;
    196     static_assert(std::is_move_assignable<V>::value, "");
    197   }
    198   {
    199     using V = std::variant<int, MoveOnlyNT>;
    200     static_assert(std::is_move_assignable<V>::value, "");
    201   }
    202   {
    203     // variant only provides move assignment when the types also provide
    204     // a move constructor.
    205     using V = std::variant<int, MoveAssignOnly>;
    206     static_assert(!std::is_move_assignable<V>::value, "");
    207   }
    208 
    209   // Make sure we properly propagate triviality (see P0602R4).
    210 #if TEST_STD_VER > 17
    211   {
    212     using V = std::variant<int, long>;
    213     static_assert(std::is_trivially_move_assignable<V>::value, "");
    214   }
    215   {
    216     using V = std::variant<int, NTMoveAssign>;
    217     static_assert(!std::is_trivially_move_assignable<V>::value, "");
    218     static_assert(std::is_move_assignable<V>::value, "");
    219   }
    220   {
    221     using V = std::variant<int, TMoveAssign>;
    222     static_assert(std::is_trivially_move_assignable<V>::value, "");
    223   }
    224   {
    225     using V = std::variant<int, TMoveAssignNTCopyAssign>;
    226     static_assert(std::is_trivially_move_assignable<V>::value, "");
    227   }
    228   {
    229     using V = std::variant<int, TrivialCopyNontrivialMove>;
    230     static_assert(!std::is_trivially_move_assignable<V>::value, "");
    231   }
    232   {
    233     using V = std::variant<int, CopyOnly>;
    234     static_assert(std::is_trivially_move_assignable<V>::value, "");
    235   }
    236 #endif // > C++17
    237 }
    238 
    239 void test_move_assignment_empty_empty() {
    240 #ifndef TEST_HAS_NO_EXCEPTIONS
    241   using MET = MakeEmptyT;
    242   {
    243     using V = std::variant<int, long, MET>;
    244     V v1(std::in_place_index<0>);
    245     makeEmpty(v1);
    246     V v2(std::in_place_index<0>);
    247     makeEmpty(v2);
    248     V &vref = (v1 = std::move(v2));
    249     assert(&vref == &v1);
    250     assert(v1.valueless_by_exception());
    251     assert(v1.index() == std::variant_npos);
    252   }
    253 #endif // TEST_HAS_NO_EXCEPTIONS
    254 }
    255 
    256 void test_move_assignment_non_empty_empty() {
    257 #ifndef TEST_HAS_NO_EXCEPTIONS
    258   using MET = MakeEmptyT;
    259   {
    260     using V = std::variant<int, MET>;
    261     V v1(std::in_place_index<0>, 42);
    262     V v2(std::in_place_index<0>);
    263     makeEmpty(v2);
    264     V &vref = (v1 = std::move(v2));
    265     assert(&vref == &v1);
    266     assert(v1.valueless_by_exception());
    267     assert(v1.index() == std::variant_npos);
    268   }
    269   {
    270     using V = std::variant<int, MET, std::string>;
    271     V v1(std::in_place_index<2>, "hello");
    272     V v2(std::in_place_index<0>);
    273     makeEmpty(v2);
    274     V &vref = (v1 = std::move(v2));
    275     assert(&vref == &v1);
    276     assert(v1.valueless_by_exception());
    277     assert(v1.index() == std::variant_npos);
    278   }
    279 #endif // TEST_HAS_NO_EXCEPTIONS
    280 }
    281 
    282 void test_move_assignment_empty_non_empty() {
    283 #ifndef TEST_HAS_NO_EXCEPTIONS
    284   using MET = MakeEmptyT;
    285   {
    286     using V = std::variant<int, MET>;
    287     V v1(std::in_place_index<0>);
    288     makeEmpty(v1);
    289     V v2(std::in_place_index<0>, 42);
    290     V &vref = (v1 = std::move(v2));
    291     assert(&vref == &v1);
    292     assert(v1.index() == 0);
    293     assert(std::get<0>(v1) == 42);
    294   }
    295   {
    296     using V = std::variant<int, MET, std::string>;
    297     V v1(std::in_place_index<0>);
    298     makeEmpty(v1);
    299     V v2(std::in_place_type<std::string>, "hello");
    300     V &vref = (v1 = std::move(v2));
    301     assert(&vref == &v1);
    302     assert(v1.index() == 2);
    303     assert(std::get<2>(v1) == "hello");
    304   }
    305 #endif // TEST_HAS_NO_EXCEPTIONS
    306 }
    307 
    308 template <typename T> struct Result { size_t index; T value; };
    309 
    310 void test_move_assignment_same_index() {
    311   {
    312     using V = std::variant<int>;
    313     V v1(43);
    314     V v2(42);
    315     V &vref = (v1 = std::move(v2));
    316     assert(&vref == &v1);
    317     assert(v1.index() == 0);
    318     assert(std::get<0>(v1) == 42);
    319   }
    320   {
    321     using V = std::variant<int, long, unsigned>;
    322     V v1(43l);
    323     V v2(42l);
    324     V &vref = (v1 = std::move(v2));
    325     assert(&vref == &v1);
    326     assert(v1.index() == 1);
    327     assert(std::get<1>(v1) == 42);
    328   }
    329   {
    330     using V = std::variant<int, MoveAssign, unsigned>;
    331     V v1(std::in_place_type<MoveAssign>, 43);
    332     V v2(std::in_place_type<MoveAssign>, 42);
    333     MoveAssign::reset();
    334     V &vref = (v1 = std::move(v2));
    335     assert(&vref == &v1);
    336     assert(v1.index() == 1);
    337     assert(std::get<1>(v1).value == 42);
    338     assert(MoveAssign::move_construct == 0);
    339     assert(MoveAssign::move_assign == 1);
    340   }
    341 #ifndef TEST_HAS_NO_EXCEPTIONS
    342   using MET = MakeEmptyT;
    343   {
    344     using V = std::variant<int, MET, std::string>;
    345     V v1(std::in_place_type<MET>);
    346     MET &mref = std::get<1>(v1);
    347     V v2(std::in_place_type<MET>);
    348     try {
    349       v1 = std::move(v2);
    350       assert(false);
    351     } catch (...) {
    352     }
    353     assert(v1.index() == 1);
    354     assert(&std::get<1>(v1) == &mref);
    355   }
    356 #endif // TEST_HAS_NO_EXCEPTIONS
    357 
    358   // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
    359 #if TEST_STD_VER > 17
    360   {
    361     struct {
    362       constexpr Result<int> operator()() const {
    363         using V = std::variant<int>;
    364         V v(43);
    365         V v2(42);
    366         v = std::move(v2);
    367         return {v.index(), std::get<0>(v)};
    368       }
    369     } test;
    370     constexpr auto result = test();
    371     static_assert(result.index == 0, "");
    372     static_assert(result.value == 42, "");
    373   }
    374   {
    375     struct {
    376       constexpr Result<long> operator()() const {
    377         using V = std::variant<int, long, unsigned>;
    378         V v(43l);
    379         V v2(42l);
    380         v = std::move(v2);
    381         return {v.index(), std::get<1>(v)};
    382       }
    383     } test;
    384     constexpr auto result = test();
    385     static_assert(result.index == 1, "");
    386     static_assert(result.value == 42l, "");
    387   }
    388   {
    389     struct {
    390       constexpr Result<int> operator()() const {
    391         using V = std::variant<int, TMoveAssign, unsigned>;
    392         V v(std::in_place_type<TMoveAssign>, 43);
    393         V v2(std::in_place_type<TMoveAssign>, 42);
    394         v = std::move(v2);
    395         return {v.index(), std::get<1>(v).value};
    396       }
    397     } test;
    398     constexpr auto result = test();
    399     static_assert(result.index == 1, "");
    400     static_assert(result.value == 42, "");
    401   }
    402 #endif // > C++17
    403 }
    404 
    405 void test_move_assignment_different_index() {
    406   {
    407     using V = std::variant<int, long, unsigned>;
    408     V v1(43);
    409     V v2(42l);
    410     V &vref = (v1 = std::move(v2));
    411     assert(&vref == &v1);
    412     assert(v1.index() == 1);
    413     assert(std::get<1>(v1) == 42);
    414   }
    415   {
    416     using V = std::variant<int, MoveAssign, unsigned>;
    417     V v1(std::in_place_type<unsigned>, 43);
    418     V v2(std::in_place_type<MoveAssign>, 42);
    419     MoveAssign::reset();
    420     V &vref = (v1 = std::move(v2));
    421     assert(&vref == &v1);
    422     assert(v1.index() == 1);
    423     assert(std::get<1>(v1).value == 42);
    424     assert(MoveAssign::move_construct == 1);
    425     assert(MoveAssign::move_assign == 0);
    426   }
    427 #ifndef TEST_HAS_NO_EXCEPTIONS
    428   using MET = MakeEmptyT;
    429   {
    430     using V = std::variant<int, MET, std::string>;
    431     V v1(std::in_place_type<int>);
    432     V v2(std::in_place_type<MET>);
    433     try {
    434       v1 = std::move(v2);
    435       assert(false);
    436     } catch (...) {
    437     }
    438     assert(v1.valueless_by_exception());
    439     assert(v1.index() == std::variant_npos);
    440   }
    441   {
    442     using V = std::variant<int, MET, std::string>;
    443     V v1(std::in_place_type<MET>);
    444     V v2(std::in_place_type<std::string>, "hello");
    445     V &vref = (v1 = std::move(v2));
    446     assert(&vref == &v1);
    447     assert(v1.index() == 2);
    448     assert(std::get<2>(v1) == "hello");
    449   }
    450 #endif // TEST_HAS_NO_EXCEPTIONS
    451 
    452   // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
    453 #if TEST_STD_VER > 17
    454   {
    455     struct {
    456       constexpr Result<long> operator()() const {
    457         using V = std::variant<int, long, unsigned>;
    458         V v(43);
    459         V v2(42l);
    460         v = std::move(v2);
    461         return {v.index(), std::get<1>(v)};
    462       }
    463     } test;
    464     constexpr auto result = test();
    465     static_assert(result.index == 1, "");
    466     static_assert(result.value == 42l, "");
    467   }
    468   {
    469     struct {
    470       constexpr Result<long> operator()() const {
    471         using V = std::variant<int, TMoveAssign, unsigned>;
    472         V v(std::in_place_type<unsigned>, 43);
    473         V v2(std::in_place_type<TMoveAssign>, 42);
    474         v = std::move(v2);
    475         return {v.index(), std::get<1>(v).value};
    476       }
    477     } test;
    478     constexpr auto result = test();
    479     static_assert(result.index == 1, "");
    480     static_assert(result.value == 42, "");
    481   }
    482 #endif // > C++17
    483 }
    484 
    485 template <size_t NewIdx, class ValueType>
    486 constexpr bool test_constexpr_assign_imp(
    487     std::variant<long, void*, int>&& v, ValueType&& new_value)
    488 {
    489   std::variant<long, void*, int> v2(
    490       std::forward<ValueType>(new_value));
    491   const auto cp = v2;
    492   v = std::move(v2);
    493   return v.index() == NewIdx &&
    494         std::get<NewIdx>(v) == std::get<NewIdx>(cp);
    495 }
    496 
    497 void test_constexpr_move_assignment() {
    498   // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4).
    499 #if TEST_STD_VER > 17
    500   using V = std::variant<long, void*, int>;
    501   static_assert(std::is_trivially_copyable<V>::value, "");
    502   static_assert(std::is_trivially_move_assignable<V>::value, "");
    503   static_assert(test_constexpr_assign_imp<0>(V(42l), 101l), "");
    504   static_assert(test_constexpr_assign_imp<0>(V(nullptr), 101l), "");
    505   static_assert(test_constexpr_assign_imp<1>(V(42l), nullptr), "");
    506   static_assert(test_constexpr_assign_imp<2>(V(42l), 101), "");
    507 #endif // > C++17
    508 }
    509 
    510 int main() {
    511   test_move_assignment_empty_empty();
    512   test_move_assignment_non_empty_empty();
    513   test_move_assignment_empty_non_empty();
    514   test_move_assignment_same_index();
    515   test_move_assignment_different_index();
    516   test_move_assignment_sfinae();
    517   test_move_assignment_noexcept();
    518   test_constexpr_move_assignment();
    519 }