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