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