• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // variant(variant&&) noexcept(see below);
18 
19 #include <cassert>
20 #include <string>
21 #include <type_traits>
22 #include <variant>
23 
24 #include "test_macros.h"
25 
26 struct ThrowsMove {
ThrowsMoveThrowsMove27   ThrowsMove(ThrowsMove &&) noexcept(false) {}
28 };
29 
30 struct NoCopy {
31   NoCopy(const NoCopy &) = delete;
32 };
33 
34 struct MoveOnly {
35   int value;
MoveOnlyMoveOnly36   MoveOnly(int v) : value(v) {}
37   MoveOnly(const MoveOnly &) = delete;
38   MoveOnly(MoveOnly &&) = default;
39 };
40 
41 struct MoveOnlyNT {
42   int value;
MoveOnlyNTMoveOnlyNT43   MoveOnlyNT(int v) : value(v) {}
44   MoveOnlyNT(const MoveOnlyNT &) = delete;
MoveOnlyNTMoveOnlyNT45   MoveOnlyNT(MoveOnlyNT &&other) : value(other.value) { other.value = -1; }
46 };
47 
48 #ifndef TEST_HAS_NO_EXCEPTIONS
49 struct MakeEmptyT {
50   static int alive;
MakeEmptyTMakeEmptyT51   MakeEmptyT() { ++alive; }
MakeEmptyTMakeEmptyT52   MakeEmptyT(const MakeEmptyT &) {
53     ++alive;
54     // Don't throw from the copy constructor since variant's assignment
55     // operator performs a copy before committing to the assignment.
56   }
MakeEmptyTMakeEmptyT57   MakeEmptyT(MakeEmptyT &&) { throw 42; }
operator =MakeEmptyT58   MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; }
operator =MakeEmptyT59   MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; }
~MakeEmptyTMakeEmptyT60   ~MakeEmptyT() { --alive; }
61 };
62 
63 int MakeEmptyT::alive = 0;
64 
makeEmpty(Variant & v)65 template <class Variant> void makeEmpty(Variant &v) {
66   Variant v2(std::in_place_type<MakeEmptyT>);
67   try {
68     v = v2;
69     assert(false);
70   } catch (...) {
71     assert(v.valueless_by_exception());
72   }
73 }
74 #endif // TEST_HAS_NO_EXCEPTIONS
75 
test_move_noexcept()76 void test_move_noexcept() {
77   {
78     using V = std::variant<int, long>;
79     static_assert(std::is_nothrow_move_constructible<V>::value, "");
80   }
81   {
82     using V = std::variant<int, MoveOnly>;
83     static_assert(std::is_nothrow_move_constructible<V>::value, "");
84   }
85   {
86     using V = std::variant<int, MoveOnlyNT>;
87     static_assert(!std::is_nothrow_move_constructible<V>::value, "");
88   }
89   {
90     using V = std::variant<int, ThrowsMove>;
91     static_assert(!std::is_nothrow_move_constructible<V>::value, "");
92   }
93 }
94 
test_move_ctor_sfinae()95 void test_move_ctor_sfinae() {
96   {
97     using V = std::variant<int, long>;
98     static_assert(std::is_move_constructible<V>::value, "");
99   }
100   {
101     using V = std::variant<int, MoveOnly>;
102     static_assert(std::is_move_constructible<V>::value, "");
103   }
104   {
105     using V = std::variant<int, MoveOnlyNT>;
106     static_assert(std::is_move_constructible<V>::value, "");
107   }
108   {
109     using V = std::variant<int, NoCopy>;
110     static_assert(!std::is_move_constructible<V>::value, "");
111   }
112 }
113 
test_move_ctor_basic()114 void test_move_ctor_basic() {
115   {
116     std::variant<int> v(std::in_place_index<0>, 42);
117     std::variant<int> v2 = std::move(v);
118     assert(v2.index() == 0);
119     assert(std::get<0>(v2) == 42);
120   }
121   {
122     std::variant<int, long> v(std::in_place_index<1>, 42);
123     std::variant<int, long> v2 = std::move(v);
124     assert(v2.index() == 1);
125     assert(std::get<1>(v2) == 42);
126   }
127   {
128     std::variant<MoveOnly> v(std::in_place_index<0>, 42);
129     assert(v.index() == 0);
130     std::variant<MoveOnly> v2(std::move(v));
131     assert(v2.index() == 0);
132     assert(std::get<0>(v2).value == 42);
133   }
134   {
135     std::variant<int, MoveOnly> v(std::in_place_index<1>, 42);
136     assert(v.index() == 1);
137     std::variant<int, MoveOnly> v2(std::move(v));
138     assert(v2.index() == 1);
139     assert(std::get<1>(v2).value == 42);
140   }
141   {
142     std::variant<MoveOnlyNT> v(std::in_place_index<0>, 42);
143     assert(v.index() == 0);
144     std::variant<MoveOnlyNT> v2(std::move(v));
145     assert(v2.index() == 0);
146     assert(std::get<0>(v).value == -1);
147     assert(std::get<0>(v2).value == 42);
148   }
149   {
150     std::variant<int, MoveOnlyNT> v(std::in_place_index<1>, 42);
151     assert(v.index() == 1);
152     std::variant<int, MoveOnlyNT> v2(std::move(v));
153     assert(v2.index() == 1);
154     assert(std::get<1>(v).value == -1);
155     assert(std::get<1>(v2).value == 42);
156   }
157 }
158 
test_move_ctor_valueless_by_exception()159 void test_move_ctor_valueless_by_exception() {
160 #ifndef TEST_HAS_NO_EXCEPTIONS
161   using V = std::variant<int, MakeEmptyT>;
162   V v1;
163   makeEmpty(v1);
164   V v(std::move(v1));
165   assert(v.valueless_by_exception());
166 #endif
167 }
168 
169 template <size_t Idx>
test_constexpr_ctor_extension_imp(std::variant<long,void *,const int> const & v)170 constexpr bool test_constexpr_ctor_extension_imp(
171     std::variant<long, void*, const int> const& v)
172 {
173   auto copy = v;
174   auto v2 = std::move(copy);
175   return v2.index() == v.index() &&
176          v2.index() == Idx &&
177         std::get<Idx>(v2) == std::get<Idx>(v);
178 }
179 
test_constexpr_move_ctor_extension()180 void test_constexpr_move_ctor_extension() {
181 #ifdef _LIBCPP_VERSION
182   using V = std::variant<long, void*, const int>;
183   static_assert(std::is_trivially_copyable<V>::value, "");
184   static_assert(std::is_trivially_move_constructible<V>::value, "");
185   static_assert(test_constexpr_ctor_extension_imp<0>(V(42l)), "");
186   static_assert(test_constexpr_ctor_extension_imp<1>(V(nullptr)), "");
187   static_assert(test_constexpr_ctor_extension_imp<2>(V(101)), "");
188 #endif
189 }
190 
main()191 int main() {
192   test_move_ctor_basic();
193   test_move_ctor_valueless_by_exception();
194   test_move_noexcept();
195   test_move_ctor_sfinae();
196   test_constexpr_move_ctor_extension();
197 }
198