[libcxx] LWG4172 fix self-move-assignment in {unique|shared}_lock (#129542)

Fixes: https://github.com/llvm/llvm-project/issues/127861

---------

Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
This commit is contained in:
Mohamed Atef 2025-12-19 09:06:39 +02:00 committed by GitHub
parent d5326411fe
commit 2c98c6ee0e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 69 additions and 38 deletions

View File

@ -113,7 +113,7 @@
"","","","","","",""
"`LWG3578 <https://wg21.link/LWG3578>`__","Iterator SCARYness in the context of associative container merging","2025-02 (Hagenberg)","","","`#127859 <https://github.com/llvm/llvm-project/issues/127859>`__",""
"`LWG3956 <https://wg21.link/LWG3956>`__","``chrono::parse`` uses ``from_stream`` as a customization point","2025-02 (Hagenberg)","","","`#127860 <https://github.com/llvm/llvm-project/issues/127860>`__",""
"`LWG4172 <https://wg21.link/LWG4172>`__","``unique_lock`` self-move-assignment is broken","2025-02 (Hagenberg)","","","`#127861 <https://github.com/llvm/llvm-project/issues/127861>`__",""
"`LWG4172 <https://wg21.link/LWG4172>`__","``unique_lock`` self-move-assignment is broken","2025-02 (Hagenberg)","|Complete|","22","`#127861 <https://github.com/llvm/llvm-project/issues/127861>`__",""
"`LWG4175 <https://wg21.link/LWG4175>`__","``get_env()`` specified in terms of ``as_const()`` but this doesn't work with rvalue senders","2025-02 (Hagenberg)","","","`#127862 <https://github.com/llvm/llvm-project/issues/127862>`__",""
"`LWG4179 <https://wg21.link/LWG4179>`__","Wrong range in ``[alg.search]``","2025-02 (Hagenberg)","","","`#127863 <https://github.com/llvm/llvm-project/issues/127863>`__",""
"`LWG4186 <https://wg21.link/LWG4186>`__","``regex_traits::transform_primary`` mistakenly detects ``typeid`` of a function","2025-02 (Hagenberg)","","","`#127864 <https://github.com/llvm/llvm-project/issues/127864>`__",""

1 Issue # Issue Name Meeting Status First released version GitHub issue Notes
113
114 `LWG3578 <https://wg21.link/LWG3578>`__ Iterator SCARYness in the context of associative container merging 2025-02 (Hagenberg) `#127859 <https://github.com/llvm/llvm-project/issues/127859>`__
115 `LWG3956 <https://wg21.link/LWG3956>`__ ``chrono::parse`` uses ``from_stream`` as a customization point 2025-02 (Hagenberg) `#127860 <https://github.com/llvm/llvm-project/issues/127860>`__
116 `LWG4172 <https://wg21.link/LWG4172>`__ ``unique_lock`` self-move-assignment is broken 2025-02 (Hagenberg) |Complete| 22 `#127861 <https://github.com/llvm/llvm-project/issues/127861>`__
117 `LWG4175 <https://wg21.link/LWG4175>`__ ``get_env()`` specified in terms of ``as_const()`` but this doesn't work with rvalue senders 2025-02 (Hagenberg) `#127862 <https://github.com/llvm/llvm-project/issues/127862>`__
118 `LWG4179 <https://wg21.link/LWG4179>`__ Wrong range in ``[alg.search]`` 2025-02 (Hagenberg) `#127863 <https://github.com/llvm/llvm-project/issues/127863>`__
119 `LWG4186 <https://wg21.link/LWG4186>`__ ``regex_traits::transform_primary`` mistakenly detects ``typeid`` of a function 2025-02 (Hagenberg) `#127864 <https://github.com/llvm/llvm-project/issues/127864>`__

View File

@ -15,6 +15,7 @@
#include <__memory/addressof.h>
#include <__mutex/tag_types.h>
#include <__system_error/throw_system_error.h>
#include <__utility/move.h>
#include <__utility/swap.h>
#include <cerrno>
@ -22,6 +23,9 @@
# pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Mutex>
@ -74,13 +78,8 @@ public:
}
_LIBCPP_HIDE_FROM_ABI unique_lock& operator=(unique_lock&& __u) _NOEXCEPT {
if (__owns_)
__m_->unlock();
__m_ = __u.__m_;
__owns_ = __u.__owns_;
__u.__m_ = nullptr;
__u.__owns_ = false;
if (this != std::addressof(__u))
unique_lock(std::move(__u)).swap(*this);
return *this;
}
@ -170,4 +169,6 @@ inline _LIBCPP_HIDE_FROM_ABI void swap(unique_lock<_Mutex>& __x, unique_lock<_Mu
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___MUTEX_UNIQUE_LOCK_H

View File

@ -138,6 +138,7 @@ template <class Mutex>
# include <__mutex/tag_types.h>
# include <__mutex/unique_lock.h>
# include <__system_error/throw_system_error.h>
# include <__utility/move.h>
# include <__utility/swap.h>
# include <cerrno>
# include <version>
@ -340,14 +341,8 @@ public:
}
_LIBCPP_HIDE_FROM_ABI shared_lock& operator=(shared_lock&& __u) _NOEXCEPT {
if (__owns_)
__m_->unlock_shared();
__m_ = nullptr;
__owns_ = false;
__m_ = __u.__m_;
__owns_ = __u.__owns_;
__u.__m_ = nullptr;
__u.__owns_ = false;
if (this != std::addressof(__u))
shared_lock(std::move(__u)).swap(*this);
return *this;
}

