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, c++17, c++20 10 11 // constexpr expected(expected&& rhs) noexcept(is_nothrow_move_constructible_v<E>); 12 // 13 // Constraints: is_move_constructible_v<E> is true. 14 // 15 // Effects: If rhs.has_value() is false, direct-non-list-initializes unex with std::move(rhs.error()). 16 // 17 // Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true. 18 // 19 // Throws: Any exception thrown by the initialization of unex. 20 // 21 // Remarks: This constructor is trivial if is_trivially_move_constructible_v<E> is true. 22 23 #include <cassert> 24 #include <expected> 25 #include <type_traits> 26 #include <utility> 27 28 #include "test_macros.h" 29 #include "../../types.h" 30 31 struct NonMovable { 32 NonMovable(NonMovable&&) = delete; 33 }; 34 35 struct MovableNonTrivial { 36 int i; 37 constexpr MovableNonTrivial(int ii) : i(ii) {} 38 constexpr MovableNonTrivial(MovableNonTrivial&& o) : i(o.i) { o.i = 0; } 39 friend constexpr bool operator==(const MovableNonTrivial&, const MovableNonTrivial&) = default; 40 }; 41 42 struct MoveMayThrow { 43 MoveMayThrow(MoveMayThrow&&) {} 44 }; 45 46 // Test Constraints: 47 // - is_move_constructible_v<E> is true. 48 static_assert(std::is_move_constructible_v<std::expected<void, int>>); 49 static_assert(std::is_move_constructible_v<std::expected<void, MovableNonTrivial>>); 50 static_assert(!std::is_move_constructible_v<std::expected<void, NonMovable>>); 51 52 // Test: This constructor is trivial if is_trivially_move_constructible_v<E> is true. 53 static_assert(std::is_trivially_move_constructible_v<std::expected<void, int>>); 54 static_assert(!std::is_trivially_move_constructible_v<std::expected<void, MovableNonTrivial>>); 55 56 // Test: noexcept(is_nothrow_move_constructible_v<E>) 57 static_assert(std::is_nothrow_move_constructible_v<std::expected<int, int>>); 58 static_assert(!std::is_nothrow_move_constructible_v<std::expected<MoveMayThrow, int>>); 59 static_assert(!std::is_nothrow_move_constructible_v<std::expected<int, MoveMayThrow>>); 60 static_assert(!std::is_nothrow_move_constructible_v<std::expected<MoveMayThrow, MoveMayThrow>>); 61 62 constexpr bool test() { 63 // move the error non-trivial 64 { 65 std::expected<void, MovableNonTrivial> e1(std::unexpect, 5); 66 auto e2 = std::move(e1); 67 assert(!e2.has_value()); 68 assert(e2.error().i == 5); 69 assert(!e1.has_value()); 70 assert(e1.error().i == 0); 71 } 72 73 // move the error trivial 74 { 75 std::expected<void, int> e1(std::unexpect, 5); 76 auto e2 = std::move(e1); 77 assert(!e2.has_value()); 78 assert(e2.error() == 5); 79 assert(!e1.has_value()); 80 } 81 82 // move TailClobbererNonTrivialMove as error 83 { 84 std::expected<void, TailClobbererNonTrivialMove<1>> e1(std::unexpect); 85 auto e2 = std::move(e1); 86 assert(!e2.has_value()); 87 assert(!e1.has_value()); 88 } 89 90 return true; 91 } 92 93 void testException() { 94 #ifndef TEST_HAS_NO_EXCEPTIONS 95 struct Throwing { 96 Throwing() = default; 97 Throwing(Throwing&&) { throw Except{}; } 98 }; 99 100 // throw on moving error 101 { 102 std::expected<void, Throwing> e1(std::unexpect); 103 try { 104 [[maybe_unused]] auto e2 = std::move(e1); 105 assert(false); 106 } catch (Except) { 107 } 108 } 109 110 #endif // TEST_HAS_NO_EXCEPTIONS 111 } 112 113 int main(int, char**) { 114 test(); 115 static_assert(test()); 116 testException(); 117 return 0; 118 } 119