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_copyable_storable; 13 14 #include <iterator> 15 16 #include "MoveOnly.h" 17 #include "test_macros.h" 18 19 struct CopyOnly { 20 CopyOnly(CopyOnly&&) = delete; 21 CopyOnly(CopyOnly const&) = default; 22 CopyOnly& operator=(CopyOnly&&) = delete; 23 CopyOnly& operator=(CopyOnly const&) = default; 24 CopyOnly() = default; 25 }; 26 27 template<class T> 28 struct PointerTo { 29 using value_type = T; 30 T& operator*() const; 31 }; 32 33 // Copying the underlying object between pointers (or dereferenceable classes) works. This is a non-exhaustive check 34 // because this functionality comes from `indirectly_copyable`. 35 static_assert( std::indirectly_copyable_storable<int*, int*>); 36 static_assert( std::indirectly_copyable_storable<const int*, int*>); 37 static_assert(!std::indirectly_copyable_storable<int*, const int*>); 38 static_assert(!std::indirectly_copyable_storable<const int*, const int*>); 39 static_assert( std::indirectly_copyable_storable<int*, int[2]>); 40 static_assert(!std::indirectly_copyable_storable<int[2], int*>); 41 static_assert(!std::indirectly_copyable_storable<MoveOnly*, MoveOnly*>); 42 static_assert(!std::indirectly_copyable_storable<PointerTo<MoveOnly>, PointerTo<MoveOnly>>); 43 // `indirectly_copyable_storable` requires the type to be `copyable`, which in turns requires it to be `movable`. 44 static_assert(!std::indirectly_copyable_storable<CopyOnly*, CopyOnly*>); 45 static_assert(!std::indirectly_copyable_storable<PointerTo<CopyOnly>, PointerTo<CopyOnly>>); 46 47 // The dereference operator returns a different type from `value_type` and the reference type cannot be assigned from a 48 // non-const lvalue of `ValueType` (but all other forms of assignment from `ValueType` work). 49 struct NoLvalueAssignment { 50 struct ValueType; 51 52 struct ReferenceType { 53 ReferenceType& operator=(ValueType const&); 54 ReferenceType& operator=(ValueType&) = delete; 55 ReferenceType& operator=(ValueType&&); 56 ReferenceType& operator=(ValueType const&&); 57 }; 58 59 struct ValueType { 60 operator ReferenceType&() const; 61 }; 62 63 using value_type = ValueType; 64 ReferenceType& operator*() const; 65 }; 66 67 static_assert( std::indirectly_writable<NoLvalueAssignment, std::iter_reference_t<NoLvalueAssignment>>); 68 static_assert(!std::indirectly_writable<NoLvalueAssignment, std::iter_value_t<NoLvalueAssignment>&>); 69 static_assert( std::indirectly_writable<NoLvalueAssignment, const std::iter_value_t<NoLvalueAssignment>&>); 70 static_assert( std::indirectly_writable<NoLvalueAssignment, std::iter_value_t<NoLvalueAssignment>&&>); 71 static_assert( std::indirectly_writable<NoLvalueAssignment, const std::iter_value_t<NoLvalueAssignment>&&>); 72 static_assert(!std::indirectly_copyable_storable<NoLvalueAssignment, NoLvalueAssignment>); 73 74 // The dereference operator returns a different type from `value_type` and the reference type cannot be assigned from a 75 // const lvalue of `ValueType` (but all other forms of assignment from `ValueType` work). 76 struct NoConstLvalueAssignment { 77 struct ValueType; 78 79 struct ReferenceType { 80 ReferenceType& operator=(ValueType const&) = delete; 81 ReferenceType& operator=(ValueType&); 82 ReferenceType& operator=(ValueType&&); 83 ReferenceType& operator=(ValueType const&&); 84 }; 85 86 struct ValueType { 87 operator ReferenceType&() const; 88 }; 89 90 using value_type = ValueType; 91 ReferenceType& operator*() const; 92 }; 93 94 static_assert( std::indirectly_writable<NoConstLvalueAssignment, std::iter_reference_t<NoConstLvalueAssignment>>); 95 static_assert( std::indirectly_writable<NoConstLvalueAssignment, std::iter_value_t<NoConstLvalueAssignment>&>); 96 static_assert(!std::indirectly_writable<NoConstLvalueAssignment, const std::iter_value_t<NoConstLvalueAssignment>&>); 97 static_assert( std::indirectly_writable<NoConstLvalueAssignment, std::iter_value_t<NoConstLvalueAssignment>&&>); 98 static_assert( std::indirectly_writable<NoConstLvalueAssignment, const std::iter_value_t<NoConstLvalueAssignment>&&>); 99 static_assert(!std::indirectly_copyable_storable<NoConstLvalueAssignment, NoConstLvalueAssignment>); 100 101 // The dereference operator returns a different type from `value_type` and the reference type cannot be assigned from a 102 // non-const rvalue of `ValueType` (but all other forms of assignment from `ValueType` work). 103 struct NoRvalueAssignment { 104 struct ValueType; 105 106 struct ReferenceType { 107 ReferenceType& operator=(ValueType const&); 108 ReferenceType& operator=(ValueType&); 109 ReferenceType& operator=(ValueType&&) = delete; 110 ReferenceType& operator=(ValueType const&&); 111 }; 112 113 struct ValueType { 114 operator ReferenceType&() const; 115 }; 116 117 using value_type = ValueType; 118 ReferenceType& operator*() const; 119 }; 120 121 static_assert( std::indirectly_writable<NoRvalueAssignment, std::iter_reference_t<NoRvalueAssignment>>); 122 static_assert( std::indirectly_writable<NoRvalueAssignment, std::iter_value_t<NoRvalueAssignment>&>); 123 static_assert( std::indirectly_writable<NoRvalueAssignment, const std::iter_value_t<NoRvalueAssignment>&>); 124 static_assert(!std::indirectly_writable<NoRvalueAssignment, std::iter_value_t<NoRvalueAssignment>&&>); 125 static_assert( std::indirectly_writable<NoRvalueAssignment, const std::iter_value_t<NoRvalueAssignment>&&>); 126 static_assert(!std::indirectly_copyable_storable<NoRvalueAssignment, NoRvalueAssignment>); 127 128 // The dereference operator returns a different type from `value_type` and the reference type cannot be assigned from a 129 // const rvalue of `ValueType` (but all other forms of assignment from `ValueType` work). 130 struct NoConstRvalueAssignment { 131 struct ValueType; 132 133 struct ReferenceType { 134 ReferenceType& operator=(ValueType const&); 135 ReferenceType& operator=(ValueType&); 136 ReferenceType& operator=(ValueType&&); 137 ReferenceType& operator=(ValueType const&&) = delete; 138 }; 139 140 struct ValueType { 141 operator ReferenceType&() const; 142 }; 143 144 using value_type = ValueType; 145 ReferenceType& operator*() const; 146 }; 147 148 static_assert( std::indirectly_writable<NoConstRvalueAssignment, std::iter_reference_t<NoConstRvalueAssignment>>); 149 static_assert( std::indirectly_writable<NoConstRvalueAssignment, std::iter_value_t<NoConstRvalueAssignment>&>); 150 static_assert( std::indirectly_writable<NoConstRvalueAssignment, const std::iter_value_t<NoConstRvalueAssignment>&>); 151 static_assert( std::indirectly_writable<NoConstRvalueAssignment, std::iter_value_t<NoConstRvalueAssignment>&&>); 152 static_assert(!std::indirectly_writable<NoConstRvalueAssignment, const std::iter_value_t<NoConstRvalueAssignment>&&>); 153 static_assert(!std::indirectly_copyable_storable<NoConstRvalueAssignment, NoConstRvalueAssignment>); 154 155 struct DeletedCopyCtor { 156 DeletedCopyCtor(DeletedCopyCtor const&) = delete; 157 DeletedCopyCtor& operator=(DeletedCopyCtor const&) = default; 158 }; 159 160 struct DeletedNonconstCopyCtor { 161 DeletedNonconstCopyCtor(DeletedNonconstCopyCtor const&) = default; 162 DeletedNonconstCopyCtor(DeletedNonconstCopyCtor&) = delete; 163 DeletedNonconstCopyCtor& operator=(DeletedNonconstCopyCtor const&) = default; 164 }; 165 166 struct DeletedMoveCtor { 167 DeletedMoveCtor(DeletedMoveCtor&&) = delete; 168 DeletedMoveCtor& operator=(DeletedMoveCtor&&) = default; 169 }; 170 171 struct DeletedConstMoveCtor { 172 DeletedConstMoveCtor(DeletedConstMoveCtor&&) = default; 173 DeletedConstMoveCtor(DeletedConstMoveCtor const&&) = delete; 174 DeletedConstMoveCtor& operator=(DeletedConstMoveCtor&&) = default; 175 }; 176 177 struct DeletedCopyAssignment { 178 DeletedCopyAssignment(DeletedCopyAssignment const&) = default; 179 DeletedCopyAssignment& operator=(DeletedCopyAssignment const&) = delete; 180 }; 181 182 struct DeletedNonconstCopyAssignment { 183 DeletedNonconstCopyAssignment(DeletedNonconstCopyAssignment const&) = default; 184 DeletedNonconstCopyAssignment& operator=(DeletedNonconstCopyAssignment const&) = default; 185 DeletedNonconstCopyAssignment& operator=(DeletedNonconstCopyAssignment&) = delete; 186 }; 187 188 struct DeletedMoveAssignment { 189 DeletedMoveAssignment(DeletedMoveAssignment&&) = default; 190 DeletedMoveAssignment& operator=(DeletedMoveAssignment&&) = delete; 191 }; 192 193 struct DeletedConstMoveAssignment { 194 DeletedConstMoveAssignment(DeletedConstMoveAssignment&&) = default; 195 DeletedConstMoveAssignment& operator=(DeletedConstMoveAssignment&&) = delete; 196 }; 197 198 static_assert(!std::indirectly_copyable_storable<DeletedCopyCtor*, DeletedCopyCtor*>); 199 static_assert(!std::indirectly_copyable_storable<DeletedNonconstCopyCtor*, DeletedNonconstCopyCtor*>); 200 static_assert(!std::indirectly_copyable_storable<DeletedMoveCtor*, DeletedMoveCtor*>); 201 static_assert(!std::indirectly_copyable_storable<DeletedConstMoveCtor*, DeletedConstMoveCtor*>); 202 static_assert(!std::indirectly_copyable_storable<DeletedCopyAssignment*, DeletedCopyAssignment*>); 203 static_assert(!std::indirectly_copyable_storable<DeletedNonconstCopyAssignment*, DeletedNonconstCopyAssignment*>); 204 static_assert(!std::indirectly_copyable_storable<DeletedMoveAssignment*, DeletedMoveAssignment*>); 205 static_assert(!std::indirectly_copyable_storable<DeletedConstMoveAssignment*, DeletedConstMoveAssignment*>); 206 207 struct InconsistentIterator { 208 struct ValueType; 209 210 struct ReferenceType { 211 ReferenceType& operator=(ValueType const&); 212 }; 213 214 struct ValueType { 215 ValueType() = default; 216 ValueType(const ReferenceType&); 217 }; 218 219 using value_type = ValueType; 220 ReferenceType& operator*() const; 221 }; 222 223 // `ValueType` can be constructed with a `ReferenceType` and assigned to a `ReferenceType`, so it does model 224 // `indirectly_copyable_storable`. 225 static_assert( std::indirectly_copyable_storable<InconsistentIterator, InconsistentIterator>); 226 227 struct CommonType { }; 228 229 // ReferenceType is a (proxy) reference for ValueType, but ValueType is not constructible from ReferenceType. 230 struct NotConstructibleFromRefIn { 231 struct ReferenceType; 232 233 struct ValueType { 234 ValueType(ReferenceType) = delete; 235 operator CommonType&() const; 236 }; 237 238 struct ReferenceType { 239 operator CommonType&() const; 240 }; 241 242 using value_type = ValueType; 243 ReferenceType& operator*() const; 244 }; 245 246 template <template <class> class X, template <class> class Y> 247 struct std::basic_common_reference<NotConstructibleFromRefIn::ValueType, 248 NotConstructibleFromRefIn::ReferenceType, X, Y> { 249 using type = CommonType&; 250 }; 251 252 template <template <class> class X, template <class> class Y> 253 struct std::basic_common_reference<NotConstructibleFromRefIn::ReferenceType, 254 NotConstructibleFromRefIn::ValueType, X, Y> { 255 using type = CommonType&; 256 }; 257 258 static_assert(std::common_reference_with<NotConstructibleFromRefIn::ValueType&, 259 NotConstructibleFromRefIn::ReferenceType&>); 260 261 struct AssignableFromAnything { 262 template<class T> 263 AssignableFromAnything& operator=(T&&); 264 }; 265 266 // A type that can't be constructed from its own reference isn't `indirectly_copyable_storable`, even when assigning it 267 // to a type that can be assigned from anything. 268 static_assert(!std::indirectly_copyable_storable<NotConstructibleFromRefIn, AssignableFromAnything*>); 269 270 // ReferenceType is a (proxy) reference for ValueType, but ValueType is not assignable from ReferenceType. 271 struct NotAssignableFromRefIn { 272 struct ReferenceType; 273 274 struct ValueType { 275 ValueType(ReferenceType); 276 ValueType& operator=(ReferenceType) = delete; 277 operator CommonType&() const; 278 }; 279 280 struct ReferenceType { 281 operator CommonType&() const; 282 }; 283 284 using value_type = ValueType; 285 ReferenceType& operator*() const; 286 }; 287 288 template <template <class> class X, template <class> class Y> 289 struct std::basic_common_reference<NotAssignableFromRefIn::ValueType, 290 NotAssignableFromRefIn::ReferenceType, X, Y> { 291 using type = CommonType&; 292 }; 293 294 template <template <class> class X, template <class> class Y> 295 struct std::basic_common_reference<NotAssignableFromRefIn::ReferenceType, 296 NotAssignableFromRefIn::ValueType, X, Y> { 297 using type = CommonType&; 298 }; 299 300 static_assert(std::common_reference_with<NotAssignableFromRefIn::ValueType&, NotAssignableFromRefIn::ReferenceType&>); 301 302 // A type that can't be assigned from its own reference isn't `indirectly_copyable_storable`, even when assigning it 303 // to a type that can be assigned from anything. 304 static_assert(!std::indirectly_copyable_storable<NotAssignableFromRefIn, AssignableFromAnything*>); 305