Skip to content

Commit 276ca87

Browse files
committed
[libc++] Remove extension to support allocator<const T>
This extension is a portability trap for users, since no other standard library supports it. Furthermore, the Standard explicitly allows implementations to reject std::allocator<cv T>, so allowing it is really going against the current. This was discovered in D120684: this extension required `const_cast`ing in `__construct_range_forward`, a fishy bit of code that can be removed if we don't support the extension anymore. This is a re-application of dbc647643577, which was reverted in 9138666 because it broke std::shared_ptr<T const>. Tests have now been added and we've made sure that std::shared_ptr<T const> wouldn't be broken in this version. Differential Revision: https://reviews.llvm.org/D120996
1 parent e1dcda9 commit 276ca87

32 files changed

+334
-296
lines changed

libcxx/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ API Changes
7474
- The C++14 function ``std::quoted(const char*)`` is no longer supported in
7575
C++03 or C++11 modes.
7676

77+
- libc++ no longer supports containers of ``const``-qualified element type,
78+
such as ``vector<const T>`` and ``list<const T>``. This used to be supported
79+
as an extension. Likewise, ``std::allocator<const T>`` is no longer supported.
80+
If you were using ``vector<const T>``, replace it with ``vector<T>`` instead.
81+
7782
ABI Changes
7883
-----------
7984

libcxx/include/__memory/allocator.h

Lines changed: 1 addition & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,6 @@ class _LIBCPP_TEMPLATE_VIS allocator<void>
3737

3838
template <class _Up> struct _LIBCPP_DEPRECATED_IN_CXX17 rebind {typedef allocator<_Up> other;};
3939
};
40-
41-
template <>
42-
class _LIBCPP_TEMPLATE_VIS allocator<const void>
43-
{
44-
public:
45-
_LIBCPP_DEPRECATED_IN_CXX17 typedef const void* pointer;
46-
_LIBCPP_DEPRECATED_IN_CXX17 typedef const void* const_pointer;
47-
_LIBCPP_DEPRECATED_IN_CXX17 typedef const void value_type;
48-
49-
template <class _Up> struct _LIBCPP_DEPRECATED_IN_CXX17 rebind {typedef allocator<_Up> other;};
50-
};
5140
#endif
5241

5342
// This class provides a non-trivial default constructor to the class that derives from it
@@ -80,6 +69,7 @@ template <class _Tp>
8069
class _LIBCPP_TEMPLATE_VIS allocator
8170
: private __non_trivial_if<!is_void<_Tp>::value, allocator<_Tp> >
8271
{
72+
static_assert(!is_const<_Tp>::value, "std::allocator does not support const types");
8373
static_assert(!is_volatile<_Tp>::value, "std::allocator does not support volatile types");
8474
public:
8575
typedef size_t size_type;
@@ -158,84 +148,6 @@ class _LIBCPP_TEMPLATE_VIS allocator
158148
#endif
159149
};
160150

