[libcxx-commits] [libcxx] 2c98c6e - [libcxx] LWG4172 fix self-move-assignment in {unique|shared}_lock (#129542)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Dec 18 23:06:43 PST 2025
Author: Mohamed Atef
Date: 2025-12-19T15:06:39+08:00
New Revision: 2c98c6ee0ec332060993ef1b529c3d6aa605d1d9
URL: https://github.com/llvm/llvm-project/commit/2c98c6ee0ec332060993ef1b529c3d6aa605d1d9
DIFF: https://github.com/llvm/llvm-project/commit/2c98c6ee0ec332060993ef1b529c3d6aa605d1d9.diff
LOG: [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 at gmail.com>
Added:
Modified:
libcxx/docs/Status/Cxx2cIssues.csv
libcxx/include/__mutex/unique_lock.h
libcxx/include/shared_mutex
libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/move_assign.pass.cpp
libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/move_assign.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 482a9139f15cf..862a485f0a273 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -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>`__",""
diff --git a/libcxx/include/__mutex/unique_lock.h b/libcxx/include/__mutex/unique_lock.h
index aea93eb9b8c9b..6968922639673 100644
--- a/libcxx/include/__mutex/unique_lock.h
+++ b/libcxx/include/__mutex/unique_lock.h
@@ -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 @@ class unique_lock {
}
_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
diff --git a/libcxx/include/shared_mutex b/libcxx/include/shared_mutex
index 8c02e348e4de7..028bbf5650254 100644
--- a/libcxx/include/shared_mutex
+++ b/libcxx/include/shared_mutex
@@ -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;
}
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/move_assign.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/move_assign.pass.cpp
index 6d7838e8c6c95..2e1b46ae426e3 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/move_assign.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.cons/move_assign.pass.cpp
@@ -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;
}
diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/move_assign.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/move_assign.pass.cpp
index 588d8332c4164..eaa95d3c74c53 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/move_assign.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.cons/move_assign.pass.cpp
@@ -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);
-
- 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());
+ {
+ checking_mutex m0;
+ checking_mutex m1;
+ std::unique_lock<checking_mutex> lk0(m0);
+ std::unique_lock<checking_mutex> lk1(m1);
+
+ // Test self move assignment for lk0.
+ lk0 = std::move(lk0);
+ assert(lk0.mutex() == std::addressof(m0));
+ assert(lk0.owns_lock() == true);
+
+ 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;
}
More information about the libcxx-commits
mailing list