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