1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // UNSUPPORTED: c++03, c++11, c++14
11 
12 // Throwing bad_variant_access is supported starting in macosx10.13
13 // XFAIL: with_system_cxx_lib=macosx10.12 && !no-exceptions
14 // XFAIL: with_system_cxx_lib=macosx10.11 && !no-exceptions
15 // XFAIL: with_system_cxx_lib=macosx10.10 && !no-exceptions
16 // XFAIL: with_system_cxx_lib=macosx10.9 && !no-exceptions
17 
18 // <variant>
19 
20 // template <class T, class... Types> constexpr T& get(variant<Types...>& v);
21 // template <class T, class... Types> constexpr T&& get(variant<Types...>&& v);
22 // template <class T, class... Types> constexpr const T& get(const
23 // variant<Types...>& v);
24 // template <class T, class... Types> constexpr const T&& get(const
25 // variant<Types...>&& v);
26 
27 #include "test_macros.h"
28 #include "test_workarounds.h"
29 #include "variant_test_helpers.h"
30 #include <cassert>
31 #include <type_traits>
32 #include <utility>
33 #include <variant>
34 
test_const_lvalue_get()35 void test_const_lvalue_get() {
36   {
37     using V = std::variant<int, const long>;
38     constexpr V v(42);
39 #ifdef TEST_WORKAROUND_CONSTEXPR_IMPLIES_NOEXCEPT
40     ASSERT_NOEXCEPT(std::get<int>(v));
41 #else
42     ASSERT_NOT_NOEXCEPT(std::get<int>(v));
43 #endif
44     ASSERT_SAME_TYPE(decltype(std::get<int>(v)), const int &);
45     static_assert(std::get<int>(v) == 42, "");
46   }
47   {
48     using V = std::variant<int, const long>;
49     const V v(42);
50     ASSERT_NOT_NOEXCEPT(std::get<int>(v));
51     ASSERT_SAME_TYPE(decltype(std::get<int>(v)), const int &);
52     assert(std::get<int>(v) == 42);
53   }
54   {
55     using V = std::variant<int, const long>;
56     constexpr V v(42l);
57 #ifdef TEST_WORKAROUND_CONSTEXPR_IMPLIES_NOEXCEPT
58     ASSERT_NOEXCEPT(std::get<const long>(v));
59 #else
60     ASSERT_NOT_NOEXCEPT(std::get<const long>(v));
61 #endif
62     ASSERT_SAME_TYPE(decltype(std::get<const long>(v)), const long &);
63     static_assert(std::get<const long>(v) == 42, "");
64   }
65   {
66     using V = std::variant<int, const long>;
67     const V v(42l);
68     ASSERT_NOT_NOEXCEPT(std::get<const long>(v));
69     ASSERT_SAME_TYPE(decltype(std::get<const long>(v)), const long &);
70     assert(std::get<const long>(v) == 42);
71   }
72 // FIXME: Remove these once reference support is reinstated
73 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
74   {
75     using V = std::variant<int &>;
76     int x = 42;
77     const V v(x);
78     ASSERT_SAME_TYPE(decltype(std::get<int &>(v)), int &);
79     assert(&std::get<int &>(v) == &x);
80   }
81   {
82     using V = std::variant<int &&>;
83     int x = 42;
84     const V v(std::move(x));
85     ASSERT_SAME_TYPE(decltype(std::get<int &&>(v)), int &);
86     assert(&std::get<int &&>(v) == &x);
87   }
88   {
89     using V = std::variant<const int &&>;
90     int x = 42;
91     const V v(std::move(x));
92     ASSERT_SAME_TYPE(decltype(std::get<const int &&>(v)), const int &);
93     assert(&std::get<const int &&>(v) == &x);
94   }
95 #endif
96 }
97 
test_lvalue_get()98 void test_lvalue_get() {
99   {
100     using V = std::variant<int, const long>;
101     V v(42);
102     ASSERT_NOT_NOEXCEPT(std::get<int>(v));
103     ASSERT_SAME_TYPE(decltype(std::get<int>(v)), int &);
104     assert(std::get<int>(v) == 42);
105   }
106   {
107     using V = std::variant<int, const long>;
108     V v(42l);
109     ASSERT_SAME_TYPE(decltype(std::get<const long>(v)), const long &);
110     assert(std::get<const long>(v) == 42);
111   }
112 // FIXME: Remove these once reference support is reinstated
113 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
114   {
115     using V = std::variant<int &>;
116     int x = 42;
117     V v(x);
118     ASSERT_SAME_TYPE(decltype(std::get<int &>(v)), int &);
119     assert(&std::get<int &>(v) == &x);
120   }
121   {
122     using V = std::variant<const int &>;
123     int x = 42;
124     V v(x);
125     ASSERT_SAME_TYPE(decltype(std::get<const int &>(v)), const int &);
126     assert(&std::get<const int &>(v) == &x);
127   }
128   {
129     using V = std::variant<int &&>;
130     int x = 42;
131     V v(std::move(x));
132     ASSERT_SAME_TYPE(decltype(std::get<int &&>(v)), int &);
133     assert(&std::get<int &&>(v) == &x);
134   }
135   {
136     using V = std::variant<const int &&>;
137     int x = 42;
138     V v(std::move(x));
139     ASSERT_SAME_TYPE(decltype(std::get<const int &&>(v)), const int &);
140     assert(&std::get<const int &&>(v) == &x);
141   }
142 #endif
143 }
144 
test_rvalue_get()145 void test_rvalue_get() {
146   {
147     using V = std::variant<int, const long>;
148     V v(42);
149     ASSERT_NOT_NOEXCEPT(std::get<int>(std::move(v)));
150     ASSERT_SAME_TYPE(decltype(std::get<int>(std::move(v))), int &&);
151     assert(std::get<int>(std::move(v)) == 42);
152   }
153   {
154     using V = std::variant<int, const long>;
155     V v(42l);
156     ASSERT_SAME_TYPE(decltype(std::get<const long>(std::move(v))),
157                      const long &&);
158     assert(std::get<const long>(std::move(v)) == 42);
159   }
160 // FIXME: Remove these once reference support is reinstated
161 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
162   {
163     using V = std::variant<int &>;
164     int x = 42;
165     V v(x);
166     ASSERT_SAME_TYPE(decltype(std::get<int &>(std::move(v))), int &);
167     assert(&std::get<int &>(std::move(v)) == &x);
168   }
169   {
170     using V = std::variant<const int &>;
171     int x = 42;
172     V v(x);
173     ASSERT_SAME_TYPE(decltype(std::get<const int &>(std::move(v))),
174                      const int &);
175     assert(&std::get<const int &>(std::move(v)) == &x);
176   }
177   {
178     using V = std::variant<int &&>;
179     int x = 42;
180     V v(std::move(x));
181     ASSERT_SAME_TYPE(decltype(std::get<int &&>(std::move(v))), int &&);
182     int &&xref = std::get<int &&>(std::move(v));
183     assert(&xref == &x);
184   }
185   {
186     using V = std::variant<const int &&>;
187     int x = 42;
188     V v(std::move(x));
189     ASSERT_SAME_TYPE(decltype(std::get<const int &&>(std::move(v))),
190                      const int &&);
191     const int &&xref = std::get<const int &&>(std::move(v));
192     assert(&xref == &x);
193   }
194 #endif
195 }
196 
test_const_rvalue_get()197 void test_const_rvalue_get() {
198   {
199     using V = std::variant<int, const long>;
200     const V v(42);
201     ASSERT_NOT_NOEXCEPT(std::get<int>(std::move(v)));
202     ASSERT_SAME_TYPE(decltype(std::get<int>(std::move(v))), const int &&);
203     assert(std::get<int>(std::move(v)) == 42);
204   }
205   {
206     using V = std::variant<int, const long>;
207     const V v(42l);
208     ASSERT_SAME_TYPE(decltype(std::get<const long>(std::move(v))),
209                      const long &&);
210     assert(std::get<const long>(std::move(v)) == 42);
211   }
212 // FIXME: Remove these once reference support is reinstated
213 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
214   {
215     using V = std::variant<int &>;
216     int x = 42;
217     const V v(x);
218     ASSERT_SAME_TYPE(decltype(std::get<int &>(std::move(v))), int &);
219     assert(&std::get<int &>(std::move(v)) == &x);
220   }
221   {
222     using V = std::variant<const int &>;
223     int x = 42;
224     const V v(x);
225     ASSERT_SAME_TYPE(decltype(std::get<const int &>(std::move(v))),
226                      const int &);
227     assert(&std::get<const int &>(std::move(v)) == &x);
228   }
229   {
230     using V = std::variant<int &&>;
231     int x = 42;
232     const V v(std::move(x));
233     ASSERT_SAME_TYPE(decltype(std::get<int &&>(std::move(v))), int &&);
234     int &&xref = std::get<int &&>(std::move(v));
235     assert(&xref == &x);
236   }
237   {
238     using V = std::variant<const int &&>;
239     int x = 42;
240     const V v(std::move(x));
241     ASSERT_SAME_TYPE(decltype(std::get<const int &&>(std::move(v))),
242                      const int &&);
243     const int &&xref = std::get<const int &&>(std::move(v));
244     assert(&xref == &x);
245   }
246 #endif
247 }
248 
249 template <class Tp> struct identity { using type = Tp; };
250 
test_throws_for_all_value_categories()251 void test_throws_for_all_value_categories() {
252 #ifndef TEST_HAS_NO_EXCEPTIONS
253   using V = std::variant<int, long>;
254   V v0(42);
255   const V &cv0 = v0;
256   assert(v0.index() == 0);
257   V v1(42l);
258   const V &cv1 = v1;
259   assert(v1.index() == 1);
260   identity<int> zero;
261   identity<long> one;
262   auto test = [](auto idx, auto &&v) {
263     using Idx = decltype(idx);
264     try {
265       TEST_IGNORE_NODISCARD std::get<typename Idx::type>(std::forward<decltype(v)>(v));
266     } catch (const std::bad_variant_access &) {
267       return true;
268     } catch (...) { /* ... */
269     }
270     return false;
271   };
272   { // lvalue test cases
273     assert(test(one, v0));
274     assert(test(zero, v1));
275   }
276   { // const lvalue test cases
277     assert(test(one, cv0));
278     assert(test(zero, cv1));
279   }
280   { // rvalue test cases
281     assert(test(one, std::move(v0)));
282     assert(test(zero, std::move(v1)));
283   }
284   { // const rvalue test cases
285     assert(test(one, std::move(cv0)));
286     assert(test(zero, std::move(cv1)));
287   }
288 #endif
289 }
290 
main(int,char **)291 int main(int, char**) {
292   test_const_lvalue_get();
293   test_lvalue_get();
294   test_rvalue_get();
295   test_const_rvalue_get();
296   test_throws_for_all_value_categories();
297 
298   return 0;
299 }
300