diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst index 01bc2a1d57cf..ea7235e4abf8 100644 --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -69,11 +69,6 @@ API Changes - The C++14 function ``std::quoted(const char*)`` is no longer supported in C++03 or C++11 modes. -- libc++ no longer supports containers of ``const``-qualified element type, - such as ``vector`` and ``list``. This used to be supported - as an extension. Likewise, ``std::allocator`` is no longer supported. - If you were using ``vector``, replace it with ``vector`` instead. - ABI Changes ----------- diff --git a/libcxx/include/__memory/allocator.h b/libcxx/include/__memory/allocator.h index 4b5df0d17fcd..915ff7c3a516 100644 --- a/libcxx/include/__memory/allocator.h +++ b/libcxx/include/__memory/allocator.h @@ -37,6 +37,17 @@ public: template struct _LIBCPP_DEPRECATED_IN_CXX17 rebind {typedef allocator<_Up> other;}; }; + +template <> +class _LIBCPP_TEMPLATE_VIS allocator +{ +public: + _LIBCPP_DEPRECATED_IN_CXX17 typedef const void* pointer; + _LIBCPP_DEPRECATED_IN_CXX17 typedef const void* const_pointer; + _LIBCPP_DEPRECATED_IN_CXX17 typedef const void value_type; + + template struct _LIBCPP_DEPRECATED_IN_CXX17 rebind {typedef allocator<_Up> other;}; +}; #endif // This class provides a non-trivial default constructor to the class that derives from it @@ -69,7 +80,6 @@ template class _LIBCPP_TEMPLATE_VIS allocator : private __non_trivial_if::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: typedef size_t size_type; @@ -148,6 +158,84 @@ public: #endif }; +template +class _LIBCPP_TEMPLATE_VIS allocator + : private __non_trivial_if::value, allocator > +{ + static_assert(!is_volatile<_Tp>::value, "std::allocator does not support volatile types"); +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef const _Tp value_type; + typedef true_type propagate_on_container_move_assignment; + typedef true_type is_always_equal; + + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + allocator() _NOEXCEPT = default; + + template + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + allocator(const allocator<_Up>&) _NOEXCEPT { } + + _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + const _Tp* allocate(size_t __n) { + if (__n > allocator_traits::max_size(*this)) + __throw_bad_array_new_length(); + if (__libcpp_is_constant_evaluated()) { + return static_cast(::operator new(__n * sizeof(_Tp))); + } else { + return static_cast(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp))); + } + } + + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 + void deallocate(const _Tp* __p, size_t __n) { + if (__libcpp_is_constant_evaluated()) { + ::operator delete(const_cast<_Tp*>(__p)); + } else { + _VSTD::__libcpp_deallocate((void*) const_cast<_Tp *>(__p), __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)); + } + } + + // C++20 Removed members +#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_MEMBERS) + _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; + _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp& const_reference; + + template + struct _LIBCPP_DEPRECATED_IN_CXX17 rebind { + typedef allocator<_Up> other; + }; + + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY + const_pointer address(const_reference __x) const _NOEXCEPT { + return _VSTD::addressof(__x); + } + + _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_DEPRECATED_IN_CXX17 + const _Tp* allocate(size_t __n, const void*) { + return allocate(__n); + } + + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT { + return size_type(~0) / sizeof(_Tp); + } + + template + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY + void construct(_Up* __p, _Args&&... __args) { + ::new ((void*)__p) _Up(_VSTD::forward<_Args>(__args)...); + } + + _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY + void destroy(pointer __p) { + __p->~_Tp(); + } +#endif +}; + template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool operator==(const allocator<_Tp>&, const allocator<_Up>&) _NOEXCEPT {return true;} diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h index 04bc6d61668f..7401d3a891c1 100644 --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -288,7 +288,7 @@ struct __shared_ptr_emplace : __storage_(_VSTD::move(__a)) { #if _LIBCPP_STD_VER > 17 - using _TpAlloc = typename __allocator_traits_rebind<_Alloc, remove_cv_t<_Tp>>::type; + 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 @@ -305,7 +305,7 @@ struct __shared_ptr_emplace private: virtual void __on_zero_shared() _NOEXCEPT { #if _LIBCPP_STD_VER > 17 - using _TpAlloc = typename __allocator_traits_rebind<_Alloc, remove_cv_t<_Tp>>::type; + using _TpAlloc = typename __allocator_traits_rebind<_Alloc, _Tp>::type; _TpAlloc __tmp(*__get_alloc()); allocator_traits<_TpAlloc>::destroy(__tmp, __get_elem()); #else @@ -960,7 +960,7 @@ template::value> _LIBCPP_HIDE_FROM_ABI shared_ptr<_Tp> make_shared(_Args&& ...__args) { - return _VSTD::allocate_shared<_Tp>(allocator::type>(), _VSTD::forward<_Args>(__args)...); + return _VSTD::allocate_shared<_Tp>(allocator<_Tp>(), _VSTD::forward<_Args>(__args)...); } template diff --git a/libcxx/include/memory b/libcxx/include/memory index ea8ed0f9f361..1fccdacdcf86 100644 --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -895,17 +895,19 @@ void __construct_range_forward(_Alloc& __a, _Iter __begin1, _Iter __end1, _Ptr& } template ::type, + class _RawDest = typename remove_const<_Dest>::type, class = typename enable_if< is_trivially_copy_constructible<_Dest>::value && - is_same::type, _Dest>::value && + is_same<_RawSource, _RawDest>::value && (__is_default_allocator<_Alloc>::value || !__has_construct<_Alloc, _Dest*, _Source&>::value) >::type> _LIBCPP_INLINE_VISIBILITY void __construct_range_forward(_Alloc&, _Source* __begin1, _Source* __end1, _Dest*& __begin2) { ptrdiff_t _Np = __end1 - __begin1; if (_Np > 0) { - _VSTD::memcpy(__begin2, __begin1, _Np * sizeof(_Dest)); + _VSTD::memcpy(const_cast<_RawDest*>(__begin2), __begin1, _Np * sizeof(_Dest)); __begin2 += _Np; } } diff --git a/libcxx/test/libcxx/containers/sequences/vector/const_value_type.pass.cpp b/libcxx/test/libcxx/containers/sequences/vector/const_value_type.pass.cpp new file mode 100644 index 000000000000..1ad505a76d3f --- /dev/null +++ b/libcxx/test/libcxx/containers/sequences/vector/const_value_type.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03 + +// + +// vector v; // an extension + +#include +#include + +#include "test_macros.h" + +int main(int, char**) +{ + std::vector v = {1, 2, 3}; + + return 0; +} diff --git a/libcxx/test/libcxx/memory/allocator_void.trivial.compile.pass.cpp b/libcxx/test/libcxx/memory/allocator_void.trivial.compile.pass.cpp index 69a4b8943caa..f9d67c065de8 100644 --- a/libcxx/test/libcxx/memory/allocator_void.trivial.compile.pass.cpp +++ b/libcxx/test/libcxx/memory/allocator_void.trivial.compile.pass.cpp @@ -17,10 +17,18 @@ #include typedef std::allocator A1; -struct A2 : std::allocator { }; +typedef std::allocator A2; +struct A3 : std::allocator { }; +struct A4 : std::allocator { }; static_assert(std::is_trivially_default_constructible::value, ""); static_assert(std::is_trivial::value, ""); static_assert(std::is_trivially_default_constructible::value, ""); static_assert(std::is_trivial::value, ""); + +static_assert(std::is_trivially_default_constructible::value, ""); +static_assert(std::is_trivial::value, ""); + +static_assert(std::is_trivially_default_constructible::value, ""); +static_assert(std::is_trivial::value, ""); diff --git a/libcxx/test/libcxx/memory/allocator.cv.verify.cpp b/libcxx/test/libcxx/memory/allocator_volatile.verify.cpp similarity index 78% rename from libcxx/test/libcxx/memory/allocator.cv.verify.cpp rename to libcxx/test/libcxx/memory/allocator_volatile.verify.cpp index 6515d8ae765f..6fa7fe1b1aed 100644 --- a/libcxx/test/libcxx/memory/allocator.cv.verify.cpp +++ b/libcxx/test/libcxx/memory/allocator_volatile.verify.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// -// http://wg21.link/LWG2447 gives implementors freedom to reject const or volatile types in `std::allocator`. +// http://wg21.link/LWG2447 gives implementors freedom to reject volatile types in `std::allocator`. #include std::allocator A1; // expected-error@*:* {{std::allocator does not support volatile types}} -std::allocator A2; // expected-error@*:* {{std::allocator does not support const types}} +std::allocator A2; // expected-error@*:* {{std::allocator does not support volatile types}} diff --git a/libcxx/test/std/concepts/concepts.lang/concept.default.init/default_initializable.compile.pass.cpp b/libcxx/test/std/concepts/concepts.lang/concept.default.init/default_initializable.compile.pass.cpp index 50fe3822ff83..57d3132234f5 100644 --- a/libcxx/test/std/concepts/concepts.lang/concept.default.init/default_initializable.compile.pass.cpp +++ b/libcxx/test/std/concepts/concepts.lang/concept.default.init/default_initializable.compile.pass.cpp @@ -202,6 +202,9 @@ void test() test_not_const>(); test_false >(); test_true >(); +#ifdef _LIBCPP_VERSION + test_true >(); +#endif // _LIBCPP_VERSION test_true >(); test_true >(); test_true >(); @@ -220,6 +223,9 @@ void test() // Container adaptors test_true >(); +#ifdef _LIBCPP_VERSION + test_true >(); +#endif // _LIBCPP_VERSION test_true >(); test_true >(); diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.ctor.pass.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.ctor.pass.cpp index a278bc41ef76..6e6ff1f2d134 100644 --- a/libcxx/test/std/utilities/memory/default.allocator/allocator.ctor.pass.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.ctor.pass.cpp @@ -37,12 +37,12 @@ TEST_CONSTEXPR_CXX20 bool test() { int main(int, char**) { test(); - test(); + test(); test(); #if TEST_STD_VER > 17 static_assert(test()); - static_assert(test()); + static_assert(test()); static_assert(test()); #endif return 0; diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp index 69c6595c9864..a095ca102491 100644 --- a/libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.dtor.pass.cpp @@ -26,9 +26,15 @@ int main(int, char**) { test(); test(); +#ifdef _LIBCPP_VERSION // extension + test(); +#endif // _LIBCPP_VERSION static_assert(test()); static_assert(test()); +#ifdef _LIBCPP_VERSION // extension + static_assert(test()); +#endif // _LIBCPP_VERSION return 0; } diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.constexpr.size.verify.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.constexpr.size.verify.cpp index 13d2d65881ef..f12b6808edeb 100644 --- a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.constexpr.size.verify.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.constexpr.size.verify.cpp @@ -35,5 +35,6 @@ constexpr bool test() int main(int, char**) { static_assert(test()); // expected-error {{static_assert expression is not an integral constant expression}} + LIBCPP_STATIC_ASSERT(test()); // expected-error {{static_assert expression is not an integral constant expression}} return 0; } diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp index 56efcacf067f..6b9b12c82242 100644 --- a/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator.members/allocate.size.pass.cpp @@ -44,6 +44,7 @@ void test() int main(int, char**) { test(); + LIBCPP_ONLY(test()); return 0; } diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator_types.deprecated_in_cxx17.verify.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator_types.deprecated_in_cxx17.verify.cpp index 15c247a82b99..901f04730ee8 100644 --- a/libcxx/test/std/utilities/memory/default.allocator/allocator_types.deprecated_in_cxx17.verify.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator_types.deprecated_in_cxx17.verify.cpp @@ -35,6 +35,13 @@ int main(int, char**) { typedef std::allocator::const_reference ConstReference; // expected-warning {{'const_reference' is deprecated}} typedef std::allocator::rebind::other Rebind; // expected-warning {{'rebind' is deprecated}} } + { + typedef std::allocator::pointer Pointer; // expected-warning {{'pointer' is deprecated}} + typedef std::allocator::const_pointer ConstPointer; // expected-warning {{'const_pointer' is deprecated}} + typedef std::allocator::reference Reference; // expected-warning {{'reference' is deprecated}} + typedef std::allocator::const_reference ConstReference; // expected-warning {{'const_reference' is deprecated}} + typedef std::allocator::rebind::other Rebind; // expected-warning {{'rebind' is deprecated}} + } { typedef std::allocator::pointer Pointer; // expected-warning {{'pointer' is deprecated}} typedef std::allocator::const_pointer ConstPointer; // expected-warning {{'const_pointer' is deprecated}} diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp index 5761c28da09d..74adc6943594 100644 --- a/libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator_types.pass.cpp @@ -59,5 +59,8 @@ void test() { int main(int, char**) { test(); +#ifdef _LIBCPP_VERSION + test(); // extension +#endif return 0; } diff --git a/libcxx/test/std/utilities/memory/default.allocator/allocator_types.removed_in_cxx20.verify.cpp b/libcxx/test/std/utilities/memory/default.allocator/allocator_types.removed_in_cxx20.verify.cpp index 47cdf399ee47..1d91a022867d 100644 --- a/libcxx/test/std/utilities/memory/default.allocator/allocator_types.removed_in_cxx20.verify.cpp +++ b/libcxx/test/std/utilities/memory/default.allocator/allocator_types.removed_in_cxx20.verify.cpp @@ -31,16 +31,17 @@ template void check() { - typedef typename std::allocator::pointer AP; // expected-error 2 {{no type named 'pointer'}} - typedef typename std::allocator::const_pointer ACP; // expected-error 2 {{no type named 'const_pointer'}} - typedef typename std::allocator::reference AR; // expected-error 2 {{no type named 'reference'}} - typedef typename std::allocator::const_reference ACR; // expected-error 2 {{no type named 'const_reference'}} - typedef typename std::allocator::template rebind::other ARO; // expected-error 2 {{no member named 'rebind'}} + typedef typename std::allocator::pointer AP; // expected-error 3 {{no type named 'pointer'}} + typedef typename std::allocator::const_pointer ACP; // expected-error 3 {{no type named 'const_pointer'}} + typedef typename std::allocator::reference AR; // expected-error 3 {{no type named 'reference'}} + typedef typename std::allocator::const_reference ACR; // expected-error 3 {{no type named 'const_reference'}} + typedef typename std::allocator::template rebind::other ARO; // expected-error 3 {{no member named 'rebind'}} } int main(int, char**) { check(); + check(); check(); return 0; } diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp index 028eebbb974a..e7fd79796671 100644 --- a/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp @@ -82,7 +82,7 @@ constexpr bool test() } { - std::allocator a; + std::allocator a; Counted const* p = a.allocate(2); int count = 0; std::construct_at(p, count); @@ -93,7 +93,7 @@ constexpr bool test() assert(count == 1); p->~Counted(); assert(count == 0); - a.deallocate(const_cast(p), 2); + a.deallocate(p, 2); } return true;