1// -*- C++ -*- 2//===----------------------------------------------------------------------===// 3// 4// The LLVM Compiler Infrastructure 5// 6// This file is dual licensed under the MIT and the University of Illinois Open 7// Source Licenses. See LICENSE.TXT for details. 8// 9//===----------------------------------------------------------------------===// 10 11// UNSUPPORTED: c++98, c++03, c++11, c++14 12 13// XFAIL: with_system_cxx_lib=macosx10.12 14// XFAIL: with_system_cxx_lib=macosx10.11 15// XFAIL: with_system_cxx_lib=macosx10.10 16// XFAIL: with_system_cxx_lib=macosx10.9 17// XFAIL: with_system_cxx_lib=macosx10.7 18// XFAIL: with_system_cxx_lib=macosx10.8 19 20// <variant> 21 22// template <class ...Types> class variant; 23 24// template <class T> 25// variant& operator=(T&&) noexcept(see below); 26 27#include <cassert> 28#include <string> 29#include <type_traits> 30#include <variant> 31 32#include "test_macros.h" 33#include "variant_test_helpers.hpp" 34 35namespace MetaHelpers { 36 37struct Dummy { 38 Dummy() = default; 39}; 40 41struct ThrowsCtorT { 42 ThrowsCtorT(int) noexcept(false) {} 43 ThrowsCtorT &operator=(int) noexcept { return *this; } 44}; 45 46struct ThrowsAssignT { 47 ThrowsAssignT(int) noexcept {} 48 ThrowsAssignT &operator=(int) noexcept(false) { return *this; } 49}; 50 51struct NoThrowT { 52 NoThrowT(int) noexcept {} 53 NoThrowT &operator=(int) noexcept { return *this; } 54}; 55 56} // namespace MetaHelpers 57 58namespace RuntimeHelpers { 59#ifndef TEST_HAS_NO_EXCEPTIONS 60 61struct ThrowsCtorT { 62 int value; 63 ThrowsCtorT() : value(0) {} 64 ThrowsCtorT(int) noexcept(false) { throw 42; } 65 ThrowsCtorT &operator=(int v) noexcept { 66 value = v; 67 return *this; 68 } 69}; 70 71struct MoveCrashes { 72 int value; 73 MoveCrashes(int v = 0) noexcept : value{v} {} 74 MoveCrashes(MoveCrashes &&) noexcept { assert(false); } 75 MoveCrashes &operator=(MoveCrashes &&) noexcept { assert(false); return *this; } 76 MoveCrashes &operator=(int v) noexcept { 77 value = v; 78 return *this; 79 } 80}; 81 82struct ThrowsCtorTandMove { 83 int value; 84 ThrowsCtorTandMove() : value(0) {} 85 ThrowsCtorTandMove(int) noexcept(false) { throw 42; } 86 ThrowsCtorTandMove(ThrowsCtorTandMove &&) noexcept(false) { assert(false); } 87 ThrowsCtorTandMove &operator=(int v) noexcept { 88 value = v; 89 return *this; 90 } 91}; 92 93struct ThrowsAssignT { 94 int value; 95 ThrowsAssignT() : value(0) {} 96 ThrowsAssignT(int v) noexcept : value(v) {} 97 ThrowsAssignT &operator=(int) noexcept(false) { throw 42; } 98}; 99 100struct NoThrowT { 101 int value; 102 NoThrowT() : value(0) {} 103 NoThrowT(int v) noexcept : value(v) {} 104 NoThrowT &operator=(int v) noexcept { 105 value = v; 106 return *this; 107 } 108}; 109 110#endif // !defined(TEST_HAS_NO_EXCEPTIONS) 111} // namespace RuntimeHelpers 112 113void test_T_assignment_noexcept() { 114 using namespace MetaHelpers; 115 { 116 using V = std::variant<Dummy, NoThrowT>; 117 static_assert(std::is_nothrow_assignable<V, int>::value, ""); 118 } 119 { 120 using V = std::variant<Dummy, ThrowsCtorT>; 121 static_assert(!std::is_nothrow_assignable<V, int>::value, ""); 122 } 123 { 124 using V = std::variant<Dummy, ThrowsAssignT>; 125 static_assert(!std::is_nothrow_assignable<V, int>::value, ""); 126 } 127} 128 129void test_T_assignment_sfinae() { 130 { 131 using V = std::variant<long, unsigned>; 132 static_assert(!std::is_assignable<V, int>::value, "ambiguous"); 133 } 134 { 135 using V = std::variant<std::string, std::string>; 136 static_assert(!std::is_assignable<V, const char *>::value, "ambiguous"); 137 } 138 { 139 using V = std::variant<std::string, void *>; 140 static_assert(!std::is_assignable<V, int>::value, "no matching operator="); 141 } 142#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) 143 { 144 using V = std::variant<int, int &&>; 145 static_assert(!std::is_assignable<V, int>::value, "ambiguous"); 146 } 147 { 148 using V = std::variant<int, const int &>; 149 static_assert(!std::is_assignable<V, int>::value, "ambiguous"); 150 } 151#endif // TEST_VARIANT_HAS_NO_REFERENCES 152} 153 154void test_T_assignment_basic() { 155 { 156 std::variant<int> v(43); 157 v = 42; 158 assert(v.index() == 0); 159 assert(std::get<0>(v) == 42); 160 } 161 { 162 std::variant<int, long> v(43l); 163 v = 42; 164 assert(v.index() == 0); 165 assert(std::get<0>(v) == 42); 166 v = 43l; 167 assert(v.index() == 1); 168 assert(std::get<1>(v) == 43); 169 } 170#if !defined(TEST_VARIANT_HAS_NO_REFERENCES) 171 { 172 using V = std::variant<int &, int &&, long>; 173 int x = 42; 174 V v(43l); 175 v = x; 176 assert(v.index() == 0); 177 assert(&std::get<0>(v) == &x); 178 v = std::move(x); 179 assert(v.index() == 1); 180 assert(&std::get<1>(v) == &x); 181 // 'long' is selected by FUN(const int &) since 'const int &' cannot bind 182 // to 'int&'. 183 const int &cx = x; 184 v = cx; 185 assert(v.index() == 2); 186 assert(std::get<2>(v) == 42); 187 } 188#endif // TEST_VARIANT_HAS_NO_REFERENCES 189} 190 191void test_T_assignment_performs_construction() { 192 using namespace RuntimeHelpers; 193#ifndef TEST_HAS_NO_EXCEPTIONS 194 { 195 using V = std::variant<std::string, ThrowsCtorT>; 196 V v(std::in_place_type<std::string>, "hello"); 197 try { 198 v = 42; 199 assert(false); 200 } catch (...) { /* ... */ 201 } 202 assert(v.index() == 0); 203 assert(std::get<0>(v) == "hello"); 204 } 205 { 206 using V = std::variant<ThrowsAssignT, std::string>; 207 V v(std::in_place_type<std::string>, "hello"); 208 v = 42; 209 assert(v.index() == 0); 210 assert(std::get<0>(v).value == 42); 211 } 212#endif // TEST_HAS_NO_EXCEPTIONS 213} 214 215void test_T_assignment_performs_assignment() { 216 using namespace RuntimeHelpers; 217#ifndef TEST_HAS_NO_EXCEPTIONS 218 { 219 using V = std::variant<ThrowsCtorT>; 220 V v; 221 v = 42; 222 assert(v.index() == 0); 223 assert(std::get<0>(v).value == 42); 224 } 225 { 226 using V = std::variant<ThrowsCtorT, std::string>; 227 V v; 228 v = 42; 229 assert(v.index() == 0); 230 assert(std::get<0>(v).value == 42); 231 } 232 { 233 using V = std::variant<ThrowsAssignT>; 234 V v(100); 235 try { 236 v = 42; 237 assert(false); 238 } catch (...) { /* ... */ 239 } 240 assert(v.index() == 0); 241 assert(std::get<0>(v).value == 100); 242 } 243 { 244 using V = std::variant<std::string, ThrowsAssignT>; 245 V v(100); 246 try { 247 v = 42; 248 assert(false); 249 } catch (...) { /* ... */ 250 } 251 assert(v.index() == 1); 252 assert(std::get<1>(v).value == 100); 253 } 254#endif // TEST_HAS_NO_EXCEPTIONS 255} 256 257int main() { 258 test_T_assignment_basic(); 259 test_T_assignment_performs_construction(); 260 test_T_assignment_performs_assignment(); 261 test_T_assignment_noexcept(); 262 test_T_assignment_sfinae(); 263} 264