Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<utility>: Remove self swap check from pair. #4674

Merged
merged 13 commits into from
May 21, 2024
12 changes: 4 additions & 8 deletions stl/inc/utility
Original file line number Diff line number Diff line change
Expand Up @@ -441,21 +441,17 @@ struct pair { // store a pair of values
_CONSTEXPR20 void swap(pair& _Right) noexcept(
_Is_nothrow_swappable<_Ty1>::value && _Is_nothrow_swappable<_Ty2>::value) {
using _STD swap;
if (this != _STD addressof(_Right)) {
swap(first, _Right.first); // intentional ADL
swap(second, _Right.second); // intentional ADL
}
swap(first, _Right.first); // intentional ADL
swap(second, _Right.second); // intentional ADL
}

#if _HAS_CXX23
template <int = 0> // see GH-3013
constexpr void swap(const pair& _Right) const
noexcept(is_nothrow_swappable_v<const _Ty1> && is_nothrow_swappable_v<const _Ty2>) {
using _STD swap;
if (this != _STD addressof(_Right)) {
swap(first, _Right.first); // intentional ADL
swap(second, _Right.second); // intentional ADL
}
swap(first, _Right.first); // intentional ADL
swap(second, _Right.second); // intentional ADL
Andor233 marked this conversation as resolved.
Show resolved Hide resolved
}
#endif // _HAS_CXX23

Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/GH_004597_self_swap/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_matrix.lst
80 changes: 80 additions & 0 deletions tests/std/tests/GH_004597_self_swap/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <cassert>
#include <utility>

// Test GH-4597 "<utility>: Side effects in self-swaps of pair are skipped"
Andor233 marked this conversation as resolved.
Show resolved Hide resolved
struct swap_counter {
unsigned int* pcnt_ = nullptr;

friend _CONSTEXPR20 void swap(swap_counter& lhs, swap_counter& rhs) noexcept {
std::swap(lhs.pcnt_, rhs.pcnt_);
if (lhs.pcnt_ != nullptr) {
++(*lhs.pcnt_);
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
}
if (rhs.pcnt_ != nullptr) {
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
++(*rhs.pcnt_);
}
}

_CONSTEXPR20 bool operator==(unsigned int x) const {
return *pcnt_ == x;
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
}
};


_CONSTEXPR20 bool test_gh_4595() {
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
auto res1 = [] {
unsigned int cnt{};
std::pair<swap_counter, int> pr{swap_counter{&cnt}, 0};
pr.swap(pr);
return (cnt == 2u) && (pr.first == 2u) && (pr.second == 0);
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
}();


auto res2 = [] {
unsigned int cnt{};
std::pair<swap_counter, int> p1{swap_counter{&cnt}, 0};
std::pair<swap_counter, int> p2{swap_counter{&cnt}, 1};
p1.swap(p2);
return (cnt == 2u) && (p1.first == 2u) && (p1.second == 1) && (p2.first == 2u) && (p2.second == 0);
}();


auto res3 = [] {
unsigned int c1{};
unsigned int c2{2};
std::pair<swap_counter, int> p1{swap_counter{&c1}, 1};
std::pair<swap_counter, int> p2{swap_counter{&c2}, 3};
p1.swap(p2);
return (c1 == 1u) && (c2 == 3u) && (p1.first == 3u) && (p1.second == 3) && (p2.first == 1u) && (p2.second == 1);
}();

auto res4 = true;

#if _HAS_CXX23
res4 = [] {
unsigned int c1{};
unsigned int c2{2};
int i1 = 1;
int i2 = 3;
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
auto s1 = swap_counter{&c1};
auto s2 = swap_counter{&c2};
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
const std::pair<swap_counter&, int&> p1{s1, i1};
const std::pair<swap_counter&, int&> p2{s2, i2};
p1.swap(p2);
return (c1 == 1u) && (c2 == 3u) && (p1.first == 3u) && (p1.second == 3) && (p2.first == 1u) && (p2.second == 1);
}();

#endif
Andor233 marked this conversation as resolved.
Show resolved Hide resolved
return res1 && res2 && res3 && res4;
}

int main() {
#if _HAS_CXX20
static_assert(test_gh_4595());
#else
assert(test_gh_4595());
#endif
Andor233 marked this conversation as resolved.
Show resolved Hide resolved
}