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 const&);
     25 
     26 #include <cassert>
     27 #include <type_traits>
     28 #include <variant>
     29 
     30 #include "test_macros.h"
     31 #include "test_workarounds.h"
     32 
     33 struct NonT {
     34   NonT(int v) : value(v) {}
     35   NonT(const NonT &o) : value(o.value) {}
     36   int value;
     37 };
     38 static_assert(!std::is_trivially_copy_constructible<NonT>::value, "");
     39 
     40 struct NoCopy {
     41   NoCopy(const NoCopy &) = delete;
     42 };
     43 
     44 struct MoveOnly {
     45   MoveOnly(const MoveOnly &) = delete;
     46   MoveOnly(MoveOnly &&) = default;
     47 };
     48 
     49 struct MoveOnlyNT {
     50   MoveOnlyNT(const MoveOnlyNT &) = delete;
     51   MoveOnlyNT(MoveOnlyNT &&) {}
     52 };
     53 
     54 struct NTCopy {
     55   constexpr NTCopy(int v) : value(v) {}
     56   NTCopy(const NTCopy &that) : value(that.value) {}
     57   NTCopy(NTCopy &&) = delete;
     58   int value;
     59 };
     60 
     61 static_assert(!std::is_trivially_copy_constructible<NTCopy>::value, "");
     62 static_assert(std::is_copy_constructible<NTCopy>::value, "");
     63 
     64 struct TCopy {
     65   constexpr TCopy(int v) : value(v) {}
     66   TCopy(TCopy const &) = default;
     67   TCopy(TCopy &&) = delete;
     68   int value;
     69 };
     70 
     71 static_assert(std::is_trivially_copy_constructible<TCopy>::value, "");
     72 
     73 struct TCopyNTMove {
     74   constexpr TCopyNTMove(int v) : value(v) {}
     75   TCopyNTMove(const TCopyNTMove&) = default;
     76   TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; }
     77   int value;
     78 };
     79 
     80 static_assert(std::is_trivially_copy_constructible<TCopyNTMove>::value, "");
     81 
     82 #ifndef TEST_HAS_NO_EXCEPTIONS
     83 struct MakeEmptyT {
     84   static int alive;
     85   MakeEmptyT() { ++alive; }
     86   MakeEmptyT(const MakeEmptyT &) {
     87     ++alive;
     88     // Don't throw from the copy constructor since variant's assignment
     89     // operator performs a copy before committing to the assignment.
     90   }
     91   MakeEmptyT(MakeEmptyT &&) { throw 42; }
     92   MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; }
     93   MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
     94   ~MakeEmptyT() { --alive; }
     95 };
     96 
     97 int MakeEmptyT::alive = 0;
     98 
     99 template <class Variant> void makeEmpty(Variant &v) {
    100   Variant v2(std::in_place_type<MakeEmptyT>);
    101   try {
    102     v = std::move(v2);
    103     assert(false);
    104   } catch (...) {
    105     assert(v.valueless_by_exception());
    106   }
    107 }
    108 #endif // TEST_HAS_NO_EXCEPTIONS
    109 
    110 void test_copy_ctor_sfinae() {
    111   {
    112     using V = std::variant<int, long>;
    113     static_assert(std::is_copy_constructible<V>::value, "");
    114   }
    115   {
    116     using V = std::variant<int, NoCopy>;
    117     static_assert(!std::is_copy_constructible<V>::value, "");
    118   }
    119   {
    120     using V = std::variant<int, MoveOnly>;
    121     static_assert(!std::is_copy_constructible<V>::value, "");
    122   }
    123   {
    124     using V = std::variant<int, MoveOnlyNT>;
    125     static_assert(!std::is_copy_constructible<V>::value, "");
    126   }
    127 
    128   // The following tests are for not-yet-standardized behavior (P0602):
    129   {
    130     using V = std::variant<int, long>;
    131     static_assert(std::is_trivially_copy_constructible<V>::value, "");
    132   }
    133   {
    134     using V = std::variant<int, NTCopy>;
    135     static_assert(!std::is_trivially_copy_constructible<V>::value, "");
    136     static_assert(std::is_copy_constructible<V>::value, "");
    137   }
    138   {
    139     using V = std::variant<int, TCopy>;
    140     static_assert(std::is_trivially_copy_constructible<V>::value, "");
    141   }
    142   {
    143     using V = std::variant<int, TCopyNTMove>;
    144     static_assert(std::is_trivially_copy_constructible<V>::value, "");
    145   }
    146 }
    147 
    148 void test_copy_ctor_basic() {
    149   {
    150     std::variant<int> v(std::in_place_index<0>, 42);
    151     std::variant<int> v2 = v;
    152     assert(v2.index() == 0);
    153     assert(std::get<0>(v2) == 42);
    154   }
    155   {
    156     std::variant<int, long> v(std::in_place_index<1>, 42);
    157     std::variant<int, long> v2 = v;
    158     assert(v2.index() == 1);
    159     assert(std::get<1>(v2) == 42);
    160   }
    161   {
    162     std::variant<NonT> v(std::in_place_index<0>, 42);
    163     assert(v.index() == 0);
    164     std::variant<NonT> v2(v);
    165     assert(v2.index() == 0);
    166     assert(std::get<0>(v2).value == 42);
    167   }
    168   {
    169     std::variant<int, NonT> v(std::in_place_index<1>, 42);
    170     assert(v.index() == 1);
    171     std::variant<int, NonT> v2(v);
    172     assert(v2.index() == 1);
    173     assert(std::get<1>(v2).value == 42);
    174   }
    175 
    176   // The following tests are for not-yet-standardized behavior (P0602):
    177   {
    178     constexpr std::variant<int> v(std::in_place_index<0>, 42);
    179     static_assert(v.index() == 0, "");
    180     constexpr std::variant<int> v2 = v;
    181     static_assert(v2.index() == 0, "");
    182     static_assert(std::get<0>(v2) == 42, "");
    183   }
    184   {
    185     constexpr std::variant<int, long> v(std::in_place_index<1>, 42);
    186     static_assert(v.index() == 1, "");
    187     constexpr std::variant<int, long> v2 = v;
    188     static_assert(v2.index() == 1, "");
    189     static_assert(std::get<1>(v2) == 42, "");
    190   }
    191   {
    192     constexpr std::variant<TCopy> v(std::in_place_index<0>, 42);
    193     static_assert(v.index() == 0, "");
    194     constexpr std::variant<TCopy> v2(v);
    195     static_assert(v2.index() == 0, "");
    196     static_assert(std::get<0>(v2).value == 42, "");
    197   }
    198   {
    199     constexpr std::variant<int, TCopy> v(std::in_place_index<1>, 42);
    200     static_assert(v.index() == 1, "");
    201     constexpr std::variant<int, TCopy> v2(v);
    202     static_assert(v2.index() == 1, "");
    203     static_assert(std::get<1>(v2).value == 42, "");
    204   }
    205   {
    206     constexpr std::variant<TCopyNTMove> v(std::in_place_index<0>, 42);
    207     static_assert(v.index() == 0, "");
    208     constexpr std::variant<TCopyNTMove> v2(v);
    209     static_assert(v2.index() == 0, "");
    210     static_assert(std::get<0>(v2).value == 42, "");
    211   }
    212   {
    213     constexpr std::variant<int, TCopyNTMove> v(std::in_place_index<1>, 42);
    214     static_assert(v.index() == 1, "");
    215     constexpr std::variant<int, TCopyNTMove> v2(v);
    216     static_assert(v2.index() == 1, "");
    217     static_assert(std::get<1>(v2).value == 42, "");
    218   }
    219 }
    220 
    221 void test_copy_ctor_valueless_by_exception() {
    222 #ifndef TEST_HAS_NO_EXCEPTIONS
    223   using V = std::variant<int, MakeEmptyT>;
    224   V v1;
    225   makeEmpty(v1);
    226   const V &cv1 = v1;
    227   V v(cv1);
    228   assert(v.valueless_by_exception());
    229 #endif // TEST_HAS_NO_EXCEPTIONS
    230 }
    231 
    232 template <size_t Idx>
    233 constexpr bool test_constexpr_copy_ctor_extension_imp(
    234     std::variant<long, void*, const int> const& v)
    235 {
    236   auto v2 = v;
    237   return v2.index() == v.index() &&
    238          v2.index() == Idx &&
    239          std::get<Idx>(v2) == std::get<Idx>(v);
    240 }
    241 
    242 void test_constexpr_copy_ctor_extension() {
    243   // NOTE: This test is for not yet standardized behavior. (P0602)
    244   using V = std::variant<long, void*, const int>;
    245 #ifdef TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
    246   static_assert(std::is_trivially_destructible<V>::value, "");
    247   static_assert(std::is_trivially_copy_constructible<V>::value, "");
    248   static_assert(std::is_trivially_move_constructible<V>::value, "");
    249   static_assert(!std::is_copy_assignable<V>::value, "");
    250   static_assert(!std::is_move_assignable<V>::value, "");
    251 #else // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
    252   static_assert(std::is_trivially_copyable<V>::value, "");
    253 #endif // TEST_WORKAROUND_C1XX_BROKEN_IS_TRIVIALLY_COPYABLE
    254   static_assert(test_constexpr_copy_ctor_extension_imp<0>(V(42l)), "");
    255   static_assert(test_constexpr_copy_ctor_extension_imp<1>(V(nullptr)), "");
    256   static_assert(test_constexpr_copy_ctor_extension_imp<2>(V(101)), "");
    257 }
    258 
    259 int main() {
    260   test_copy_ctor_basic();
    261   test_copy_ctor_valueless_by_exception();
    262   test_copy_ctor_sfinae();
    263   test_constexpr_copy_ctor_extension();
    264 #if 0
    265 // disable this for the moment; it fails on older compilers.
    266 //  Need to figure out which compilers will support it.
    267 { // This is the motivating example from P0739R0
    268   std::variant<int, double> v1(3);
    269   std::variant v2 = v1;
    270   (void) v2;
    271 }
    272 #endif
    273 }
    274