diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv index 482a9139f15c..862a485f0a27 100644 --- a/libcxx/docs/Status/Cxx2cIssues.csv +++ b/libcxx/docs/Status/Cxx2cIssues.csv @@ -113,7 +113,7 @@ "","","","","","","" "`LWG3578 `__","Iterator SCARYness in the context of associative container merging","2025-02 (Hagenberg)","","","`#127859 `__","" "`LWG3956 `__","``chrono::parse`` uses ``from_stream`` as a customization point","2025-02 (Hagenberg)","","","`#127860 `__","" -"`LWG4172 `__","``unique_lock`` self-move-assignment is broken","2025-02 (Hagenberg)","","","`#127861 `__","" +"`LWG4172 `__","``unique_lock`` self-move-assignment is broken","2025-02 (Hagenberg)","|Complete|","22","`#127861 `__","" "`LWG4175 `__","``get_env()`` specified in terms of ``as_const()`` but this doesn't work with rvalue senders","2025-02 (Hagenberg)","","","`#127862 `__","" "`LWG4179 `__","Wrong range in ``[alg.search]``","2025-02 (Hagenberg)","","","`#127863 `__","" "`LWG4186 `__","``regex_traits::transform_primary`` mistakenly detects ``typeid`` of a function","2025-02 (Hagenberg)","","","`#127864 `__","" diff --git a/libcxx/include/__mutex/unique_lock.h b/libcxx/include/__mutex/unique_lock.h index aea93eb9b8c9..696892263967 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 @@ -22,6 +23,9 @@ # pragma GCC system_header #endif +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + _LIBCPP_BEGIN_NAMESPACE_STD template @@ -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 diff --git a/libcxx/include/shared_mutex b/libcxx/include/shared_mutex index 8c02e348e4de..028bbf565025 100644 --- a/libcxx/include/shared_mutex +++ b/libcxx/include/shared_mutex @@ -138,6 +138,7 @@ template # 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 # include @@ -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 6d7838e8c6c9..2e1b46ae426e 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 shared_lock; -// shared_lock& operator=(shared_lock&& u); +// shared_lock& operator=(shared_lock&& u) noexcept; -#include #include -#include "nasty_containers.h" +#include +#include +#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 >::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 >::value, ""); + } + { + // Test self move-assignment (LWG4172) + typedef std::shared_timed_mutex M; + M m0; + std::shared_lock 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 588d8332c416..eaa95d3c74c5 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 + // // template class unique_lock; -// unique_lock& operator=(unique_lock&& u); +// unique_lock& operator=(unique_lock&& u) noexcept; #include #include #include +#include #include "checking_mutex.h" int main(int, char**) { - checking_mutex m0; - checking_mutex m1; - std::unique_lock lk0(m0); - std::unique_lock lk1(m1); + { + checking_mutex m0; + checking_mutex m1; + std::unique_lock lk0(m0); + std::unique_lock 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 >::value, ""); + } + + { + // Test self move-assignment (LWG4172) + checking_mutex m0; + std::unique_lock lk0(m0); + lk0 = std::move(lk0); + assert(lk0.mutex() == std::addressof(m0)); + assert(lk0.owns_lock() == true); + } return 0; }