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 | |