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