Skip to content

[libc++] Remove the allocator<const T> extension #96319

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions libcxx/docs/ReleaseNotes/19.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ Deprecations and Removals
- The ``_LIBCPP_DISABLE_ADDITIONAL_DIAGNOSTICS`` macro has been removed and is not honored anymore. Additional
warnings provided by libc++ as a matter of QoI will now be provided unconditionally.

- libc++ no longer supports ``std::allocator<const T>`` and containers of ``const``-qualified element type, such
as ``std::vector<const T>`` and ``std::list<const T>``. This used to be supported as an undocumented extension.
If you were using ``std::vector<const T>``, replace it with ``std::vector<T>`` instead. The
``_LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST`` macro can be defined to temporarily re-enable this extension as
folks transition their code. This macro will be honored for one released and ignored starting in LLVM 20.
To assist with the clean-up process, consider running your code through Clang Tidy, with
`std-allocator-const <https://clang.llvm.org/extra/clang-tidy/checks/portability/std-allocator-const.html>`
enabled.


Upcoming Deprecations and Removals
----------------------------------
Expand Down
28 changes: 15 additions & 13 deletions libcxx/include/__memory/allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <__memory/addressof.h>
#include <__memory/allocate_at_least.h>
#include <__memory/allocator_traits.h>
#include <__type_traits/is_const.h>
#include <__type_traits/is_constant_evaluated.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_void.h>
Expand All @@ -36,8 +37,6 @@ class allocator;
// Specializing allocator<void> is deprecated, but not using it.
template <>
class _LIBCPP_TEMPLATE_VIS allocator<void> {
# if _LIBCPP_STD_VER <= 17

public:
_LIBCPP_DEPRECATED_IN_CXX17 typedef void* pointer;
_LIBCPP_DEPRECATED_IN_CXX17 typedef const void* const_pointer;
Expand All @@ -47,13 +46,12 @@ class _LIBCPP_TEMPLATE_VIS allocator<void> {
struct _LIBCPP_DEPRECATED_IN_CXX17 rebind {
typedef allocator<_Up> other;
};
# endif
};

// TODO(LLVM 20): Remove the escape hatch
# ifdef _LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST
template <>
class _LIBCPP_TEMPLATE_VIS allocator<const void> {
# if _LIBCPP_STD_VER <= 17

public:
_LIBCPP_DEPRECATED_IN_CXX17 typedef const void* pointer;
_LIBCPP_DEPRECATED_IN_CXX17 typedef const void* const_pointer;
Expand All @@ -63,9 +61,9 @@ class _LIBCPP_TEMPLATE_VIS allocator<const void> {
struct _LIBCPP_DEPRECATED_IN_CXX17 rebind {
typedef allocator<_Up> other;
};
# endif
};
#endif
# endif // _LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST
#endif // _LIBCPP_STD_VER <= 17

// This class provides a non-trivial default constructor to the class that derives from it
// if the condition is satisfied.
Expand Down Expand Up @@ -94,6 +92,7 @@ struct __non_trivial_if<true, _Unique> {

template <class _Tp>
class _LIBCPP_TEMPLATE_VIS allocator : private __non_trivial_if<!is_void<_Tp>::value, allocator<_Tp> > {
static_assert(!is_const<_Tp>::value, "std::allocator does not support const types");
static_assert(!is_volatile<_Tp>::value, "std::allocator does not support volatile types");

public:
Expand Down Expand Up @@ -170,6 +169,8 @@ class _LIBCPP_TEMPLATE_VIS allocator : private __non_trivial_if<!is_void<_Tp>::v
#endif
};

// TODO(LLVM 20): Remove the escape hatch
#ifdef _LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST
template <class _Tp>
class _LIBCPP_TEMPLATE_VIS allocator<const _Tp>
: private __non_trivial_if<!is_void<_Tp>::value, allocator<const _Tp> > {
Expand All @@ -180,9 +181,9 @@ class _LIBCPP_TEMPLATE_VIS allocator<const _Tp>
typedef ptrdiff_t difference_type;
typedef const _Tp value_type;
typedef true_type propagate_on_container_move_assignment;
#if _LIBCPP_STD_VER <= 23 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_ALLOCATOR_MEMBERS)
# if _LIBCPP_STD_VER <= 23 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_ALLOCATOR_MEMBERS)
_LIBCPP_DEPRECATED_IN_CXX23 typedef true_type is_always_equal;
#endif
# endif

_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 allocator() _NOEXCEPT = default;

Expand All @@ -199,11 +200,11 @@ class _LIBCPP_TEMPLATE_VIS allocator<const _Tp>
}
}

#if _LIBCPP_STD_VER >= 23
# if _LIBCPP_STD_VER >= 23
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr allocation_result<const _Tp*> allocate_at_least(size_t __n) {
return {allocate(__n), __n};
}
#endif
# endif

_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void deallocate(const _Tp* __p, size_t __n) {
if (__libcpp_is_constant_evaluated()) {
Expand All @@ -214,7 +215,7 @@ class _LIBCPP_TEMPLATE_VIS allocator<const _Tp>
}

// C++20 Removed members
#if _LIBCPP_STD_VER <= 17
# if _LIBCPP_STD_VER <= 17
_LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp* pointer;
_LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp* const_pointer;
_LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp& reference;
Expand Down Expand Up @@ -243,8 +244,9 @@ class _LIBCPP_TEMPLATE_VIS allocator<const _Tp>
}

_LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_HIDE_FROM_ABI void destroy(pointer __p) { __p->~_Tp(); }
#endif
# endif
};
#endif // _LIBCPP_ENABLE_REMOVED_ALLOCATOR_CONST

template <class _Tp, class _Up>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool
Expand Down
14 changes: 7 additions & 7 deletions libcxx/include/__memory/shared_ptr.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ struct __shared_ptr_emplace : __shared_weak_count {
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_(std::move(__a)) {
using _TpAlloc = typename __allocator_traits_rebind<_Alloc, _Tp>::type;
using _TpAlloc = typename __allocator_traits_rebind<_Alloc, __remove_cv_t<_Tp> >::type;
_TpAlloc __tmp(*__get_alloc());
allocator_traits<_TpAlloc>::construct(__tmp, __get_elem(), std::forward<_Args>(__args)...);
}
Expand All @@ -278,7 +278,7 @@ struct __shared_ptr_emplace : __shared_weak_count {
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;
using _TpAlloc = typename __allocator_traits_rebind<_Allocator, __remove_cv_t<_Tp> >::type;
_TpAlloc __tmp(*__get_alloc());
allocator_traits<_TpAlloc>::destroy(__tmp, __get_elem());
}
Expand Down Expand Up @@ -598,8 +598,8 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr {
#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR)
template <class _Yp, __enable_if_t<is_convertible<_Yp*, element_type*>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI shared_ptr(auto_ptr<_Yp>&& __r) : __ptr_(__r.get()) {
typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, allocator<_Yp> > _CntrlBlk;
__cntrl_ = new _CntrlBlk(__r.get(), default_delete<_Yp>(), allocator<_Yp>());
typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, allocator<__remove_cv_t<_Yp> > > _CntrlBlk;
__cntrl_ = new _CntrlBlk(__r.get(), default_delete<_Yp>(), allocator<__remove_cv_t<_Yp> >());
__enable_weak_this(__r.get(), __r.get());
__r.release();
}
Expand Down Expand Up @@ -776,7 +776,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr {
private:
template <class _Yp, bool = is_function<_Yp>::value>
struct __shared_ptr_default_allocator {
typedef allocator<_Yp> type;
typedef allocator<__remove_cv_t<_Yp> > type;
};

template <class _Yp>
Expand Down Expand Up @@ -834,7 +834,7 @@ _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared(const _Alloc& __a, _Args&&

template <class _Tp, class... _Args, __enable_if_t<!is_array<_Tp>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared(_Args&&... __args) {
return std::allocate_shared<_Tp>(allocator<_Tp>(), std::forward<_Args>(__args)...);
return std::allocate_shared<_Tp>(allocator<__remove_cv_t<_Tp> >(), std::forward<_Args>(__args)...);
}

#if _LIBCPP_STD_VER >= 20
Expand All @@ -848,7 +848,7 @@ _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> allocate_shared_for_overwrite(const _Alloc

template <class _Tp, __enable_if_t<!is_array<_Tp>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared_for_overwrite() {
return std::allocate_shared_for_overwrite<_Tp>(allocator<_Tp>());
return std::allocate_shared_for_overwrite<_Tp>(allocator<__remove_cv_t<_Tp>>());
}

#endif // _LIBCPP_STD_VER >= 20
Expand Down

This file was deleted.

This file was deleted.

12 changes: 0 additions & 12 deletions libcxx/test/libcxx/diagnostics/memory.nodiscard.verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,3 @@ void test_allocator() {
allocator.allocate_at_least(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
#endif
}

void test_const_allocator() {
std::allocator<const int> allocator;
allocator.allocate(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}

#if TEST_STD_VER <= 17
allocator.allocate(1, nullptr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
#endif
#if TEST_STD_VER >= 23
allocator.allocate_at_least(1); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,10 @@
#include <type_traits>

typedef std::allocator<void> A1;
typedef std::allocator<void const> A2;
struct A3 : std::allocator<void> { };
struct A4 : std::allocator<void const> { };
struct A2 : std::allocator<void> { };

static_assert(std::is_trivially_default_constructible<A1>::value, "");
static_assert(std::is_trivial<A1>::value, "");

static_assert(std::is_trivially_default_constructible<A2>::value, "");
static_assert(std::is_trivial<A2>::value, "");

static_assert(std::is_trivially_default_constructible<A3>::value, "");
static_assert(std::is_trivial<A3>::value, "");

static_assert(std::is_trivially_default_constructible<A4>::value, "");
static_assert(std::is_trivial<A4>::value, "");
6 changes: 3 additions & 3 deletions libcxx/test/libcxx/memory/allocator_volatile.verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
//
//===----------------------------------------------------------------------===//

// http://wg21.link/LWG2447 gives implementors freedom to reject volatile types in `std::allocator`.
// http://wg21.link/LWG2447 gives implementors freedom to reject const or volatile types in `std::allocator`.

#include <memory>

std::allocator<volatile int> A1; // expected-error@*:* {{std::allocator does not support volatile types}}
std::allocator<const volatile int> A2; // expected-error@*:* {{std::allocator does not support volatile types}}
std::allocator<const int> A1; // expected-error@*:* {{std::allocator does not support const types}}
std::allocator<volatile int> A2; // expected-error@*:* {{std::allocator does not support volatile types}}
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,6 @@ void test()
test_not_const<std::array< volatile int, 1>>();
test_false <std::array<const volatile int, 1>>();
test_true <std::deque< int>>();
#ifdef _LIBCPP_VERSION
test_true <std::deque<const int>>();
#endif // _LIBCPP_VERSION
test_true <std::forward_list<int>>();
test_true <std::list<int>>();
test_true <std::vector<int>>();
Expand All @@ -226,9 +223,6 @@ void test()

// Container adaptors
test_true <std::stack< int>>();
#ifdef _LIBCPP_VERSION
test_true <std::stack<const int>>();
#endif // _LIBCPP_VERSION
test_true <std::queue<int>>();
test_true <std::priority_queue<int>>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ TEST_CONSTEXPR_CXX20 bool test() {

int main(int, char**) {
test<char>();
test<char const>();
test<int>();
test<void>();

#if TEST_STD_VER > 17
static_assert(test<char>());
static_assert(test<char const>());
static_assert(test<int>());
static_assert(test<void>());
#endif
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,9 @@ int main(int, char**)
{
test<int>();
test<void>();
#ifdef _LIBCPP_VERSION // extension
test<int const>();
#endif // _LIBCPP_VERSION

static_assert(test<int>());
static_assert(test<void>());
#ifdef _LIBCPP_VERSION // extension
static_assert(test<int const>());
#endif // _LIBCPP_VERSION

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,4 @@ constexpr bool test()

void f() {
static_assert(test<double>()); // expected-error {{static assertion expression is not an integral constant expression}}
LIBCPP_STATIC_ASSERT(test<const double>()); // expected-error {{static assertion expression is not an integral constant expression}}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ void test()
int main(int, char**)
{
test<double>();
LIBCPP_ONLY(test<const double>());

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,6 @@ void f() {
typedef std::allocator<char>::const_reference ConstReference; // expected-warning {{'const_reference' is deprecated}}
typedef std::allocator<char>::rebind<int>::other Rebind; // expected-warning {{'rebind<int>' is deprecated}}
}
{
typedef std::allocator<char const>::pointer Pointer; // expected-warning {{'pointer' is deprecated}}
typedef std::allocator<char const>::const_pointer ConstPointer; // expected-warning {{'const_pointer' is deprecated}}
typedef std::allocator<char const>::reference Reference; // expected-warning {{'reference' is deprecated}}
typedef std::allocator<char const>::const_reference ConstReference; // expected-warning {{'const_reference' is deprecated}}
typedef std::allocator<char const>::rebind<int>::other Rebind; // expected-warning {{'rebind<int>' is deprecated}}
}
{
typedef std::allocator<void>::pointer Pointer; // expected-warning {{'pointer' is deprecated}}
typedef std::allocator<void>::const_pointer ConstPointer; // expected-warning {{'const_pointer' is deprecated}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ void test() {
typedef std::allocator<char>::is_always_equal IAE; // expected-warning {{'is_always_equal' is deprecated}}
}
{
typedef std::allocator<const char>::is_always_equal IAE; // expected-warning {{'is_always_equal' is deprecated}}
typedef std::allocator<int>::is_always_equal IAE; // expected-warning {{'is_always_equal' is deprecated}}
}
{
typedef std::allocator<void>::is_always_equal IAE; // expected-warning {{'is_always_equal' is deprecated}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,5 @@ void test() {

int main(int, char**) {
test<char>();
#ifdef _LIBCPP_VERSION
test<char const>(); // extension
#endif
return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ void check()

void f() {
check<char>();
check<char const>();
check<int>();
check<void>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ void check() {

void test() {
check<char>();
check<char const>();
check<int>();
check<void>();
}
Loading
Loading