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 // <optional> 12 13 // From LWG2451: 14 // template <class U> 15 // optional<T>& operator=(optional<U>&& rhs); 16 17 #include <optional> 18 #include <type_traits> 19 #include <memory> 20 #include <cassert> 21 22 #include "test_macros.h" 23 #include "archetypes.hpp" 24 25 using std::optional; 26 27 struct X 28 { 29 static bool throw_now; 30 31 X() = default; 32 X(int &&) 33 { 34 if (throw_now) 35 TEST_THROW(6); 36 } 37 }; 38 39 bool X::throw_now = false; 40 41 struct Y1 42 { 43 Y1() = default; 44 Y1(const int&) {} 45 Y1& operator=(const Y1&) = delete; 46 }; 47 48 struct Y2 49 { 50 Y2() = default; 51 Y2(const int&) = delete; 52 Y2& operator=(const int&) { return *this; } 53 }; 54 55 class B {}; 56 class D : public B {}; 57 58 59 template <class T> 60 struct AssignableFrom { 61 static int type_constructed; 62 static int type_assigned; 63 static int int_constructed; 64 static int int_assigned; 65 66 static void reset() { 67 type_constructed = int_constructed = 0; 68 type_assigned = int_assigned = 0; 69 } 70 71 AssignableFrom() = default; 72 73 explicit AssignableFrom(T) { ++type_constructed; } 74 AssignableFrom& operator=(T) { ++type_assigned; return *this; } 75 76 AssignableFrom(int) { ++int_constructed; } 77 AssignableFrom& operator=(int) { ++int_assigned; return *this; } 78 private: 79 AssignableFrom(AssignableFrom const&) = delete; 80 AssignableFrom& operator=(AssignableFrom const&) = delete; 81 }; 82 83 template <class T> int AssignableFrom<T>::type_constructed = 0; 84 template <class T> int AssignableFrom<T>::type_assigned = 0; 85 template <class T> int AssignableFrom<T>::int_constructed = 0; 86 template <class T> int AssignableFrom<T>::int_assigned = 0; 87 88 void test_with_test_type() { 89 using T = TestTypes::TestType; 90 T::reset(); 91 { // non-empty to empty 92 T::reset_constructors(); 93 optional<T> opt; 94 optional<int> other(42); 95 opt = std::move(other); 96 assert(T::alive == 1); 97 assert(T::constructed == 1); 98 assert(T::value_constructed == 1); 99 assert(T::assigned == 0); 100 assert(T::destroyed == 0); 101 assert(static_cast<bool>(other) == true); 102 assert(*other == 42); 103 assert(static_cast<bool>(opt) == true); 104 assert(*opt == T(42)); 105 } 106 assert(T::alive == 0); 107 { // non-empty to non-empty 108 optional<T> opt(101); 109 optional<int> other(42); 110 T::reset_constructors(); 111 opt = std::move(other); 112 assert(T::alive == 1); 113 assert(T::constructed == 0); 114 assert(T::assigned == 1); 115 assert(T::value_assigned == 1); 116 assert(T::destroyed == 0); 117 assert(static_cast<bool>(other) == true); 118 assert(*other == 42); 119 assert(static_cast<bool>(opt) == true); 120 assert(*opt == T(42)); 121 } 122 assert(T::alive == 0); 123 { // empty to non-empty 124 optional<T> opt(101); 125 optional<int> other; 126 T::reset_constructors(); 127 opt = std::move(other); 128 assert(T::alive == 0); 129 assert(T::constructed == 0); 130 assert(T::assigned == 0); 131 assert(T::destroyed == 1); 132 assert(static_cast<bool>(other) == false); 133 assert(static_cast<bool>(opt) == false); 134 } 135 assert(T::alive == 0); 136 { // empty to empty 137 optional<T> opt; 138 optional<int> other; 139 T::reset_constructors(); 140 opt = std::move(other); 141 assert(T::alive == 0); 142 assert(T::constructed == 0); 143 assert(T::assigned == 0); 144 assert(T::destroyed == 0); 145 assert(static_cast<bool>(other) == false); 146 assert(static_cast<bool>(opt) == false); 147 } 148 assert(T::alive == 0); 149 } 150 151 152 void test_ambigious_assign() { 153 using OptInt = std::optional<int>; 154 { 155 using T = AssignableFrom<OptInt&&>; 156 T::reset(); 157 { 158 OptInt a(42); 159 std::optional<T> t; 160 t = std::move(a); 161 assert(T::type_constructed == 1); 162 assert(T::type_assigned == 0); 163 assert(T::int_constructed == 0); 164 assert(T::int_assigned == 0); 165 } 166 { 167 using Opt = std::optional<T>; 168 static_assert(!std::is_assignable<Opt&, const OptInt&&>::value, ""); 169 static_assert(!std::is_assignable<Opt&, const OptInt&>::value, ""); 170 static_assert(!std::is_assignable<Opt&, OptInt&>::value, ""); 171 } 172 } 173 { 174 using T = AssignableFrom<OptInt const&&>; 175 T::reset(); 176 { 177 const OptInt a(42); 178 std::optional<T> t; 179 t = std::move(a); 180 assert(T::type_constructed == 1); 181 assert(T::type_assigned == 0); 182 assert(T::int_constructed == 0); 183 assert(T::int_assigned == 0); 184 } 185 T::reset(); 186 { 187 OptInt a(42); 188 std::optional<T> t; 189 t = std::move(a); 190 assert(T::type_constructed == 1); 191 assert(T::type_assigned == 0); 192 assert(T::int_constructed == 0); 193 assert(T::int_assigned == 0); 194 } 195 { 196 using Opt = std::optional<T>; 197 static_assert(std::is_assignable<Opt&, OptInt&&>::value, ""); 198 static_assert(!std::is_assignable<Opt&, const OptInt&>::value, ""); 199 static_assert(!std::is_assignable<Opt&, OptInt&>::value, ""); 200 } 201 } 202 } 203 204 205 int main() 206 { 207 test_with_test_type(); 208 test_ambigious_assign(); 209 { 210 optional<int> opt; 211 optional<short> opt2; 212 opt = std::move(opt2); 213 assert(static_cast<bool>(opt2) == false); 214 assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); 215 } 216 { 217 optional<int> opt; 218 optional<short> opt2(short{2}); 219 opt = std::move(opt2); 220 assert(static_cast<bool>(opt2) == true); 221 assert(*opt2 == 2); 222 assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); 223 assert(*opt == *opt2); 224 } 225 { 226 optional<int> opt(3); 227 optional<short> opt2; 228 opt = std::move(opt2); 229 assert(static_cast<bool>(opt2) == false); 230 assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); 231 } 232 { 233 optional<int> opt(3); 234 optional<short> opt2(short{2}); 235 opt = std::move(opt2); 236 assert(static_cast<bool>(opt2) == true); 237 assert(*opt2 == 2); 238 assert(static_cast<bool>(opt) == static_cast<bool>(opt2)); 239 assert(*opt == *opt2); 240 } 241 { 242 optional<std::unique_ptr<B>> opt; 243 optional<std::unique_ptr<D>> other(new D()); 244 opt = std::move(other); 245 assert(static_cast<bool>(opt) == true); 246 assert(static_cast<bool>(other) == true); 247 assert(opt->get() != nullptr); 248 assert(other->get() == nullptr); 249 } 250 #ifndef TEST_HAS_NO_EXCEPTIONS 251 { 252 optional<X> opt; 253 optional<int> opt2(42); 254 assert(static_cast<bool>(opt2) == true); 255 try 256 { 257 X::throw_now = true; 258 opt = std::move(opt2); 259 assert(false); 260 } 261 catch (int i) 262 { 263 assert(i == 6); 264 assert(static_cast<bool>(opt) == false); 265 } 266 } 267 #endif 268 } 269