Home | History | Annotate | Download | only in variant.ctor
      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 // XFAIL: with_system_cxx_lib=macosx10.12
     14 // XFAIL: with_system_cxx_lib=macosx10.11
     15 // XFAIL: with_system_cxx_lib=macosx10.10
     16 // XFAIL: with_system_cxx_lib=macosx10.9
     17 // XFAIL: with_system_cxx_lib=macosx10.7
     18 // XFAIL: with_system_cxx_lib=macosx10.8
     19 
     20 // <variant>
     21 
     22 // template <class ...Types> class variant;
     23 
     24 // variant(variant&&) noexcept(see below);
     25 
     26 #include <cassert>
     27 #include <string>
     28 #include <type_traits>
     29 #include <variant>
     30 
     31 #include "test_macros.h"
     32 #include "test_workarounds.h"
     33 
     34 struct ThrowsMove {
     35   ThrowsMove(ThrowsMove &&) noexcept(false) {}
     36 };
     37 
     38 struct NoCopy {
     39   NoCopy(const NoCopy &) = delete;
     40 };
     41 
     42 struct MoveOnly {
     43   int value;
     44   MoveOnly(int v) : value(v) {}
     45   MoveOnly(const MoveOnly &) = delete;
     46   MoveOnly(MoveOnly &&) = default;
     47 };
     48 
     49 struct MoveOnlyNT {
     50   int value;
     51   MoveOnlyNT(int v) : value(v) {}
     52   MoveOnlyNT(const MoveOnlyNT &) = delete;
     53   MoveOnlyNT(MoveOnlyNT &&other) : value(other.value) { other.value = -1; }
     54 };
     55 
     56 struct NTMove {
     57   constexpr NTMove(int v) : value(v) {}
     58   NTMove(const NTMove &) = delete;
     59   NTMove(NTMove &&that) : value(that.value) { that.value = -1; }
     60   int value;
     61 };
     62 
     63 static_assert(!std::is_trivially_move_constructible<NTMove>::value, "");
     64 static_assert(std::is_move_constructible<NTMove>::value, "");
     65 
     66 struct TMove {
     67   constexpr TMove(int v) : value(v) {}
     68   TMove(const TMove &) = delete;
     69   TMove(TMove &&) = default;
     70   int value;
     71 };
     72 
     73 static_assert(std::is_trivially_move_constructible<TMove>::value, "");
     74 
     75 struct TMoveNTCopy {
     76   constexpr TMoveNTCopy(int v) : value(v) {}
     77   TMoveNTCopy(const TMoveNTCopy& that) : value(that.value) {}
     78   TMoveNTCopy(TMoveNTCopy&&) = default;
     79   int value;
     80 };
     81 
     82 static_assert(std::is_trivially_move_constructible<TMoveNTCopy>::value, "");
     83 
     84 #ifndef TEST_HAS_NO_EXCEPTIONS
     85 struct MakeEmptyT {
     86   static int alive;
     87   MakeEmptyT() { ++alive; }
     88   MakeEmptyT(const MakeEmptyT &) {
     89     ++alive;
     90     // Don't throw from the copy constructor since variant's assignment
     91     // operator performs a copy before committing to the assignment.
     92   }
     93   MakeEmptyT(MakeEmptyT &&) { throw 42; }
     94   MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; }
     95   MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
     96   ~MakeEmptyT() { --alive; }
     97 };
     98 
     99 int MakeEmptyT::alive = 0;
    100 
    101 template <class Variant> void makeEmpty(Variant &v) {
    102   Variant v2(std::in_place_type<MakeEmptyT>);
    103   try {
    104     v = std::move(v2);
    105     assert(false);
    106   } catch (...) {
    107     assert(v.valueless_by_exception());
    108   }
    109 }
    110 #endif // TEST_HAS_NO_EXCEPTIONS
    111 
    112 void test_move_noexcept() {
    113   {
    114     using V = std::variant<int, long>;
    115     static_assert(std::is_nothrow_move_constructible<V>::value, "");
    116   }
    117   {
    118     using V = std::variant<int, MoveOnly>;
    119     static_assert(std::is_nothrow_move_constructible<V>::value, "");
    120   }
    121   {
    122     using V = std::variant<int, MoveOnlyNT>;
    123     static_assert(!std::is_nothrow_move_constructible<V>::value, "");
    124   }
    125   {
    126     using V = std::variant<int, ThrowsMove>;
    127     static_assert(!std::is_nothrow_move_constructible<V>::value, "");
    128   }
    129 }
    130 
    131 void test_move_ctor_sfinae() {
    132   {
    133     using V = std::variant<int, long>;
    134     static_assert(std::is_move_constructible<V>::value, "");
    135   }
    136   {
    137     using V = std::variant<int, MoveOnly>;
    138     static_assert(std::is_move_constructible<V>::value, "");
    139   }
    140   {
    141     using V = std::variant<int, MoveOnlyNT>;
    142     static_assert(std::is_move_constructible<V>::value, "");
    143   }
    144   {
    145     using V = std::variant<int, NoCopy>;
    146     static_assert(!std::is_move_constructible<V>::value, "");
    147   }
    148 
    149   // The following tests are for not-yet-standardized behavior (P0602):
    150   {
    151     using V = std::variant<int, long>;
    152     static_assert(std::is_trivially_move_constructible<V>::value, "");
    153   }
    154   {
    155     using V = std::variant<int, NTMove>;
    156     static_assert(!std::is_trivially_move_constructible<V>::value, "");
    157     static_assert(std::is_move_constructible<V>::value, "");
    158   }
    159   {
    160     using V = std::variant<int, TMove>;
    161     static_assert(std::is_trivially_move_constructible<V>::value, "");
    162   }
    163   {
    164     using V = std::variant<int, TMoveNTCopy>;
    165     static_assert(std::is_trivially_move_constructible<V>::value, "");
    166   }
    167 }
    168 
    169 template <typename T>
    170 struct Result { size_t index; T value; };
    171 
    172 void test_move_ctor_basic() {
    173   {
    174     std::variant<int> v(std::in_place_index<0>, 42);
    175     std::variant<int> v2 = std::move(v);
    176     assert(v2.index() == 0);
    177     assert(std::get<0>(v2) == 42);
    178   }
    179   {
    180     std::variant<int, long> v(std::in_place_index<1>, 42);
    181     std::variant<int, long> v2 = std::move(v);
    182     assert(v2.index() == 1);
    183     assert(std::get<1>(v2) == 42);
    184   }
    185   {
    186     std::variant<MoveOnly> v(std::in_place_index<0>, 42);
    187     assert(v.index() == 0);
    188     std::variant<MoveOnly> v2(std::move(v));
    189     assert(v2.index() == 0);
    190     assert(std::get<0>(v2).value == 42);
    191   }
    192   {
    193     std::variant<int, MoveOnly> v(std::in_place_index<1>, 42);
    194     assert(v.index() == 1);
    195     std::variant<int, MoveOnly> v2(std::move(v));
    196     assert(v2.index() == 1);
    197     assert(std::get<1>(v2).value == 42);
    198   }
    199   {
    200     std::variant<MoveOnlyNT> v(std::in_place_index<0>, 42);
    201     assert(v.index() == 0);
    202     std::variant<MoveOnlyNT> v2(std::move(v));
    203     assert(v2.index() == 0);
    204     assert(std::get<0>(v).value == -1);
    205     assert(std::get<0>(v2).value == 42);
    206   }
    207   {
    208     std::variant<int, MoveOnlyNT> v(std::in_place_index<1>, 42);
    209     assert(v.index() == 1);
    210     std::variant<int, MoveOnlyNT> v2(std::move(v));
    211     assert(v2.index() == 1);
    212     assert(std::get<1>(v).value == -1);
    213     assert(std::get<1>(v2).value == 42);
    214   }
    215 
    216   // The following tests are for not-yet-standardized behavior (P0602):
    217   {
    218     struct {
    219       constexpr Result<int> operator()() const {
    220         std::variant<int> v(std::in_place_index<0>, 42);
    221         std::variant<int> v2 = std::move(v);
    222         return {v2.index(), std::get<0>(std::move(v2))};
    223       }
    224     } test;
    225     constexpr auto result = test();
    226     static_assert(result.index == 0, "");
    227     static_assert(result.value == 42, "");
    228   }
    229   {
    230     struct {
    231       constexpr Result<long> operator()() const {
    232         std::variant<int, long> v(std::in_place_index<1>, 42);
    233         std::variant<int, long> v2 = std::move(v);
    234         return {v2.index(), std::get<1>(std::move(v2))};
    235       }
    236     } test;
    237     constexpr auto result = test();
    238     static_assert(result.index == 1, "");
    239     static_assert(result.value == 42, "");
    240   }
    241   {
    242     struct {
    243       constexpr Result<TMove> operator()() const {
    244         std::variant<TMove> v(std::in_place_index<0>, 42);
    245         std::variant<TMove> v2(std::move(v));
    246         return {v2.index(), std::get<0>(std::move(v2))};
    247       }
    248     } test;
    249     constexpr auto result = test();
    250     static_assert(result.index == 0, "");
    251     static_assert(result.value.value == 42, "");
    252   }
    253   {
    254     struct {
    255       constexpr Result<TMove> operator()() const {
    256         std::variant<int, TMove> v(std::in_place_index<1>, 42);
    257         std::variant<int, TMove> v2(std::move(v));
    258         return {v2.index(), std::get<1>(std::move(v2))};
    259       }
    260     } test;
    261     constexpr auto result = test();
    262     static_assert(result.index == 1, "");
    263     static_assert(result.value.value == 42, "");
    264   }
    265   {
    266     struct {
    267       constexpr Result<TMoveNTCopy> operator()() const {
    268         std::variant<TMoveNTCopy> v(std::in_place_index<0>, 42);
    269         std::variant<TMoveNTCopy> v2(std::move(v));
    270         return {v2.index(), std::get<0>(std::move(v2))};
    271       }
    272     } test;
    273     constexpr auto result = test();
    274     static_assert(result.index == 0, "");
    275     static_assert(result.value.value == 42, "");
    276   }
    277   {
    278     struct {
    279       constexpr Result<TMoveNTCopy> operator()() const {
    280         std::variant<int, TMoveNTCopy> v(std::in_place_index<1>, 42);
    281         std::variant<int, TMoveNTCopy> v2(std::move(v));
    282         return {v2.index(), std::get<1>(std::move(v2))};
    283       }
    284     } test;
    285     constexpr auto result = test();
    286     static_assert(result.index == 1, "");
    287     static_assert(result.value.value == 42, "");
    288   }
    289 }
    290 
    291 void test_move_ctor_valueless_by_exception() {
    292 #ifndef TEST_HAS_NO_EXCEPTIONS
    293   using V = std::variant<int, MakeEmptyT>;
    294   V v1;
    295   makeEmpty(v1);
    296   V v(std::move(v1));
    297   assert(v.valueless_by_exception());
    298 #endif // TEST_HAS_NO_EXCEPTIONS
    299 }
    300 
    301 template <size_t Idx>
    302 constexpr bool test_constexpr_ctor_extension_imp(
    303     std::variant<long, void*, const int> const& v)
    304 {
    305   auto copy = v;
    306   auto v2 = std::move(copy);
    307   return v2.index() == v.index() &&
    308          v2.index() == Idx &&
    309         std::get<Idx>(v2) == std::get<Idx>(v);
    310 }
    311 
    312 void test_constexpr_move_ctor_extension() {
    313   // NOTE: This test is for not yet standardized behavior. (P0602)
    314   using V = std::variant<long, void*, const int>;
    315 #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
    316   static_assert(std::is_trivially_destructible<V>::value, "");
    317   static_assert(std::is_trivially_copy_constructible<V>::value, "");
    318   static_assert(std::is_trivially_move_constructible<V>::value, "");
    319   static_assert(!std::is_copy_assignable<V>::value, "");
    320   static_assert(!std::is_move_assignable<V>::value, "");
    321 #else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
    322   static_assert(std::is_trivially_copyable<V>::value, "");
    323 #endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
    324   static_assert(std::is_trivially_move_constructible<V>::value, "");
    325   static_assert(test_constexpr_ctor_extension_imp<0>(V(42l)), "");
    326   static_assert(test_constexpr_ctor_extension_imp<1>(V(nullptr)), "");
    327   static_assert(test_constexpr_ctor_extension_imp<2>(V(101)), "");
    328 }
    329 
    330 int main() {
    331   test_move_ctor_basic();
    332   test_move_ctor_valueless_by_exception();
    333   test_move_noexcept();
    334   test_move_ctor_sfinae();
    335   test_constexpr_move_ctor_extension();
    336 }
    337