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 11 // Throwing bad_optional_access is supported starting in macosx10.13 12 // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12}} && !no-exceptions 13 14 // <optional> 15 16 // constexpr optional(optional<T>&& rhs); 17 18 #include <optional> 19 #include <type_traits> 20 #include <cassert> 21 22 #include "test_macros.h" 23 #include "archetypes.h" 24 25 using std::optional; 26 27 template <class T, class ...InitArgs> 28 void test(InitArgs&&... args) 29 { 30 const optional<T> orig(std::forward<InitArgs>(args)...); 31 optional<T> rhs(orig); 32 bool rhs_engaged = static_cast<bool>(rhs); 33 optional<T> lhs = std::move(rhs); 34 assert(static_cast<bool>(lhs) == rhs_engaged); 35 if (rhs_engaged) 36 assert(*lhs == *orig); 37 } 38 39 template <class T, class ...InitArgs> 40 constexpr bool constexpr_test(InitArgs&&... args) 41 { 42 static_assert( std::is_trivially_copy_constructible_v<T>, ""); // requirement 43 const optional<T> orig(std::forward<InitArgs>(args)...); 44 optional<T> rhs(orig); 45 optional<T> lhs = std::move(rhs); 46 return (lhs.has_value() == orig.has_value()) && 47 (lhs.has_value() ? *lhs == *orig : true); 48 } 49 50 void test_throwing_ctor() { 51 #ifndef TEST_HAS_NO_EXCEPTIONS 52 struct Z { 53 Z() : count(0) {} 54 Z(Z&& o) : count(o.count + 1) 55 { if (count == 2) throw 6; } 56 int count; 57 }; 58 Z z; 59 optional<Z> rhs(std::move(z)); 60 try 61 { 62 optional<Z> lhs(std::move(rhs)); 63 assert(false); 64 } 65 catch (int i) 66 { 67 assert(i == 6); 68 } 69 #endif 70 } 71 72 73 template <class T, class ...InitArgs> 74 void test_ref(InitArgs&&... args) 75 { 76 optional<T> rhs(std::forward<InitArgs>(args)...); 77 bool rhs_engaged = static_cast<bool>(rhs); 78 optional<T> lhs = std::move(rhs); 79 assert(static_cast<bool>(lhs) == rhs_engaged); 80 if (rhs_engaged) 81 assert(&(*lhs) == &(*rhs)); 82 } 83 84 void test_reference_extension() 85 { 86 #if defined(_LIBCPP_VERSION) && 0 // FIXME these extensions are currently disabled. 87 using T = TestTypes::TestType; 88 T::reset(); 89 { 90 T t; 91 T::reset_constructors(); 92 test_ref<T&>(); 93 test_ref<T&>(t); 94 assert(T::alive == 1); 95 assert(T::constructed == 0); 96 assert(T::assigned == 0); 97 assert(T::destroyed == 0); 98 } 99 assert(T::destroyed == 1); 100 assert(T::alive == 0); 101 { 102 T t; 103 const T& ct = t; 104 T::reset_constructors(); 105 test_ref<T const&>(); 106 test_ref<T const&>(t); 107 test_ref<T const&>(ct); 108 assert(T::alive == 1); 109 assert(T::constructed == 0); 110 assert(T::assigned == 0); 111 assert(T::destroyed == 0); 112 } 113 assert(T::alive == 0); 114 assert(T::destroyed == 1); 115 { 116 T t; 117 T::reset_constructors(); 118 test_ref<T&&>(); 119 test_ref<T&&>(std::move(t)); 120 assert(T::alive == 1); 121 assert(T::constructed == 0); 122 assert(T::assigned == 0); 123 assert(T::destroyed == 0); 124 } 125 assert(T::alive == 0); 126 assert(T::destroyed == 1); 127 { 128 T t; 129 const T& ct = t; 130 T::reset_constructors(); 131 test_ref<T const&&>(); 132 test_ref<T const&&>(std::move(t)); 133 test_ref<T const&&>(std::move(ct)); 134 assert(T::alive == 1); 135 assert(T::constructed == 0); 136 assert(T::assigned == 0); 137 assert(T::destroyed == 0); 138 } 139 assert(T::alive == 0); 140 assert(T::destroyed == 1); 141 { 142 static_assert(!std::is_copy_constructible<std::optional<T&&>>::value, ""); 143 static_assert(!std::is_copy_constructible<std::optional<T const&&>>::value, ""); 144 } 145 #endif 146 } 147 148 149 int main(int, char**) 150 { 151 test<int>(); 152 test<int>(3); 153 static_assert(constexpr_test<int>(), "" ); 154 static_assert(constexpr_test<int>(3), "" ); 155 156 { 157 optional<const int> o(42); 158 optional<const int> o2(std::move(o)); 159 assert(*o2 == 42); 160 } 161 { 162 using T = TestTypes::TestType; 163 T::reset(); 164 optional<T> rhs; 165 assert(T::alive == 0); 166 const optional<T> lhs(std::move(rhs)); 167 assert(lhs.has_value() == false); 168 assert(rhs.has_value() == false); 169 assert(T::alive == 0); 170 } 171 TestTypes::TestType::reset(); 172 { 173 using T = TestTypes::TestType; 174 T::reset(); 175 optional<T> rhs(42); 176 assert(T::alive == 1); 177 assert(T::value_constructed == 1); 178 assert(T::move_constructed == 0); 179 const optional<T> lhs(std::move(rhs)); 180 assert(lhs.has_value()); 181 assert(rhs.has_value()); 182 assert(lhs.value().value == 42); 183 assert(rhs.value().value == -1); 184 assert(T::move_constructed == 1); 185 assert(T::alive == 2); 186 } 187 TestTypes::TestType::reset(); 188 { 189 using namespace ConstexprTestTypes; 190 test<TestType>(); 191 test<TestType>(42); 192 } 193 { 194 using namespace TrivialTestTypes; 195 test<TestType>(); 196 test<TestType>(42); 197 } 198 { 199 test_throwing_ctor(); 200 } 201 { 202 struct ThrowsMove { 203 ThrowsMove() noexcept(false) {} 204 ThrowsMove(ThrowsMove const&) noexcept(false) {} 205 ThrowsMove(ThrowsMove &&) noexcept(false) {} 206 }; 207 static_assert(!std::is_nothrow_move_constructible<optional<ThrowsMove>>::value, ""); 208 struct NoThrowMove { 209 NoThrowMove() noexcept(false) {} 210 NoThrowMove(NoThrowMove const&) noexcept(false) {} 211 NoThrowMove(NoThrowMove &&) noexcept(true) {} 212 }; 213 static_assert(std::is_nothrow_move_constructible<optional<NoThrowMove>>::value, ""); 214 } 215 { 216 test_reference_extension(); 217 } 218 { 219 constexpr std::optional<int> o1{4}; 220 constexpr std::optional<int> o2 = std::move(o1); 221 static_assert( *o2 == 4, "" ); 222 } 223 224 return 0; 225 } 226