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> |
12 | // concept indirectly_readable; |
13 | |
14 | #include <concepts> |
15 | #include <iterator> |
16 | #include <type_traits> |
17 | |
18 | #include "read_write.h" |
19 | |
20 | template <class In> |
21 | constexpr bool check_indirectly_readable() { |
22 | constexpr bool result = std::indirectly_readable<In>; |
23 | static_assert(std::indirectly_readable<In const> == result); |
24 | static_assert(std::indirectly_readable<In volatile> == result); |
25 | static_assert(std::indirectly_readable<In const volatile> == result); |
26 | static_assert(std::indirectly_readable<In const&> == result); |
27 | static_assert(std::indirectly_readable<In volatile&> == result); |
28 | static_assert(std::indirectly_readable<In const volatile&> == result); |
29 | static_assert(std::indirectly_readable<In const&&> == result); |
30 | static_assert(std::indirectly_readable<In volatile&&> == result); |
31 | static_assert(std::indirectly_readable<In const volatile&&> == result); |
32 | return result; |
33 | } |
34 | |
35 | static_assert(!check_indirectly_readable<void*>()); |
36 | static_assert(!check_indirectly_readable<void const*>()); |
37 | static_assert(!check_indirectly_readable<void volatile*>()); |
38 | static_assert(!check_indirectly_readable<void const volatile*>()); |
39 | |
40 | static_assert(check_indirectly_readable<int*>()); |
41 | static_assert(check_indirectly_readable<int const*>()); |
42 | static_assert(check_indirectly_readable<int volatile*>()); |
43 | static_assert(check_indirectly_readable<int const volatile*>()); |
44 | |
45 | static_assert(check_indirectly_readable<value_type_indirection>()); |
46 | static_assert(check_indirectly_readable<element_type_indirection>()); |
47 | static_assert(check_indirectly_readable<proxy_indirection>()); |
48 | static_assert(check_indirectly_readable<read_only_indirection>()); |
49 | |
50 | struct indirection_mismatch { |
51 | using value_type = int; |
52 | float& operator*() const; |
53 | }; |
54 | static_assert(!std::same_as<std::iter_value_t<indirection_mismatch>, std::iter_reference_t<indirection_mismatch> > && |
55 | check_indirectly_readable<indirection_mismatch>()); |
56 | static_assert(!check_indirectly_readable<missing_dereference>()); |
57 | |
58 | // `iter_rvalue_reference_t` can't be missing unless the dereference operator is also missing. |
59 | |
60 | struct iter_move_mismatch { |
61 | using value_type = int; |
62 | value_type& operator*() const; |
63 | |
64 | friend float& iter_move(iter_move_mismatch&); |
65 | }; |
66 | static_assert(!check_indirectly_readable<iter_move_mismatch>()); |
67 | |
68 | struct indirection_and_iter_move_mismatch { |
69 | using value_type = int; |
70 | float& operator*() const; |
71 | |
72 | friend unsigned long long& iter_move(indirection_and_iter_move_mismatch&); |
73 | }; |
74 | static_assert(!check_indirectly_readable<indirection_and_iter_move_mismatch>()); |
75 | |
76 | struct missing_iter_value_t { |
77 | int operator*() const; |
78 | }; |
79 | static_assert(!check_indirectly_readable<missing_iter_value_t>()); |
80 | |
81 | struct unrelated_lvalue_ref_and_rvalue_ref {}; |
82 | |
83 | struct iter_ref1 {}; |
84 | namespace std { |
85 | template <> |
86 | struct common_reference<iter_ref1&, iter_ref1&&> {}; |
87 | |
88 | template <> |
89 | struct common_reference<iter_ref1&&, iter_ref1&> {}; |
90 | } // namespace std |
91 | static_assert(!std::common_reference_with<iter_ref1&, iter_ref1&&>); |
92 | |
93 | struct bad_iter_reference_t { |
94 | using value_type = int; |
95 | iter_ref1& operator*() const; |
96 | }; |
97 | static_assert(!check_indirectly_readable<bad_iter_reference_t>()); |
98 | |
99 | struct iter_ref2 {}; |
100 | struct iter_rvalue_ref {}; |
101 | |
102 | struct unrelated_iter_ref_rvalue_and_iter_rvalue_ref_rvalue { |
103 | using value_type = iter_ref2; |
104 | iter_ref2& operator*() const; |
105 | friend iter_rvalue_ref&& iter_move(unrelated_iter_ref_rvalue_and_iter_rvalue_ref_rvalue); |
106 | }; |
107 | static_assert(!check_indirectly_readable<unrelated_iter_ref_rvalue_and_iter_rvalue_ref_rvalue>()); |
108 | |
109 | struct iter_ref3 { |
110 | operator iter_rvalue_ref() const; |
111 | }; |
112 | namespace std { |
113 | template <template <class> class XQual, template <class> class YQual> |
114 | struct basic_common_reference<iter_ref3, iter_rvalue_ref, XQual, YQual> { |
115 | using type = iter_rvalue_ref; |
116 | }; |
117 | template <template <class> class XQual, template <class> class YQual> |
118 | struct basic_common_reference<iter_rvalue_ref, iter_ref3, XQual, YQual> { |
119 | using type = iter_rvalue_ref; |
120 | }; |
121 | } // namespace std |
122 | static_assert(std::common_reference_with<iter_ref3&&, iter_rvalue_ref&&>); |
123 | |
124 | struct different_reference_types_with_common_reference { |
125 | using value_type = iter_ref3; |
126 | iter_ref3& operator*() const; |
127 | friend iter_rvalue_ref&& iter_move(different_reference_types_with_common_reference); |
128 | }; |
129 | static_assert(check_indirectly_readable<different_reference_types_with_common_reference>()); |
130 | |
131 | struct iter_ref4 { |
132 | operator iter_rvalue_ref() const; |
133 | }; |
134 | namespace std { |
135 | template <template <class> class XQual, template <class> class YQual> |
136 | struct basic_common_reference<iter_ref4, iter_rvalue_ref, XQual, YQual> { |
137 | using type = iter_rvalue_ref; |
138 | }; |
139 | template <template <class> class XQual, template <class> class YQual> |
140 | struct basic_common_reference<iter_rvalue_ref, iter_ref4, XQual, YQual> { |
141 | using type = iter_rvalue_ref; |
142 | }; |
143 | |
144 | template <> |
145 | struct common_reference<iter_ref4 const&, iter_rvalue_ref&&> {}; |
146 | template <> |
147 | struct common_reference<iter_rvalue_ref&&, iter_ref4 const&> {}; |
148 | } // namespace std |
149 | static_assert(std::common_reference_with<iter_ref4&&, iter_rvalue_ref&&>); |
150 | static_assert(!std::common_reference_with<iter_ref4 const&, iter_rvalue_ref&&>); |
151 | |
152 | struct different_reference_types_without_common_reference_to_const { |
153 | using value_type = iter_ref4; |
154 | iter_ref4& operator*() const; |
155 | friend iter_rvalue_ref&& iter_move(different_reference_types_without_common_reference_to_const); |
156 | }; |
157 | static_assert(!check_indirectly_readable<different_reference_types_without_common_reference_to_const>()); |
158 | |
159 | struct non_const_deref { |
160 | int& operator*(); |
161 | }; |
162 | static_assert(!check_indirectly_readable<non_const_deref>()); |
163 | |
164 | struct not_referenceable { |
165 | using value_type = void; |
166 | void operator*() const; |
167 | }; |
168 | static_assert(!std::indirectly_readable<not_referenceable>); |
169 | |
170 | struct legacy_output_iterator { |
171 | using value_type = void; |
172 | legacy_output_iterator& operator*(); |
173 | }; |
174 | |
175 | static_assert(!std::indirectly_readable<legacy_output_iterator>); |
176 | |
177 | struct S {}; |
178 | static_assert(!std::indirectly_readable<S>); |
179 | static_assert(!std::indirectly_readable<int S::*>); |
180 | static_assert(!std::indirectly_readable<int (S::*)()>); |
181 | static_assert(!std::indirectly_readable<int (S::*)() noexcept>); |
182 | static_assert(!std::indirectly_readable<int (S::*)() &>); |
183 | static_assert(!std::indirectly_readable<int (S::*)() & noexcept>); |
184 | static_assert(!std::indirectly_readable<int (S::*)() &&>); |
185 | static_assert(!std::indirectly_readable < int (S::*)() && noexcept >); |
186 | static_assert(!std::indirectly_readable<int (S::*)() const>); |
187 | static_assert(!std::indirectly_readable<int (S::*)() const noexcept>); |
188 | static_assert(!std::indirectly_readable<int (S::*)() const&>); |
189 | static_assert(!std::indirectly_readable<int (S::*)() const & noexcept>); |
190 | static_assert(!std::indirectly_readable<int (S::*)() const&&>); |
191 | static_assert(!std::indirectly_readable < int (S::*)() const&& noexcept >); |
192 | static_assert(!std::indirectly_readable<int (S::*)() volatile>); |
193 | static_assert(!std::indirectly_readable<int (S::*)() volatile noexcept>); |
194 | static_assert(!std::indirectly_readable<int (S::*)() volatile&>); |
195 | static_assert(!std::indirectly_readable<int (S::*)() volatile & noexcept>); |
196 | static_assert(!std::indirectly_readable<int (S::*)() volatile&&>); |
197 | static_assert(!std::indirectly_readable < int (S::*)() volatile&& noexcept >); |
198 | |