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_20_matrix.lst
61 changes: 61 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,61 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#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 constexpr void swap(swap_counter& lhs, swap_counter& rhs) noexcept {
Andor233 marked this conversation as resolved.
Show resolved Hide resolved
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_);
}
}

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


void test_gh_4595() {
{
static_assert([] {
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);
}());
Andor233 marked this conversation as resolved.
Show resolved Hide resolved
}

{
static_assert([] {
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);
}());
}

{
static_assert([] {
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);
}());
}
}

int main() {
test_gh_4595();
}
Loading