Home | History | Annotate | Download | only in variant.assign
      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 // <variant>
     14 
     15 // template <class ...Types> class variant;
     16 
     17 // template <class T>
     18 // variant& operator=(T&&) noexcept(see below);
     19 
     20 #include <cassert>
     21 #include <string>
     22 #include <type_traits>
     23 #include <variant>
     24 
     25 #include "test_macros.h"
     26 #include "variant_test_helpers.hpp"
     27 
     28 namespace MetaHelpers {
     29 
     30 struct Dummy {
     31   Dummy() = default;
     32 };
     33 
     34 struct ThrowsCtorT {
     35   ThrowsCtorT(int) noexcept(false) {}
     36   ThrowsCtorT &operator=(int) noexcept { return *this; }
     37 };
     38 
     39 struct ThrowsAssignT {
     40   ThrowsAssignT(int) noexcept {}
     41   ThrowsAssignT &operator=(int) noexcept(false) { return *this; }
     42 };
     43 
     44 struct NoThrowT {
     45   NoThrowT(int) noexcept {}
     46   NoThrowT &operator=(int) noexcept { return *this; }
     47 };
     48 
     49 } // namespace MetaHelpers
     50 
     51 namespace RuntimeHelpers {
     52 #ifndef TEST_HAS_NO_EXCEPTIONS
     53 
     54 struct ThrowsCtorT {
     55   int value;
     56   ThrowsCtorT() : value(0) {}
     57   ThrowsCtorT(int) noexcept(false) { throw 42; }
     58   ThrowsCtorT &operator=(int v) noexcept {
     59     value = v;
     60     return *this;
     61   }
     62 };
     63 
     64 struct ThrowsAssignT {
     65   int value;
     66   ThrowsAssignT() : value(0) {}
     67   ThrowsAssignT(int v) noexcept : value(v) {}
     68   ThrowsAssignT &operator=(int) noexcept(false) { throw 42; }
     69 };
     70 
     71 struct NoThrowT {
     72   int value;
     73   NoThrowT() : value(0) {}
     74   NoThrowT(int v) noexcept : value(v) {}
     75   NoThrowT &operator=(int v) noexcept {
     76     value = v;
     77     return *this;
     78   }
     79 };
     80 
     81 #endif // !defined(TEST_HAS_NO_EXCEPTIONS)
     82 } // namespace RuntimeHelpers
     83 
     84 void test_T_assignment_noexcept() {
     85   using namespace MetaHelpers;
     86   {
     87     using V = std::variant<Dummy, NoThrowT>;
     88     static_assert(std::is_nothrow_assignable<V, int>::value, "");
     89   }
     90   {
     91     using V = std::variant<Dummy, ThrowsCtorT>;
     92     static_assert(!std::is_nothrow_assignable<V, int>::value, "");
     93   }
     94   {
     95     using V = std::variant<Dummy, ThrowsAssignT>;
     96     static_assert(!std::is_nothrow_assignable<V, int>::value, "");
     97   }
     98 }
     99 
    100 void test_T_assignment_sfinae() {
    101   {
    102     using V = std::variant<long, unsigned>;
    103     static_assert(!std::is_assignable<V, int>::value, "ambiguous");
    104   }
    105   {
    106     using V = std::variant<std::string, std::string>;
    107     static_assert(!std::is_assignable<V, const char *>::value, "ambiguous");
    108   }
    109   {
    110     using V = std::variant<std::string, void *>;
    111     static_assert(!std::is_assignable<V, int>::value, "no matching operator=");
    112   }
    113 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
    114   {
    115     using V = std::variant<int, int &&>;
    116     static_assert(!std::is_assignable<V, int>::value, "ambiguous");
    117   }
    118   {
    119     using V = std::variant<int, const int &>;
    120     static_assert(!std::is_assignable<V, int>::value, "ambiguous");
    121   }
    122 #endif
    123 }
    124 
    125 void test_T_assignment_basic() {
    126   {
    127     std::variant<int> v(43);
    128     v = 42;
    129     assert(v.index() == 0);
    130     assert(std::get<0>(v) == 42);
    131   }
    132   {
    133     std::variant<int, long> v(43l);
    134     v = 42;
    135     assert(v.index() == 0);
    136     assert(std::get<0>(v) == 42);
    137     v = 43l;
    138     assert(v.index() == 1);
    139     assert(std::get<1>(v) == 43);
    140   }
    141 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
    142   {
    143     using V = std::variant<int &, int &&, long>;
    144     int x = 42;
    145     V v(43l);
    146     v = x;
    147     assert(v.index() == 0);
    148     assert(&std::get<0>(v) == &x);
    149     v = std::move(x);
    150     assert(v.index() == 1);
    151     assert(&std::get<1>(v) == &x);
    152     // 'long' is selected by FUN(const int &) since 'const int &' cannot bind
    153     // to 'int&'.
    154     const int &cx = x;
    155     v = cx;
    156     assert(v.index() == 2);
    157     assert(std::get<2>(v) == 42);
    158   }
    159 #endif
    160 }
    161 
    162 void test_T_assignment_performs_construction() {
    163   using namespace RuntimeHelpers;
    164 #ifndef TEST_HAS_NO_EXCEPTIONS
    165   {
    166     using V = std::variant<std::string, ThrowsCtorT>;
    167     V v(std::in_place_type<std::string>, "hello");
    168     try {
    169       v = 42;
    170     } catch (...) { /* ... */
    171     }
    172     assert(v.valueless_by_exception());
    173   }
    174   {
    175     using V = std::variant<ThrowsAssignT, std::string>;
    176     V v(std::in_place_type<std::string>, "hello");
    177     v = 42;
    178     assert(v.index() == 0);
    179     assert(std::get<0>(v).value == 42);
    180   }
    181 #endif
    182 }
    183 
    184 void test_T_assignment_performs_assignment() {
    185   using namespace RuntimeHelpers;
    186 #ifndef TEST_HAS_NO_EXCEPTIONS
    187   {
    188     using V = std::variant<ThrowsCtorT>;
    189     V v;
    190     v = 42;
    191     assert(v.index() == 0);
    192     assert(std::get<0>(v).value == 42);
    193   }
    194   {
    195     using V = std::variant<ThrowsCtorT, std::string>;
    196     V v;
    197     v = 42;
    198     assert(v.index() == 0);
    199     assert(std::get<0>(v).value == 42);
    200   }
    201   {
    202     using V = std::variant<ThrowsAssignT>;
    203     V v(100);
    204     try {
    205       v = 42;
    206       assert(false);
    207     } catch (...) { /* ... */
    208     }
    209     assert(v.index() == 0);
    210     assert(std::get<0>(v).value == 100);
    211   }
    212   {
    213     using V = std::variant<std::string, ThrowsAssignT>;
    214     V v(100);
    215     try {
    216       v = 42;
    217       assert(false);
    218     } catch (...) { /* ... */
    219     }
    220     assert(v.index() == 1);
    221     assert(std::get<1>(v).value == 100);
    222   }
    223 #endif
    224 }
    225 
    226 int main() {
    227   test_T_assignment_basic();
    228   test_T_assignment_performs_construction();
    229   test_T_assignment_performs_assignment();
    230   test_T_assignment_noexcept();
    231   test_T_assignment_sfinae();
    232 }
    233