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 // template<class In, class Out> 12 // concept indirectly_movable_storable; 13 14 #include <iterator> 15 16 #include "MoveOnly.h" 17 #include "test_macros.h" 18 19 template <class T> 20 struct PointerTo { 21 using value_type = T; 22 T& operator*() const; 23 }; 24 25 // Copying the underlying object between pointers (or dereferenceable classes) works. This is a non-exhaustive check 26 // because this functionality comes from `indirectly_movable`. 27 static_assert( std::indirectly_movable_storable<int*, int*>); 28 static_assert( std::indirectly_movable_storable<const int*, int*>); 29 static_assert(!std::indirectly_movable_storable<int*, const int*>); 30 static_assert(!std::indirectly_movable_storable<const int*, const int*>); 31 static_assert( std::indirectly_movable_storable<int*, int[2]>); 32 static_assert(!std::indirectly_movable_storable<int[2], int*>); 33 static_assert( std::indirectly_movable_storable<MoveOnly*, MoveOnly*>); 34 static_assert( std::indirectly_movable_storable<PointerTo<MoveOnly>, PointerTo<MoveOnly>>); 35 36 // The dereference operator returns a different type from `value_type` and the reference type cannot be assigned from a 37 // `ValueType`. 38 struct NoAssignment { 39 struct ValueType; 40 41 struct ReferenceType { 42 ReferenceType& operator=(ValueType) = delete; 43 }; 44 45 // `ValueType` is convertible to `ReferenceType` but not assignable to it. This is implemented by explicitly deleting 46 // `operator=(ValueType)` in `ReferenceType`. 47 struct ValueType { 48 operator ReferenceType&() const; 49 }; 50 51 using value_type = ValueType; 52 ReferenceType& operator*() const; 53 }; 54 55 // The case when `indirectly_writable<iter_rvalue_reference>` but not `indirectly_writable<iter_value>` (you can 56 // do `ReferenceType r = ValueType();` but not `r = ValueType();`). 57 static_assert( std::indirectly_writable<NoAssignment, std::iter_rvalue_reference_t<NoAssignment>>); 58 static_assert(!std::indirectly_writable<NoAssignment, std::iter_value_t<NoAssignment>>); 59 static_assert(!std::indirectly_movable_storable<NoAssignment, NoAssignment>); 60 61 struct DeletedMoveCtor { 62 DeletedMoveCtor(DeletedMoveCtor&&) = delete; 63 DeletedMoveCtor& operator=(DeletedMoveCtor&&) = default; 64 }; 65 66 struct DeletedMoveAssignment { 67 DeletedMoveAssignment(DeletedMoveAssignment&&) = default; 68 DeletedMoveAssignment& operator=(DeletedMoveAssignment&&) = delete; 69 }; 70 71 static_assert(!std::indirectly_movable_storable<DeletedMoveCtor*, DeletedMoveCtor*>); 72 static_assert(!std::indirectly_movable_storable<DeletedMoveAssignment*, DeletedMoveAssignment*>); 73 74 struct InconsistentIterator { 75 struct ValueType; 76 77 struct ReferenceType { 78 ReferenceType& operator=(ValueType const&); 79 }; 80 81 struct ValueType { 82 ValueType() = default; 83 ValueType(const ReferenceType&); 84 }; 85 86 using value_type = ValueType; 87 ReferenceType& operator*() const; 88 }; 89 90 // `ValueType` can be constructed with a `ReferenceType` and assigned to a `ReferenceType`, so it does model 91 // `indirectly_movable_storable`. 92 static_assert( std::indirectly_movable_storable<InconsistentIterator, InconsistentIterator>); 93 94 // ReferenceType is a (proxy) reference for ValueType, but ValueType is not constructible from ReferenceType. 95 struct NotConstructibleFromRefIn { 96 struct CommonType { }; 97 98 struct ReferenceType { 99 operator CommonType&() const; 100 }; 101 102 struct ValueType { 103 ValueType(ReferenceType) = delete; 104 operator CommonType&() const; 105 }; 106 107 using value_type = ValueType; 108 ReferenceType& operator*() const; 109 }; 110 111 template <template <class> class X, template <class> class Y> 112 struct std::basic_common_reference<NotConstructibleFromRefIn::ValueType, 113 NotConstructibleFromRefIn::ReferenceType, X, Y> { 114 using type = NotConstructibleFromRefIn::CommonType&; 115 }; 116 117 template <template <class> class X, template <class> class Y> 118 struct std::basic_common_reference<NotConstructibleFromRefIn::ReferenceType, 119 NotConstructibleFromRefIn::ValueType, X, Y> { 120 using type = NotConstructibleFromRefIn::CommonType&; 121 }; 122 123 static_assert(std::common_reference_with<NotConstructibleFromRefIn::ValueType&, 124 NotConstructibleFromRefIn::ReferenceType&>); 125 126 struct AssignableFromAnything { 127 template<class T> 128 AssignableFromAnything& operator=(T&&); 129 }; 130 131 // A type that can't be constructed from its own reference isn't `indirectly_movable_storable`, even when assigning it 132 // to a type that can be assigned from anything. 133 static_assert( std::indirectly_movable_storable<int*, AssignableFromAnything*>); 134 static_assert(!std::indirectly_movable_storable<NotConstructibleFromRefIn, AssignableFromAnything*>); 135 136 // ReferenceType is a (proxy) reference for ValueType, but ValueType is not assignable from ReferenceType. 137 struct NotAssignableFromRefIn { 138 struct CommonType { }; 139 140 struct ReferenceType { 141 operator CommonType&() const; 142 }; 143 144 struct ValueType { 145 ValueType(ReferenceType); 146 ValueType& operator=(ReferenceType) = delete; 147 operator CommonType&() const; 148 }; 149 150 using value_type = ValueType; 151 ReferenceType& operator*() const; 152 }; 153 154 template <template <class> class X, template <class> class Y> 155 struct std::basic_common_reference<NotAssignableFromRefIn::ValueType, 156 NotAssignableFromRefIn::ReferenceType, X, Y> { 157 using type = NotAssignableFromRefIn::CommonType&; 158 }; 159 160 template <template <class> class X, template <class> class Y> 161 struct std::basic_common_reference<NotAssignableFromRefIn::ReferenceType, 162 NotAssignableFromRefIn::ValueType, X, Y> { 163 using type = NotAssignableFromRefIn::CommonType&; 164 }; 165 166 static_assert(std::common_reference_with<NotAssignableFromRefIn::ValueType&, NotAssignableFromRefIn::ReferenceType&>); 167 168 // A type that can't be assigned from its own reference isn't `indirectly_movable_storable`, even when assigning it 169 // to a type that can be assigned from anything. 170 static_assert(!std::indirectly_movable_storable<NotAssignableFromRefIn, AssignableFromAnything*>); 171