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 T, class U>
12 // concept same_as;
13 
14 #include <concepts>
15 #include <type_traits>
16 
17 struct S1 {};
18 struct S2 {
19   int i;
20 
21   int& f();
22   double g(int x) const;
23 };
24 struct S3 {
25   int& r;
26 };
27 struct S4 {
28   int&& r;
29 };
30 struct S5 {
31   int* p;
32 };
33 
34 class C1 {};
35 class C2 {
36   [[maybe_unused]] int i;
37 };
38 
39 class C3 {
40 public:
41   int i;
42 };
43 
44 template <class T1, class T2 = T1>
45 class C4 {
46   int t1;
47   int t2;
48 };
49 
50 template <class T1, class T2 = T1>
51 class C5 {
52   [[maybe_unused]] T1 t1;
53 
54 public:
55   T2 t2;
56 };
57 
58 template <class T1, class T2 = T1>
59 class C6 {
60 public:
61   [[maybe_unused]] T1 t1;
62   [[maybe_unused]] T2 t2;
63 };
64 
65 template <class T>
66 struct identity {
67   using type = T;
68 };
69 
70 template <template <typename> class Modifier = identity>
CheckSameAs()71 void CheckSameAs() {
72   static_assert(
73       std::same_as<typename Modifier<int>::type, typename Modifier<int>::type>);
74   static_assert(
75       std::same_as<typename Modifier<S1>::type, typename Modifier<S1>::type>);
76   static_assert(
77       std::same_as<typename Modifier<S2>::type, typename Modifier<S2>::type>);
78   static_assert(
79       std::same_as<typename Modifier<S3>::type, typename Modifier<S3>::type>);
80   static_assert(
81       std::same_as<typename Modifier<S4>::type, typename Modifier<S4>::type>);
82   static_assert(
83       std::same_as<typename Modifier<S5>::type, typename Modifier<S5>::type>);
84   static_assert(
85       std::same_as<typename Modifier<C1>::type, typename Modifier<C1>::type>);
86   static_assert(
87       std::same_as<typename Modifier<C2>::type, typename Modifier<C2>::type>);
88   static_assert(
89       std::same_as<typename Modifier<C3>::type, typename Modifier<C3>::type>);
90   static_assert(std::same_as<typename Modifier<C4<int> >::type,
91                              typename Modifier<C4<int> >::type>);
92   static_assert(std::same_as<typename Modifier<C4<int&> >::type,
93                              typename Modifier<C4<int&> >::type>);
94   static_assert(std::same_as<typename Modifier<C4<int&&> >::type,
95                              typename Modifier<C4<int&&> >::type>);
96   static_assert(std::same_as<typename Modifier<C5<int> >::type,
97                              typename Modifier<C5<int> >::type>);
98   static_assert(std::same_as<typename Modifier<C5<int&> >::type,
99                              typename Modifier<C5<int&> >::type>);
100   static_assert(std::same_as<typename Modifier<C5<int&&> >::type,
101                              typename Modifier<C5<int&&> >::type>);
102   static_assert(std::same_as<typename Modifier<C6<int> >::type,
103                              typename Modifier<C6<int> >::type>);
104   static_assert(std::same_as<typename Modifier<C6<int&> >::type,
105                              typename Modifier<C6<int&> >::type>);
106   static_assert(std::same_as<typename Modifier<C6<int&&> >::type,
107                              typename Modifier<C6<int&&> >::type>);
108 
109   static_assert(std::same_as<typename Modifier<void>::type,
110                              typename Modifier<void>::type>);
111 }
112 
113 template <template <typename> class Modifier1,
114           template <typename> class Modifier2>
CheckNotSameAs()115 void CheckNotSameAs() {
116   static_assert(!std::same_as<typename Modifier1<int>::type,
117                               typename Modifier2<int>::type>);
118   static_assert(!std::same_as<typename Modifier1<S1>::type,
119                               typename Modifier2<S1>::type>);
120   static_assert(!std::same_as<typename Modifier1<S2>::type,
121                               typename Modifier2<S2>::type>);
122   static_assert(!std::same_as<typename Modifier1<S3>::type,
123                               typename Modifier2<S3>::type>);
124   static_assert(!std::same_as<typename Modifier1<S4>::type,
125                               typename Modifier2<S4>::type>);
126   static_assert(!std::same_as<typename Modifier1<S5>::type,
127                               typename Modifier2<S5>::type>);
128   static_assert(!std::same_as<typename Modifier1<C1>::type,
129                               typename Modifier2<C1>::type>);
130   static_assert(!std::same_as<typename Modifier1<C2>::type,
131                               typename Modifier2<C2>::type>);
132   static_assert(!std::same_as<typename Modifier1<C3>::type,
133                               typename Modifier2<C3>::type>);
134   static_assert(!std::same_as<typename Modifier1<C4<int> >::type,
135                               typename Modifier2<C4<int> >::type>);
136   static_assert(!std::same_as<typename Modifier1<C4<int&> >::type,
137                               typename Modifier2<C4<int&> >::type>);
138   static_assert(!std::same_as<typename Modifier1<C4<int&&> >::type,
139                               typename Modifier2<C4<int&&> >::type>);
140   static_assert(!std::same_as<typename Modifier1<C5<int> >::type,
141                               typename Modifier2<C5<int> >::type>);
142   static_assert(!std::same_as<typename Modifier1<C5<int&> >::type,
143                               typename Modifier2<C5<int&> >::type>);
144   static_assert(!std::same_as<typename Modifier1<C5<int&&> >::type,
145                               typename Modifier2<C5<int&&> >::type>);
146   static_assert(!std::same_as<typename Modifier1<C6<int> >::type,
147                               typename Modifier2<C6<int> >::type>);
148   static_assert(!std::same_as<typename Modifier1<C6<int&> >::type,
149                               typename Modifier2<C6<int&> >::type>);
150   static_assert(!std::same_as<typename Modifier1<C6<int&&> >::type,
151                               typename Modifier2<C6<int&&> >::type>);
152 }
153 
154 // Checks subsumption works as intended
155 template <class T, class U>
156 requires std::same_as<T, U> void SubsumptionTest();
157 
158 // clang-format off
159 template <class T, class U>
160 requires std::same_as<U, T> && true // NOLINT(readability-simplify-boolean-expr)
161 int SubsumptionTest();
162 // clang-format on
163 
164 static_assert(std::same_as<int, decltype(SubsumptionTest<int, int>())>);
165 static_assert(std::same_as<int, decltype(SubsumptionTest<void, void>())>);
166 static_assert(
167     std::same_as<int, decltype(SubsumptionTest<int (*)(), int (*)()>())>);
168 static_assert(
169     std::same_as<
170         int, decltype(SubsumptionTest<double (&)(int), double (&)(int)>())>);
171 static_assert(
172     std::same_as<int, decltype(SubsumptionTest<int S2::*, int S2::*>())>);
173 static_assert(
174     std::same_as<int,
175                  decltype(SubsumptionTest<int& (S2::*)(), int& (S2::*)()>())>);
176 
main(int,char **)177 int main(int, char**) {
178   { // Checks std::same_as<T, T> is true
179     CheckSameAs();
180 
181     // Checks std::same_as<T&, T&> is true
182     CheckSameAs<std::add_lvalue_reference>();
183 
184     // Checks std::same_as<T&&, T&&> is true
185     CheckSameAs<std::add_rvalue_reference>();
186 
187     // Checks std::same_as<const T, const T> is true
188     CheckSameAs<std::add_const>();
189 
190     // Checks std::same_as<volatile T, volatile T> is true
191     CheckSameAs<std::add_volatile>();
192 
193     // Checks std::same_as<const volatile T, const volatile T> is true
194     CheckSameAs<std::add_cv>();
195 
196     // Checks std::same_as<T*, T*> is true
197     CheckSameAs<std::add_pointer>();
198 
199     // Checks concrete types are identical
200     static_assert(std::same_as<void, void>);
201 
202     using Void = void;
203     static_assert(std::same_as<void, Void>);
204 
205     static_assert(std::same_as<int[1], int[1]>);
206     static_assert(std::same_as<int[2], int[2]>);
207 
208     static_assert(std::same_as<int (*)(), int (*)()>);
209     static_assert(std::same_as<void (&)(), void (&)()>);
210     static_assert(std::same_as<S1& (*)(S1), S1& (*)(S1)>);
211     static_assert(std::same_as<C1& (&)(S1, int), C1& (&)(S1, int)>);
212 
213     static_assert(std::same_as<int S2::*, int S2::*>);
214     static_assert(std::same_as<double S2::*, double S2::*>);
215 
216     static_assert(std::same_as<int& (S2::*)(), int& (S2::*)()>);
217     static_assert(std::same_as<double& (S2::*)(int), double& (S2::*)(int)>);
218   }
219 
220   { // Checks that `T` and `T&` are distinct types
221     CheckNotSameAs<identity, std::add_lvalue_reference>();
222     CheckNotSameAs<std::add_lvalue_reference, identity>();
223 
224     // Checks that `T` and `T&&` are distinct types
225     CheckNotSameAs<identity, std::add_rvalue_reference>();
226     CheckNotSameAs<std::add_rvalue_reference, identity>();
227 
228     // Checks that `T` and `const T` are distinct types
229     CheckNotSameAs<identity, std::add_const>();
230     CheckNotSameAs<std::add_const, identity>();
231 
232     // Checks that `T` and `volatile T` are distinct types
233     CheckNotSameAs<identity, std::add_volatile>();
234     CheckNotSameAs<std::add_volatile, identity>();
235 
236     // Checks that `T` and `const volatile T` are distinct types
237     CheckNotSameAs<identity, std::add_cv>();
238     CheckNotSameAs<std::add_cv, identity>();
239 
240     // Checks that `const T` and `volatile T` are distinct types
241     CheckNotSameAs<std::add_const, std::add_volatile>();
242     CheckNotSameAs<std::add_volatile, std::add_const>();
243 
244     // Checks that `const T` and `const volatile T` are distinct types
245     CheckNotSameAs<std::add_const, std::add_cv>();
246     CheckNotSameAs<std::add_cv, std::add_const>();
247 
248     // Checks that `volatile T` and `const volatile T` are distinct types
249     CheckNotSameAs<std::add_volatile, std::add_cv>();
250     CheckNotSameAs<std::add_cv, std::add_volatile>();
251 
252     // Checks `T&` and `T&&` are distinct types
253     CheckNotSameAs<std::add_lvalue_reference, std::add_rvalue_reference>();
254     CheckNotSameAs<std::add_rvalue_reference, std::add_lvalue_reference>();
255   }
256 
257   { // Checks different type names are distinct types
258     static_assert(!std::same_as<S1, C1>);
259     static_assert(!std::same_as<C4<int>, C5<int> >);
260     static_assert(!std::same_as<C4<int>, C5<int> >);
261     static_assert(!std::same_as<C5<int, double>, C5<double, int> >);
262 
263     static_assert(!std::same_as<int&, const int&>);
264     static_assert(!std::same_as<int&, volatile int&>);
265     static_assert(!std::same_as<int&, const volatile int&>);
266 
267     static_assert(!std::same_as<int&&, const int&>);
268     static_assert(!std::same_as<int&&, volatile int&>);
269     static_assert(!std::same_as<int&&, const volatile int&>);
270 
271     static_assert(!std::same_as<int&, const int&&>);
272     static_assert(!std::same_as<int&, volatile int&&>);
273     static_assert(!std::same_as<int&, const volatile int&&>);
274 
275     static_assert(!std::same_as<int&&, const int&&>);
276     static_assert(!std::same_as<int&&, volatile int&&>);
277     static_assert(!std::same_as<int&&, const volatile int&&>);
278 
279     static_assert(!std::same_as<void, int>);
280 
281     static_assert(!std::same_as<int[1], int[2]>);
282     static_assert(!std::same_as<double[1], int[2]>);
283 
284     static_assert(!std::same_as<int* (*)(), const int* (*)()>);
285     static_assert(!std::same_as<void (&)(), void (&)(S1)>);
286     static_assert(!std::same_as<S1 (*)(S1), S1& (*)(S1)>);
287     static_assert(!std::same_as<C3 (&)(int), C1& (&)(S1, int)>);
288 
289     static_assert(!std::same_as<int S2::*, double S2::*>);
290 
291     static_assert(!std::same_as<int& (S2::*)(), double& (S2::*)(int)>);
292   }
293 
294   return 0;
295 }
296