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 iter_ref1 { |
82 | iter_ref1(const iter_ref1&) = delete; |
83 | iter_ref1(iter_ref1&&) = delete; |
84 | }; |
85 | |
86 | struct bad_iter_reference_t { |
87 | using value_type = int; |
88 | iter_ref1& operator*() const; |
89 | }; |
90 | static_assert(!check_indirectly_readable<bad_iter_reference_t>()); |
91 | |
92 | struct iter_ref2 {}; |
93 | struct iter_rvalue_ref {}; |
94 | |
95 | struct unrelated_iter_ref_rvalue_and_iter_rvalue_ref_rvalue { |
96 | using value_type = iter_ref2; |
97 | iter_ref2& operator*() const; |
98 | friend iter_rvalue_ref&& iter_move(unrelated_iter_ref_rvalue_and_iter_rvalue_ref_rvalue); |
99 | }; |
100 | static_assert(!check_indirectly_readable<unrelated_iter_ref_rvalue_and_iter_rvalue_ref_rvalue>()); |
101 | |
102 | struct iter_ref3 { |
103 | operator iter_rvalue_ref() const; |
104 | }; |
105 | |
106 | template <template <class> class XQual, template <class> class YQual> |
107 | struct std::basic_common_reference<iter_ref3, iter_rvalue_ref, XQual, YQual> { |
108 | using type = iter_rvalue_ref; |
109 | }; |
110 | template <template <class> class XQual, template <class> class YQual> |
111 | struct std::basic_common_reference<iter_rvalue_ref, iter_ref3, XQual, YQual> { |
112 | using type = iter_rvalue_ref; |
113 | }; |
114 | |
115 | static_assert(std::common_reference_with<iter_ref3&&, iter_rvalue_ref&&>); |
116 | |
117 | struct different_reference_types_with_common_reference { |
118 | using value_type = iter_ref3; |
119 | iter_ref3& operator*() const; |
120 | friend iter_rvalue_ref&& iter_move(different_reference_types_with_common_reference); |
121 | }; |
122 | static_assert(check_indirectly_readable<different_reference_types_with_common_reference>()); |
123 | |
124 | struct iter_ref4 { |
125 | operator iter_rvalue_ref(); |
126 | }; |
127 | |
128 | static_assert(std::common_reference_with<iter_ref4&&, iter_rvalue_ref&&>); |
129 | static_assert(!std::common_reference_with<iter_ref4 const&, iter_rvalue_ref&&>); |
130 | |
131 | struct different_reference_types_without_common_reference_to_const { |
132 | using value_type = iter_ref4; |
133 | iter_ref4& operator*() const; |
134 | friend iter_rvalue_ref&& iter_move(different_reference_types_without_common_reference_to_const); |
135 | }; |
136 | static_assert(!check_indirectly_readable<different_reference_types_without_common_reference_to_const>()); |
137 | |
138 | struct non_const_deref { |
139 | int& operator*(); |
140 | }; |
141 | static_assert(!check_indirectly_readable<non_const_deref>()); |
142 | |
143 | struct not_referenceable { |
144 | using value_type = void; |
145 | void operator*() const; |
146 | }; |
147 | static_assert(!std::indirectly_readable<not_referenceable>); |
148 | |
149 | struct legacy_output_iterator { |
150 | using value_type = void; |
151 | legacy_output_iterator& operator*(); |
152 | }; |
153 | |
154 | static_assert(!std::indirectly_readable<legacy_output_iterator>); |
155 | |
156 | struct S {}; |
157 | static_assert(!std::indirectly_readable<S>); |
158 | static_assert(!std::indirectly_readable<int S::*>); |
159 | static_assert(!std::indirectly_readable<int (S::*)()>); |
160 | static_assert(!std::indirectly_readable<int (S::*)() noexcept>); |
161 | static_assert(!std::indirectly_readable<int (S::*)() &>); |
162 | static_assert(!std::indirectly_readable<int (S::*)() & noexcept>); |
163 | static_assert(!std::indirectly_readable<int (S::*)() &&>); |
164 | static_assert(!std::indirectly_readable < int (S::*)() && noexcept >); |
165 | static_assert(!std::indirectly_readable<int (S::*)() const>); |
166 | static_assert(!std::indirectly_readable<int (S::*)() const noexcept>); |
167 | static_assert(!std::indirectly_readable<int (S::*)() const&>); |
168 | static_assert(!std::indirectly_readable<int (S::*)() const & noexcept>); |
169 | static_assert(!std::indirectly_readable<int (S::*)() const&&>); |
170 | static_assert(!std::indirectly_readable < int (S::*)() const&& noexcept >); |
171 | static_assert(!std::indirectly_readable<int (S::*)() volatile>); |
172 | static_assert(!std::indirectly_readable<int (S::*)() volatile noexcept>); |
173 | static_assert(!std::indirectly_readable<int (S::*)() volatile&>); |
174 | static_assert(!std::indirectly_readable<int (S::*)() volatile & noexcept>); |
175 | static_assert(!std::indirectly_readable<int (S::*)() volatile&&>); |
176 | static_assert(!std::indirectly_readable < int (S::*)() volatile&& noexcept >); |
177 | |