161-
template <class _Tp>
162-
class _LIBCPP_TEMPLATE_VIS allocator<const _Tp>
163-
: private __non_trivial_if<!is_void<_Tp>::value, allocator<const _Tp> >
164-
{
165-
static_assert(!is_volatile<_Tp>::value, "std::allocator does not support volatile types");
166-
public:
167-
typedef size_t size_type;
168-
typedef ptrdiff_t difference_type;
169-
typedef const _Tp value_type;
170-
typedef true_type propagate_on_container_move_assignment;
171-
typedef true_type is_always_equal;
172-
173-
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
174-
allocator() _NOEXCEPT = default;
175-
176-
template <class _Up>
177-
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
178-
allocator(const allocator<_Up>&) _NOEXCEPT { }
179-
180-
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
181-
const _Tp* allocate(size_t __n) {
182-
if (__n > allocator_traits<allocator>::max_size(*this))
183-
__throw_bad_array_new_length();
184-
if (__libcpp_is_constant_evaluated()) {
185-
return static_cast<const _Tp*>(::operator new(__n * sizeof(_Tp)));
186-
} else {
187-
return static_cast<const _Tp*>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)));
188-
}
189-
}
190-
191-
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
192-
void deallocate(const _Tp* __p, size_t __n) {
193-
if (__libcpp_is_constant_evaluated()) {
194-
::operator delete(const_cast<_Tp*>(__p));
195-
} else {
196-
_VSTD::__libcpp_deallocate((void*) const_cast<_Tp *>(__p), __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp));
197-
}
198-
}
199-
200-
// C++20 Removed members
201-
#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_MEMBERS)
202-
_LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp* pointer;
203-
_LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp* const_pointer;
204-
_LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp& reference;
205-
_LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp& const_reference;
206-
207-
template <class _Up>
208-
struct _LIBCPP_DEPRECATED_IN_CXX17 rebind {
209-
typedef allocator<_Up> other;
210-
};
211-
212-
_LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY
213-
const_pointer address(const_reference __x) const _NOEXCEPT {
214-
return _VSTD::addressof(__x);
215-
}
216-
217-
_LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_DEPRECATED_IN_CXX17
218-
const _Tp* allocate(size_t __n, const void*) {
219-
return allocate(__n);
220-
}
221-
222-
_LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {
223-
return size_type(~0) / sizeof(_Tp);
224-
}
225-
226-
template <class _Up, class... _Args>
227-
_LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY
228-
void construct(_Up* __p, _Args&&... __args) {
229-
::new ((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
230-
}
231-
232-
_LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY
233-
void destroy(pointer __p) {
234-
__p->~_Tp();
235-
}
236-
#endif
237-
};
238-
239151
template <class _Tp, class _Up>
240152
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
241153
bool operator==(const allocator<_Tp>&, const allocator<_Up>&) _NOEXCEPT {return true;}

libcxx/include/__memory/shared_ptr.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -282,13 +282,15 @@ template <class _Tp, class _Alloc>
282282
struct __shared_ptr_emplace
283283
: __shared_weak_count
284284
{
285+
using _TpAlloc = typename __allocator_traits_rebind<_Alloc, typename remove_cv<_Tp>::type>::type;
286+
using _ControlBlockAlloc = typename __allocator_traits_rebind<_Alloc, __shared_ptr_emplace>::type;
287+
285288
template<class ..._Args>
286289
_LIBCPP_HIDE_FROM_ABI
287290
explicit __shared_ptr_emplace(_Alloc __a, _Args&& ...__args)
288291
: __storage_(_VSTD::move(__a))
289292
{
290293
#if _LIBCPP_STD_VER > 17
291-
using _TpAlloc = typename __allocator_traits_rebind<_Alloc, _Tp>::type;
292294
_TpAlloc __tmp(*__get_alloc());
293295
allocator_traits<_TpAlloc>::construct(__tmp, __get_elem(), _VSTD::forward<_Args>(__args)...);
294296
#else
@@ -305,7 +307,6 @@ struct __shared_ptr_emplace
305307
private:
306308
virtual void __on_zero_shared() _NOEXCEPT {
307309
#if _LIBCPP_STD_VER > 17
308-
using _TpAlloc = typename __allocator_traits_rebind<_Alloc, _Tp>::type;
309310
_TpAlloc __tmp(*__get_alloc());
310311
allocator_traits<_TpAlloc>::destroy(__tmp, __get_elem());
311312
#else
@@ -314,7 +315,6 @@ struct __shared_ptr_emplace
314315
}
315316

316317
virtual void __on_zero_shared_weak() _NOEXCEPT {
317-
using _ControlBlockAlloc = typename __allocator_traits_rebind<_Alloc, __shared_ptr_emplace>::type;
318318
using _ControlBlockPointer = typename allocator_traits<_ControlBlockAlloc>::pointer;
319319
_ControlBlockAlloc __tmp(*__get_alloc());
320320
__storage_.~_Storage();
@@ -643,8 +643,9 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr
643643
shared_ptr(auto_ptr<_Yp>&& __r)
644644
: __ptr_(__r.get())
645645
{
646-
typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, allocator<_Yp> > _CntrlBlk;
647-
__cntrl_ = new _CntrlBlk(__r.get(), default_delete<_Yp>(), allocator<_Yp>());
646+
typedef allocator<typename remove_cv<_Yp>::type> _YpAlloc;
647+
typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, _YpAlloc> _CntrlBlk;
648+
__cntrl_ = new _CntrlBlk(__r.get(), default_delete<_Yp>(), _YpAlloc());
648649
__enable_weak_this(__r.get(), __r.get());
649650
__r.release();
650651
}
@@ -890,7 +891,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr
890891
template <class _Yp, bool = is_function<_Yp>::value>
891892
struct __shared_ptr_default_allocator
892893
{
893-
typedef allocator<_Yp> type;
894+
typedef allocator<typename remove_cv<_Yp>::type> type;
894895
};
895896

896897
template <class _Yp>
@@ -960,7 +961,7 @@ template<class _Tp, class ..._Args, class = __enable_if_t<!is_array<_Tp>::value>
960961
_LIBCPP_HIDE_FROM_ABI
961962
shared_ptr<_Tp> make_shared(_Args&& ...__args)
962963
{
963-
return _VSTD::allocate_shared<_Tp>(allocator<_Tp>(), _VSTD::forward<_Args>(__args)...);
964+
return _VSTD::allocate_shared<_Tp>(allocator<typename remove_cv<_Tp>::type>(), _VSTD::forward<_Args>(__args)...);
964965
}
965966

966967
template<class _Tp, class _Up>

libcxx/include/memory

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -895,19 +895,17 @@ void __construct_range_forward(_Alloc& __a, _Iter __begin1, _Iter __end1, _Ptr&
895895
}
896896

897897
template <class _Alloc, class _Source, class _Dest,
898-
class _RawSource = typename remove_const<_Source>::type,
899-
class _RawDest = typename remove_const<_Dest>::type,
900898
class =
901899
typename enable_if<
902900
is_trivially_copy_constructible<_Dest>::value &&
903-
is_same<_RawSource, _RawDest>::value &&
901+
is_same<typename remove_const<_Source>::type, _Dest>::value &&
904902
(__is_default_allocator<_Alloc>::value || !__has_construct<_Alloc, _Dest*, _Source&>::value)
905903
>::type>
906904
_LIBCPP_INLINE_VISIBILITY
907905
void __construct_range_forward(_Alloc&, _Source* __begin1, _Source* __end1, _Dest*& __begin2) {
908906
ptrdiff_t _Np = __end1 - __begin1;
909907
if (_Np > 0) {
910-
_VSTD::memcpy(const_cast<_RawDest*>(__begin2), __begin1, _Np * sizeof(_Dest));
908+
_VSTD::memcpy(__begin2, __begin1, _Np * sizeof(_Dest));
911909
__begin2 += _Np;
912910
}
913911
}

libcxx/test/libcxx/containers/sequences/vector/const_value_type.pass.cpp

Lines changed: 0 additions & 25 deletions
This file was deleted.

libcxx/test/libcxx/memory/allocator_volatile.verify.cpp renamed to libcxx/test/libcxx/memory/allocator.cv.verify.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
//
77
//===----------------------------------------------------------------------===//
88

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

1111
#include <memory>
1212

1313
std::allocator<volatile int> A1; // expected-error@*:* {{std::allocator does not support volatile types}}
14-
std::allocator<const volatile int> A2; // expected-error@*:* {{std::allocator does not support volatile types}}
14+
std::allocator<const int> A2; // expected-error@*:* {{std::allocator does not support const types}}

libcxx/test/libcxx/memory/allocator_void.trivial.compile.pass.cpp

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,10 @@
1717
#include <type_traits>
1818

1919
typedef std::allocator<void> A1;
20-
typedef std::allocator<void const> A2;
21-
struct A3 : std::allocator<void> { };
22-
struct A4 : std::allocator<void const> { };
20+
struct A2 : std::allocator<void> { };
2321

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

2725
static_assert(std::is_trivially_default_constructible<A2>::value, "");
2826
static_assert(std::is_trivial<A2>::value, "");
29-
30-
static_assert(std::is_trivially_default_constructible<A3>::value, "");
31-
static_assert(std::is_trivial<A3>::value, "");
32-
33-
static_assert(std::is_trivially_default_constructible<A4>::value, "");
34-
static_assert(std::is_trivial<A4>::value, "");

libcxx/test/std/concepts/concepts.lang/concept.default.init/default_initializable.compile.pass.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,6 @@ void test()
202202
test_not_const<std::array< volatile int, 1>>();
203203
test_false <std::array<const volatile int, 1>>();
204204
test_true <std::deque< int>>();
205-
#ifdef _LIBCPP_VERSION
206-
test_true <std::deque<const int>>();
207-
#endif // _LIBCPP_VERSION
208205
test_true <std::forward_list<int>>();
209206
test_true <std::list<int>>();
210207
test_true <std::vector<int>>();
@@ -223,9 +220,6 @@ void test()
223220

224221
// Container adaptors
225222
test_true <std::stack< int>>();
226-
#ifdef _LIBCPP_VERSION
227-
test_true <std::stack<const int>>();
228-
#endif // _LIBCPP_VERSION
229223
test_true <std::queue<int>>();
230224
test_true <std::priority_queue<int>>();
231225

libcxx/test/std/utilities/memory/default.allocator/allocator.ctor.pass.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ TEST_CONSTEXPR_CXX20 bool test() {
3737

3838
int main(int, char**) {
3939
test<char>();
40-
test<char const>();
40+
test<int>();
4141
test<void>();
4242

4343
#if TEST_STD_VER > 17
4444
static_assert(test<char>());
45-
static_assert(test<char const>());
45+
static_assert(test<int>());
4646
static_assert(test<void>());
4747
#endif
4848
return 0;

libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,9 @@ int main(int, char**)
2626
{
2727
test<int>();
2828
test<void>();
29-
#ifdef _LIBCPP_VERSION // extension
30-
test<int const>();
31-
#endif // _LIBCPP_VERSION
3229

3330
static_assert(test<int>());
3431
static_assert(test<void>());
35-
#ifdef _LIBCPP_VERSION // extension
36-
static_assert(test<int const>());
37-
#endif // _LIBCPP_VERSION
3832

3933
return 0;
4034
}

libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.constexpr.size.verify.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,5 @@ constexpr bool test()
3535
int main(int, char**)
3636
{
3737
static_assert(test<double>()); // expected-error {{static_assert expression is not an integral constant expression}}
38-
LIBCPP_STATIC_ASSERT(test<const double>()); // expected-error {{static_assert expression is not an integral constant expression}}
3938
return 0;
4039
}

libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ void test()
4444
int main(int, char**)
4545
{
4646
test<double>();
47-
LIBCPP_ONLY(test<const double>());
4847

4948
return 0;
5049
}

libcxx/test/std/utilities/memory/default.allocator/allocator_types.deprecated_in_cxx17.verify.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,6 @@ int main(int, char**) {
3535
typedef std::allocator<char>::const_reference ConstReference; // expected-warning {{'const_reference' is deprecated}}
3636
typedef std::allocator<char>::rebind<int>::other Rebind; // expected-warning {{'rebind<int>' is deprecated}}
3737
}
38-
{
39-
typedef std::allocator<char const>::pointer Pointer; // expected-warning {{'pointer' is deprecated}}
40-
typedef std::allocator<char const>::const_pointer ConstPointer; // expected-warning {{'const_pointer' is deprecated}}
41-
typedef std::allocator<char const>::reference Reference; // expected-warning {{'reference' is deprecated}}
42-
typedef std::allocator<char const>::const_reference ConstReference; // expected-warning {{'const_reference' is deprecated}}
43-
typedef std::allocator<char const>::rebind<int>::other Rebind; // expected-warning {{'rebind<int>' is deprecated}}
44-
}
4538
{
4639
typedef std::allocator<void>::pointer Pointer; // expected-warning {{'pointer' is deprecated}}
4740
typedef std::allocator<void>::const_pointer ConstPointer; // expected-warning {{'const_pointer' is deprecated}}

libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,5 @@ void test() {
5959

6060
int main(int, char**) {
6161
test<char>();
62-
#ifdef _LIBCPP_VERSION
63-
test<char const>(); // extension
64-
#endif
6562
return 0;
6663
}

libcxx/test/std/utilities/memory/default.allocator/allocator_types.removed_in_cxx20.verify.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,16 @@
3131
template <typename T>
3232
void check()
3333
{
34-
typedef typename std::allocator<T>::pointer AP; // expected-error 3 {{no type named 'pointer'}}
35-
typedef typename std::allocator<T>::const_pointer ACP; // expected-error 3 {{no type named 'const_pointer'}}
36-
typedef typename std::allocator<T>::reference AR; // expected-error 3 {{no type named 'reference'}}
37-
typedef typename std::allocator<T>::const_reference ACR; // expected-error 3 {{no type named 'const_reference'}}
38-
typedef typename std::allocator<T>::template rebind<int>::other ARO; // expected-error 3 {{no member named 'rebind'}}
34+
typedef typename std::allocator<T>::pointer AP; // expected-error 2 {{no type named 'pointer'}}
35+
typedef typename std::allocator<T>::const_pointer ACP; // expected-error 2 {{no type named 'const_pointer'}}
36+
typedef typename std::allocator<T>::reference AR; // expected-error 2 {{no type named 'reference'}}
37+
typedef typename std::allocator<T>::const_reference ACR; // expected-error 2 {{no type named 'const_reference'}}
38+
typedef typename std::allocator<T>::template rebind<int>::other ARO; // expected-error 2 {{no member named 'rebind'}}
3939
}
4040

4141
int main(int, char**)
4242
{
4343
check<char>();
44-
check<char const>();
4544
check<void>();
4645
return 0;
4746
}

libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ constexpr bool test()
8282
}
8383

8484
{
85-
std::allocator<Counted const> a;
85+
std::allocator<Counted> a;
8686
Counted const* p = a.allocate(2);
8787
int count = 0;
8888
std::construct_at(p, count);
@@ -93,7 +93,7 @@ constexpr bool test()
9393
assert(count == 1);
9494
p->~Counted();
9595
assert(count == 0);
96-
a.deallocate(p, 2);
96+
a.deallocate(const_cast<Counted*>(p), 2);
9797
}
9898

9999
return true;

0 commit comments

Comments
 (0)