1 //===----------------------------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is dual licensed under the MIT and the University of Illinois Open 6 // Source Licenses. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // UNSUPPORTED: c++98, c++03, c++11, c++14 11 12 // <any> 13 14 // template <class ValueType> 15 // any& operator=(ValueType&&); 16 17 // Test value copy and move assignment. 18 19 #include <any> 20 #include <cassert> 21 22 #include "any_helpers.h" 23 #include "count_new.hpp" 24 #include "test_macros.h" 25 26 using std::any; 27 using std::any_cast; 28 29 template <class LHS, class RHS> 30 void test_assign_value() { 31 assert(LHS::count == 0); 32 assert(RHS::count == 0); 33 LHS::reset(); 34 RHS::reset(); 35 { 36 any lhs(LHS(1)); 37 any const rhs(RHS(2)); 38 39 assert(LHS::count == 1); 40 assert(RHS::count == 1); 41 assert(RHS::copied == 0); 42 43 lhs = rhs; 44 45 assert(RHS::copied == 1); 46 assert(LHS::count == 0); 47 assert(RHS::count == 2); 48 49 assertContains<RHS>(lhs, 2); 50 assertContains<RHS>(rhs, 2); 51 } 52 assert(LHS::count == 0); 53 assert(RHS::count == 0); 54 LHS::reset(); 55 RHS::reset(); 56 { 57 any lhs(LHS(1)); 58 any rhs(RHS(2)); 59 60 assert(LHS::count == 1); 61 assert(RHS::count == 1); 62 assert(RHS::moved == 1); 63 64 lhs = std::move(rhs); 65 66 assert(RHS::moved >= 1); 67 assert(RHS::copied == 0); 68 assert(LHS::count == 0); 69 assert(RHS::count == 1 + rhs.has_value()); 70 LIBCPP_ASSERT(!rhs.has_value()); 71 72 assertContains<RHS>(lhs, 2); 73 if (rhs.has_value()) 74 assertContains<RHS>(rhs, 0); 75 } 76 assert(LHS::count == 0); 77 assert(RHS::count == 0); 78 } 79 80 template <class RHS> 81 void test_assign_value_empty() { 82 assert(RHS::count == 0); 83 RHS::reset(); 84 { 85 any lhs; 86 RHS rhs(42); 87 assert(RHS::count == 1); 88 assert(RHS::copied == 0); 89 90 lhs = rhs; 91 92 assert(RHS::count == 2); 93 assert(RHS::copied == 1); 94 assert(RHS::moved >= 0); 95 assertContains<RHS>(lhs, 42); 96 } 97 assert(RHS::count == 0); 98 RHS::reset(); 99 { 100 any lhs; 101 RHS rhs(42); 102 assert(RHS::count == 1); 103 assert(RHS::moved == 0); 104 105 lhs = std::move(rhs); 106 107 assert(RHS::count == 2); 108 assert(RHS::copied == 0); 109 assert(RHS::moved >= 1); 110 assertContains<RHS>(lhs, 42); 111 } 112 assert(RHS::count == 0); 113 RHS::reset(); 114 } 115 116 117 template <class Tp, bool Move = false> 118 void test_assign_throws() { 119 #if !defined(TEST_HAS_NO_EXCEPTIONS) 120 auto try_throw = 121 [](any& lhs, auto&& rhs) { 122 try { 123 Move ? lhs = std::move(rhs) 124 : lhs = rhs; 125 assert(false); 126 } catch (my_any_exception const &) { 127 // do nothing 128 } catch (...) { 129 assert(false); 130 } 131 }; 132 // const lvalue to empty 133 { 134 any lhs; 135 Tp rhs(1); 136 assert(Tp::count == 1); 137 138 try_throw(lhs, rhs); 139 140 assert(Tp::count == 1); 141 assertEmpty<Tp>(lhs); 142 } 143 { 144 any lhs((small(2))); 145 Tp rhs(1); 146 assert(small::count == 1); 147 assert(Tp::count == 1); 148 149 try_throw(lhs, rhs); 150 151 assert(small::count == 1); 152 assert(Tp::count == 1); 153 assertContains<small>(lhs, 2); 154 } 155 { 156 any lhs((large(2))); 157 Tp rhs(1); 158 assert(large::count == 1); 159 assert(Tp::count == 1); 160 161 try_throw(lhs, rhs); 162 163 assert(large::count == 1); 164 assert(Tp::count == 1); 165 assertContains<large>(lhs, 2); 166 } 167 #endif 168 } 169 170 171 // Test that any& operator=(ValueType&&) is *never* selected for: 172 // * std::in_place type. 173 // * Non-copyable types 174 void test_sfinae_constraints() { 175 { // Only the constructors are required to SFINAE on in_place_t 176 using Tag = std::in_place_type_t<int>; 177 using RawTag = std::remove_reference_t<Tag>; 178 static_assert(std::is_assignable<std::any, RawTag&&>::value, ""); 179 } 180 { 181 struct Dummy { Dummy() = delete; }; 182 using T = std::in_place_type_t<Dummy>; 183 static_assert(std::is_assignable<std::any, T>::value, ""); 184 } 185 { 186 // Test that the ValueType&& constructor SFINAE's away when the 187 // argument is non-copyable 188 struct NoCopy { 189 NoCopy() = default; 190 NoCopy(NoCopy const&) = delete; 191 NoCopy(NoCopy&&) = default; 192 }; 193 static_assert(!std::is_assignable<std::any, NoCopy>::value, ""); 194 static_assert(!std::is_assignable<std::any, NoCopy&>::value, ""); 195 } 196 } 197 198 int main() { 199 test_assign_value<small1, small2>(); 200 test_assign_value<large1, large2>(); 201 test_assign_value<small, large>(); 202 test_assign_value<large, small>(); 203 test_assign_value_empty<small>(); 204 test_assign_value_empty<large>(); 205 test_assign_throws<small_throws_on_copy>(); 206 test_assign_throws<large_throws_on_copy>(); 207 test_assign_throws<throws_on_move, /* Move = */ true>(); 208 test_sfinae_constraints(); 209 } 210