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++03, c++11, c++14 10 // <optional> 11 12 // template <class U> optional<T>& operator=(U&& v); 13 14 #include <optional> 15 #include <type_traits> 16 #include <cassert> 17 #include <memory> 18 19 #include "test_macros.h" 20 #include "archetypes.h" 21 22 using std::optional; 23 24 struct ThrowAssign { 25 static int dtor_called; 26 ThrowAssign() = default; 27 ThrowAssign(int) { TEST_THROW(42); } 28 ThrowAssign& operator=(int) { 29 TEST_THROW(42); 30 } 31 ~ThrowAssign() { ++dtor_called; } 32 }; 33 int ThrowAssign::dtor_called = 0; 34 35 template <class T, class Arg = T, bool Expect = true> 36 void assert_assignable() { 37 static_assert(std::is_assignable<optional<T>&, Arg>::value == Expect, ""); 38 static_assert(!std::is_assignable<const optional<T>&, Arg>::value, ""); 39 } 40 41 struct MismatchType { 42 explicit MismatchType(int) {} 43 explicit MismatchType(char*) {} 44 explicit MismatchType(int*) = delete; 45 MismatchType& operator=(int) { return *this; } 46 MismatchType& operator=(int*) { return *this; } 47 MismatchType& operator=(char*) = delete; 48 }; 49 50 struct FromOptionalType { 51 using Opt = std::optional<FromOptionalType>; 52 FromOptionalType() = default; 53 FromOptionalType(FromOptionalType const&) = delete; 54 template <class Dummy = void> 55 constexpr FromOptionalType(Opt&) { Dummy::BARK; } 56 template <class Dummy = void> 57 constexpr FromOptionalType& operator=(Opt&) { Dummy::BARK; return *this; } 58 }; 59 60 void test_sfinae() { 61 using I = TestTypes::TestType; 62 using E = ExplicitTestTypes::TestType; 63 assert_assignable<int>(); 64 assert_assignable<int, int&>(); 65 assert_assignable<int, int const&>(); 66 // Implicit test type 67 assert_assignable<I, I const&>(); 68 assert_assignable<I, I&&>(); 69 assert_assignable<I, int>(); 70 assert_assignable<I, void*, false>(); 71 // Explicit test type 72 assert_assignable<E, E const&>(); 73 assert_assignable<E, E &&>(); 74 assert_assignable<E, int>(); 75 assert_assignable<E, void*, false>(); 76 // Mismatch type 77 assert_assignable<MismatchType, int>(); 78 assert_assignable<MismatchType, int*, false>(); 79 assert_assignable<MismatchType, char*, false>(); 80 // Type constructible from optional 81 assert_assignable<FromOptionalType, std::optional<FromOptionalType>&, false>(); 82 } 83 84 void test_with_test_type() 85 { 86 using T = TestTypes::TestType; 87 T::reset(); 88 { // to empty 89 optional<T> opt; 90 opt = 3; 91 assert(T::alive == 1); 92 assert(T::constructed == 1); 93 assert(T::value_constructed == 1); 94 assert(T::assigned == 0); 95 assert(T::destroyed == 0); 96 assert(static_cast<bool>(opt) == true); 97 assert(*opt == T(3)); 98 } 99 { // to existing 100 optional<T> opt(42); 101 T::reset_constructors(); 102 opt = 3; 103 assert(T::alive == 1); 104 assert(T::constructed == 0); 105 assert(T::assigned == 1); 106 assert(T::value_assigned == 1); 107 assert(T::destroyed == 0); 108 assert(static_cast<bool>(opt) == true); 109 assert(*opt == T(3)); 110 } 111 { // test default argument 112 optional<T> opt; 113 T::reset_constructors(); 114 opt = {1, 2}; 115 assert(T::alive == 1); 116 assert(T::constructed == 2); 117 assert(T::value_constructed == 1); 118 assert(T::move_constructed == 1); 119 assert(T::assigned == 0); 120 assert(T::destroyed == 1); 121 assert(static_cast<bool>(opt) == true); 122 assert(*opt == T(1, 2)); 123 } 124 { // test default argument 125 optional<T> opt(42); 126 T::reset_constructors(); 127 opt = {1, 2}; 128 assert(T::alive == 1); 129 assert(T::constructed == 1); 130 assert(T::value_constructed == 1); 131 assert(T::assigned == 1); 132 assert(T::move_assigned == 1); 133 assert(T::destroyed == 1); 134 assert(static_cast<bool>(opt) == true); 135 assert(*opt == T(1, 2)); 136 } 137 { // test default argument 138 optional<T> opt; 139 T::reset_constructors(); 140 opt = {1}; 141 assert(T::alive == 1); 142 assert(T::constructed == 2); 143 assert(T::value_constructed == 1); 144 assert(T::move_constructed == 1); 145 assert(T::assigned == 0); 146 assert(T::destroyed == 1); 147 assert(static_cast<bool>(opt) == true); 148 assert(*opt == T(1)); 149 } 150 { // test default argument 151 optional<T> opt(42); 152 T::reset_constructors(); 153 opt = {}; 154 assert(static_cast<bool>(opt) == false); 155 assert(T::alive == 0); 156 assert(T::constructed == 0); 157 assert(T::assigned == 0); 158 assert(T::destroyed == 1); 159 } 160 } 161 162 template <class T, class Value = int> 163 void test_with_type() { 164 { // to empty 165 optional<T> opt; 166 opt = Value(3); 167 assert(static_cast<bool>(opt) == true); 168 assert(*opt == T(3)); 169 } 170 { // to existing 171 optional<T> opt(Value(42)); 172 opt = Value(3); 173 assert(static_cast<bool>(opt) == true); 174 assert(*opt == T(3)); 175 } 176 { // test const 177 optional<T> opt(Value(42)); 178 const T t(Value(3)); 179 opt = t; 180 assert(static_cast<bool>(opt) == true); 181 assert(*opt == T(3)); 182 } 183 { // test default argument 184 optional<T> opt; 185 opt = {Value(1)}; 186 assert(static_cast<bool>(opt) == true); 187 assert(*opt == T(1)); 188 } 189 { // test default argument 190 optional<T> opt(Value(42)); 191 opt = {}; 192 assert(static_cast<bool>(opt) == false); 193 } 194 } 195 196 template <class T> 197 void test_with_type_multi() { 198 test_with_type<T>(); 199 { // test default argument 200 optional<T> opt; 201 opt = {1, 2}; 202 assert(static_cast<bool>(opt) == true); 203 assert(*opt == T(1, 2)); 204 } 205 { // test default argument 206 optional<T> opt(42); 207 opt = {1, 2}; 208 assert(static_cast<bool>(opt) == true); 209 assert(*opt == T(1, 2)); 210 } 211 } 212 213 void test_throws() 214 { 215 #ifndef TEST_HAS_NO_EXCEPTIONS 216 using T = ThrowAssign; 217 { 218 optional<T> opt; 219 try { 220 opt = 42; 221 assert(false); 222 } catch (int) {} 223 assert(static_cast<bool>(opt) == false); 224 } 225 assert(T::dtor_called == 0); 226 { 227 T::dtor_called = 0; 228 optional<T> opt(std::in_place); 229 try { 230 opt = 42; 231 assert(false); 232 } catch (int) {} 233 assert(static_cast<bool>(opt) == true); 234 assert(T::dtor_called == 0); 235 } 236 assert(T::dtor_called == 1); 237 #endif 238 } 239 240 enum MyEnum { Zero, One, Two, Three, FortyTwo = 42 }; 241 242 using Fn = void(*)(); 243 244 // https://llvm.org/PR38638 245 template <class T> 246 constexpr T pr38638(T v) 247 { 248 std::optional<T> o; 249 o = v; 250 return *o + 2; 251 } 252 253 254 int main(int, char**) 255 { 256 test_sfinae(); 257 // Test with instrumented type 258 test_with_test_type(); 259 // Test with various scalar types 260 test_with_type<int>(); 261 test_with_type<MyEnum, MyEnum>(); 262 test_with_type<int, MyEnum>(); 263 test_with_type<Fn, Fn>(); 264 // Test types with multi argument constructors 265 test_with_type_multi<ConstexprTestTypes::TestType>(); 266 test_with_type_multi<TrivialTestTypes::TestType>(); 267 // Test move only types 268 { 269 optional<std::unique_ptr<int>> opt; 270 opt = std::unique_ptr<int>(new int(3)); 271 assert(static_cast<bool>(opt) == true); 272 assert(**opt == 3); 273 } 274 { 275 optional<std::unique_ptr<int>> opt(std::unique_ptr<int>(new int(2))); 276 opt = std::unique_ptr<int>(new int(3)); 277 assert(static_cast<bool>(opt) == true); 278 assert(**opt == 3); 279 } 280 test_throws(); 281 282 static_assert(pr38638(3) == 5, ""); 283 284 return 0; 285 } 286