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 10 11 // __non_propagating_cache& operator=(__non_propagating_cache&&); 12 13 // ADDITIONAL_COMPILE_FLAGS: -Wno-self-assign 14 15 #include <ranges> 16 17 #include <cassert> 18 #include <type_traits> 19 #include <utility> 20 21 template<bool NoexceptMove> 22 struct MoveAssignable { 23 int x; MoveAssignableMoveAssignable24 constexpr explicit MoveAssignable(int i) : x(i) { } 25 MoveAssignable(MoveAssignable&&) = default; operator =MoveAssignable26 constexpr MoveAssignable& operator=(MoveAssignable&& other) noexcept(NoexceptMove) { 27 x = other.x; 28 other.x = -1; 29 return *this; 30 } 31 }; 32 33 struct NotMoveAssignable { 34 int x; NotMoveAssignableNotMoveAssignable35 constexpr explicit NotMoveAssignable(int i) : x(i) { } 36 NotMoveAssignable(NotMoveAssignable&&) = default; 37 NotMoveAssignable& operator=(NotMoveAssignable&&) = delete; 38 }; 39 40 template <class T> test()41constexpr void test() { 42 using Cache = std::ranges::__non_propagating_cache<T>; 43 static_assert(std::is_nothrow_move_assignable_v<Cache>); 44 45 // Assign to an empty cache 46 { 47 Cache a; a.__emplace(3); 48 Cache b; 49 50 Cache& result = (b = std::move(a)); 51 assert(&result == &b); 52 assert(!b.__has_value()); // make sure we don't propagate 53 assert(!a.__has_value()); // make sure we disengage the source 54 } 55 56 // Assign to a non-empty cache 57 { 58 Cache a; a.__emplace(3); 59 Cache b; b.__emplace(5); 60 61 Cache& result = (b = std::move(a)); 62 assert(&result == &b); 63 assert(!b.__has_value()); // make sure we don't propagate 64 assert(!a.__has_value()); // make sure we disengage the source 65 } 66 67 // Self-assignment should clear the cache (case with empty cache) 68 { 69 Cache b; 70 71 Cache& result = (b = std::move(b)); 72 assert(&result == &b); 73 assert(!b.__has_value()); 74 } 75 76 // Self-assignment should clear the cache (case with non-empty cache) 77 { 78 Cache b; b.__emplace(5); 79 80 Cache& result = (b = std::move(b)); 81 assert(&result == &b); 82 assert(!b.__has_value()); 83 } 84 } 85 tests()86constexpr bool tests() { 87 test<MoveAssignable<true>>(); 88 test<MoveAssignable<false>>(); 89 test<NotMoveAssignable>(); 90 test<int>(); 91 return true; 92 } 93 main(int,char **)94int main(int, char**) { 95 static_assert(tests()); 96 tests(); 97 return 0; 98 } 99