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