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