diff --git a/stl/inc/mutex b/stl/inc/mutex index 25cb1aed891..8cb450c59d7 100644 --- a/stl/inc/mutex +++ b/stl/inc/mutex @@ -170,17 +170,8 @@ public: _Other._Owns = false; } - unique_lock& operator=(unique_lock&& _Other) noexcept /* strengthened */ { - if (this != _STD addressof(_Other)) { - if (_Owns) { - _Pmtx->unlock(); - } - - _Pmtx = _Other._Pmtx; - _Owns = _Other._Owns; - _Other._Pmtx = nullptr; - _Other._Owns = false; - } + unique_lock& operator=(unique_lock&& _Other) noexcept { + unique_lock{_STD move(_Other)}.swap(*this); return *this; } diff --git a/stl/inc/shared_mutex b/stl/inc/shared_mutex index 3c67475e645..06ebb758e3f 100644 --- a/stl/inc/shared_mutex +++ b/stl/inc/shared_mutex @@ -251,14 +251,7 @@ public: } shared_lock& operator=(shared_lock&& _Right) noexcept { - if (_Owns) { - _Pmtx->unlock_shared(); - } - - _Pmtx = _Right._Pmtx; - _Owns = _Right._Owns; - _Right._Pmtx = nullptr; - _Right._Owns = false; + shared_lock{_STD move(_Right)}.swap(*this); return *this; } diff --git a/tests/std/test.lst b/tests/std/test.lst index 1c40a3294d8..484a11f3a14 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -269,6 +269,7 @@ tests\LWG3561_discard_block_engine_counter tests\LWG3610_iota_view_size_and_integer_class tests\LWG4084_iostream_uppercase_inf_nan tests\LWG4105_ranges_ends_with_and_integer_class +tests\LWG4172_unique_lock_self_move_assignment tests\P0009R18_mdspan_default_accessor tests\P0009R18_mdspan_extents tests\P0009R18_mdspan_extents_death diff --git a/tests/std/tests/LWG4172_unique_lock_self_move_assignment/env.lst b/tests/std/tests/LWG4172_unique_lock_self_move_assignment/env.lst new file mode 100644 index 00000000000..f141421b292 --- /dev/null +++ b/tests/std/tests/LWG4172_unique_lock_self_move_assignment/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\impure_matrix.lst diff --git a/tests/std/tests/LWG4172_unique_lock_self_move_assignment/test.cpp b/tests/std/tests/LWG4172_unique_lock_self_move_assignment/test.cpp new file mode 100644 index 00000000000..bf2aca86448 --- /dev/null +++ b/tests/std/tests/LWG4172_unique_lock_self_move_assignment/test.cpp @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +using namespace std; + +struct lockable_with_counters { + void lock() { + ++lock_count; + } + + void unlock() { + ++unlock_count; + } + + void lock_shared() { + ++shared_lock_count; + } + + void unlock_shared() { + ++shared_unlock_count; + } + + int lock_count = 0; + int unlock_count = 0; + int shared_lock_count = 0; + int shared_unlock_count = 0; +}; + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wself-move" +#endif // __clang__ +#pragma warning(push) +#pragma warning(disable : 26800) // use a moved-from object +int main() { + lockable_with_counters lockable1; + lockable_with_counters lockable2; + + { + unique_lock lock_a(lockable1); + assert(lockable1.lock_count == 1); + assert(lockable1.unlock_count == 0); + + lock_a = move(lock_a); + assert(lockable1.lock_count == 1); + assert(lockable1.unlock_count == 0); + { + unique_lock lock_b(lockable2); + assert(lockable2.lock_count == 1); + assert(lockable2.unlock_count == 0); + + lock_a = move(lock_b); + + assert(lockable1.lock_count == 1); + assert(lockable1.unlock_count == 1); + assert(lockable2.lock_count == 1); + assert(lockable2.unlock_count == 0); + } + + assert(lockable1.lock_count == 1); + assert(lockable1.unlock_count == 1); + assert(lockable2.lock_count == 1); + assert(lockable2.unlock_count == 0); + } + + assert(lockable1.lock_count == 1); + assert(lockable1.unlock_count == 1); + assert(lockable2.lock_count == 1); + assert(lockable2.unlock_count == 1); + + { + shared_lock lock_a(lockable1); + assert(lockable1.shared_lock_count == 1); + assert(lockable1.shared_unlock_count == 0); + + lock_a = move(lock_a); + assert(lockable1.shared_lock_count == 1); + assert(lockable1.shared_unlock_count == 0); + { + shared_lock lock_b(lockable2); + assert(lockable2.shared_lock_count == 1); + assert(lockable2.shared_unlock_count == 0); + + lock_a = move(lock_b); + + assert(lockable1.shared_lock_count == 1); + assert(lockable1.shared_unlock_count == 1); + assert(lockable2.shared_lock_count == 1); + assert(lockable2.shared_unlock_count == 0); + } + + assert(lockable1.shared_lock_count == 1); + assert(lockable1.shared_unlock_count == 1); + assert(lockable2.shared_lock_count == 1); + assert(lockable2.shared_unlock_count == 0); + } + + assert(lockable1.shared_lock_count == 1); + assert(lockable1.shared_unlock_count == 1); + assert(lockable2.shared_lock_count == 1); + assert(lockable2.shared_unlock_count == 1); +} +#pragma warning(pop) +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__