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