1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | // UNSUPPORTED: c++03, c++11, c++14 |
10 | |
11 | // <variant> |
12 | |
13 | // template <class ...Types> class variant; |
14 | |
15 | // constexpr variant(variant const&); |
16 | |
17 | #include <cassert> |
18 | #include <type_traits> |
19 | #include <variant> |
20 | |
21 | #include "test_macros.h" |
22 | #include "test_workarounds.h" |
23 | |
24 | struct NonT { |
25 | NonT(int v) : value(v) {} |
26 | NonT(const NonT &o) : value(o.value) {} |
27 | int value; |
28 | }; |
29 | static_assert(!std::is_trivially_copy_constructible<NonT>::value, "" ); |
30 | |
31 | struct NoCopy { |
32 | NoCopy(const NoCopy &) = delete; |
33 | }; |
34 | |
35 | struct MoveOnly { |
36 | MoveOnly(const MoveOnly &) = delete; |
37 | MoveOnly(MoveOnly &&) = default; |
38 | }; |
39 | |
40 | struct MoveOnlyNT { |
41 | MoveOnlyNT(const MoveOnlyNT &) = delete; |
42 | MoveOnlyNT(MoveOnlyNT &&) {} |
43 | }; |
44 | |
45 | struct NTCopy { |
46 | constexpr NTCopy(int v) : value(v) {} |
47 | NTCopy(const NTCopy &that) : value(that.value) {} |
48 | NTCopy(NTCopy &&) = delete; |
49 | int value; |
50 | }; |
51 | |
52 | static_assert(!std::is_trivially_copy_constructible<NTCopy>::value, "" ); |
53 | static_assert(std::is_copy_constructible<NTCopy>::value, "" ); |
54 | |
55 | struct TCopy { |
56 | constexpr TCopy(int v) : value(v) {} |
57 | TCopy(TCopy const &) = default; |
58 | TCopy(TCopy &&) = delete; |
59 | int value; |
60 | }; |
61 | |
62 | static_assert(std::is_trivially_copy_constructible<TCopy>::value, "" ); |
63 | |
64 | struct TCopyNTMove { |
65 | constexpr TCopyNTMove(int v) : value(v) {} |
66 | TCopyNTMove(const TCopyNTMove&) = default; |
67 | TCopyNTMove(TCopyNTMove&& that) : value(that.value) { that.value = -1; } |
68 | int value; |
69 | }; |
70 | |
71 | static_assert(std::is_trivially_copy_constructible<TCopyNTMove>::value, "" ); |
72 | |
73 | #ifndef TEST_HAS_NO_EXCEPTIONS |
74 | struct MakeEmptyT { |
75 | static int alive; |
76 | MakeEmptyT() { ++alive; } |
77 | MakeEmptyT(const MakeEmptyT &) { |
78 | ++alive; |
79 | // Don't throw from the copy constructor since variant's assignment |
80 | // operator performs a copy before committing to the assignment. |
81 | } |
82 | MakeEmptyT(MakeEmptyT &&) { throw 42; } |
83 | MakeEmptyT &operator=(const MakeEmptyT &) { throw 42; } |
84 | MakeEmptyT &operator=(MakeEmptyT &&) { throw 42; } |
85 | ~MakeEmptyT() { --alive; } |
86 | }; |
87 | |
88 | int MakeEmptyT::alive = 0; |
89 | |
90 | template <class Variant> void makeEmpty(Variant &v) { |
91 | Variant v2(std::in_place_type<MakeEmptyT>); |
92 | try { |
93 | v = std::move(v2); |
94 | assert(false); |
95 | } catch (...) { |
96 | assert(v.valueless_by_exception()); |
97 | } |
98 | } |
99 | #endif // TEST_HAS_NO_EXCEPTIONS |
100 | |
101 | void test_copy_ctor_sfinae() { |
102 | { |
103 | using V = std::variant<int, long>; |
104 | static_assert(std::is_copy_constructible<V>::value, "" ); |
105 | } |
106 | { |
107 | using V = std::variant<int, NoCopy>; |
108 | static_assert(!std::is_copy_constructible<V>::value, "" ); |
109 | } |
110 | { |
111 | using V = std::variant<int, MoveOnly>; |
112 | static_assert(!std::is_copy_constructible<V>::value, "" ); |
113 | } |
114 | { |
115 | using V = std::variant<int, MoveOnlyNT>; |
116 | static_assert(!std::is_copy_constructible<V>::value, "" ); |
117 | } |
118 | |
119 | // Make sure we properly propagate triviality (see P0602R4). |
120 | { |
121 | using V = std::variant<int, long>; |
122 | static_assert(std::is_trivially_copy_constructible<V>::value, "" ); |
123 | } |
124 | { |
125 | using V = std::variant<int, NTCopy>; |
126 | static_assert(!std::is_trivially_copy_constructible<V>::value, "" ); |
127 | static_assert(std::is_copy_constructible<V>::value, "" ); |
128 | } |
129 | { |
130 | using V = std::variant<int, TCopy>; |
131 | static_assert(std::is_trivially_copy_constructible<V>::value, "" ); |
132 | } |
133 | { |
134 | using V = std::variant<int, TCopyNTMove>; |
135 | static_assert(std::is_trivially_copy_constructible<V>::value, "" ); |
136 | } |
137 | } |
138 | |
139 | void test_copy_ctor_basic() { |
140 | { |
141 | std::variant<int> v(std::in_place_index<0>, 42); |
142 | std::variant<int> v2 = v; |
143 | assert(v2.index() == 0); |
144 | assert(std::get<0>(v2) == 42); |
145 | } |
146 | { |
147 | std::variant<int, long> v(std::in_place_index<1>, 42); |
148 | std::variant<int, long> v2 = v; |
149 | assert(v2.index() == 1); |
150 | assert(std::get<1>(v2) == 42); |
151 | } |
152 | { |
153 | std::variant<NonT> v(std::in_place_index<0>, 42); |
154 | assert(v.index() == 0); |
155 | std::variant<NonT> v2(v); |
156 | assert(v2.index() == 0); |
157 | assert(std::get<0>(v2).value == 42); |
158 | } |
159 | { |
160 | std::variant<int, NonT> v(std::in_place_index<1>, 42); |
161 | assert(v.index() == 1); |
162 | std::variant<int, NonT> v2(v); |
163 | assert(v2.index() == 1); |
164 | assert(std::get<1>(v2).value == 42); |
165 | } |
166 | |
167 | // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). |
168 | { |
169 | constexpr std::variant<int> v(std::in_place_index<0>, 42); |
170 | static_assert(v.index() == 0, "" ); |
171 | constexpr std::variant<int> v2 = v; |
172 | static_assert(v2.index() == 0, "" ); |
173 | static_assert(std::get<0>(v: v2) == 42, "" ); |
174 | } |
175 | { |
176 | constexpr std::variant<int, long> v(std::in_place_index<1>, 42); |
177 | static_assert(v.index() == 1, "" ); |
178 | constexpr std::variant<int, long> v2 = v; |
179 | static_assert(v2.index() == 1, "" ); |
180 | static_assert(std::get<1>(v: v2) == 42, "" ); |
181 | } |
182 | { |
183 | constexpr std::variant<TCopy> v(std::in_place_index<0>, 42); |
184 | static_assert(v.index() == 0, "" ); |
185 | constexpr std::variant<TCopy> v2(v); |
186 | static_assert(v2.index() == 0, "" ); |
187 | static_assert(std::get<0>(v: v2).value == 42, "" ); |
188 | } |
189 | { |
190 | constexpr std::variant<int, TCopy> v(std::in_place_index<1>, 42); |
191 | static_assert(v.index() == 1, "" ); |
192 | constexpr std::variant<int, TCopy> v2(v); |
193 | static_assert(v2.index() == 1, "" ); |
194 | static_assert(std::get<1>(v: v2).value == 42, "" ); |
195 | } |
196 | { |
197 | constexpr std::variant<TCopyNTMove> v(std::in_place_index<0>, 42); |
198 | static_assert(v.index() == 0, "" ); |
199 | constexpr std::variant<TCopyNTMove> v2(v); |
200 | static_assert(v2.index() == 0, "" ); |
201 | static_assert(std::get<0>(v: v2).value == 42, "" ); |
202 | } |
203 | { |
204 | constexpr std::variant<int, TCopyNTMove> v(std::in_place_index<1>, 42); |
205 | static_assert(v.index() == 1, "" ); |
206 | constexpr std::variant<int, TCopyNTMove> v2(v); |
207 | static_assert(v2.index() == 1, "" ); |
208 | static_assert(std::get<1>(v: v2).value == 42, "" ); |
209 | } |
210 | } |
211 | |
212 | void test_copy_ctor_valueless_by_exception() { |
213 | #ifndef TEST_HAS_NO_EXCEPTIONS |
214 | using V = std::variant<int, MakeEmptyT>; |
215 | V v1; |
216 | makeEmpty(v&: v1); |
217 | const V &cv1 = v1; |
218 | V v(cv1); |
219 | assert(v.valueless_by_exception()); |
220 | #endif // TEST_HAS_NO_EXCEPTIONS |
221 | } |
222 | |
223 | template <std::size_t Idx> |
224 | constexpr bool test_constexpr_copy_ctor_imp(std::variant<long, void*, const int> const& v) { |
225 | auto v2 = v; |
226 | return v2.index() == v.index() && |
227 | v2.index() == Idx && |
228 | std::get<Idx>(v2) == std::get<Idx>(v); |
229 | } |
230 | |
231 | void test_constexpr_copy_ctor() { |
232 | // Make sure we properly propagate triviality, which implies constexpr-ness (see P0602R4). |
233 | using V = std::variant<long, void*, const int>; |
234 | #ifdef TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE |
235 | static_assert(std::is_trivially_destructible<V>::value, "" ); |
236 | static_assert(std::is_trivially_copy_constructible<V>::value, "" ); |
237 | static_assert(std::is_trivially_move_constructible<V>::value, "" ); |
238 | static_assert(!std::is_copy_assignable<V>::value, "" ); |
239 | static_assert(!std::is_move_assignable<V>::value, "" ); |
240 | #else // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE |
241 | static_assert(std::is_trivially_copyable<V>::value, "" ); |
242 | #endif // TEST_WORKAROUND_MSVC_BROKEN_IS_TRIVIALLY_COPYABLE |
243 | static_assert(test_constexpr_copy_ctor_imp<0>(v: V(42l)), "" ); |
244 | static_assert(test_constexpr_copy_ctor_imp<1>(v: V(nullptr)), "" ); |
245 | static_assert(test_constexpr_copy_ctor_imp<2>(v: V(101)), "" ); |
246 | } |
247 | |
248 | int main(int, char**) { |
249 | test_copy_ctor_basic(); |
250 | test_copy_ctor_valueless_by_exception(); |
251 | test_copy_ctor_sfinae(); |
252 | test_constexpr_copy_ctor(); |
253 | return 0; |
254 | } |
255 | |