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