diff --git a/stl/inc/utility b/stl/inc/utility index 49acc0badd..d5e58acc00 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -441,10 +441,8 @@ 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 @@ -452,10 +450,8 @@ struct pair { // store a pair of values constexpr void swap(const pair& _Right) const noexcept(is_nothrow_swappable_v && is_nothrow_swappable_v) { 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 } #endif // _HAS_CXX23 diff --git a/tests/std/test.lst b/tests/std/test.lst index 57a6751751..e821096af6 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -243,6 +243,7 @@ tests\GH_004201_chrono_formatter tests\GH_004275_seeking_fancy_iterators tests\GH_004388_unordered_meow_operator_equal tests\GH_004477_mdspan_warning_5246 +tests\GH_004597_self_swap tests\GH_004618_mixed_operator_usage_keeps_statistical_properties tests\GH_004618_normal_distribution_avoids_resets tests\GH_004657_expected_constraints_permissive diff --git a/tests/std/tests/GH_004597_self_swap/env.lst b/tests/std/tests/GH_004597_self_swap/env.lst new file mode 100644 index 0000000000..19f025bd0e --- /dev/null +++ b/tests/std/tests/GH_004597_self_swap/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_004597_self_swap/test.cpp b/tests/std/tests/GH_004597_self_swap/test.cpp new file mode 100644 index 0000000000..e9bdc3e78f --- /dev/null +++ b/tests/std/tests/GH_004597_self_swap/test.cpp @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +struct swap_counter { + unsigned int* pcnt_ = nullptr; + + friend _CONSTEXPR20 void swap(swap_counter& lhs, swap_counter& rhs) noexcept { + assert(lhs.pcnt_ != nullptr); + assert(rhs.pcnt_ != nullptr); + std::swap(lhs.pcnt_, rhs.pcnt_); + ++*lhs.pcnt_; + ++*rhs.pcnt_; + } + + _CONSTEXPR20 bool operator==(unsigned int x) const { + assert(pcnt_ != nullptr); + return *pcnt_ == x; + } +}; + + +// Test GH-4597 ": Side effects in self-swaps of pair are skipped" +_CONSTEXPR20 bool test_gh_4597() { + { + unsigned int cnt{}; + std::pair pr{swap_counter{&cnt}, 10}; + pr.swap(pr); + assert(cnt == 2u); + assert(pr.first == 2u); + assert(pr.second == 10); + } + + { + unsigned int cnt{}; + std::pair p1{swap_counter{&cnt}, 10}; + std::pair p2{swap_counter{&cnt}, 11}; + p1.swap(p2); + assert(cnt == 2u); + assert(p1.first == 2u); + assert(p1.second == 11); + assert(p2.first == 2u); + assert(p2.second == 10); + } + + { + unsigned int c1{}; + unsigned int c2{2}; + std::pair p1{swap_counter{&c1}, 11}; + std::pair p2{swap_counter{&c2}, 13}; + p1.swap(p2); + assert(c1 == 1u); + assert(c2 == 3u); + assert(p1.first == 3u); + assert(p1.second == 13); + assert(p2.first == 1u); + assert(p2.second == 11); + } + +#if _HAS_CXX23 + { + unsigned int c1{}; + unsigned int c2{2}; + int i1 = 11; + int i2 = 13; + swap_counter s1{&c1}; + swap_counter s2{&c2}; + const std::pair p1{s1, i1}; + const std::pair p2{s2, i2}; + p1.swap(p2); + assert(c1 == 1u); + assert(c2 == 3u); + assert(p1.first == 3u); + assert(p1.second == 13); + assert(p2.first == 1u); + assert(p2.second == 11); + } +#endif // _HAS_CXX23 + + return true; +} + +int main() { +#if _HAS_CXX20 + static_assert(test_gh_4597()); +#endif // _HAS_CXX20 + assert(test_gh_4597()); +}