| 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(v: 3) == 5, "" ); |
| 283 | |
| 284 | return 0; |
| 285 | } |
| 286 | |