|
| 1 | +// Copyright (c) Microsoft Corporation. |
| 2 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 3 | + |
| 4 | +#include <cassert> |
| 5 | +#include <utility> |
| 6 | + |
| 7 | +struct swap_counter { |
| 8 | + unsigned int* pcnt_ = nullptr; |
| 9 | + |
| 10 | + friend _CONSTEXPR20 void swap(swap_counter& lhs, swap_counter& rhs) noexcept { |
| 11 | + assert(lhs.pcnt_ != nullptr); |
| 12 | + assert(rhs.pcnt_ != nullptr); |
| 13 | + std::swap(lhs.pcnt_, rhs.pcnt_); |
| 14 | + ++*lhs.pcnt_; |
| 15 | + ++*rhs.pcnt_; |
| 16 | + } |
| 17 | + |
| 18 | + _CONSTEXPR20 bool operator==(unsigned int x) const { |
| 19 | + assert(pcnt_ != nullptr); |
| 20 | + return *pcnt_ == x; |
| 21 | + } |
| 22 | +}; |
| 23 | + |
| 24 | + |
| 25 | +// Test GH-4597 "<utility>: Side effects in self-swaps of pair are skipped" |
| 26 | +_CONSTEXPR20 bool test_gh_4597() { |
| 27 | + { |
| 28 | + unsigned int cnt{}; |
| 29 | + std::pair<swap_counter, int> pr{swap_counter{&cnt}, 10}; |
| 30 | + pr.swap(pr); |
| 31 | + assert(cnt == 2u); |
| 32 | + assert(pr.first == 2u); |
| 33 | + assert(pr.second == 10); |
| 34 | + } |
| 35 | + |
| 36 | + { |
| 37 | + unsigned int cnt{}; |
| 38 | + std::pair<swap_counter, int> p1{swap_counter{&cnt}, 10}; |
| 39 | + std::pair<swap_counter, int> p2{swap_counter{&cnt}, 11}; |
| 40 | + p1.swap(p2); |
| 41 | + assert(cnt == 2u); |
| 42 | + assert(p1.first == 2u); |
| 43 | + assert(p1.second == 11); |
| 44 | + assert(p2.first == 2u); |
| 45 | + assert(p2.second == 10); |
| 46 | + } |
| 47 | + |
| 48 | + { |
| 49 | + unsigned int c1{}; |
| 50 | + unsigned int c2{2}; |
| 51 | + std::pair<swap_counter, int> p1{swap_counter{&c1}, 11}; |
| 52 | + std::pair<swap_counter, int> p2{swap_counter{&c2}, 13}; |
| 53 | + p1.swap(p2); |
| 54 | + assert(c1 == 1u); |
| 55 | + assert(c2 == 3u); |
| 56 | + assert(p1.first == 3u); |
| 57 | + assert(p1.second == 13); |
| 58 | + assert(p2.first == 1u); |
| 59 | + assert(p2.second == 11); |
| 60 | + } |
| 61 | + |
| 62 | +#if _HAS_CXX23 |
| 63 | + { |
| 64 | + unsigned int c1{}; |
| 65 | + unsigned int c2{2}; |
| 66 | + int i1 = 11; |
| 67 | + int i2 = 13; |
| 68 | + swap_counter s1{&c1}; |
| 69 | + swap_counter s2{&c2}; |
| 70 | + const std::pair<swap_counter&, int&> p1{s1, i1}; |
| 71 | + const std::pair<swap_counter&, int&> p2{s2, i2}; |
| 72 | + p1.swap(p2); |
| 73 | + assert(c1 == 1u); |
| 74 | + assert(c2 == 3u); |
| 75 | + assert(p1.first == 3u); |
| 76 | + assert(p1.second == 13); |
| 77 | + assert(p2.first == 1u); |
| 78 | + assert(p2.second == 11); |
| 79 | + } |
| 80 | +#endif // _HAS_CXX23 |
| 81 | + |
| 82 | + return true; |
| 83 | +} |
| 84 | + |
| 85 | +int main() { |
| 86 | +#if _HAS_CXX20 |
| 87 | + static_assert(test_gh_4597()); |
| 88 | +#endif // _HAS_CXX20 |
| 89 | + assert(test_gh_4597()); |
| 90 | +} |
0 commit comments