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 swappable_with = // see below
14 
15 #include <concepts>
16 
17 #include <array>
18 #include <cassert>
19 #include <deque>
20 #include <forward_list>
21 #include <list>
22 #include <map>
23 #include <memory>
24 #include <optional>
25 #include <set>
26 #include <unordered_map>
27 #include <unordered_set>
28 #include <vector>
29 
30 #include "type_classification/moveconstructible.h"
31 #include "type_classification/swappable.h"
32 
33 template <class T, class U>
34 constexpr bool check_swappable_with_impl() {
35   static_assert(std::swappable_with<T, U> == std::swappable_with<U, T>);
36   return std::swappable_with<T, U>;
37 }
38 
39 template <class T, class U>
40 constexpr bool check_swappable_with() {
41   static_assert(!check_swappable_with_impl<T, U>());
42   static_assert(!check_swappable_with_impl<T, U const>());
43   static_assert(!check_swappable_with_impl<T const, U>());
44   static_assert(!check_swappable_with_impl<T const, U const>());
45 
46   static_assert(!check_swappable_with_impl<T, U&>());
47   static_assert(!check_swappable_with_impl<T, U const&>());
48   static_assert(!check_swappable_with_impl<T, U volatile&>());
49   static_assert(!check_swappable_with_impl<T, U const volatile&>());
50   static_assert(!check_swappable_with_impl<T const, U&>());
51   static_assert(!check_swappable_with_impl<T const, U const&>());
52   static_assert(!check_swappable_with_impl<T const, U volatile&>());
53   static_assert(!check_swappable_with_impl<T const, U const volatile&>());
54 
55   static_assert(!check_swappable_with_impl<T&, U>());
56   static_assert(!check_swappable_with_impl<T&, U const>());
57   static_assert(!check_swappable_with_impl<T const&, U>());
58   static_assert(!check_swappable_with_impl<T const&, U const>());
59   static_assert(!check_swappable_with_impl<T volatile&, U>());
60   static_assert(!check_swappable_with_impl<T volatile&, U const>());
61   static_assert(!check_swappable_with_impl<T const volatile&, U>());
62   static_assert(!check_swappable_with_impl<T const volatile&, U const>());
63 
64   static_assert(!check_swappable_with_impl<T&, U const&>());
65   static_assert(!check_swappable_with_impl<T&, U volatile&>());
66   static_assert(!check_swappable_with_impl<T&, U const volatile&>());
67   static_assert(!check_swappable_with_impl<T const&, U&>());
68   static_assert(!check_swappable_with_impl<T const&, U const&>());
69   static_assert(!check_swappable_with_impl<T const&, U volatile&>());
70   static_assert(!check_swappable_with_impl<T const&, U const volatile&>());
71   static_assert(!check_swappable_with_impl<T volatile&, U&>());
72   static_assert(!check_swappable_with_impl<T volatile&, U const&>());
73   static_assert(!check_swappable_with_impl<T volatile&, U const volatile&>());
74   static_assert(!check_swappable_with_impl<T const volatile&, U&>());
75   static_assert(!check_swappable_with_impl<T const volatile&, U const&>());
76   static_assert(!check_swappable_with_impl<T const volatile&, U volatile&>());
77   static_assert(
78       !check_swappable_with_impl<T const volatile&, U const volatile&>());
79 
80   static_assert(!check_swappable_with_impl<T, U&&>());
81   static_assert(!check_swappable_with_impl<T, U const&&>());
82   static_assert(!check_swappable_with_impl<T, U volatile&&>());
83   static_assert(!check_swappable_with_impl<T, U const volatile&&>());
84   static_assert(!check_swappable_with_impl<T const, U&&>());
85   static_assert(!check_swappable_with_impl<T const, U const&&>());
86   static_assert(!check_swappable_with_impl<T const, U volatile&&>());
87   static_assert(!check_swappable_with_impl<T const, U const volatile&&>());
88 
89   static_assert(!check_swappable_with_impl<T&&, U>());
90   static_assert(!check_swappable_with_impl<T&&, U const>());
91   static_assert(!check_swappable_with_impl<T const&&, U>());
92   static_assert(!check_swappable_with_impl<T const&&, U const>());
93   static_assert(!check_swappable_with_impl<T volatile&&, U>());
94   static_assert(!check_swappable_with_impl<T volatile&&, U const>());
95   static_assert(!check_swappable_with_impl<T const volatile&&, U>());
96   static_assert(!check_swappable_with_impl<T const volatile&&, U const>());
97 
98   static_assert(!check_swappable_with_impl<T&, U&&>());
99   static_assert(!check_swappable_with_impl<T&, U const&&>());
100   static_assert(!check_swappable_with_impl<T&, U volatile&&>());
101   static_assert(!check_swappable_with_impl<T&, U const volatile&&>());
102   static_assert(!check_swappable_with_impl<T const&, U&&>());
103   static_assert(!check_swappable_with_impl<T const&, U const&&>());
104   static_assert(!check_swappable_with_impl<T const&, U volatile&&>());
105   static_assert(!check_swappable_with_impl<T const&, U const volatile&&>());
106   static_assert(!check_swappable_with_impl<T volatile&, U&&>());
107   static_assert(!check_swappable_with_impl<T volatile&, U const&&>());
108   static_assert(!check_swappable_with_impl<T volatile&, U volatile&&>());
109   static_assert(!check_swappable_with_impl<T volatile&, U const volatile&&>());
110   static_assert(!check_swappable_with_impl<T const volatile&, U&&>());
111   static_assert(!check_swappable_with_impl<T const volatile&, U const&&>());
112   static_assert(!check_swappable_with_impl<T const volatile&, U volatile&&>());
113   static_assert(
114       !check_swappable_with_impl<T const volatile&, U const volatile&&>());
115 
116   static_assert(!check_swappable_with_impl<T&&, U&>());
117   static_assert(!check_swappable_with_impl<T&&, U const&>());
118   static_assert(!check_swappable_with_impl<T&&, U volatile&>());
119   static_assert(!check_swappable_with_impl<T&&, U const volatile&>());
120   static_assert(!check_swappable_with_impl<T const&&, U&>());
121   static_assert(!check_swappable_with_impl<T const&&, U const&>());
122   static_assert(!check_swappable_with_impl<T const&&, U volatile&>());
123   static_assert(!check_swappable_with_impl<T const&&, U const volatile&>());
124   static_assert(!check_swappable_with_impl<T volatile&&, U&>());
125   static_assert(!check_swappable_with_impl<T volatile&&, U const&>());
126   static_assert(!check_swappable_with_impl<T volatile&&, U volatile&>());
127   static_assert(!check_swappable_with_impl<T volatile&&, U const volatile&>());
128   static_assert(!check_swappable_with_impl<T const volatile&&, U&>());
129   static_assert(!check_swappable_with_impl<T const volatile&&, U const&>());
130   static_assert(!check_swappable_with_impl<T const volatile&&, U volatile&>());
131   static_assert(
132       !check_swappable_with_impl<T const volatile&&, U const volatile&>());
133 
134   static_assert(!check_swappable_with_impl<T&&, U&&>());
135   static_assert(!check_swappable_with_impl<T&&, U const&&>());
136   static_assert(!check_swappable_with_impl<T&&, U volatile&&>());
137   static_assert(!check_swappable_with_impl<T&&, U const volatile&&>());
138   static_assert(!check_swappable_with_impl<T const&&, U&&>());
139   static_assert(!check_swappable_with_impl<T const&&, U const&&>());
140   static_assert(!check_swappable_with_impl<T const&&, U volatile&&>());
141   static_assert(!check_swappable_with_impl<T const&&, U const volatile&&>());
142   static_assert(!check_swappable_with_impl<T volatile&&, U&&>());
143   static_assert(!check_swappable_with_impl<T volatile&&, U const&&>());
144   static_assert(!check_swappable_with_impl<T volatile&&, U volatile&&>());
145   static_assert(!check_swappable_with_impl<T volatile&&, U const volatile&&>());
146   static_assert(!check_swappable_with_impl<T const volatile&&, U&&>());
147   static_assert(!check_swappable_with_impl<T const volatile&&, U const&&>());
148   static_assert(!check_swappable_with_impl<T const volatile&&, U volatile&&>());
149   static_assert(
150       !check_swappable_with_impl<T const volatile&&, U const volatile&&>());
151   return check_swappable_with_impl<T&, U&>();
152 }
153 
154 template <class T, class U>
155 constexpr bool check_swappable_with_including_lvalue_ref_to_volatile() {
156   constexpr auto result = check_swappable_with<T, U>();
157   static_assert(check_swappable_with_impl<T volatile&, U volatile&>() ==
158                 result);
159   return result;
160 }
161 
162 namespace fundamental {
163 static_assert(
164     check_swappable_with_including_lvalue_ref_to_volatile<int, int>());
165 static_assert(
166     check_swappable_with_including_lvalue_ref_to_volatile<double, double>());
167 static_assert(
168     !check_swappable_with_including_lvalue_ref_to_volatile<int, double>());
169 
170 static_assert(
171     check_swappable_with_including_lvalue_ref_to_volatile<int*, int*>());
172 static_assert(
173     !check_swappable_with_including_lvalue_ref_to_volatile<int, int*>());
174 static_assert(check_swappable_with_including_lvalue_ref_to_volatile<
175               int (*)(), int (*)()>());
176 static_assert(
177     !check_swappable_with_including_lvalue_ref_to_volatile<int, int (*)()>());
178 
179 struct S {};
180 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<int, S>());
181 static_assert(check_swappable_with_including_lvalue_ref_to_volatile<
182               int S::*, int S::*>());
183 static_assert(
184     !check_swappable_with_including_lvalue_ref_to_volatile<int, int S::*>());
185 static_assert(check_swappable_with_including_lvalue_ref_to_volatile<
186               int (S::*)(), int (S::*)()>());
187 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
188               int, int (S::*)()>());
189 static_assert(check_swappable_with_including_lvalue_ref_to_volatile<
190               int (S::*)() noexcept, int (S::*)() noexcept>());
191 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
192               int (S::*)() noexcept, int (S::*)()>());
193 static_assert(check_swappable_with_including_lvalue_ref_to_volatile<
194               int (S::*)() const, int (S::*)() const>());
195 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
196               int (S::*)() const, int (S::*)()>());
197 static_assert(check_swappable_with_including_lvalue_ref_to_volatile<
198               int (S::*)() const noexcept, int (S::*)() const noexcept>());
199 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
200               int (S::*)() const, int (S::*)() const noexcept>());
201 static_assert(check_swappable_with_including_lvalue_ref_to_volatile<
202               int (S::*)() volatile, int (S::*)() volatile>());
203 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
204               int (S::*)() volatile, int (S::*)()>());
205 static_assert(check_swappable_with_including_lvalue_ref_to_volatile<
206               int (S::*)() const volatile, int (S::*)() const volatile>());
207 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
208               int (S::*)() const volatile, int (S::*)()>());
209 
210 static_assert(
211     check_swappable_with_including_lvalue_ref_to_volatile<int[5], int[5]>());
212 static_assert(
213     !check_swappable_with_including_lvalue_ref_to_volatile<int[5], int[6]>());
214 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
215               int[5], double[5]>());
216 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
217               int[5], double[6]>());
218 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<int[5][6],
219                                                                      int[5]>());
220 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<int[5][6],
221                                                                      int[6]>());
222 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
223               int[5][6], double[5]>());
224 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
225               int[5][6], double[6]>());
226 static_assert(check_swappable_with_including_lvalue_ref_to_volatile<
227               int[5][6], int[5][6]>());
228 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
229               int[5][6], int[5][4]>());
230 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
231               int[5][6], int[6][5]>());
232 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
233               int[5][6], double[5][6]>());
234 static_assert(!check_swappable_with_including_lvalue_ref_to_volatile<
235               int[5][6], double[6][5]>());
236 
237 // always false
238 static_assert(!check_swappable_with_impl<void, void>());
239 static_assert(!check_swappable_with_impl<int, void>());
240 static_assert(!check_swappable_with_impl<int&, void>());
241 static_assert(!check_swappable_with_impl<void, int>());
242 static_assert(!check_swappable_with_impl<void, int&>());
243 static_assert(!check_swappable_with_impl<int, int()>());
244 static_assert(!check_swappable_with_impl<int, int (&)()>());
245 } // namespace fundamental
246 
247 namespace adl {
248 static_assert(
249     check_swappable_with<lvalue_adl_swappable, lvalue_adl_swappable>());
250 static_assert(check_swappable_with<lvalue_rvalue_adl_swappable,
251                                    lvalue_rvalue_adl_swappable>());
252 static_assert(check_swappable_with<rvalue_lvalue_adl_swappable,
253                                    rvalue_lvalue_adl_swappable>());
254 static_assert(
255     check_swappable_with_impl<rvalue_adl_swappable, rvalue_adl_swappable>());
256 static_assert(!check_swappable_with_impl<lvalue_rvalue_adl_swappable&,
257                                          lvalue_rvalue_adl_swappable&&>());
258 
259 struct s1 {};
260 struct no_common_reference_with_s1 {
261   friend void swap(s1&, no_common_reference_with_s1&);
262   friend void swap(no_common_reference_with_s1&, s1&);
263 };
264 static_assert(!check_swappable_with<s1, no_common_reference_with_s1>());
265 
266 struct one_way_swappable_with_s1 {
267   friend void swap(s1&, one_way_swappable_with_s1&);
268   operator s1();
269 };
270 static_assert(std::common_reference_with<one_way_swappable_with_s1, s1>);
271 static_assert(!check_swappable_with<one_way_swappable_with_s1, s1>());
272 
273 struct one_way_swappable_with_s1_other_way {
274   friend void swap(one_way_swappable_with_s1_other_way&, s1&);
275   operator s1();
276 };
277 static_assert(
278     std::common_reference_with<one_way_swappable_with_s1_other_way, s1>);
279 static_assert(!check_swappable_with<one_way_swappable_with_s1_other_way, s1>());
280 
281 struct can_swap_with_s1_but_not_swappable {
282   can_swap_with_s1_but_not_swappable(can_swap_with_s1_but_not_swappable&&) =
283       delete;
284   friend void swap(s1&, can_swap_with_s1_but_not_swappable&);
285   friend void swap(can_swap_with_s1_but_not_swappable&, s1&);
286 
287   operator s1() const;
288 };
289 static_assert(
290     std::common_reference_with<can_swap_with_s1_but_not_swappable, s1>);
291 static_assert(!std::swappable<can_swap_with_s1_but_not_swappable>);
292 static_assert(
293     !check_swappable_with<can_swap_with_s1_but_not_swappable&, s1&>());
294 
295 struct swappable_with_s1 {
296   friend void swap(s1&, swappable_with_s1&);
297   friend void swap(swappable_with_s1&, s1&);
298   operator s1() const;
299 };
300 static_assert(check_swappable_with<swappable_with_s1, s1>());
301 
302 struct swappable_with_const_s1_but_not_swappable {
303   swappable_with_const_s1_but_not_swappable(
304       swappable_with_const_s1_but_not_swappable const&);
305   swappable_with_const_s1_but_not_swappable(
306       swappable_with_const_s1_but_not_swappable const&&);
307   swappable_with_const_s1_but_not_swappable&
308   operator=(swappable_with_const_s1_but_not_swappable const&);
309   swappable_with_const_s1_but_not_swappable&
310   operator=(swappable_with_const_s1_but_not_swappable const&&);
311 
312   friend void swap(s1 const&, swappable_with_const_s1_but_not_swappable const&);
313   friend void swap(swappable_with_const_s1_but_not_swappable const&, s1 const&);
314 
315   operator s1 const &() const;
316 };
317 static_assert(
318     !std::swappable<swappable_with_const_s1_but_not_swappable const&>);
319 static_assert(!std::swappable_with<
320               swappable_with_const_s1_but_not_swappable const&, s1 const&>);
321 
322 struct swappable_with_volatile_s1_but_not_swappable {
323   swappable_with_volatile_s1_but_not_swappable(
324       swappable_with_volatile_s1_but_not_swappable volatile&);
325   swappable_with_volatile_s1_but_not_swappable(
326       swappable_with_volatile_s1_but_not_swappable volatile&&);
327   swappable_with_volatile_s1_but_not_swappable&
328   operator=(swappable_with_volatile_s1_but_not_swappable volatile&);
329   swappable_with_volatile_s1_but_not_swappable&
330   operator=(swappable_with_volatile_s1_but_not_swappable volatile&&);
331 
332   friend void swap(s1 volatile&,
333                    swappable_with_volatile_s1_but_not_swappable volatile&);
334   friend void swap(swappable_with_volatile_s1_but_not_swappable volatile&,
335                    s1 volatile&);
336 
337   operator s1 volatile &() volatile;
338 };
339 static_assert(
340     !std::swappable<swappable_with_volatile_s1_but_not_swappable volatile&>);
341 static_assert(
342     !std::swappable_with<swappable_with_volatile_s1_but_not_swappable volatile&,
343                          s1 volatile&>);
344 
345 struct swappable_with_cv_s1_but_not_swappable {
346   swappable_with_cv_s1_but_not_swappable(
347       swappable_with_cv_s1_but_not_swappable const volatile&);
348   swappable_with_cv_s1_but_not_swappable(
349       swappable_with_cv_s1_but_not_swappable const volatile&&);
350   swappable_with_cv_s1_but_not_swappable&
351   operator=(swappable_with_cv_s1_but_not_swappable const volatile&);
352   swappable_with_cv_s1_but_not_swappable&
353   operator=(swappable_with_cv_s1_but_not_swappable const volatile&&);
354 
355   friend void swap(s1 const volatile&,
356                    swappable_with_cv_s1_but_not_swappable const volatile&);
357   friend void swap(swappable_with_cv_s1_but_not_swappable const volatile&,
358                    s1 const volatile&);
359 
360   operator s1 const volatile &() const volatile;
361 };
362 static_assert(
363     !std::swappable<swappable_with_cv_s1_but_not_swappable const volatile&>);
364 static_assert(
365     !std::swappable_with<swappable_with_cv_s1_but_not_swappable const volatile&,
366                          s1 const volatile&>);
367 
368 struct s2 {
369   friend void swap(s2 const&, s2 const&);
370   friend void swap(s2 volatile&, s2 volatile&);
371   friend void swap(s2 const volatile&, s2 const volatile&);
372 };
373 
374 struct swappable_with_const_s2 {
375   swappable_with_const_s2(swappable_with_const_s2 const&);
376   swappable_with_const_s2(swappable_with_const_s2 const&&);
377   swappable_with_const_s2& operator=(swappable_with_const_s2 const&);
378   swappable_with_const_s2& operator=(swappable_with_const_s2 const&&);
379 
380   friend void swap(swappable_with_const_s2 const&,
381                    swappable_with_const_s2 const&);
382   friend void swap(s2 const&, swappable_with_const_s2 const&);
383   friend void swap(swappable_with_const_s2 const&, s2 const&);
384 
385   operator s2 const &() const;
386 };
387 static_assert(std::swappable_with<swappable_with_const_s2 const&, s2 const&>);
388 
389 struct swappable_with_volatile_s2 {
390   swappable_with_volatile_s2(swappable_with_volatile_s2 volatile&);
391   swappable_with_volatile_s2(swappable_with_volatile_s2 volatile&&);
392   swappable_with_volatile_s2& operator=(swappable_with_volatile_s2 volatile&);
393   swappable_with_volatile_s2& operator=(swappable_with_volatile_s2 volatile&&);
394 
395   friend void swap(swappable_with_volatile_s2 volatile&,
396                    swappable_with_volatile_s2 volatile&);
397   friend void swap(s2 volatile&, swappable_with_volatile_s2 volatile&);
398   friend void swap(swappable_with_volatile_s2 volatile&, s2 volatile&);
399 
400   operator s2 volatile &() volatile;
401 };
402 static_assert(
403     std::swappable_with<swappable_with_volatile_s2 volatile&, s2 volatile&>);
404 
405 struct swappable_with_cv_s2 {
406   swappable_with_cv_s2(swappable_with_cv_s2 const volatile&);
407   swappable_with_cv_s2(swappable_with_cv_s2 const volatile&&);
408   swappable_with_cv_s2& operator=(swappable_with_cv_s2 const volatile&);
409   swappable_with_cv_s2& operator=(swappable_with_cv_s2 const volatile&&);
410 
411   friend void swap(swappable_with_cv_s2 const volatile&,
412                    swappable_with_cv_s2 const volatile&);
413   friend void swap(s2 const volatile&, swappable_with_cv_s2 const volatile&);
414   friend void swap(swappable_with_cv_s2 const volatile&, s2 const volatile&);
415 
416   operator s2 const volatile &() const volatile;
417 };
418 static_assert(std::swappable_with<swappable_with_cv_s2 const volatile&,
419                                   s2 const volatile&>);
420 
421 struct swappable_with_rvalue_ref_to_s1_but_not_swappable {
422   friend void swap(swappable_with_rvalue_ref_to_s1_but_not_swappable&&,
423                    swappable_with_rvalue_ref_to_s1_but_not_swappable&&);
424   friend void swap(s1&&, swappable_with_rvalue_ref_to_s1_but_not_swappable&&);
425   friend void swap(swappable_with_rvalue_ref_to_s1_but_not_swappable&&, s1&&);
426 
427   operator s1() const;
428 };
429 static_assert(
430     !std::swappable<swappable_with_rvalue_ref_to_s1_but_not_swappable const&&>);
431 static_assert(
432     !std::swappable_with<
433         swappable_with_rvalue_ref_to_s1_but_not_swappable const&&, s1 const&&>);
434 
435 struct swappable_with_rvalue_ref_to_const_s1_but_not_swappable {
436   friend void
437   swap(s1 const&&,
438        swappable_with_rvalue_ref_to_const_s1_but_not_swappable const&&);
439   friend void
440   swap(swappable_with_rvalue_ref_to_const_s1_but_not_swappable const&&,
441        s1 const&&);
442 
443   operator s1 const() const;
444 };
445 static_assert(!std::swappable<
446               swappable_with_rvalue_ref_to_const_s1_but_not_swappable const&&>);
447 static_assert(!std::swappable_with<
448               swappable_with_rvalue_ref_to_const_s1_but_not_swappable const&&,
449               s1 const&&>);
450 
451 struct swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable {
452   swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable(
453       swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&);
454   swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable(
455       swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&&);
456   swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable& operator=(
457       swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&);
458   swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable& operator=(
459       swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&&);
460 
461   friend void
462   swap(s1 volatile&&,
463        swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&&);
464   friend void
465   swap(swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&&,
466        s1 volatile&&);
467 
468   operator s1 volatile &&() volatile&&;
469 };
470 static_assert(
471     !std::swappable<
472         swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&&>);
473 static_assert(
474     !std::swappable_with<
475         swappable_with_rvalue_ref_to_volatile_s1_but_not_swappable volatile&&,
476         s1 volatile&&>);
477 
478 struct swappable_with_rvalue_ref_to_cv_s1_but_not_swappable {
479   swappable_with_rvalue_ref_to_cv_s1_but_not_swappable(
480       swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&);
481   swappable_with_rvalue_ref_to_cv_s1_but_not_swappable(
482       swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&&);
483   swappable_with_rvalue_ref_to_cv_s1_but_not_swappable& operator=(
484       swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&);
485   swappable_with_rvalue_ref_to_cv_s1_but_not_swappable& operator=(
486       swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&&);
487 
488   friend void
489   swap(s1 const volatile&&,
490        swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&&);
491   friend void
492   swap(swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&&,
493        s1 const volatile&&);
494 
495   operator s1 const volatile &&() const volatile&&;
496 };
497 static_assert(
498     !std::swappable<
499         swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&&>);
500 static_assert(
501     !std::swappable_with<
502         swappable_with_rvalue_ref_to_cv_s1_but_not_swappable const volatile&&,
503         s1 const volatile&&>);
504 
505 struct s3 {
506   friend void swap(s3&&, s3&&);
507   friend void swap(s3 const&&, s3 const&&);
508   friend void swap(s3 volatile&&, s3 volatile&&);
509   friend void swap(s3 const volatile&&, s3 const volatile&&);
510 };
511 
512 struct swappable_with_rvalue_ref_to_s3 {
513   friend void swap(swappable_with_rvalue_ref_to_s3&&,
514                    swappable_with_rvalue_ref_to_s3&&);
515   friend void swap(s3&&, swappable_with_rvalue_ref_to_s3&&);
516   friend void swap(swappable_with_rvalue_ref_to_s3&&, s3&&);
517 
518   operator s3() const;
519 };
520 static_assert(std::swappable_with<swappable_with_rvalue_ref_to_s3&&, s3&&>);
521 
522 struct swappable_with_rvalue_ref_to_const_s3 {
523   swappable_with_rvalue_ref_to_const_s3(
524       swappable_with_rvalue_ref_to_const_s3 const&);
525   swappable_with_rvalue_ref_to_const_s3(
526       swappable_with_rvalue_ref_to_const_s3 const&&);
527   swappable_with_rvalue_ref_to_const_s3&
528   operator=(swappable_with_rvalue_ref_to_const_s3 const&);
529   swappable_with_rvalue_ref_to_const_s3&
530   operator=(swappable_with_rvalue_ref_to_const_s3 const&&);
531 
532   friend void swap(swappable_with_rvalue_ref_to_const_s3 const&&,
533                    swappable_with_rvalue_ref_to_const_s3 const&&);
534   friend void swap(s3 const&&, swappable_with_rvalue_ref_to_const_s3 const&&);
535   friend void swap(swappable_with_rvalue_ref_to_const_s3 const&&, s3 const&&);
536 
537   operator s3() const;
538 };
539 static_assert(std::swappable_with<swappable_with_rvalue_ref_to_const_s3 const&&,
540                                   s3 const&&>);
541 
542 struct swappable_with_rvalue_ref_to_volatile_s3 {
543   swappable_with_rvalue_ref_to_volatile_s3(
544       swappable_with_rvalue_ref_to_volatile_s3 volatile&);
545   swappable_with_rvalue_ref_to_volatile_s3(
546       swappable_with_rvalue_ref_to_volatile_s3 volatile&&);
547   swappable_with_rvalue_ref_to_volatile_s3&
548   operator=(swappable_with_rvalue_ref_to_volatile_s3 volatile&);
549   swappable_with_rvalue_ref_to_volatile_s3&
550   operator=(swappable_with_rvalue_ref_to_volatile_s3 volatile&&);
551 
552   friend void swap(swappable_with_rvalue_ref_to_volatile_s3 volatile&&,
553                    swappable_with_rvalue_ref_to_volatile_s3 volatile&&);
554   friend void swap(s3 volatile&&,
555                    swappable_with_rvalue_ref_to_volatile_s3 volatile&&);
556   friend void swap(swappable_with_rvalue_ref_to_volatile_s3 volatile&&,
557                    s3 volatile&&);
558 
559   operator s3 volatile &&() volatile;
560 };
561 static_assert(
562     std::swappable_with<swappable_with_rvalue_ref_to_volatile_s3 volatile&&,
563                         s3 volatile&&>);
564 
565 struct swappable_with_rvalue_ref_to_cv_s3 {
566   swappable_with_rvalue_ref_to_cv_s3(
567       swappable_with_rvalue_ref_to_cv_s3 const volatile&);
568   swappable_with_rvalue_ref_to_cv_s3(
569       swappable_with_rvalue_ref_to_cv_s3 const volatile&&);
570   swappable_with_rvalue_ref_to_cv_s3&
571   operator=(swappable_with_rvalue_ref_to_cv_s3 const volatile&);
572   swappable_with_rvalue_ref_to_cv_s3&
573   operator=(swappable_with_rvalue_ref_to_cv_s3 const volatile&&);
574 
575   friend void swap(swappable_with_rvalue_ref_to_cv_s3 const volatile&&,
576                    swappable_with_rvalue_ref_to_cv_s3 const volatile&&);
577   friend void swap(s3 const volatile&&,
578                    swappable_with_rvalue_ref_to_cv_s3 const volatile&&);
579   friend void swap(swappable_with_rvalue_ref_to_cv_s3 const volatile&&,
580                    s3 const volatile&&);
581 
582   operator s3 const volatile &&() const volatile;
583 };
584 static_assert(
585     std::swappable_with<swappable_with_rvalue_ref_to_cv_s3 const volatile&&,
586                         s3 const volatile&&>);
587 
588 namespace union_swap {
589 union adl_swappable {
590   int x;
591   double y;
592 
593   operator int() const;
594 };
595 
596 void swap(adl_swappable&, adl_swappable&) noexcept;
597 void swap(adl_swappable&&, adl_swappable&&) noexcept;
598 void swap(adl_swappable&, int&) noexcept;
599 void swap(int&, adl_swappable&) noexcept;
600 } // namespace union_swap
601 static_assert(
602     std::swappable_with<union_swap::adl_swappable, union_swap::adl_swappable>);
603 static_assert(std::swappable_with<union_swap::adl_swappable&,
604                                   union_swap::adl_swappable&>);
605 static_assert(std::swappable_with<union_swap::adl_swappable&&,
606                                   union_swap::adl_swappable&&>);
607 static_assert(std::swappable_with<union_swap::adl_swappable&, int&>);
608 } // namespace adl
609 
610 namespace standard_types {
611 static_assert(
612     check_swappable_with<std::array<int, 10>, std::array<int, 10> >());
613 static_assert(
614     !check_swappable_with<std::array<int, 10>, std::array<double, 10> >());
615 static_assert(check_swappable_with<std::deque<int>, std::deque<int> >());
616 static_assert(!check_swappable_with<std::deque<int>, std::vector<int> >());
617 static_assert(
618     check_swappable_with<std::forward_list<int>, std::forward_list<int> >());
619 static_assert(
620     !check_swappable_with<std::forward_list<int>, std::vector<int> >());
621 static_assert(check_swappable_with<std::list<int>, std::list<int> >());
622 static_assert(!check_swappable_with<std::list<int>, std::vector<int> >());
623 
624 static_assert(
625     check_swappable_with<std::map<int, void*>, std::map<int, void*> >());
626 static_assert(!check_swappable_with<std::map<int, void*>, std::vector<int> >());
627 static_assert(check_swappable_with<std::optional<std::vector<int> >,
628                                    std::optional<std::vector<int> > >());
629 static_assert(!check_swappable_with<std::optional<std::vector<int> >,
630                                     std::vector<int> >());
631 static_assert(check_swappable_with<std::vector<int>, std::vector<int> >());
632 static_assert(!check_swappable_with<std::vector<int>, int>());
633 } // namespace standard_types
634 
635 namespace types_with_purpose {
636 static_assert(!check_swappable_with<DeletedMoveCtor, DeletedMoveCtor>());
637 static_assert(!check_swappable_with<ImplicitlyDeletedMoveCtor,
638                                     ImplicitlyDeletedMoveCtor>());
639 static_assert(!check_swappable_with<DeletedMoveAssign, DeletedMoveAssign>());
640 static_assert(!check_swappable_with<ImplicitlyDeletedMoveAssign,
641                                     ImplicitlyDeletedMoveAssign>());
642 static_assert(!check_swappable_with<NonMovable, NonMovable>());
643 static_assert(
644     !check_swappable_with<DerivedFromNonMovable, DerivedFromNonMovable>());
645 static_assert(!check_swappable_with<HasANonMovable, HasANonMovable>());
646 } // namespace types_with_purpose
647 
648 namespace LWG3175 {
649 // Example taken directly from [concept.swappable]
650 template <class T, std::swappable_with<T> U>
651 constexpr void value_swap(T&& t, U&& u) {
652   std::ranges::swap(std::forward<T>(t), std::forward<U>(u));
653 }
654 
655 template <std::swappable T>
656 constexpr void lv_swap(T& t1, T& t2) {
657   std::ranges::swap(t1, t2);
658 }
659 
660 namespace N {
661 struct A {
662   int m;
663 };
664 struct Proxy {
665   A* a;
666   constexpr Proxy(A& a_) : a{&a_} {}
667   friend constexpr void swap(Proxy x, Proxy y) {
668     std::ranges::swap(*x.a, *y.a);
669   }
670 };
671 constexpr Proxy proxy(A& a) { return Proxy{a}; }
672 } // namespace N
673 
674 constexpr bool CheckRegression() {
675   int i = 1, j = 2;
676   lv_swap(i, j);
677   assert(i == 2 && j == 1);
678 
679   N::A a1 = {5}, a2 = {-5};
680   value_swap(a1, proxy(a2));
681   assert(a1.m == -5 && a2.m == 5);
682   return true;
683 }
684 
685 static_assert(CheckRegression());
686 } // namespace LWG3175
687