Skip to content

Commit c8f45be

Browse files
<utility>: Remove self swap check from pair. (#4674)
Co-authored-by: Stephan T. Lavavej <[email protected]>
1 parent d1489f2 commit c8f45be

File tree

4 files changed

+99
-8
lines changed

4 files changed

+99
-8
lines changed

stl/inc/utility

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -441,21 +441,17 @@ struct pair { // store a pair of values
441441
_CONSTEXPR20 void swap(pair& _Right) noexcept(
442442
_Is_nothrow_swappable<_Ty1>::value && _Is_nothrow_swappable<_Ty2>::value) {
443443
using _STD swap;
444-
if (this != _STD addressof(_Right)) {
445-
swap(first, _Right.first); // intentional ADL
446-
swap(second, _Right.second); // intentional ADL
447-
}
444+
swap(first, _Right.first); // intentional ADL
445+
swap(second, _Right.second); // intentional ADL
448446
}
449447

450448
#if _HAS_CXX23
451449
template <int = 0> // see GH-3013
452450
constexpr void swap(const pair& _Right) const
453451
noexcept(is_nothrow_swappable_v<const _Ty1> && is_nothrow_swappable_v<const _Ty2>) {
454452
using _STD swap;
455-
if (this != _STD addressof(_Right)) {
456-
swap(first, _Right.first); // intentional ADL
457-
swap(second, _Right.second); // intentional ADL
458-
}
453+
swap(first, _Right.first); // intentional ADL
454+
swap(second, _Right.second); // intentional ADL
459455
}
460456
#endif // _HAS_CXX23
461457

tests/std/test.lst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ tests\GH_004201_chrono_formatter
243243
tests\GH_004275_seeking_fancy_iterators
244244
tests\GH_004388_unordered_meow_operator_equal
245245
tests\GH_004477_mdspan_warning_5246
246+
tests\GH_004597_self_swap
246247
tests\GH_004618_mixed_operator_usage_keeps_statistical_properties
247248
tests\GH_004618_normal_distribution_avoids_resets
248249
tests\GH_004657_expected_constraints_permissive
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
RUNALL_INCLUDE ..\usual_matrix.lst
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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

Comments
 (0)