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