diff options
author | Louis Dionne <ldionne.2@gmail.com> | 2023-09-14 15:12:06 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-14 15:12:06 -0400 |
commit | 85f27d126dbe696070a0c79c476070a67e40aa29 (patch) | |
tree | 6bde46cfe55cb58760577c357e6ec5a05352fde7 | |
parent | 4a6426a802c008509715f7d777ab3cf419525c7a (diff) | |
download | llvm-85f27d126dbe696070a0c79c476070a67e40aa29.zip llvm-85f27d126dbe696070a0c79c476070a67e40aa29.tar.gz llvm-85f27d126dbe696070a0c79c476070a67e40aa29.tar.bz2 |
[libc++] Make sure LWG2070 is implemented as a DR (#65998)
When we implemented C++20's P0674R1, we didn't enable the part of
P0674R1 that was resolving LWG2070 as a DR. This patch fixes that and
makes sure that we consistently go through the allocator when
constructing and destroying the underlying object in
std::allocate_shared.
Fixes #54365.
-rw-r--r-- | libcxx/include/__memory/shared_ptr.h | 50 | ||||
-rw-r--r-- | libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.lwg2070.pass.cpp (renamed from libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_construct.pass.cpp) | 23 | ||||
-rw-r--r-- | libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp | 23 |
3 files changed, 39 insertions, 57 deletions
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h index 845882a..6be2f22 100644 --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -285,23 +285,23 @@ template <class _Tp, class _Alloc> struct __shared_ptr_emplace : __shared_weak_count { - template<class ..._Args> + template <class... _Args, class _Allocator = _Alloc, __enable_if_t<is_same<typename _Allocator::value_type, __for_overwrite_tag>::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI + explicit __shared_ptr_emplace(_Alloc __a, _Args&& ...) + : __storage_(_VSTD::move(__a)) + { + static_assert(sizeof...(_Args) == 0, "No argument should be provided to the control block when using _for_overwrite"); + ::new ((void*)__get_elem()) _Tp; + } + + template <class... _Args, class _Allocator = _Alloc, __enable_if_t<!is_same<typename _Allocator::value_type, __for_overwrite_tag>::value, int> = 0> _LIBCPP_HIDE_FROM_ABI explicit __shared_ptr_emplace(_Alloc __a, _Args&& ...__args) : __storage_(_VSTD::move(__a)) { -#if _LIBCPP_STD_VER >= 20 - if constexpr (is_same_v<typename _Alloc::value_type, __for_overwrite_tag>) { - static_assert(sizeof...(_Args) == 0, "No argument should be provided to the control block when using _for_overwrite"); - ::new ((void*)__get_elem()) _Tp; - } else { - using _TpAlloc = typename __allocator_traits_rebind<_Alloc, _Tp>::type; - _TpAlloc __tmp(*__get_alloc()); - allocator_traits<_TpAlloc>::construct(__tmp, __get_elem(), _VSTD::forward<_Args>(__args)...); - } -#else - ::new ((void*)__get_elem()) _Tp(_VSTD::forward<_Args>(__args)...); -#endif + using _TpAlloc = typename __allocator_traits_rebind<_Alloc, _Tp>::type; + _TpAlloc __tmp(*__get_alloc()); + allocator_traits<_TpAlloc>::construct(__tmp, __get_elem(), _VSTD::forward<_Args>(__args)...); } _LIBCPP_HIDE_FROM_ABI @@ -311,18 +311,20 @@ struct __shared_ptr_emplace _Tp* __get_elem() _NOEXCEPT { return __storage_.__get_elem(); } private: - _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared() _NOEXCEPT override { -#if _LIBCPP_STD_VER >= 20 - if constexpr (is_same_v<typename _Alloc::value_type, __for_overwrite_tag>) { - __get_elem()->~_Tp(); - } else { - using _TpAlloc = typename __allocator_traits_rebind<_Alloc, _Tp>::type; - _TpAlloc __tmp(*__get_alloc()); - allocator_traits<_TpAlloc>::destroy(__tmp, __get_elem()); - } -#else + template <class _Allocator = _Alloc, __enable_if_t<is_same<typename _Allocator::value_type, __for_overwrite_tag>::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI void __on_zero_shared_impl() _NOEXCEPT { __get_elem()->~_Tp(); -#endif + } + + template <class _Allocator = _Alloc, __enable_if_t<!is_same<typename _Allocator::value_type, __for_overwrite_tag>::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI void __on_zero_shared_impl() _NOEXCEPT { + using _TpAlloc = typename __allocator_traits_rebind<_Allocator, _Tp>::type; + _TpAlloc __tmp(*__get_alloc()); + allocator_traits<_TpAlloc>::destroy(__tmp, __get_elem()); + } + + _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared() _NOEXCEPT override { + __on_zero_shared_impl(); } _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared_weak() _NOEXCEPT override { diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_construct.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.lwg2070.pass.cpp index 4281cc1..bf86327 100644 --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_construct.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.lwg2070.pass.cpp @@ -6,8 +6,6 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17 - // <memory> // shared_ptr @@ -15,17 +13,20 @@ // template<class T, class A, class... Args> // shared_ptr<T> allocate_shared(const A& a, Args&&... args); -// This test checks that allocator_traits::construct is used in allocate_shared -// as requested in C++20 (via P0674R1). - -#include "test_macros.h" +// This test checks that allocator_traits::construct and allocator_traits::destroy +// are used in allocate_shared as requested for the resolution of LWG2070. Note +// that LWG2070 was resolved by P0674R1 (which is a C++20 paper), but we implement +// LWG issue resolutions as DRs per our policy. #include <cassert> +#include <cstddef> #include <cstdint> #include <memory> #include <new> #include <utility> +#include "test_macros.h" + static bool construct_called = false; static bool destroy_called = false; static unsigned allocator_id = 0; @@ -118,10 +119,6 @@ struct Foo { Foo(Foo a, Foo b) : val(a.val + b.val) {} }; -struct Bar { - std::max_align_t y; -}; - void test_aligned(void* p, std::size_t align) { assert(reinterpret_cast<std::uintptr_t>(p) % align == 0); } @@ -170,10 +167,16 @@ int main(int, char**) { assert(p->id == 42); } +#if TEST_STD_VER >= 11 { + struct Bar { + std::max_align_t y; + }; + std::shared_ptr<Bar> p; test_aligned(p.get(), alignof(Bar)); } +#endif return 0; } diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp index ac7a991..341a442 100644 --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp @@ -90,22 +90,6 @@ struct Three int Three::count = 0; -template<class T> -struct AllocNoConstruct : std::allocator<T> -{ - AllocNoConstruct() = default; - - template <class T1> - AllocNoConstruct(AllocNoConstruct<T1>) {} - - template <class T1> - struct rebind { - typedef AllocNoConstruct<T1> other; - }; - - void construct(void*) { assert(false); } -}; - template <class Alloc> void test() { @@ -182,12 +166,5 @@ int main(int, char**) assert(p2 != nullptr); } - // Test that we don't call construct before C++20. -#if TEST_STD_VER < 20 - { - (void)std::allocate_shared<int>(AllocNoConstruct<int>()); - } -#endif // TEST_STD_VER < 20 - return 0; } |