From db262ab8349420ca2f4e7144a0deb9218fa18ed0 Mon Sep 17 00:00:00 2001 From: Mital Ashok Date: Tue, 16 Jan 2024 16:26:39 +0000 Subject: [PATCH] [libc++] Implement P0718R2: atomic> Also implemented LWG3661, LWG3893 --- libcxx/docs/FeatureTestMacroTable.rst | 2 +- libcxx/docs/ReleaseNotes/18.rst | 1 + libcxx/docs/Status/Cxx20Papers.csv | 2 +- libcxx/docs/Status/Cxx23Issues.csv | 2 +- libcxx/docs/Status/Cxx2cIssues.csv | 2 +- libcxx/include/CMakeLists.txt | 1 + libcxx/include/__atomic/atomic.h | 10 + libcxx/include/__memory/atomic_shared_ptr.h | 233 ++++++++++++++++++ libcxx/include/__memory/shared_ptr.h | 104 -------- libcxx/include/memory | 93 ++++++- libcxx/include/module.modulemap.in | 1 + libcxx/include/version | 2 +- libcxx/modules/std/memory.inc | 3 + libcxx/test/std/atomics/types.pass.cpp | 3 +- .../atomic.version.compile.pass.cpp | 48 ++-- .../version.version.compile.pass.cpp | 48 ++-- .../generate_feature_test_macro_components.py | 1 - 17 files changed, 368 insertions(+), 188 deletions(-) create mode 100644 libcxx/include/__memory/atomic_shared_ptr.h diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 893a3b13ca06e..ea411ee8d6727 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -180,7 +180,7 @@ Status --------------------------------------------------- ----------------- ``__cpp_lib_atomic_ref`` *unimplemented* --------------------------------------------------- ----------------- - ``__cpp_lib_atomic_shared_ptr`` *unimplemented* + ``__cpp_lib_atomic_shared_ptr`` ``201711L`` --------------------------------------------------- ----------------- ``__cpp_lib_atomic_value_initialization`` ``201911L`` --------------------------------------------------- ----------------- diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst index 62a1fec627d0c..c6efadd4ba1e2 100644 --- a/libcxx/docs/ReleaseNotes/18.rst +++ b/libcxx/docs/ReleaseNotes/18.rst @@ -60,6 +60,7 @@ Implemented Papers - P0521R0 - Proposed Resolution for CA 14 (``shared_ptr`` ``use_count/unique``) - P1759R6 - Native handles and file streams - P2517R1 - Add a conditional ``noexcept`` specification to ``std::apply`` +- P0718R2 - Revising ``atomic_shared_ptr`` for C++20 Improvements and New Features diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv index d73088687975c..eae002a35d334 100644 --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -12,7 +12,7 @@ "`P0600R1 `__","LWG","nodiscard in the Library","Albuquerque","|Complete|","16.0" "`P0616R0 `__","LWG","de-pessimize legacy algorithms with std::move","Albuquerque","|Complete|","12.0" "`P0653R2 `__","LWG","Utility to convert a pointer to a raw pointer","Albuquerque","|Complete|","6.0" -"`P0718R2 `__","LWG","Atomic shared_ptr","Albuquerque","","" +"`P0718R2 `__","LWG","Atomic shared_ptr","Albuquerque","|Complete|","18.0" "`P0767R1 `__","CWG","Deprecate POD","Albuquerque","|Complete|","7.0" "`P0768R1 `__","CWG","Library Support for the Spaceship (Comparison) Operator","Albuquerque","|Complete|","" "`P0777R1 `__","LWG","Treating Unnecessary ``decay``\ ","Albuquerque","|Complete|","7.0" diff --git a/libcxx/docs/Status/Cxx23Issues.csv b/libcxx/docs/Status/Cxx23Issues.csv index b24ecc5525a14..5978614090391 100644 --- a/libcxx/docs/Status/Cxx23Issues.csv +++ b/libcxx/docs/Status/Cxx23Issues.csv @@ -157,7 +157,7 @@ "`3654 `__","``basic_format_context::arg(size_t)`` should be ``noexcept`` ","February 2022","|Complete|","15.0","|format|" "`3657 `__","``std::hash`` is not enabled","February 2022","|Complete|","17.0" "`3660 `__","``iterator_traits::pointer`` should conform to ยง[iterator.traits]","February 2022","|Complete|","14.0","|ranges|" -"`3661 `__","``constinit atomic> a(nullptr);`` should work","February 2022","","" +"`3661 `__","``constinit atomic> a(nullptr);`` should work","February 2022","|Complete|","18.0" "","","","","","" "`3564 `__","``transform_view::iterator::value_type`` and ``iterator_category`` should use ``const F&``","July 2022","","","|ranges|" "`3617 `__","``function``/``packaged_task`` deduction guides and deducing ``this``","July 2022","","" diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv index fe0f13f6e8cb2..88a08b01d4982 100644 --- a/libcxx/docs/Status/Cxx2cIssues.csv +++ b/libcxx/docs/Status/Cxx2cIssues.csv @@ -3,7 +3,7 @@ "`3884 `__","``flat_foo`` is missing allocator-extended copy/move constructors","Varna June 2023","","","|flat_containers|" "`3885 `__","``op`` should be in [zombie.names]","Varna June 2023","|Nothing To Do|","","" "`3887 `__","Version macro for ``allocate_at_least``","Varna June 2023","","","" -"`3893 `__","LWG 3661 broke ``atomic> a; a = nullptr;``","Varna June 2023","","","" +"`3893 `__","LWG 3661 broke ``atomic> a; a = nullptr;``","Varna June 2023","|Complete|","18.0","" "`3894 `__","``generator::promise_type::yield_value(ranges::elements_of)`` should not be ``noexcept``","Varna June 2023","","","" "`3903 `__","span destructor is redundantly noexcept","Varna June 2023","|Complete|","7.0","" "`3904 `__","``lazy_split_view::outer-iterator``'s const-converting constructor isn't setting ``trailing_empty_``","Varna June 2023","","","|ranges|" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 0fe3ab44d2466..0fd51788c7571 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -526,6 +526,7 @@ set(files __memory/allocator_destructor.h __memory/allocator_traits.h __memory/assume_aligned.h + __memory/atomic_shared_ptr.h __memory/auto_ptr.h __memory/builtin_new_allocator.h __memory/compressed_pair.h diff --git a/libcxx/include/__atomic/atomic.h b/libcxx/include/__atomic/atomic.h index 3dfb6937d0325..da12b36568fb3 100644 --- a/libcxx/include/__atomic/atomic.h +++ b/libcxx/include/__atomic/atomic.h @@ -249,6 +249,16 @@ struct atomic<_Tp> : __atomic_base<_Tp> { _LIBCPP_HIDE_FROM_ABI _Tp operator-=(_Tp __op) noexcept { return fetch_sub(__op) - __op; } }; +template +class shared_ptr; +template +class weak_ptr; + +template +struct atomic>; +template +struct atomic>; + #endif // _LIBCPP_STD_VER >= 20 // atomic_is_lock_free diff --git a/libcxx/include/__memory/atomic_shared_ptr.h b/libcxx/include/__memory/atomic_shared_ptr.h new file mode 100644 index 0000000000000..f3fa2260ac910 --- /dev/null +++ b/libcxx/include/__memory/atomic_shared_ptr.h @@ -0,0 +1,233 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MEMORY_ATOMIC_SHARED_PTR_H +#define _LIBCPP___MEMORY_ATOMIC_SHARED_PTR_H + +#include <__memory/addressof.h> +#include <__memory/shared_ptr.h> +#include +#if !defined(_LIBCPP_HAS_NO_ATOMIC_HEADER) +# include <__atomic/memory_order.h> +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if !defined(_LIBCPP_HAS_NO_THREADS) + +class _LIBCPP_EXPORTED_FROM_ABI __sp_mut { + void* __lx_; + +public: + void lock() _NOEXCEPT; + void unlock() _NOEXCEPT; + +private: + _LIBCPP_CONSTEXPR __sp_mut(void*) _NOEXCEPT; + __sp_mut(const __sp_mut&); + __sp_mut& operator=(const __sp_mut&); + + friend _LIBCPP_EXPORTED_FROM_ABI __sp_mut& __get_sp_mut(const void*); +}; + +_LIBCPP_EXPORTED_FROM_ABI __sp_mut& __get_sp_mut(const void*); + +template +_LIBCPP_HIDE_FROM_ABI _Tp __sp_atomic_load(const _Tp* __p) { + __sp_mut& __m = std::__get_sp_mut(__p); + __m.lock(); + _Tp __q = *__p; + __m.unlock(); + return __q; +} + +template +_LIBCPP_HIDE_FROM_ABI void __sp_atomic_store(_Tp* __p, _Tp& __r) { + __sp_mut& __m = std::__get_sp_mut(__p); + __m.lock(); + __p->swap(__r); + __m.unlock(); +} + +template +_LIBCPP_HIDE_FROM_ABI bool __sp_atomic_compare_exchange_strong(_Tp* __p, _Tp* __v, _Tp& __w) { + _Tp __temp; + __sp_mut& __m = std::__get_sp_mut(__p); + __m.lock(); + if (__p->__owner_equivalent(*__v)) { + std::swap(__temp, *__p); + *__p = __w; + __m.unlock(); + return true; + } + std::swap(__temp, *__v); + *__v = *__p; + __m.unlock(); + return false; +} + +template +_LIBCPP_HIDE_FROM_ABI _Tp __sp_atomic_exchange(_Tp* __p, _Tp& __r) { + __sp_mut& __m = std::__get_sp_mut(__p); + __m.lock(); + __p->swap(__r); + __m.unlock(); + return __r; +} + +# if _LIBCPP_STD_VER >= 20 +template +struct atomic; + +template +struct __sp_atomic_base { + using value_type = _Tp; + + static constexpr bool is_always_lock_free = false; + _LIBCPP_HIDE_FROM_ABI bool is_lock_free() const noexcept { return false; } + + _LIBCPP_HIDE_FROM_ABI constexpr __sp_atomic_base() noexcept = default; + _LIBCPP_HIDE_FROM_ABI __sp_atomic_base(_Tp&& __d) noexcept : __p(std::move(__d)) {} + _LIBCPP_HIDE_FROM_ABI __sp_atomic_base(const __sp_atomic_base&) = delete; + _LIBCPP_HIDE_FROM_ABI void operator=(const __sp_atomic_base&) = delete; + + _LIBCPP_HIDE_FROM_ABI _Tp load(memory_order = memory_order_seq_cst) noexcept { + return std::__sp_atomic_load(std::addressof(__p)); + } + _LIBCPP_HIDE_FROM_ABI operator _Tp() const noexcept { return load(); } + _LIBCPP_HIDE_FROM_ABI void store(_Tp __d, memory_order = memory_order_seq_cst) noexcept { + std::__sp_atomic_store(std::addressof(__p), __d); + } + _LIBCPP_HIDE_FROM_ABI void operator=(_Tp __d) noexcept { std::__sp_atomic_store(std::addressof(__p), __d); } + _LIBCPP_HIDE_FROM_ABI void operator=(nullptr_t) noexcept { store(nullptr); } + + _LIBCPP_HIDE_FROM_ABI _Tp exchange(_Tp __d, memory_order = memory_order_seq_cst) noexcept { + return std::__sp_atomic_exchange(std::addressof(__p), __d); + } + _LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __e, _Tp __d, memory_order, memory_order) noexcept { + return std::__sp_atomic_compare_exchange_strong(std::addressof(__p), std::addressof(__e), __d); + } + _LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __e, _Tp __d, memory_order, memory_order) noexcept { + return std::__sp_atomic_compare_exchange_strong(std::addressof(__p), std::addressof(__e), __d); + } + _LIBCPP_HIDE_FROM_ABI bool compare_exchange_weak(_Tp& __e, _Tp __d, memory_order = memory_order_seq_cst) noexcept { + return std::__sp_atomic_compare_exchange_strong(std::addressof(__p), std::addressof(__e), __d); + } + _LIBCPP_HIDE_FROM_ABI bool compare_exchange_strong(_Tp& __e, _Tp __d, memory_order = memory_order_seq_cst) noexcept { + return std::__sp_atomic_compare_exchange_strong(std::addressof(__p), std::addressof(__e), __d); + } + + // P1644R0 not implemented + // void wait(_Tp old, memory_order order = memory_order::seq_cst) const noexcept; + // void notify_one() noexcept; + // void notify_all() noexcept; + +private: + _Tp __p; +}; + +template +struct atomic> : __sp_atomic_base> { + _LIBCPP_HIDE_FROM_ABI constexpr atomic() noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr atomic(nullptr_t) noexcept : atomic() {} + _LIBCPP_HIDE_FROM_ABI atomic(shared_ptr<_Tp> desired) noexcept + : __sp_atomic_base>(std::move(desired)) {} + _LIBCPP_HIDE_FROM_ABI atomic(const atomic&) = delete; + + _LIBCPP_HIDE_FROM_ABI void operator=(const atomic&) = delete; + using __sp_atomic_base>::operator=; +}; + +template +struct atomic> : __sp_atomic_base> { + _LIBCPP_HIDE_FROM_ABI constexpr atomic() noexcept = default; + _LIBCPP_HIDE_FROM_ABI constexpr atomic(nullptr_t) noexcept : atomic() {} + _LIBCPP_HIDE_FROM_ABI atomic(weak_ptr<_Tp> desired) noexcept : __sp_atomic_base>(std::move(desired)) {} + _LIBCPP_HIDE_FROM_ABI atomic(const atomic&) = delete; + + _LIBCPP_HIDE_FROM_ABI void operator=(const atomic&) = delete; + using __sp_atomic_base>::operator=; +}; +# endif // _LIBCPP_STD_VER >= 20 + +// [depr.util.smartptr.shared.atomic] + +template +inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const shared_ptr<_Tp>*) { + return false; +} + +template +_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> +atomic_load(const shared_ptr<_Tp>* __p) { + return std::__sp_atomic_load(__p); +} + +template +inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> +atomic_load_explicit(const shared_ptr<_Tp>* __p, memory_order) { + return std::atomic_load(__p); +} + +template +_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI void atomic_store(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r) { + std::__sp_atomic_store(__p, __r); +} + +template +inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI void +atomic_store_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r, memory_order) { + std::atomic_store(__p, __r); +} + +template +_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> +atomic_exchange(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r) { + return std::__sp_atomic_exchange(__p, __r); +} + +template +inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> +atomic_exchange_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r, memory_order) { + return std::atomic_exchange(__p, std::move(__r)); +} + +template +_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI bool +atomic_compare_exchange_strong(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w) { + return std::__sp_atomic_compare_exchange_strong(__p, __v, __w); +} + +template +inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI bool +atomic_compare_exchange_weak(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w) { + return std::atomic_compare_exchange_strong(__p, __v, std::move(__w)); +} + +template +inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong_explicit( + shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w, memory_order, memory_order) { + return std::atomic_compare_exchange_strong(__p, __v, std::move(__w)); +} + +template +inline _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_weak_explicit( + shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w, memory_order, memory_order) { + return std::atomic_compare_exchange_weak(__p, __v, std::move(__w)); +} + +#endif // !defined(_LIBCPP_HAS_NO_THREADS) + +_LIBCPP_END_NAMESPACE_STD + +#endif // LLVM_ATOMIC_ATOMIC_SHARED_PTR_H diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h index 9a73d439306d9..c2a6953382dcd 100644 --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -1556,110 +1556,6 @@ template inline _LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& __os, shared_ptr<_Yp> const& __p); -#if !defined(_LIBCPP_HAS_NO_THREADS) - -class _LIBCPP_EXPORTED_FROM_ABI __sp_mut { - void* __lx_; - -public: - void lock() _NOEXCEPT; - void unlock() _NOEXCEPT; - -private: - _LIBCPP_CONSTEXPR __sp_mut(void*) _NOEXCEPT; - __sp_mut(const __sp_mut&); - __sp_mut& operator=(const __sp_mut&); - - friend _LIBCPP_EXPORTED_FROM_ABI __sp_mut& __get_sp_mut(const void*); -}; - -_LIBCPP_EXPORTED_FROM_ABI __sp_mut& __get_sp_mut(const void*); - -template -inline _LIBCPP_HIDE_FROM_ABI bool atomic_is_lock_free(const shared_ptr<_Tp>*) { - return false; -} - -template -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> atomic_load(const shared_ptr<_Tp>* __p) { - __sp_mut& __m = std::__get_sp_mut(__p); - __m.lock(); - shared_ptr<_Tp> __q = *__p; - __m.unlock(); - return __q; -} - -template -inline _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> atomic_load_explicit(const shared_ptr<_Tp>* __p, memory_order) { - return std::atomic_load(__p); -} - -template -_LIBCPP_HIDE_FROM_ABI void atomic_store(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r) { - __sp_mut& __m = std::__get_sp_mut(__p); - __m.lock(); - __p->swap(__r); - __m.unlock(); -} - -template -inline _LIBCPP_HIDE_FROM_ABI void atomic_store_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r, memory_order) { - std::atomic_store(__p, __r); -} - -template -_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> atomic_exchange(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r) { - __sp_mut& __m = std::__get_sp_mut(__p); - __m.lock(); - __p->swap(__r); - __m.unlock(); - return __r; -} - -template -inline _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> -atomic_exchange_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r, memory_order) { - return std::atomic_exchange(__p, __r); -} - -template -_LIBCPP_HIDE_FROM_ABI bool -atomic_compare_exchange_strong(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w) { - shared_ptr<_Tp> __temp; - __sp_mut& __m = std::__get_sp_mut(__p); - __m.lock(); - if (__p->__owner_equivalent(*__v)) { - std::swap(__temp, *__p); - *__p = __w; - __m.unlock(); - return true; - } - std::swap(__temp, *__v); - *__v = *__p; - __m.unlock(); - return false; -} - -template -inline _LIBCPP_HIDE_FROM_ABI bool -atomic_compare_exchange_weak(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w) { - return std::atomic_compare_exchange_strong(__p, __v, __w); -} - -template -inline _LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_strong_explicit( - shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w, memory_order, memory_order) { - return std::atomic_compare_exchange_strong(__p, __v, __w); -} - -template -inline _LIBCPP_HIDE_FROM_ABI bool atomic_compare_exchange_weak_explicit( - shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, shared_ptr<_Tp> __w, memory_order, memory_order) { - return std::atomic_compare_exchange_weak(__p, __v, __w); -} - -#endif // !defined(_LIBCPP_HAS_NO_THREADS) - _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___MEMORY_SHARED_PTR_H diff --git a/libcxx/include/memory b/libcxx/include/memory index ee245d5fd2dcb..6c0ec59119f6d 100644 --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -831,29 +831,29 @@ public: }; template - bool atomic_is_lock_free(const shared_ptr* p); + bool atomic_is_lock_free(const shared_ptr* p); // Deprecated in C++20 template - shared_ptr atomic_load(const shared_ptr* p); + shared_ptr atomic_load(const shared_ptr* p); // Deprecated in C++20 template - shared_ptr atomic_load_explicit(const shared_ptr* p, memory_order mo); + shared_ptr atomic_load_explicit(const shared_ptr* p, memory_order mo); // Deprecated in C++20 template - void atomic_store(shared_ptr* p, shared_ptr r); + void atomic_store(shared_ptr* p, shared_ptr r); // Deprecated in C++20 template - void atomic_store_explicit(shared_ptr* p, shared_ptr r, memory_order mo); + void atomic_store_explicit(shared_ptr* p, shared_ptr r, memory_order mo); // Deprecated in C++20 template - shared_ptr atomic_exchange(shared_ptr* p, shared_ptr r); + shared_ptr atomic_exchange(shared_ptr* p, shared_ptr r); // Deprecated in C++20 template shared_ptr - atomic_exchange_explicit(shared_ptr* p, shared_ptr r, memory_order mo); + atomic_exchange_explicit(shared_ptr* p, shared_ptr r, memory_order mo); // Deprecated in C++20 template bool - atomic_compare_exchange_weak(shared_ptr* p, shared_ptr* v, shared_ptr w); + atomic_compare_exchange_weak(shared_ptr* p, shared_ptr* v, shared_ptr w); // Deprecated in C++20 template bool - atomic_compare_exchange_strong( shared_ptr* p, shared_ptr* v, shared_ptr w); + atomic_compare_exchange_strong( shared_ptr* p, shared_ptr* v, shared_ptr w); // Deprecated in C++20 template bool - atomic_compare_exchange_weak_explicit(shared_ptr* p, shared_ptr* v, + atomic_compare_exchange_weak_explicit(shared_ptr* p, shared_ptr* v, // Deprecated in C++20 shared_ptr w, memory_order success, memory_order failure); template @@ -912,6 +912,78 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space); template [[nodiscard]] constexpr T* assume_aligned(T* ptr); // since C++20 +// [util.smartptr.atomic], atomic smart pointers +template struct atomic; // since C++20 +template // since C++20 +struct atomic> +{ + using value_type = shared_ptr; + + static constexpr bool is_always_lock_free = implementation-defined; + bool is_lock_free() const noexcept; + + constexpr atomic() noexcept; + constexpr atomic(nullptr_t) noexcept : atomic() { } + atomic(shared_ptr desired) noexcept; + atomic(const atomic&) = delete; + void operator=(const atomic&) = delete; + + shared_ptr load(memory_order order = memory_order::seq_cst) const noexcept; + operator shared_ptr() const noexcept; + void store(shared_ptr desired, memory_order order = memory_order::seq_cst) noexcept; + void operator=(shared_ptr desired) noexcept; + void operator=(nullptr_t) noexcept; + + shared_ptr exchange(shared_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; + bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, + memory_order success, memory_order failure) noexcept; + bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, + memory_order success, memory_order failure) noexcept; + bool compare_exchange_weak(shared_ptr& expected, shared_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; + bool compare_exchange_strong(shared_ptr& expected, shared_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; + + void wait(shared_ptr old, memory_order order = memory_order::seq_cst) const noexcept; + void notify_one() noexcept; + void notify_all() noexcept; +}; +template // since C++20 +struct atomic> +{ + + using value_type = weak_ptr; + + static constexpr bool is_always_lock_free = implementation-defined; + bool is_lock_free() const noexcept; + + constexpr atomic() noexcept; + atomic(weak_ptr desired) noexcept; + atomic(const atomic&) = delete; + void operator=(const atomic&) = delete; + + weak_ptr load(memory_order order = memory_order::seq_cst) const noexcept; + operator weak_ptr() const noexcept; + void store(weak_ptr desired, memory_order order = memory_order::seq_cst) noexcept; + void operator=(weak_ptr desired) noexcept; + + weak_ptr exchange(weak_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; + bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, + memory_order success, memory_order failure) noexcept; + bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, + memory_order success, memory_order failure) noexcept; + bool compare_exchange_weak(weak_ptr& expected, weak_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; + bool compare_exchange_strong(weak_ptr& expected, weak_ptr desired, + memory_order order = memory_order::seq_cst) noexcept; + + void wait(weak_ptr old, memory_order order = memory_order::seq_cst) const noexcept; + void notify_one() noexcept; + void notify_all() noexcept; +}; + } // std */ @@ -928,6 +1000,7 @@ template #include <__memory/allocator_arg_t.h> #include <__memory/allocator_traits.h> #include <__memory/assume_aligned.h> +#include <__memory/atomic_shared_ptr.h> #include <__memory/auto_ptr.h> #include <__memory/compressed_pair.h> #include <__memory/concepts.h> diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index d10670d4faaff..dd65019e292e2 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1508,6 +1508,7 @@ module std_private_memory_allocator_arg_t [system] { header "__m module std_private_memory_allocator_destructor [system] { header "__memory/allocator_destructor.h" } module std_private_memory_allocator_traits [system] { header "__memory/allocator_traits.h" } module std_private_memory_assume_aligned [system] { header "__memory/assume_aligned.h" } +module std_private_memory_atomic_shared_ptr [system] { header "__memory/atomic_shared_ptr.h" } module std_private_memory_auto_ptr [system] { header "__memory/auto_ptr.h" } module std_private_memory_builtin_new_allocator [system] { header "__memory/builtin_new_allocator.h" diff --git a/libcxx/include/version b/libcxx/include/version index c96647894dce6..2a0d8b6db626e 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -348,7 +348,7 @@ __cpp_lib_within_lifetime 202306L // # define __cpp_lib_atomic_float 201711L # define __cpp_lib_atomic_lock_free_type_aliases 201907L // # define __cpp_lib_atomic_ref 201806L -// # define __cpp_lib_atomic_shared_ptr 201711L +# define __cpp_lib_atomic_shared_ptr 201711L # define __cpp_lib_atomic_value_initialization 201911L # if _LIBCPP_AVAILABILITY_HAS_SYNC # define __cpp_lib_atomic_wait 201907L diff --git a/libcxx/modules/std/memory.inc b/libcxx/modules/std/memory.inc index fba2461732c1b..9263bbf0cc49e 100644 --- a/libcxx/modules/std/memory.inc +++ b/libcxx/modules/std/memory.inc @@ -190,6 +190,9 @@ export namespace std { // using std::inout_ptr; #ifndef _LIBCPP_HAS_NO_THREADS + // [util.smartptr.atomic] + using std::atomic; + // [depr.util.smartptr.shared.atomic] using std::atomic_is_lock_free; diff --git a/libcxx/test/std/atomics/types.pass.cpp b/libcxx/test/std/atomics/types.pass.cpp index cebf66ee7f1af..4fb62d9d13caa 100644 --- a/libcxx/test/std/atomics/types.pass.cpp +++ b/libcxx/test/std/atomics/types.pass.cpp @@ -181,9 +181,8 @@ int main(int, char**) test(); static_assert(std::is_unsigned_v); static_assert(std::is_integral_v); -/* test>(); -*/ + test>(); #endif return 0; diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp index 86315c23a496b..346d31304cd35 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/atomic.version.compile.pass.cpp @@ -196,17 +196,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_atomic_shared_ptr -# error "__cpp_lib_atomic_shared_ptr should be defined in c++20" -# endif -# if __cpp_lib_atomic_shared_ptr != 201711L -# error "__cpp_lib_atomic_shared_ptr should have the value 201711L in c++20" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_atomic_shared_ptr -# error "__cpp_lib_atomic_shared_ptr should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_atomic_shared_ptr +# error "__cpp_lib_atomic_shared_ptr should be defined in c++20" +# endif +# if __cpp_lib_atomic_shared_ptr != 201711L +# error "__cpp_lib_atomic_shared_ptr should have the value 201711L in c++20" # endif # ifndef __cpp_lib_atomic_value_initialization @@ -291,17 +285,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_atomic_shared_ptr -# error "__cpp_lib_atomic_shared_ptr should be defined in c++23" -# endif -# if __cpp_lib_atomic_shared_ptr != 201711L -# error "__cpp_lib_atomic_shared_ptr should have the value 201711L in c++23" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_atomic_shared_ptr -# error "__cpp_lib_atomic_shared_ptr should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_atomic_shared_ptr +# error "__cpp_lib_atomic_shared_ptr should be defined in c++23" +# endif +# if __cpp_lib_atomic_shared_ptr != 201711L +# error "__cpp_lib_atomic_shared_ptr should have the value 201711L in c++23" # endif # ifndef __cpp_lib_atomic_value_initialization @@ -386,17 +374,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_atomic_shared_ptr -# error "__cpp_lib_atomic_shared_ptr should be defined in c++26" -# endif -# if __cpp_lib_atomic_shared_ptr != 201711L -# error "__cpp_lib_atomic_shared_ptr should have the value 201711L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_atomic_shared_ptr -# error "__cpp_lib_atomic_shared_ptr should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_atomic_shared_ptr +# error "__cpp_lib_atomic_shared_ptr should be defined in c++26" +# endif +# if __cpp_lib_atomic_shared_ptr != 201711L +# error "__cpp_lib_atomic_shared_ptr should have the value 201711L in c++26" # endif # ifndef __cpp_lib_atomic_value_initialization diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index d5a0839b30f82..acc30418fbb77 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -3038,17 +3038,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_atomic_shared_ptr -# error "__cpp_lib_atomic_shared_ptr should be defined in c++20" -# endif -# if __cpp_lib_atomic_shared_ptr != 201711L -# error "__cpp_lib_atomic_shared_ptr should have the value 201711L in c++20" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_atomic_shared_ptr -# error "__cpp_lib_atomic_shared_ptr should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_atomic_shared_ptr +# error "__cpp_lib_atomic_shared_ptr should be defined in c++20" +# endif +# if __cpp_lib_atomic_shared_ptr != 201711L +# error "__cpp_lib_atomic_shared_ptr should have the value 201711L in c++20" # endif # ifndef __cpp_lib_atomic_value_initialization @@ -4389,17 +4383,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_atomic_shared_ptr -# error "__cpp_lib_atomic_shared_ptr should be defined in c++23" -# endif -# if __cpp_lib_atomic_shared_ptr != 201711L -# error "__cpp_lib_atomic_shared_ptr should have the value 201711L in c++23" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_atomic_shared_ptr -# error "__cpp_lib_atomic_shared_ptr should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_atomic_shared_ptr +# error "__cpp_lib_atomic_shared_ptr should be defined in c++23" +# endif +# if __cpp_lib_atomic_shared_ptr != 201711L +# error "__cpp_lib_atomic_shared_ptr should have the value 201711L in c++23" # endif # ifndef __cpp_lib_atomic_value_initialization @@ -5965,17 +5953,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_atomic_shared_ptr -# error "__cpp_lib_atomic_shared_ptr should be defined in c++26" -# endif -# if __cpp_lib_atomic_shared_ptr != 201711L -# error "__cpp_lib_atomic_shared_ptr should have the value 201711L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_atomic_shared_ptr -# error "__cpp_lib_atomic_shared_ptr should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_atomic_shared_ptr +# error "__cpp_lib_atomic_shared_ptr should be defined in c++26" +# endif +# if __cpp_lib_atomic_shared_ptr != 201711L +# error "__cpp_lib_atomic_shared_ptr should have the value 201711L in c++26" # endif # ifndef __cpp_lib_atomic_value_initialization diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index 8ee92909dfa53..d32d976fbc4a6 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -181,7 +181,6 @@ def add_version_header(tc): "name": "__cpp_lib_atomic_shared_ptr", "values": {"c++20": 201711}, "headers": ["atomic"], - "unimplemented": True, }, { "name": "__cpp_lib_atomic_value_initialization",