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