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 ...Types> class variant;
21
22 // template <class T> constexpr variant(T&&) noexcept(see below);
23
24 #include <cassert>
25 #include <string>
26 #include <type_traits>
27 #include <variant>
28 #include <memory>
29
30 #include "test_macros.h"
31 #include "variant_test_helpers.h"
32
33 struct Dummy {
34 Dummy() = default;
35 };
36
37 struct ThrowsT {
ThrowsTThrowsT38 ThrowsT(int) noexcept(false) {}
39 };
40
41 struct NoThrowT {
NoThrowTNoThrowT42 NoThrowT(int) noexcept(true) {}
43 };
44
AnyConstructibleAnyConstructible45 struct AnyConstructible { template <typename T> AnyConstructible(T&&) {} };
46 struct NoConstructible { NoConstructible() = delete; };
47 template <class T>
RValueConvertibleFromRValueConvertibleFrom48 struct RValueConvertibleFrom { RValueConvertibleFrom(T&&) {} };
49
test_T_ctor_noexcept()50 void test_T_ctor_noexcept() {
51 {
52 using V = std::variant<Dummy, NoThrowT>;
53 static_assert(std::is_nothrow_constructible<V, int>::value, "");
54 }
55 {
56 using V = std::variant<Dummy, ThrowsT>;
57 static_assert(!std::is_nothrow_constructible<V, int>::value, "");
58 }
59 }
60
test_T_ctor_sfinae()61 void test_T_ctor_sfinae() {
62 {
63 using V = std::variant<long, long long>;
64 static_assert(!std::is_constructible<V, int>::value, "ambiguous");
65 }
66 {
67 using V = std::variant<std::string, std::string>;
68 static_assert(!std::is_constructible<V, const char *>::value, "ambiguous");
69 }
70 {
71 using V = std::variant<std::string, void *>;
72 static_assert(!std::is_constructible<V, int>::value,
73 "no matching constructor");
74 }
75 {
76 using V = std::variant<std::string, float>;
77 static_assert(std::is_constructible<V, int>::value == VariantAllowsNarrowingConversions,
78 "no matching constructor");
79 }
80 {
81 using V = std::variant<std::unique_ptr<int>, bool>;
82 static_assert(!std::is_constructible<V, std::unique_ptr<char>>::value,
83 "no explicit bool in constructor");
84 struct X {
85 operator void*();
86 };
87 static_assert(!std::is_constructible<V, X>::value,
88 "no boolean conversion in constructor");
89 static_assert(!std::is_constructible<V, std::false_type>::value,
90 "no converted to bool in constructor");
91 }
92 {
93 struct X {};
94 struct Y {
95 operator X();
96 };
97 using V = std::variant<X>;
98 static_assert(std::is_constructible<V, Y>::value,
99 "regression on user-defined conversions in constructor");
100 }
101 {
102 using V = std::variant<AnyConstructible, NoConstructible>;
103 static_assert(
104 !std::is_constructible<V, std::in_place_type_t<NoConstructible>>::value,
105 "no matching constructor");
106 static_assert(!std::is_constructible<V, std::in_place_index_t<1>>::value,
107 "no matching constructor");
108 }
109
110
111
112 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
113 {
114 using V = std::variant<int, int &&>;
115 static_assert(!std::is_constructible<V, int>::value, "ambiguous");
116 }
117 {
118 using V = std::variant<int, const int &>;
119 static_assert(!std::is_constructible<V, int>::value, "ambiguous");
120 }
121 #endif
122 }
123
test_T_ctor_basic()124 void test_T_ctor_basic() {
125 {
126 constexpr std::variant<int> v(42);
127 static_assert(v.index() == 0, "");
128 static_assert(std::get<0>(v) == 42, "");
129 }
130 {
131 constexpr std::variant<int, long> v(42l);
132 static_assert(v.index() == 1, "");
133 static_assert(std::get<1>(v) == 42, "");
134 }
135 #ifndef TEST_VARIANT_ALLOWS_NARROWING_CONVERSIONS
136 {
137 constexpr std::variant<unsigned, long> v(42);
138 static_assert(v.index() == 1, "");
139 static_assert(std::get<1>(v) == 42, "");
140 }
141 #endif
142 {
143 std::variant<std::string, bool const> v = "foo";
144 assert(v.index() == 0);
145 assert(std::get<0>(v) == "foo");
146 }
147 {
148 std::variant<bool volatile, std::unique_ptr<int>> v = nullptr;
149 assert(v.index() == 1);
150 assert(std::get<1>(v) == nullptr);
151 }
152 {
153 std::variant<bool volatile const, int> v = true;
154 assert(v.index() == 0);
155 assert(std::get<0>(v));
156 }
157 {
158 std::variant<RValueConvertibleFrom<int>> v1 = 42;
159 assert(v1.index() == 0);
160
161 int x = 42;
162 std::variant<RValueConvertibleFrom<int>, AnyConstructible> v2 = x;
163 assert(v2.index() == 1);
164 }
165 #if !defined(TEST_VARIANT_HAS_NO_REFERENCES)
166 {
167 using V = std::variant<const int &, int &&, long>;
168 static_assert(std::is_convertible<int &, V>::value, "must be implicit");
169 int x = 42;
170 V v(x);
171 assert(v.index() == 0);
172 assert(&std::get<0>(v) == &x);
173 }
174 {
175 using V = std::variant<const int &, int &&, long>;
176 static_assert(std::is_convertible<int, V>::value, "must be implicit");
177 int x = 42;
178 V v(std::move(x));
179 assert(v.index() == 1);
180 assert(&std::get<1>(v) == &x);
181 }
182 #endif
183 }
184
185 struct BoomOnAnything {
186 template <class T>
BoomOnAnythingBoomOnAnything187 constexpr BoomOnAnything(T) { static_assert(!std::is_same<T, T>::value, ""); }
188 };
189
test_no_narrowing_check_for_class_types()190 void test_no_narrowing_check_for_class_types() {
191 using V = std::variant<int, BoomOnAnything>;
192 V v(42);
193 assert(v.index() == 0);
194 assert(std::get<0>(v) == 42);
195 }
196
197 struct Bar {};
198 struct Baz {};
test_construction_with_repeated_types()199 void test_construction_with_repeated_types() {
200 using V = std::variant<int, Bar, Baz, int, Baz, int, int>;
201 static_assert(!std::is_constructible<V, int>::value, "");
202 static_assert(!std::is_constructible<V, Baz>::value, "");
203 // OK, the selected type appears only once and so it shouldn't
204 // be affected by the duplicate types.
205 static_assert(std::is_constructible<V, Bar>::value, "");
206 }
207
main(int,char **)208 int main(int, char**) {
209 test_T_ctor_basic();
210 test_T_ctor_noexcept();
211 test_T_ctor_sfinae();
212 test_no_narrowing_check_for_class_types();
213 test_construction_with_repeated_types();
214 return 0;
215 }
216