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