View File

@ -5,7 +5,9 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
// UNSUPPORTED: no-threads
// UNSUPPORTED: c++03, c++11
@ -13,18 +15,17 @@
// template <class Mutex> class shared_lock;
// shared_lock& operator=(shared_lock&& u);
// shared_lock& operator=(shared_lock&& u) noexcept;
#include <shared_mutex>
#include <cassert>
#include "nasty_containers.h"
#include <shared_mutex>
#include <type_traits>
#include "nasty_containers.h"
#include "test_macros.h"
int main(int, char**)
{
{
int main(int, char**) {
{
typedef std::shared_timed_mutex M;
M m0;
M m1;
@ -35,8 +36,10 @@ int main(int, char**)
assert(lk1.owns_lock() == true);
assert(lk0.mutex() == nullptr);
assert(lk0.owns_lock() == false);
}
{
static_assert(std::is_nothrow_move_assignable<std::shared_lock<M> >::value, "");
}
{
typedef nasty_mutex M;
M m0;
M m1;
@ -47,7 +50,18 @@ int main(int, char**)
assert(lk1.owns_lock() == true);
assert(lk0.mutex() == nullptr);
assert(lk0.owns_lock() == false);
}
static_assert(std::is_nothrow_move_assignable<std::shared_lock<M> >::value, "");
}
{
// Test self move-assignment (LWG4172)
typedef std::shared_timed_mutex M;
M m0;
std::shared_lock<M> lk0(m0);
lk0 = std::move(lk0);
assert(lk0.mutex() == std::addressof(m0));
assert(lk0.owns_lock() == true);
}
return 0;
}

View File

@ -6,31 +6,52 @@
//
//===----------------------------------------------------------------------===//
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
// <mutex>
// template <class Mutex> class unique_lock;
// unique_lock& operator=(unique_lock&& u);
// unique_lock& operator=(unique_lock&& u) noexcept;
#include <cassert>
#include <memory>
#include <mutex>
#include <type_traits>
#include "checking_mutex.h"
int main(int, char**) {
checking_mutex m0;
checking_mutex m1;
std::unique_lock<checking_mutex> lk0(m0);
std::unique_lock<checking_mutex> lk1(m1);
{
checking_mutex m0;
checking_mutex m1;
std::unique_lock<checking_mutex> lk0(m0);
std::unique_lock<checking_mutex> lk1(m1);
auto& result = (lk1 = std::move(lk0));
// Test self move assignment for lk0.
lk0 = std::move(lk0);
assert(lk0.mutex() == std::addressof(m0));
assert(lk0.owns_lock() == true);
assert(&result == &lk1);
assert(lk1.mutex() == std::addressof(m0));
assert(lk1.owns_lock());
assert(lk0.mutex() == nullptr);
assert(!lk0.owns_lock());
auto& result = (lk1 = std::move(lk0));
assert(&result == &lk1);
assert(lk1.mutex() == std::addressof(m0));
assert(lk1.owns_lock());
assert(lk0.mutex() == nullptr);
assert(lk0.owns_lock() == false);
static_assert(std::is_nothrow_move_assignable<std::unique_lock<checking_mutex> >::value, "");
}
{
// Test self move-assignment (LWG4172)
checking_mutex m0;
std::unique_lock<checking_mutex> lk0(m0);
lk0 = std::move(lk0);
assert(lk0.mutex() == std::addressof(m0));
assert(lk0.owns_lock() == true);
}
return 0;
}