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