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