From b03c70857f55a553b681c43850491fc45bad2f11 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Mon, 21 Dec 2020 13:37:57 +0100 Subject: [PATCH 01/13] Prepare the constexpr machinery needed for string and vector --- stl/inc/xmemory | 431 +++++++++++++++++++++++++++++------------------ stl/inc/xutility | 14 +- 2 files changed, 280 insertions(+), 165 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 38209d5c9cd..73ecb33edbb 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -27,7 +27,7 @@ _STD_BEGIN template struct _NODISCARD _Tidy_guard { // class with destructor that calls _Tidy _Ty* _Target; - ~_Tidy_guard() { + _CONSTEXPR20_DYNALLOC ~_Tidy_guard() { if (_Target) { _Target->_Tidy(); } @@ -38,7 +38,7 @@ struct _NODISCARD _Tidy_guard { // class with destructor that calls _Tidy template struct _NODISCARD _Tidy_deallocate_guard { // class with destructor that calls _Tidy_deallocate _Ty* _Target; - ~_Tidy_deallocate_guard() { + _CONSTEXPR20_DYNALLOC ~_Tidy_deallocate_guard() { if (_Target) { _Target->_Tidy_deallocate(); } @@ -265,10 +265,10 @@ _CONSTEXPR20_DYNALLOC void _Deallocate(void* _Ptr, size_t _Bytes) noexcept { // FUNCTION TEMPLATE _Global_new template -_Ty* _Global_new(_Types&&... _Args) { // acts as "new" while disallowing user overload selection +_CONSTEXPR20_DYNALLOC _Ty* _Global_new(_Types&&... _Args) { // acts as "new" while disallowing user overload selection struct _NODISCARD _Guard_type { void* _Result; - ~_Guard_type() { + _CONSTEXPR20_DYNALLOC ~_Guard_type() { if (_Result) { _Deallocate<_New_alignof<_Ty>>(_Result, sizeof(_Ty)); } @@ -286,12 +286,12 @@ using _Rebind_pointer_t = typename pointer_traits<_Ptr>::template rebind<_Ty>; // FUNCTION TEMPLATE _Refancy template , int> = 0> -_Pointer _Refancy(typename pointer_traits<_Pointer>::element_type* _Ptr) noexcept { +_CONSTEXPR20 _Pointer _Refancy(typename pointer_traits<_Pointer>::element_type* _Ptr) noexcept { return pointer_traits<_Pointer>::pointer_to(*_Ptr); } template , int> = 0> -_Pointer _Refancy(_Pointer _Ptr) noexcept { +_CONSTEXPR20 _Pointer _Refancy(_Pointer _Ptr) noexcept { return _Ptr; } @@ -837,7 +837,7 @@ public: template _CXX17_DEPRECATE_OLD_ALLOCATOR_MEMBERS void construct(_Objty* const _Ptr, _Types&&... _Args) { - ::new (const_cast(static_cast(_Ptr))) _Objty(_STD forward<_Types>(_Args)...); + ::new (_Voidify_iter(_Ptr)) _Objty(_STD forward<_Types>(_Args)...); } template @@ -897,7 +897,7 @@ using _Alloc_size_t = typename allocator_traits<_Alloc>::size_type; // FUNCTION TEMPLATE _Pocca template -void _Pocca(_Alloc& _Left, const _Alloc& _Right) noexcept { +_CONSTEXPR20 void _Pocca(_Alloc& _Left, const _Alloc& _Right) noexcept { if constexpr (allocator_traits<_Alloc>::propagate_on_container_copy_assignment::value) { _Left = _Right; } @@ -905,7 +905,7 @@ void _Pocca(_Alloc& _Left, const _Alloc& _Right) noexcept { // FUNCTION TEMPLATE _Pocma template -void _Pocma(_Alloc& _Left, _Alloc& _Right) noexcept { // (maybe) propagate on container move assignment +_CONSTEXPR20 void _Pocma(_Alloc& _Left, _Alloc& _Right) noexcept { // (maybe) propagate on container move assignment if constexpr (allocator_traits<_Alloc>::propagate_on_container_move_assignment::value) { _Left = _STD move(_Right); } @@ -913,7 +913,7 @@ void _Pocma(_Alloc& _Left, _Alloc& _Right) noexcept { // (maybe) propagate on co // FUNCTION TEMPLATE _Pocs template -void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { +_CONSTEXPR20 void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { if constexpr (allocator_traits<_Alloc>::propagate_on_container_swap::value) { _Swap_adl(_Left, _Right); } else { @@ -923,7 +923,8 @@ void _Pocs(_Alloc& _Left, _Alloc& _Right) noexcept { // FUNCTION TEMPLATE _Destroy_range WITH ALLOC template -void _Destroy_range(_Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Last, _Alloc& _Al) noexcept { +_CONSTEXPR20_DYNALLOC void _Destroy_range( + _Alloc_ptr_t<_Alloc> _First, const _Alloc_ptr_t<_Alloc> _Last, _Alloc& _Al) noexcept { // note that this is an optimization for debug mode codegen; in release mode the BE removes all of this using _Ty = typename _Alloc::value_type; if constexpr (!conjunction_v, _Uses_default_destroy<_Alloc, _Ty*>>) { @@ -963,7 +964,7 @@ _NODISCARD constexpr size_t _Convert_size(const size_t _Len) noexcept { // FUNCTION TEMPLATE _Deallocate_plain template -void _Deallocate_plain(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noexcept { +_CONSTEXPR20_DYNALLOC void _Deallocate_plain(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noexcept { // deallocate a plain pointer using an allocator using _Alloc_traits = allocator_traits<_Alloc>; if constexpr (is_same_v<_Alloc_ptr_t<_Alloc>, typename _Alloc::value_type*>) { @@ -976,7 +977,7 @@ void _Deallocate_plain(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noe // FUNCTION TEMPLATE _Delete_plain_internal template -void _Delete_plain_internal(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noexcept { +_CONSTEXPR20_DYNALLOC void _Delete_plain_internal(_Alloc& _Al, typename _Alloc::value_type* const _Ptr) noexcept { // destroy *_Ptr in place, then deallocate _Ptr using _Al; used for internal container types the user didn't name using _Ty = typename _Alloc::value_type; _Ptr->~_Ty(); @@ -992,16 +993,16 @@ struct _Alloc_construct_ptr { // pointer used to help construct 1 _Alloc::value_ explicit _Alloc_construct_ptr(_Alloc& _Al_) : _Al(_Al_), _Ptr(nullptr) {} - _NODISCARD pointer _Release() noexcept { // disengage *this and return contained pointer + _NODISCARD _CONSTEXPR20_DYNALLOC pointer _Release() noexcept { // disengage *this and return contained pointer return _STD exchange(_Ptr, nullptr); } - void _Allocate() { // disengage *this, then allocate a new memory block + _CONSTEXPR20_DYNALLOC void _Allocate() { // disengage *this, then allocate a new memory block _Ptr = nullptr; // if allocate throws, prevents double-free _Ptr = _Al.allocate(1); } - ~_Alloc_construct_ptr() { // if this instance is engaged, deallocate storage + _CONSTEXPR20_DYNALLOC ~_Alloc_construct_ptr() { // if this instance is engaged, deallocate storage if (_Ptr) { _Al.deallocate(_Ptr, 1); } @@ -1015,15 +1016,15 @@ struct _Alloc_construct_ptr { // pointer used to help construct 1 _Alloc::value_ struct _Fake_allocator {}; struct _Container_base0 { - void _Orphan_all() noexcept {} - void _Swap_proxy_and_iterators(_Container_base0&) noexcept {} - void _Alloc_proxy(const _Fake_allocator&) noexcept {} - void _Reload_proxy(const _Fake_allocator&, const _Fake_allocator&) noexcept {} + _CONSTEXPR20 void _Orphan_all() noexcept {} + _CONSTEXPR20 void _Swap_proxy_and_iterators(_Container_base0&) noexcept {} + _CONSTEXPR20 void _Alloc_proxy(const _Fake_allocator&) noexcept {} + _CONSTEXPR20 void _Reload_proxy(const _Fake_allocator&, const _Fake_allocator&) noexcept {} }; struct _Iterator_base0 { - void _Adopt(const void*) noexcept {} - const _Container_base0* _Getcont() const noexcept { + _CONSTEXPR20 void _Adopt(const void*) noexcept {} + _CONSTEXPR20 const _Container_base0* _Getcont() const noexcept { return nullptr; } @@ -1033,25 +1034,25 @@ struct _Iterator_base0 { // CLASS _Container_proxy struct _Container_base12; struct _Container_proxy { // store head of iterator chain and back pointer - _Container_proxy() noexcept : _Mycont(nullptr), _Myfirstiter(nullptr) {} - _Container_proxy(_Container_base12* _Mycont_) noexcept : _Mycont(_Mycont_), _Myfirstiter(nullptr) {} + _CONSTEXPR20 _Container_proxy() noexcept = default; + _CONSTEXPR20 _Container_proxy(_Container_base12* _Mycont_) noexcept : _Mycont(_Mycont_) {} const _Container_base12* _Mycont; - _Iterator_base12* _Myfirstiter; + mutable _Iterator_base12* _Myfirstiter; }; struct _Container_base12 { public: - _Container_base12() noexcept : _Myproxy(nullptr) {} + _CONSTEXPR20_DYNALLOC _Container_base12() noexcept = default; _Container_base12(const _Container_base12&) = delete; _Container_base12& operator=(const _Container_base12&) = delete; - void _Orphan_all() noexcept; - void _Swap_proxy_and_iterators(_Container_base12&) noexcept; + _CONSTEXPR20_DYNALLOC void _Orphan_all() noexcept; + _CONSTEXPR20_DYNALLOC void _Swap_proxy_and_iterators(_Container_base12&) noexcept; template - void _Alloc_proxy(_Alloc&& _Al) { + _CONSTEXPR20_DYNALLOC void _Alloc_proxy(_Alloc&& _Al) { _Container_proxy* const _New_proxy = _Unfancy(_Al.allocate(1)); _Construct_in_place(*_New_proxy, this); _Myproxy = _New_proxy; @@ -1059,7 +1060,7 @@ public: } template - void _Reload_proxy(_Alloc&& _Old_alloc, _Alloc&& _New_alloc) { + _CONSTEXPR20_DYNALLOC void _Reload_proxy(_Alloc&& _Old_alloc, _Alloc&& _New_alloc) { // pre: no iterators refer to the existing proxy _Container_proxy* const _New_proxy = _Unfancy(_New_alloc.allocate(1)); _Construct_in_place(*_New_proxy, this); @@ -1067,113 +1068,156 @@ public: _Delete_plain_internal(_Old_alloc, _STD exchange(_Myproxy, _New_proxy)); } - _Container_proxy* _Myproxy; + _Container_proxy* _Myproxy = nullptr; + +private: + _CONSTEXPR20_DYNALLOC void _Orphan_all_unlocked() noexcept; + inline void _Orphan_all_locked() noexcept; + _CONSTEXPR20_DYNALLOC void _Swap_proxy_and_iterators_unlocked(_Container_base12&) noexcept; + inline void _Swap_proxy_and_iterators_locked(_Container_base12&) noexcept; }; struct _Iterator_base12 { // store links to container proxy, next iterator - _Iterator_base12() noexcept : _Myproxy(nullptr), _Mynextiter(nullptr) {} // construct orphaned iterator +public: + _CONSTEXPR20_DYNALLOC _Iterator_base12() noexcept = default; // construct orphaned iterator - _Iterator_base12(const _Iterator_base12& _Right) noexcept : _Myproxy(nullptr), _Mynextiter(nullptr) { + _CONSTEXPR20_DYNALLOC _Iterator_base12(const _Iterator_base12& _Right) noexcept { *this = _Right; } - _Iterator_base12& operator=(const _Iterator_base12& _Right) noexcept { + _CONSTEXPR20_DYNALLOC _Iterator_base12& operator=(const _Iterator_base12& _Right) noexcept { if (_Myproxy != _Right._Myproxy) { if (_Right._Myproxy) { _Adopt(_Right._Myproxy->_Mycont); } else { // becoming invalid, disown current parent #if _ITERATOR_DEBUG_LEVEL == 2 - _Lockit _Lock(_LOCK_DEBUG); _Orphan_me(); #else // _ITERATOR_DEBUG_LEVEL == 2 _Myproxy = nullptr; #endif // _ITERATOR_DEBUG_LEVEL == 2 } } - return *this; } - ~_Iterator_base12() noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 - _Lockit _Lock(_LOCK_DEBUG); + _CONSTEXPR20_DYNALLOC ~_Iterator_base12() noexcept { _Orphan_me(); -#endif // _ITERATOR_DEBUG_LEVEL == 2 } - void _Adopt(const _Container_base12* _Parent) noexcept { - if (_Parent) { - // have a parent, do adoption + _CONSTEXPR20_DYNALLOC void _Adopt(const _Container_base12* _Parent) noexcept { + if (_Parent) { // have a parent, do adoption _Container_proxy* _Parent_proxy = _Parent->_Myproxy; - -#if _ITERATOR_DEBUG_LEVEL == 2 if (_Myproxy != _Parent_proxy) { // change parentage - _Lockit _Lock(_LOCK_DEBUG); - _Orphan_me(); - _Mynextiter = _Parent_proxy->_Myfirstiter; - _Parent_proxy->_Myfirstiter = this; - _Myproxy = _Parent_proxy; +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Adopt_unlocked(_Parent_proxy); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Adopt_locked(_Parent_proxy); + } } - -#else // _ITERATOR_DEBUG_LEVEL == 2 - _Myproxy = _Parent_proxy; -#endif // _ITERATOR_DEBUG_LEVEL == 2 - } else { - // no future parent, just disown current parent -#if _ITERATOR_DEBUG_LEVEL == 2 - _Lockit _Lock(_LOCK_DEBUG); + } else { // no future parent, just disown current parent _Orphan_me(); -#else // _ITERATOR_DEBUG_LEVEL == 2 - _Myproxy = nullptr; -#endif // _ITERATOR_DEBUG_LEVEL == 2 } } - const _Container_base12* _Getcont() const noexcept { - return _Myproxy ? _Myproxy->_Mycont : nullptr; - } - -#if _ITERATOR_DEBUG_LEVEL == 2 - void _Orphan_me() noexcept { + _CONSTEXPR20_DYNALLOC void _Orphan_me() noexcept { if (_Myproxy) { // adopted, remove self from list - _Iterator_base12** _Pnext = &_Myproxy->_Myfirstiter; - while (*_Pnext && *_Pnext != this) { - _Pnext = &(*_Pnext)->_Mynextiter; +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Orphan_me_unlocked(); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Orphan_me_locked(); } + } + } - _STL_VERIFY(*_Pnext, "ITERATOR LIST CORRUPTED!"); - *_Pnext = _Mynextiter; +#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL != 2 vvv + _CONSTEXPR20_DYNALLOC void _Adopt(const _Container_base12* _Parent) noexcept { + if (_Parent) { // have a parent, do adoption + _Myproxy = _Parent->_Myproxy; + } else { // no future parent, just disown current parent _Myproxy = nullptr; } } -#endif // _ITERATOR_DEBUG_LEVEL == 2 +#endif // _ITERATOR_DEBUG_LEVEL != 2 + + _CONSTEXPR20_DYNALLOC const _Container_base12* _Getcont() const noexcept { + return _Myproxy ? _Myproxy->_Mycont : nullptr; + } static constexpr bool _Unwrap_when_unverified = _ITERATOR_DEBUG_LEVEL == 0; - _Container_proxy* _Myproxy; - _Iterator_base12* _Mynextiter; -}; + _Container_proxy* _Myproxy = nullptr; + _Iterator_base12* _Mynextiter = nullptr; -// MEMBER FUNCTIONS FOR _Container_base12 -inline void _Container_base12::_Orphan_all() noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 - if (_Myproxy) { // proxy allocated, drain it +private: + _CONSTEXPR20_DYNALLOC void _Adopt_unlocked(_Container_proxy* _Parent_proxy) noexcept { + if (_Myproxy) { // adopted, remove self from list + _Orphan_me_unlocked(); + } + _Mynextiter = _Parent_proxy->_Myfirstiter; + _Parent_proxy->_Myfirstiter = this; + _Myproxy = _Parent_proxy; + } + + void _Adopt_locked(_Container_proxy* _Parent_proxy) noexcept { _Lockit _Lock(_LOCK_DEBUG); + _Adopt_unlocked(_Parent_proxy); + } - for (auto _Pnext = &_Myproxy->_Myfirstiter; *_Pnext; *_Pnext = (*_Pnext)->_Mynextiter) { - (*_Pnext)->_Myproxy = nullptr; + _CONSTEXPR20_DYNALLOC void _Orphan_me_unlocked() noexcept { + _Iterator_base12** _Pnext = &_Myproxy->_Myfirstiter; + while (*_Pnext && *_Pnext != this) { + _Pnext = &(*_Pnext)->_Mynextiter; } - _Myproxy->_Myfirstiter = nullptr; + _STL_VERIFY(*_Pnext, "ITERATOR LIST CORRUPTED!"); + *_Pnext = _Mynextiter; + _Myproxy = nullptr; + } + + void _Orphan_me_locked() noexcept { + _Lockit _Lock(_LOCK_DEBUG); + _Orphan_me_unlocked(); } #endif // _ITERATOR_DEBUG_LEVEL == 2 +}; + +// MEMBER FUNCTIONS FOR _Container_base12 +_CONSTEXPR20_DYNALLOC void _Container_base12::_Orphan_all_unlocked() noexcept { + for (auto _Pnext = &_Myproxy->_Myfirstiter; *_Pnext; *_Pnext = (*_Pnext)->_Mynextiter) { + (*_Pnext)->_Myproxy = nullptr; + } + _Myproxy->_Myfirstiter = nullptr; } -inline void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { -#if _ITERATOR_DEBUG_LEVEL == 2 +inline void _Container_base12::_Orphan_all_locked() noexcept { _Lockit _Lock(_LOCK_DEBUG); + _Orphan_all_unlocked(); +} + +_CONSTEXPR20_DYNALLOC void _Container_base12::_Orphan_all() noexcept { +#if _ITERATOR_DEBUG_LEVEL == 2 + if (_Myproxy) { // proxy allocated, drain it +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Orphan_all_unlocked(); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Orphan_all_locked(); + } + } #endif // _ITERATOR_DEBUG_LEVEL == 2 +} +_CONSTEXPR20_DYNALLOC void _Container_base12::_Swap_proxy_and_iterators_unlocked(_Container_base12& _Right) noexcept { _Container_proxy* _Temp = _Myproxy; _Myproxy = _Right._Myproxy; _Right._Myproxy = _Temp; @@ -1187,6 +1231,26 @@ inline void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Rig } } +inline void _Container_base12::_Swap_proxy_and_iterators_locked(_Container_base12& _Right) noexcept { + _Lockit _Lock(_LOCK_DEBUG); + _Swap_proxy_and_iterators_unlocked(_Right); +} + +_CONSTEXPR20_DYNALLOC void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { +#if _ITERATOR_DEBUG_LEVEL != 2 + _Swap_proxy_and_iterators_unlocked(_Right); +#else // ^^^ _ITERATOR_DEBUG_LEVEL != 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL == 2 vvv +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _Swap_proxy_and_iterators_unlocked(_Right); + } else +#endif // __cpp_lib_is_constant_evaluated + { + _Swap_proxy_and_iterators_locked(_Right); + } +#endif // _ITERATOR_DEBUG_LEVEL == 2 +} + #if _ITERATOR_DEBUG_LEVEL == 0 using _Container_base = _Container_base0; using _Iterator_base = _Iterator_base0; @@ -1203,23 +1267,23 @@ struct _Leave_proxy_unbound { struct _Fake_proxy_ptr_impl { // fake replacement for a container proxy smart pointer when no container proxy is in use _Fake_proxy_ptr_impl(const _Fake_proxy_ptr_impl&) = delete; _Fake_proxy_ptr_impl& operator=(const _Fake_proxy_ptr_impl&) = delete; - _Fake_proxy_ptr_impl(const _Fake_allocator&, _Leave_proxy_unbound) noexcept {} - _Fake_proxy_ptr_impl(const _Fake_allocator&, const _Container_base0&) noexcept {} + _CONSTEXPR20_DYNALLOC _Fake_proxy_ptr_impl(const _Fake_allocator&, _Leave_proxy_unbound) noexcept {} + _CONSTEXPR20_DYNALLOC _Fake_proxy_ptr_impl(const _Fake_allocator&, const _Container_base0&) noexcept {} - void _Bind(const _Fake_allocator&, _Container_base0*) noexcept {} - void _Release() noexcept {} + _CONSTEXPR20_DYNALLOC void _Bind(const _Fake_allocator&, _Container_base0*) noexcept {} + _CONSTEXPR20_DYNALLOC void _Release() noexcept {} }; struct _Basic_container_proxy_ptr12 { // smart pointer components for a _Container_proxy * that don't depend on the allocator _Container_proxy* _Ptr; - void _Release() noexcept { // disengage this _Basic_container_proxy_ptr12 + constexpr void _Release() noexcept { // disengage this _Basic_container_proxy_ptr12 _Ptr = nullptr; } protected: - _Basic_container_proxy_ptr12() = default; + _CONSTEXPR20_DYNALLOC _Basic_container_proxy_ptr12() = default; _Basic_container_proxy_ptr12(const _Basic_container_proxy_ptr12&) = delete; _Basic_container_proxy_ptr12(_Basic_container_proxy_ptr12&&) = delete; }; @@ -1229,26 +1293,27 @@ struct _Container_proxy_ptr12 : _Basic_container_proxy_ptr12 { // smart pointer components for a _Container_proxy * for an allocator family _Alloc& _Al; - _Container_proxy_ptr12(_Alloc& _Al_, _Leave_proxy_unbound) : _Al(_Al_) { // create a new unbound _Container_proxy + _CONSTEXPR20_DYNALLOC _Container_proxy_ptr12(_Alloc& _Al_, _Leave_proxy_unbound) : _Al(_Al_) { + // create a new unbound _Container_proxy _Ptr = _Unfancy(_Al_.allocate(1)); _Construct_in_place(*_Ptr); } - _Container_proxy_ptr12(_Alloc& _Al_, _Container_base12& _Mycont) - : _Al(_Al_) { // create a new _Container_proxy pointing at _Mycont + _CONSTEXPR20_DYNALLOC _Container_proxy_ptr12(_Alloc& _Al_, _Container_base12& _Mycont) : _Al(_Al_) { + // create a new _Container_proxy pointing at _Mycont _Ptr = _Unfancy(_Al_.allocate(1)); _Construct_in_place(*_Ptr, _STD addressof(_Mycont)); _Mycont._Myproxy = _Ptr; } - void _Bind(_Alloc& _Old_alloc, _Container_base12* _Mycont) noexcept { + _CONSTEXPR20_DYNALLOC void _Bind(_Alloc& _Old_alloc, _Container_base12* _Mycont) noexcept { // Attach the proxy stored in *this to _Mycont, and destroy _Mycont's existing proxy // with _Old_alloc. Requires that no iterators are alive referring to _Mycont. _Ptr->_Mycont = _Mycont; _Delete_plain_internal(_Old_alloc, _STD exchange(_Mycont->_Myproxy, _STD exchange(_Ptr, nullptr))); } - ~_Container_proxy_ptr12() { + _CONSTEXPR20_DYNALLOC ~_Container_proxy_ptr12() { if (_Ptr) { _Delete_plain_internal(_Al, _Ptr); } @@ -1381,18 +1446,18 @@ struct _NODISCARD _Uninitialized_backout { _Uninitialized_backout(const _Uninitialized_backout&) = delete; _Uninitialized_backout& operator=(const _Uninitialized_backout&) = delete; - ~_Uninitialized_backout() { + _CONSTEXPR20_DYNALLOC ~_Uninitialized_backout() { _Destroy_range(_First, _Last); } template - void _Emplace_back(_Types&&... _Vals) { + _CONSTEXPR20_DYNALLOC void _Emplace_back(_Types&&... _Vals) { // construct a new element at *_Last and increment _Construct_in_place(*_Last, _STD forward<_Types>(_Vals)...); ++_Last; } - _NoThrowFwdIt _Release() { // suppress any exception handling backout and return _Last + constexpr _NoThrowFwdIt _Release() { // suppress any exception handling backout and return _Last _First = _Last; return _Last; } @@ -1425,18 +1490,23 @@ namespace ranges { // FUNCTION TEMPLATE _Uninitialized_move_unchecked template -_NoThrowFwdIt _Uninitialized_move_unchecked(_InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { +_CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_move_unchecked( + _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // move [_First, _Last) to raw [_Dest, ...) if constexpr (_Ptr_move_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) { - return _Copy_memmove(_First, _Last, _Dest); - } else { - _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; - for (; _First != _Last; ++_First) { - _Backout._Emplace_back(_STD move(*_First)); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + return _Copy_memmove(_First, _Last, _Dest); } - - return _Backout._Release(); } + _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; + for (; _First != _Last; ++_First) { + _Backout._Emplace_back(_STD move(*_First)); + } + + return _Backout._Release(); } // STRUCT TEMPLATE _Uninitialized_backout_al @@ -1446,22 +1516,23 @@ class _NODISCARD _Uninitialized_backout_al { using pointer = _Alloc_ptr_t<_Alloc>; public: - _Uninitialized_backout_al(pointer _Dest, _Alloc& _Al_) : _First(_Dest), _Last(_Dest), _Al(_Al_) {} + _CONSTEXPR20_DYNALLOC _Uninitialized_backout_al(pointer _Dest, _Alloc& _Al_) + : _First(_Dest), _Last(_Dest), _Al(_Al_) {} _Uninitialized_backout_al(const _Uninitialized_backout_al&) = delete; _Uninitialized_backout_al& operator=(const _Uninitialized_backout_al&) = delete; - ~_Uninitialized_backout_al() { + _CONSTEXPR20_DYNALLOC ~_Uninitialized_backout_al() { _Destroy_range(_First, _Last, _Al); } template - void _Emplace_back(_Types&&... _Vals) { // construct a new element at *_Last and increment + _CONSTEXPR20_DYNALLOC void _Emplace_back(_Types&&... _Vals) { // construct a new element at *_Last and increment allocator_traits<_Alloc>::construct(_Al, _Unfancy(_Last), _STD forward<_Types>(_Vals)...); ++_Last; } - pointer _Release() { // suppress any exception handling backout and return _Last + _CONSTEXPR20_DYNALLOC pointer _Release() { // suppress any exception handling backout and return _Last _First = _Last; return _Last; } @@ -1474,7 +1545,7 @@ private: // FUNCTION TEMPLATE _Uninitialized_copy WITH ALLOCATOR template -_Alloc_ptr_t<_Alloc> _Uninitialized_copy( +_CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_copy( const _InIt _First, const _InIt _Last, _Alloc_ptr_t<_Alloc> _Dest, _Alloc& _Al) { // copy [_First, _Last) to raw _Dest, using _Al // note: only called internally from elsewhere in the STL @@ -1485,21 +1556,48 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_copy( if constexpr (conjunction_v::_Really_trivial>, _Uses_default_construct<_Alloc, _Ptrval, decltype(*_UFirst)>>) { - _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); - _Dest += _ULast - _UFirst; - } else { - _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; - for (; _UFirst != _ULast; ++_UFirst) { - _Backout._Emplace_back(*_UFirst); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); + _Dest += _ULast - _UFirst; + return _Dest; } - - _Dest = _Backout._Release(); + } + _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; + for (; _UFirst != _ULast; ++_UFirst) { + _Backout._Emplace_back(*_UFirst); } + _Dest = _Backout._Release(); + return _Dest; } // FUNCTION TEMPLATE uninitialized_copy +template +_CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_copy_unchecked( + _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { + // copy [_First, _Last) to raw [_Dest, ...) + if constexpr (_Ptr_move_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + return _Copy_memmove(_First, _Last, _Dest); + } + } + _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; + for (; _First != _Last; ++_First) { + _Backout._Emplace_back(*_First); + } + + _Dest = _Backout._Release(); + + return _Dest; +} + template _NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // copy [_First, _Last) to raw [_Dest, ...) @@ -1507,24 +1605,13 @@ _NoThrowFwdIt uninitialized_copy(const _InIt _First, const _InIt _Last, _NoThrow auto _UFirst = _Get_unwrapped(_First); const auto _ULast = _Get_unwrapped(_Last); auto _UDest = _Get_unwrapped_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast)); - if constexpr (_Ptr_copy_cat::_Really_trivial) { - _UDest = _Copy_memmove(_UFirst, _ULast, _UDest); - } else { - _Uninitialized_backout _Backout{_UDest}; - for (; _UFirst != _ULast; ++_UFirst) { - _Backout._Emplace_back(*_UFirst); - } - - _UDest = _Backout._Release(); - } - - _Seek_wrapped(_Dest, _UDest); + _Seek_wrapped(_Dest, _Uninitialized_copy_unchecked(_UFirst, _ULast, _UDest)); return _Dest; } // FUNCTION TEMPLATE _Uninitialized_move WITH ALLOCATOR template -_Alloc_ptr_t<_Alloc> _Uninitialized_move( +_CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_move( const _InIt _First, const _InIt _Last, _Alloc_ptr_t<_Alloc> _Dest, _Alloc& _Al) { // move [_First, _Last) to raw _Dest, using _Al // note: only called internally from elsewhere in the STL @@ -1533,41 +1620,54 @@ _Alloc_ptr_t<_Alloc> _Uninitialized_move( const auto _ULast = _Get_unwrapped(_Last); if constexpr (conjunction_v::_Really_trivial>, _Uses_default_construct<_Alloc, _Ptrval, decltype(_STD move(*_UFirst))>>) { - _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); - return _Dest + (_ULast - _UFirst); - } else { - _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; - for (; _UFirst != _ULast; ++_UFirst) { - _Backout._Emplace_back(_STD move(*_UFirst)); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); + return _Dest + (_ULast - _UFirst); } - - return _Backout._Release(); } + _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; + for (; _UFirst != _ULast; ++_UFirst) { + _Backout._Emplace_back(_STD move(*_UFirst)); + } + + return _Backout._Release(); } // FUNCTION TEMPLATE _Uninitialized_fill_n WITH ALLOCATOR template -_Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( +_CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( _Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, const typename _Alloc::value_type& _Val, _Alloc& _Al) { // copy _Count copies of _Val to raw _First, using _Al using _Ty = typename _Alloc::value_type; if constexpr (_Fill_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { - _Fill_memset(_Unfancy(_First), _Val, static_cast(_Count)); - return _First + _Count; - } else { - if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _Fill_memset(_Unfancy(_First), _Val, static_cast(_Count)); + return _First + _Count; + } + } else if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_Unfancy(_First), static_cast(_Count)); return _First + _Count; } } - _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; - for (; 0 < _Count; --_Count) { - _Backout._Emplace_back(_Val); - } + } + _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; - return _Backout._Release(); + for (; 0 < _Count; --_Count) { + _Backout._Emplace_back(_Val); } + + return _Backout._Release(); } // FUNCTION TEMPLATE uninitialized_fill @@ -1610,22 +1710,26 @@ _Ptr _Zero_range(const _Ptr _First, const _Ptr _Last) { // fill [_First, _Last) } template -_Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n( +_CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n( _Alloc_ptr_t<_Alloc> _First, _Alloc_size_t<_Alloc> _Count, _Alloc& _Al) { // value-initialize _Count objects to raw _First, using _Al using _Ptrty = typename _Alloc::value_type*; if constexpr (_Use_memset_value_construct_v<_Ptrty> && _Uses_default_construct<_Alloc, _Ptrty>::value) { - auto _PFirst = _Unfancy(_First); - _Zero_range(_PFirst, _PFirst + _Count); - return _First + _Count; - } else { - _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; - for (; 0 < _Count; --_Count) { - _Backout._Emplace_back(); +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + auto _PFirst = _Unfancy(_First); + _Zero_range(_PFirst, _PFirst + _Count); + return _First + _Count; } - - return _Backout._Release(); } + _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; + for (; 0 < _Count; --_Count) { + _Backout._Emplace_back(); + } + + return _Backout._Release(); } template @@ -1788,7 +1892,8 @@ _NODISCARD _CONSTEXPR20 _FwdIt remove_if(_FwdIt _First, const _FwdIt _Last, _Pr // FUNCTION TEMPLATE _Erase_remove template -typename _Container::size_type _Erase_remove(_Container& _Cont, const _Uty& _Val) { // erase each element matching _Val +_CONSTEXPR20_DYNALLOC typename _Container::size_type _Erase_remove(_Container& _Cont, const _Uty& _Val) { + // erase each element matching _Val auto _First = _Cont.begin(); const auto _Last = _Cont.end(); const auto _Old_size = _Cont.size(); @@ -1799,7 +1904,8 @@ typename _Container::size_type _Erase_remove(_Container& _Cont, const _Uty& _Val // FUNCTION TEMPLATE _Erase_remove_if template -typename _Container::size_type _Erase_remove_if(_Container& _Cont, _Pr _Pred) { // erase each element satisfying _Pred +_CONSTEXPR20_DYNALLOC typename _Container::size_type _Erase_remove_if(_Container& _Cont, _Pr _Pred) { + // erase each element satisfying _Pred auto _First = _Cont.begin(); const auto _Last = _Cont.end(); const auto _Old_size = _Cont.size(); @@ -1810,7 +1916,8 @@ typename _Container::size_type _Erase_remove_if(_Container& _Cont, _Pr _Pred) { // FUNCTION TEMPLATE _Erase_nodes_if template -typename _Container::size_type _Erase_nodes_if(_Container& _Cont, _Pr _Pred) { // erase each element satisfying _Pred +typename _Container::size_type _Erase_nodes_if(_Container& _Cont, _Pr _Pred) { + // erase each element satisfying _Pred auto _First = _Cont.begin(); const auto _Last = _Cont.end(); const auto _Old_size = _Cont.size(); diff --git a/stl/inc/xutility b/stl/inc/xutility index 653646d5425..67f0e54f1b6 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -141,13 +141,21 @@ _CONSTEXPR20_DYNALLOC auto construct_at(_Ty* const _Location, _Types&&... _Args) // FUNCTION TEMPLATE _Construct_in_place template -void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>) { - ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); +_CONSTEXPR20_DYNALLOC void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept( + is_nothrow_constructible_v<_Ty, _Types...>) { +#ifdef __cpp_lib_is_constant_evaluated + if (_STD is_constant_evaluated()) { + _STD construct_at(_STD addressof(_Obj), _STD forward<_Types>(_Args)...); + } else +#endif // __cpp_lib_is_constant_evaluated + { + ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); + } } // FUNCTION TEMPLATE _Default_construct_in_place template -void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { +_CONSTEXPR20_DYNALLOC void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty; } From 0d8082aacd3bd713238f5181ef643c589628f885 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Mon, 11 Jan 2021 13:19:59 +0100 Subject: [PATCH 02/13] Properly initialize --- stl/inc/xmemory | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 73ecb33edbb..745907c3651 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1037,8 +1037,8 @@ struct _Container_proxy { // store head of iterator chain and back pointer _CONSTEXPR20 _Container_proxy() noexcept = default; _CONSTEXPR20 _Container_proxy(_Container_base12* _Mycont_) noexcept : _Mycont(_Mycont_) {} - const _Container_base12* _Mycont; - mutable _Iterator_base12* _Myfirstiter; + const _Container_base12* _Mycont = nullptr; + mutable _Iterator_base12* _Myfirstiter = nullptr; }; struct _Container_base12 { From 0ca2b483658015ab23a2d007f63dac3e199730af Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Mon, 18 Jan 2021 13:09:45 +0100 Subject: [PATCH 03/13] Use _CONSTEXPR20_CONTAINER --- stl/inc/xmemory | 76 ++++++++++++++++++++++---------------------- stl/inc/yvals_core.h | 7 ++++ 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 745907c3651..3497438a30a 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1016,15 +1016,15 @@ struct _Alloc_construct_ptr { // pointer used to help construct 1 _Alloc::value_ struct _Fake_allocator {}; struct _Container_base0 { - _CONSTEXPR20 void _Orphan_all() noexcept {} - _CONSTEXPR20 void _Swap_proxy_and_iterators(_Container_base0&) noexcept {} - _CONSTEXPR20 void _Alloc_proxy(const _Fake_allocator&) noexcept {} - _CONSTEXPR20 void _Reload_proxy(const _Fake_allocator&, const _Fake_allocator&) noexcept {} + _CONSTEXPR20_CONTAINER void _Orphan_all() noexcept {} + _CONSTEXPR20_CONTAINER void _Swap_proxy_and_iterators(_Container_base0&) noexcept {} + _CONSTEXPR20_CONTAINER void _Alloc_proxy(const _Fake_allocator&) noexcept {} + _CONSTEXPR20_CONTAINER void _Reload_proxy(const _Fake_allocator&, const _Fake_allocator&) noexcept {} }; struct _Iterator_base0 { - _CONSTEXPR20 void _Adopt(const void*) noexcept {} - _CONSTEXPR20 const _Container_base0* _Getcont() const noexcept { + _CONSTEXPR20_CONTAINER void _Adopt(const void*) noexcept {} + _CONSTEXPR20_CONTAINER const _Container_base0* _Getcont() const noexcept { return nullptr; } @@ -1034,8 +1034,8 @@ struct _Iterator_base0 { // CLASS _Container_proxy struct _Container_base12; struct _Container_proxy { // store head of iterator chain and back pointer - _CONSTEXPR20 _Container_proxy() noexcept = default; - _CONSTEXPR20 _Container_proxy(_Container_base12* _Mycont_) noexcept : _Mycont(_Mycont_) {} + _CONSTEXPR20_CONTAINER _Container_proxy() noexcept = default; + _CONSTEXPR20_CONTAINER _Container_proxy(_Container_base12* _Mycont_) noexcept : _Mycont(_Mycont_) {} const _Container_base12* _Mycont = nullptr; mutable _Iterator_base12* _Myfirstiter = nullptr; @@ -1043,16 +1043,16 @@ struct _Container_proxy { // store head of iterator chain and back pointer struct _Container_base12 { public: - _CONSTEXPR20_DYNALLOC _Container_base12() noexcept = default; + _CONSTEXPR20_CONTAINER _Container_base12() noexcept = default; _Container_base12(const _Container_base12&) = delete; _Container_base12& operator=(const _Container_base12&) = delete; - _CONSTEXPR20_DYNALLOC void _Orphan_all() noexcept; - _CONSTEXPR20_DYNALLOC void _Swap_proxy_and_iterators(_Container_base12&) noexcept; + _CONSTEXPR20_CONTAINER void _Orphan_all() noexcept; + _CONSTEXPR20_CONTAINER void _Swap_proxy_and_iterators(_Container_base12&) noexcept; template - _CONSTEXPR20_DYNALLOC void _Alloc_proxy(_Alloc&& _Al) { + _CONSTEXPR20_CONTAINER void _Alloc_proxy(_Alloc&& _Al) { _Container_proxy* const _New_proxy = _Unfancy(_Al.allocate(1)); _Construct_in_place(*_New_proxy, this); _Myproxy = _New_proxy; @@ -1060,7 +1060,7 @@ public: } template - _CONSTEXPR20_DYNALLOC void _Reload_proxy(_Alloc&& _Old_alloc, _Alloc&& _New_alloc) { + _CONSTEXPR20_CONTAINER void _Reload_proxy(_Alloc&& _Old_alloc, _Alloc&& _New_alloc) { // pre: no iterators refer to the existing proxy _Container_proxy* const _New_proxy = _Unfancy(_New_alloc.allocate(1)); _Construct_in_place(*_New_proxy, this); @@ -1071,21 +1071,21 @@ public: _Container_proxy* _Myproxy = nullptr; private: - _CONSTEXPR20_DYNALLOC void _Orphan_all_unlocked() noexcept; + _CONSTEXPR20_CONTAINER void _Orphan_all_unlocked() noexcept; inline void _Orphan_all_locked() noexcept; - _CONSTEXPR20_DYNALLOC void _Swap_proxy_and_iterators_unlocked(_Container_base12&) noexcept; + _CONSTEXPR20_CONTAINER void _Swap_proxy_and_iterators_unlocked(_Container_base12&) noexcept; inline void _Swap_proxy_and_iterators_locked(_Container_base12&) noexcept; }; struct _Iterator_base12 { // store links to container proxy, next iterator public: - _CONSTEXPR20_DYNALLOC _Iterator_base12() noexcept = default; // construct orphaned iterator + _CONSTEXPR20_CONTAINER _Iterator_base12() noexcept = default; // construct orphaned iterator - _CONSTEXPR20_DYNALLOC _Iterator_base12(const _Iterator_base12& _Right) noexcept { + _CONSTEXPR20_CONTAINER _Iterator_base12(const _Iterator_base12& _Right) noexcept { *this = _Right; } - _CONSTEXPR20_DYNALLOC _Iterator_base12& operator=(const _Iterator_base12& _Right) noexcept { + _CONSTEXPR20_CONTAINER _Iterator_base12& operator=(const _Iterator_base12& _Right) noexcept { if (_Myproxy != _Right._Myproxy) { if (_Right._Myproxy) { _Adopt(_Right._Myproxy->_Mycont); @@ -1101,11 +1101,11 @@ public: } #if _ITERATOR_DEBUG_LEVEL == 2 - _CONSTEXPR20_DYNALLOC ~_Iterator_base12() noexcept { + _CONSTEXPR20_CONTAINER ~_Iterator_base12() noexcept { _Orphan_me(); } - _CONSTEXPR20_DYNALLOC void _Adopt(const _Container_base12* _Parent) noexcept { + _CONSTEXPR20_CONTAINER void _Adopt(const _Container_base12* _Parent) noexcept { if (_Parent) { // have a parent, do adoption _Container_proxy* _Parent_proxy = _Parent->_Myproxy; if (_Myproxy != _Parent_proxy) { // change parentage @@ -1123,7 +1123,7 @@ public: } } - _CONSTEXPR20_DYNALLOC void _Orphan_me() noexcept { + _CONSTEXPR20_CONTAINER void _Orphan_me() noexcept { if (_Myproxy) { // adopted, remove self from list #ifdef __cpp_lib_is_constant_evaluated if (_STD is_constant_evaluated()) { @@ -1137,7 +1137,7 @@ public: } #else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL != 2 vvv - _CONSTEXPR20_DYNALLOC void _Adopt(const _Container_base12* _Parent) noexcept { + _CONSTEXPR20_CONTAINER void _Adopt(const _Container_base12* _Parent) noexcept { if (_Parent) { // have a parent, do adoption _Myproxy = _Parent->_Myproxy; } else { // no future parent, just disown current parent @@ -1146,7 +1146,7 @@ public: } #endif // _ITERATOR_DEBUG_LEVEL != 2 - _CONSTEXPR20_DYNALLOC const _Container_base12* _Getcont() const noexcept { + _CONSTEXPR20_CONTAINER const _Container_base12* _Getcont() const noexcept { return _Myproxy ? _Myproxy->_Mycont : nullptr; } @@ -1157,7 +1157,7 @@ public: #if _ITERATOR_DEBUG_LEVEL == 2 private: - _CONSTEXPR20_DYNALLOC void _Adopt_unlocked(_Container_proxy* _Parent_proxy) noexcept { + _CONSTEXPR20_CONTAINER void _Adopt_unlocked(_Container_proxy* _Parent_proxy) noexcept { if (_Myproxy) { // adopted, remove self from list _Orphan_me_unlocked(); } @@ -1171,7 +1171,7 @@ private: _Adopt_unlocked(_Parent_proxy); } - _CONSTEXPR20_DYNALLOC void _Orphan_me_unlocked() noexcept { + _CONSTEXPR20_CONTAINER void _Orphan_me_unlocked() noexcept { _Iterator_base12** _Pnext = &_Myproxy->_Myfirstiter; while (*_Pnext && *_Pnext != this) { _Pnext = &(*_Pnext)->_Mynextiter; @@ -1190,7 +1190,7 @@ private: }; // MEMBER FUNCTIONS FOR _Container_base12 -_CONSTEXPR20_DYNALLOC void _Container_base12::_Orphan_all_unlocked() noexcept { +_CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all_unlocked() noexcept { for (auto _Pnext = &_Myproxy->_Myfirstiter; *_Pnext; *_Pnext = (*_Pnext)->_Mynextiter) { (*_Pnext)->_Myproxy = nullptr; } @@ -1202,7 +1202,7 @@ inline void _Container_base12::_Orphan_all_locked() noexcept { _Orphan_all_unlocked(); } -_CONSTEXPR20_DYNALLOC void _Container_base12::_Orphan_all() noexcept { +_CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all() noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 if (_Myproxy) { // proxy allocated, drain it #ifdef __cpp_lib_is_constant_evaluated @@ -1217,7 +1217,7 @@ _CONSTEXPR20_DYNALLOC void _Container_base12::_Orphan_all() noexcept { #endif // _ITERATOR_DEBUG_LEVEL == 2 } -_CONSTEXPR20_DYNALLOC void _Container_base12::_Swap_proxy_and_iterators_unlocked(_Container_base12& _Right) noexcept { +_CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators_unlocked(_Container_base12& _Right) noexcept { _Container_proxy* _Temp = _Myproxy; _Myproxy = _Right._Myproxy; _Right._Myproxy = _Temp; @@ -1236,7 +1236,7 @@ inline void _Container_base12::_Swap_proxy_and_iterators_locked(_Container_base1 _Swap_proxy_and_iterators_unlocked(_Right); } -_CONSTEXPR20_DYNALLOC void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { +_CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { #if _ITERATOR_DEBUG_LEVEL != 2 _Swap_proxy_and_iterators_unlocked(_Right); #else // ^^^ _ITERATOR_DEBUG_LEVEL != 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL == 2 vvv @@ -1267,11 +1267,11 @@ struct _Leave_proxy_unbound { struct _Fake_proxy_ptr_impl { // fake replacement for a container proxy smart pointer when no container proxy is in use _Fake_proxy_ptr_impl(const _Fake_proxy_ptr_impl&) = delete; _Fake_proxy_ptr_impl& operator=(const _Fake_proxy_ptr_impl&) = delete; - _CONSTEXPR20_DYNALLOC _Fake_proxy_ptr_impl(const _Fake_allocator&, _Leave_proxy_unbound) noexcept {} - _CONSTEXPR20_DYNALLOC _Fake_proxy_ptr_impl(const _Fake_allocator&, const _Container_base0&) noexcept {} + _CONSTEXPR20_CONTAINER _Fake_proxy_ptr_impl(const _Fake_allocator&, _Leave_proxy_unbound) noexcept {} + _CONSTEXPR20_CONTAINER _Fake_proxy_ptr_impl(const _Fake_allocator&, const _Container_base0&) noexcept {} - _CONSTEXPR20_DYNALLOC void _Bind(const _Fake_allocator&, _Container_base0*) noexcept {} - _CONSTEXPR20_DYNALLOC void _Release() noexcept {} + _CONSTEXPR20_CONTAINER void _Bind(const _Fake_allocator&, _Container_base0*) noexcept {} + _CONSTEXPR20_CONTAINER void _Release() noexcept {} }; struct _Basic_container_proxy_ptr12 { @@ -1283,7 +1283,7 @@ struct _Basic_container_proxy_ptr12 { } protected: - _CONSTEXPR20_DYNALLOC _Basic_container_proxy_ptr12() = default; + _CONSTEXPR20_CONTAINER _Basic_container_proxy_ptr12() = default; _Basic_container_proxy_ptr12(const _Basic_container_proxy_ptr12&) = delete; _Basic_container_proxy_ptr12(_Basic_container_proxy_ptr12&&) = delete; }; @@ -1293,27 +1293,27 @@ struct _Container_proxy_ptr12 : _Basic_container_proxy_ptr12 { // smart pointer components for a _Container_proxy * for an allocator family _Alloc& _Al; - _CONSTEXPR20_DYNALLOC _Container_proxy_ptr12(_Alloc& _Al_, _Leave_proxy_unbound) : _Al(_Al_) { + _CONSTEXPR20_CONTAINER _Container_proxy_ptr12(_Alloc& _Al_, _Leave_proxy_unbound) : _Al(_Al_) { // create a new unbound _Container_proxy _Ptr = _Unfancy(_Al_.allocate(1)); _Construct_in_place(*_Ptr); } - _CONSTEXPR20_DYNALLOC _Container_proxy_ptr12(_Alloc& _Al_, _Container_base12& _Mycont) : _Al(_Al_) { + _CONSTEXPR20_CONTAINER _Container_proxy_ptr12(_Alloc& _Al_, _Container_base12& _Mycont) : _Al(_Al_) { // create a new _Container_proxy pointing at _Mycont _Ptr = _Unfancy(_Al_.allocate(1)); _Construct_in_place(*_Ptr, _STD addressof(_Mycont)); _Mycont._Myproxy = _Ptr; } - _CONSTEXPR20_DYNALLOC void _Bind(_Alloc& _Old_alloc, _Container_base12* _Mycont) noexcept { + _CONSTEXPR20_CONTAINER void _Bind(_Alloc& _Old_alloc, _Container_base12* _Mycont) noexcept { // Attach the proxy stored in *this to _Mycont, and destroy _Mycont's existing proxy // with _Old_alloc. Requires that no iterators are alive referring to _Mycont. _Ptr->_Mycont = _Mycont; _Delete_plain_internal(_Old_alloc, _STD exchange(_Mycont->_Myproxy, _STD exchange(_Ptr, nullptr))); } - _CONSTEXPR20_DYNALLOC ~_Container_proxy_ptr12() { + _CONSTEXPR20_CONTAINER ~_Container_proxy_ptr12() { if (_Ptr) { _Delete_plain_internal(_Al, _Ptr); } diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index e37d8daf036..b5d3d18f968 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1263,6 +1263,13 @@ #define _CONSTEXPR20_DYNALLOC inline #endif +// Functions that became constexpr in C++20 via P0980R1 or P1004R2 +#if defined(__cpp_lib_constexpr_dynamic_alloc) && !defined(__clang__) // TRANSITION:LLVM-48606 +#define _CONSTEXPR20_CONTAINER constexpr +#else +#define _CONSTEXPR20_CONTAINER inline +#endif + #ifdef _RTC_CONVERSION_CHECKS_ENABLED #ifndef _ALLOW_RTCc_IN_STL #error /RTCc rejects conformant code, so it is not supported by the C++ Standard Library. Either remove this \ From 4135658ef61bdc2d1d2d43a3023caebd94af2a27 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Thu, 21 Jan 2021 22:22:25 +0100 Subject: [PATCH 04/13] Address review comments --- stl/inc/regex | 2 +- stl/inc/xmemory | 44 +++++++++++++++++++++----------------------- stl/inc/xutility | 2 +- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/stl/inc/regex b/stl/inc/regex index 0cd17c2b3a0..330944b8a28 100644 --- a/stl/inc/regex +++ b/stl/inc/regex @@ -2466,7 +2466,7 @@ public: _MyRe = nullptr; #if _ITERATOR_DEBUG_LEVEL == 2 - this->_Orphan_me(); + this->_Orphan_me_v2(); #endif // _ITERATOR_DEBUG_LEVEL return *this; diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 3497438a30a..61872788623 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -265,10 +265,10 @@ _CONSTEXPR20_DYNALLOC void _Deallocate(void* _Ptr, size_t _Bytes) noexcept { // FUNCTION TEMPLATE _Global_new template -_CONSTEXPR20_DYNALLOC _Ty* _Global_new(_Types&&... _Args) { // acts as "new" while disallowing user overload selection +_Ty* _Global_new(_Types&&... _Args) { // acts as "new" while disallowing user overload selection struct _NODISCARD _Guard_type { void* _Result; - _CONSTEXPR20_DYNALLOC ~_Guard_type() { + ~_Guard_type() { if (_Result) { _Deallocate<_New_alignof<_Ty>>(_Result, sizeof(_Ty)); } @@ -991,7 +991,7 @@ struct _Alloc_construct_ptr { // pointer used to help construct 1 _Alloc::value_ _Alloc& _Al; pointer _Ptr; - explicit _Alloc_construct_ptr(_Alloc& _Al_) : _Al(_Al_), _Ptr(nullptr) {} + _CONSTEXPR20_DYNALLOC explicit _Alloc_construct_ptr(_Alloc& _Al_) : _Al(_Al_), _Ptr(nullptr) {} _NODISCARD _CONSTEXPR20_DYNALLOC pointer _Release() noexcept { // disengage *this and return contained pointer return _STD exchange(_Ptr, nullptr); @@ -1072,9 +1072,17 @@ public: private: _CONSTEXPR20_CONTAINER void _Orphan_all_unlocked() noexcept; - inline void _Orphan_all_locked() noexcept; _CONSTEXPR20_CONTAINER void _Swap_proxy_and_iterators_unlocked(_Container_base12&) noexcept; - inline void _Swap_proxy_and_iterators_locked(_Container_base12&) noexcept; + + void _Orphan_all_locked() noexcept { + _Lockit _Lock(_LOCK_DEBUG); + _Orphan_all_unlocked(); + } + + void _Swap_proxy_and_iterators_locked(_Container_base12& _Right) noexcept { + _Lockit _Lock(_LOCK_DEBUG); + _Swap_proxy_and_iterators_unlocked(_Right); + } }; struct _Iterator_base12 { // store links to container proxy, next iterator @@ -1091,7 +1099,7 @@ public: _Adopt(_Right._Myproxy->_Mycont); } else { // becoming invalid, disown current parent #if _ITERATOR_DEBUG_LEVEL == 2 - _Orphan_me(); + _Orphan_me_v2(); #else // _ITERATOR_DEBUG_LEVEL == 2 _Myproxy = nullptr; #endif // _ITERATOR_DEBUG_LEVEL == 2 @@ -1102,7 +1110,7 @@ public: #if _ITERATOR_DEBUG_LEVEL == 2 _CONSTEXPR20_CONTAINER ~_Iterator_base12() noexcept { - _Orphan_me(); + _Orphan_me_v2(); } _CONSTEXPR20_CONTAINER void _Adopt(const _Container_base12* _Parent) noexcept { @@ -1119,11 +1127,11 @@ public: } } } else { // no future parent, just disown current parent - _Orphan_me(); + _Orphan_me_v2(); } } - _CONSTEXPR20_CONTAINER void _Orphan_me() noexcept { + _CONSTEXPR20_CONTAINER void _Orphan_me_v2() noexcept { if (_Myproxy) { // adopted, remove self from list #ifdef __cpp_lib_is_constant_evaluated if (_STD is_constant_evaluated()) { @@ -1197,11 +1205,6 @@ _CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all_unlocked() noexcept { _Myproxy->_Myfirstiter = nullptr; } -inline void _Container_base12::_Orphan_all_locked() noexcept { - _Lockit _Lock(_LOCK_DEBUG); - _Orphan_all_unlocked(); -} - _CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all() noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 if (_Myproxy) { // proxy allocated, drain it @@ -1231,15 +1234,8 @@ _CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators_unlocke } } -inline void _Container_base12::_Swap_proxy_and_iterators_locked(_Container_base12& _Right) noexcept { - _Lockit _Lock(_LOCK_DEBUG); - _Swap_proxy_and_iterators_unlocked(_Right); -} - _CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { -#if _ITERATOR_DEBUG_LEVEL != 2 - _Swap_proxy_and_iterators_unlocked(_Right); -#else // ^^^ _ITERATOR_DEBUG_LEVEL != 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL == 2 vvv +#if _ITERATOR_DEBUG_LEVEL == 2 #ifdef __cpp_lib_is_constant_evaluated if (_STD is_constant_evaluated()) { _Swap_proxy_and_iterators_unlocked(_Right); @@ -1248,7 +1244,9 @@ _CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators(_Contai { _Swap_proxy_and_iterators_locked(_Right); } -#endif // _ITERATOR_DEBUG_LEVEL == 2 +#else // ^^^ _ITERATOR_DEBUG_LEVEL == 2 ^^^ / vvv _ITERATOR_DEBUG_LEVEL != 2 vvv + _Swap_proxy_and_iterators_unlocked(_Right); +#endif // _ITERATOR_DEBUG_LEVEL != 2 } #if _ITERATOR_DEBUG_LEVEL == 0 diff --git a/stl/inc/xutility b/stl/inc/xutility index 56b05526b87..2264dfb0a0f 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -155,7 +155,7 @@ _CONSTEXPR20_DYNALLOC void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noe // FUNCTION TEMPLATE _Default_construct_in_place template -_CONSTEXPR20_DYNALLOC void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { +void _Default_construct_in_place(_Ty& _Obj) noexcept(is_nothrow_default_constructible_v<_Ty>) { ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty; } From 3000309ec78683a2d7f8495dd0e1c2f1ce528d3a Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 22 Jan 2021 08:45:03 +0100 Subject: [PATCH 05/13] Unblock __cpp_lib_constexpr_dynamic_alloc for all compilers that suppport constexpr allocations --- stl/inc/xmemory | 2 +- stl/inc/yvals_core.h | 5 ++--- .../VSO_0157762_feature_test_macros/test.compile.pass.cpp | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 61872788623..e8fcb9f4397 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1274,7 +1274,7 @@ struct _Fake_proxy_ptr_impl { // fake replacement for a container proxy smart po struct _Basic_container_proxy_ptr12 { // smart pointer components for a _Container_proxy * that don't depend on the allocator - _Container_proxy* _Ptr; + _Container_proxy* _Ptr = nullptr; constexpr void _Release() noexcept { // disengage this _Basic_container_proxy_ptr12 _Ptr = nullptr; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index b5d3d18f968..72b2d93e095 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -1183,10 +1183,9 @@ #define __cpp_lib_constexpr_algorithms 201806L #define __cpp_lib_constexpr_complex 201711L -#if defined(__cpp_constexpr_dynamic_alloc) \ - && defined(__clang__) // TRANSITION, MSVC support for constexpr dynamic allocation +#ifdef __cpp_constexpr_dynamic_alloc #define __cpp_lib_constexpr_dynamic_alloc 201907L -#endif // defined(__cpp_constexpr_dynamic_alloc) && defined(__clang__) +#endif // __cpp_constexpr_dynamic_alloc #define __cpp_lib_constexpr_functional 201907L #define __cpp_lib_constexpr_iterator 201811L diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index 9a6cd10c972..1aa7807505b 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -411,8 +411,7 @@ STATIC_ASSERT(__cpp_lib_constexpr_complex == 201711L); #endif #endif -#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) \ - && defined(__clang__) // TRANSITION, MSVC support for constexpr dynamic allocation +#if _HAS_CXX20 && defined(__cpp_constexpr_dynamic_alloc) #ifndef __cpp_lib_constexpr_dynamic_alloc #error __cpp_lib_constexpr_dynamic_alloc is not defined #elif __cpp_lib_constexpr_dynamic_alloc != 201907L From 593de17cd32036309f3a011d3a79c6e22e50f102 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 22 Jan 2021 12:25:32 +0100 Subject: [PATCH 06/13] Unskip some tests --- tests/libcxx/expected_results.txt | 9 --------- tests/libcxx/skipped_tests.txt | 9 --------- 2 files changed, 18 deletions(-) diff --git a/tests/libcxx/expected_results.txt b/tests/libcxx/expected_results.txt index 8961a1cc341..fbcaa710309 100644 --- a/tests/libcxx/expected_results.txt +++ b/tests/libcxx/expected_results.txt @@ -493,18 +493,9 @@ std/utilities/variant/variant.variant/variant.ctor/conv.pass.cpp FAIL std/utilities/variant/variant.variant/variant.ctor/T.pass.cpp FAIL # C++20 P0784R7 "More constexpr containers" -std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp:0 FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp:0 FAIL std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp:0 FAIL std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp:0 FAIL -std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp:0 FAIL -std/utilities/memory/default.allocator/allocator.globals/eq.pass.cpp:0 FAIL std/utilities/memory/specialized.algorithms/specialized.construct/construct_at.pass.cpp FAIL -std/utilities/memory/specialized.algorithms/specialized.destroy/destroy.pass.cpp:0 FAIL -std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_at.pass.cpp:0 FAIL -std/utilities/memory/specialized.algorithms/specialized.destroy/destroy_n.pass.cpp:0 FAIL # C++20 P0896R4 "" std/language.support/support.limits/support.limits.general/algorithm.version.pass.cpp FAIL diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index 61b46acc242..91eeaae1370 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -493,18 +493,9 @@ utilities\variant\variant.variant\variant.ctor\conv.pass.cpp utilities\variant\variant.variant\variant.ctor\T.pass.cpp # C++20 P0784R7 "More constexpr containers" -utilities\memory\allocator.traits\allocator.traits.members\allocate.pass.cpp -utilities\memory\allocator.traits\allocator.traits.members\allocate_hint.pass.cpp utilities\memory\allocator.traits\allocator.traits.members\construct.pass.cpp -utilities\memory\allocator.traits\allocator.traits.members\deallocate.pass.cpp utilities\memory\allocator.traits\allocator.traits.members\destroy.pass.cpp -utilities\memory\allocator.traits\allocator.traits.members\max_size.pass.cpp -utilities\memory\allocator.traits\allocator.traits.members\select_on_container_copy_construction.pass.cpp -utilities\memory\default.allocator\allocator.globals\eq.pass.cpp utilities\memory\specialized.algorithms\specialized.construct\construct_at.pass.cpp -utilities\memory\specialized.algorithms\specialized.destroy\destroy.pass.cpp -utilities\memory\specialized.algorithms\specialized.destroy\destroy_at.pass.cpp -utilities\memory\specialized.algorithms\specialized.destroy\destroy_n.pass.cpp # C++20 P0896R4 "" language.support\support.limits\support.limits.general\algorithm.version.pass.cpp From 5e56275e5081524129ef089e1ed0917cae3f07c6 Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 22 Jan 2021 12:34:18 +0100 Subject: [PATCH 07/13] Consistently use __cpp_lib_constexpr_dynamic_alloc --- stl/inc/xmemory | 44 ++++++++++++++++++++++---------------------- stl/inc/xutility | 4 ++-- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index e8fcb9f4397..58823353f0a 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1117,11 +1117,11 @@ public: if (_Parent) { // have a parent, do adoption _Container_proxy* _Parent_proxy = _Parent->_Myproxy; if (_Myproxy != _Parent_proxy) { // change parentage -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (_STD is_constant_evaluated()) { _Adopt_unlocked(_Parent_proxy); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Adopt_locked(_Parent_proxy); } @@ -1133,11 +1133,11 @@ public: _CONSTEXPR20_CONTAINER void _Orphan_me_v2() noexcept { if (_Myproxy) { // adopted, remove self from list -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (_STD is_constant_evaluated()) { _Orphan_me_unlocked(); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Orphan_me_locked(); } @@ -1208,11 +1208,11 @@ _CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all_unlocked() noexcept { _CONSTEXPR20_CONTAINER void _Container_base12::_Orphan_all() noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 if (_Myproxy) { // proxy allocated, drain it -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (_STD is_constant_evaluated()) { _Orphan_all_unlocked(); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Orphan_all_locked(); } @@ -1236,11 +1236,11 @@ _CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators_unlocke _CONSTEXPR20_CONTAINER void _Container_base12::_Swap_proxy_and_iterators(_Container_base12& _Right) noexcept { #if _ITERATOR_DEBUG_LEVEL == 2 -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (_STD is_constant_evaluated()) { _Swap_proxy_and_iterators_unlocked(_Right); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Swap_proxy_and_iterators_locked(_Right); } @@ -1492,9 +1492,9 @@ _CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_move_unchecked( _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // move [_First, _Last) to raw [_Dest, ...) if constexpr (_Ptr_move_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { return _Copy_memmove(_First, _Last, _Dest); } @@ -1554,9 +1554,9 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_copy( if constexpr (conjunction_v::_Really_trivial>, _Uses_default_construct<_Alloc, _Ptrval, decltype(*_UFirst)>>) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); _Dest += _ULast - _UFirst; @@ -1579,9 +1579,9 @@ _CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_copy_unchecked( _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // copy [_First, _Last) to raw [_Dest, ...) if constexpr (_Ptr_move_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { return _Copy_memmove(_First, _Last, _Dest); } @@ -1618,9 +1618,9 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_move( const auto _ULast = _Get_unwrapped(_Last); if constexpr (conjunction_v::_Really_trivial>, _Uses_default_construct<_Alloc, _Ptrval, decltype(_STD move(*_UFirst))>>) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Copy_memmove(_UFirst, _ULast, _Unfancy(_Dest)); return _Dest + (_ULast - _UFirst); @@ -1641,17 +1641,17 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( // copy _Count copies of _Val to raw _First, using _Al using _Ty = typename _Alloc::value_type; if constexpr (_Fill_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { _Fill_memset(_Unfancy(_First), _Val, static_cast(_Count)); return _First + _Count; } } else if constexpr (_Fill_zero_memset_is_safe<_Ty*, _Ty> && _Uses_default_construct<_Alloc, _Ty*, _Ty>::value) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { if (_Is_all_bits_zero(_Val)) { _Fill_zero_memset(_Unfancy(_First), static_cast(_Count)); @@ -1713,9 +1713,9 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n( // value-initialize _Count objects to raw _First, using _Al using _Ptrty = typename _Alloc::value_type*; if constexpr (_Use_memset_value_construct_v<_Ptrty> && _Uses_default_construct<_Alloc, _Ptrty>::value) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { auto _PFirst = _Unfancy(_First); _Zero_range(_PFirst, _PFirst + _Count); diff --git a/stl/inc/xutility b/stl/inc/xutility index 2264dfb0a0f..8c223caa7a9 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -143,11 +143,11 @@ _CONSTEXPR20_DYNALLOC auto construct_at(_Ty* const _Location, _Types&&... _Args) template _CONSTEXPR20_DYNALLOC void _Construct_in_place(_Ty& _Obj, _Types&&... _Args) noexcept( is_nothrow_constructible_v<_Ty, _Types...>) { -#ifdef __cpp_lib_is_constant_evaluated +#ifdef __cpp_lib_constexpr_dynamic_alloc if (_STD is_constant_evaluated()) { _STD construct_at(_STD addressof(_Obj), _STD forward<_Types>(_Args)...); } else -#endif // __cpp_lib_is_constant_evaluated +#endif // __cpp_lib_constexpr_dynamic_alloc { ::new (_Voidify_iter(_STD addressof(_Obj))) _Ty(_STD forward<_Types>(_Args)...); } From ed8c2dc303af03661793a9510cbcd8631eec17fa Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 22 Jan 2021 13:59:30 +0100 Subject: [PATCH 08/13] Properly guard ranges in tests --- .../test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 52da34b9f96..08a4de3ae07 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -244,9 +244,11 @@ constexpr void test_compiletime() { assert(s.object == 42); destroy_at(&s.object); +#ifdef __cpp_lib_concepts ranges::construct_at(&s.object, 1729); assert(s.object == 1729); ranges::destroy_at(&s.object); +#endif // __cpp_lib_concepts } struct nontrivial { @@ -262,9 +264,11 @@ constexpr void test_compiletime() { assert(s.object.x == 42); destroy_at(&s.object); +#ifdef __cpp_lib_concepts ranges::construct_at(&s.object, 1729); assert(s.object.x == 1729); ranges::destroy_at(&s.object); +#endif // __cpp_lib_concepts } } static_assert((test_compiletime(), true)); From 5d393af304c37fb83bda7d7f2509495f60557037 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Wed, 27 Jan 2021 11:43:24 -0800 Subject: [PATCH 09/13] Disable portions of P0784 test for EDG due to bugs --- .../test.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 08a4de3ae07..33a9fd23026 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -227,6 +227,7 @@ void test_array(const T& val) { } #ifdef __cpp_lib_constexpr_dynamic_alloc +#ifndef __EDG__ // TRANSITION, VSO-1269976 template struct storage_for { union { @@ -272,6 +273,7 @@ constexpr void test_compiletime() { } } static_assert((test_compiletime(), true)); +#endif // __EDG__ template struct A { @@ -289,7 +291,9 @@ struct nontrivial_A { constexpr ~nontrivial_A() {} }; + constexpr void test_compiletime_destroy_variants() { +#ifndef __EDG__ // TRANSITION, VSO-1270011 { allocator> alloc{}; A* a = alloc.allocate(10); @@ -308,6 +312,7 @@ constexpr void test_compiletime_destroy_variants() { destroy(a, a + 10); alloc.deallocate(a, 10); } +#endif // __EDG__ #ifdef __cpp_lib_concepts { allocator> alloc{}; @@ -389,6 +394,7 @@ constexpr void test_compiletime_destroy_variants() { } static_assert((test_compiletime_destroy_variants(), true)); +#ifndef __EDG__ // TRANSITION, VSO-1269976 template struct Alloc { using value_type = T; @@ -502,6 +508,7 @@ constexpr void test_compiletime_allocator_traits() { } } static_assert((test_compiletime_allocator_traits(), true)); +#endif // __EDG__ constexpr void test_compiletime_allocator() { { From b3140a49ab7fd679d55efc43862da517ad671fac Mon Sep 17 00:00:00 2001 From: Michael Schellenberger Costa Date: Fri, 29 Jan 2021 07:03:29 +0100 Subject: [PATCH 10/13] Try to apply workaround --- stl/inc/xmemory | 3 ++- .../test.cpp | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 58823353f0a..082cae0c57b 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1182,7 +1182,8 @@ private: _CONSTEXPR20_CONTAINER void _Orphan_me_unlocked() noexcept { _Iterator_base12** _Pnext = &_Myproxy->_Myfirstiter; while (*_Pnext && *_Pnext != this) { - _Pnext = &(*_Pnext)->_Mynextiter; + const auto _Temp = *_Pnext; // TRANSITION: ASO-XXXXX + _Pnext = &_Temp->_Mynextiter; } _STL_VERIFY(*_Pnext, "ITERATOR LIST CORRUPTED!"); diff --git a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp index 33a9fd23026..7939af14b21 100644 --- a/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp +++ b/tests/std/tests/P0784R7_library_support_for_more_constexpr_containers/test.cpp @@ -291,7 +291,6 @@ struct nontrivial_A { constexpr ~nontrivial_A() {} }; - constexpr void test_compiletime_destroy_variants() { #ifndef __EDG__ // TRANSITION, VSO-1270011 { From b3caaae81cb1a01c75741ce1c226c081ede93a15 Mon Sep 17 00:00:00 2001 From: Miya Natsuhara Date: Tue, 2 Feb 2021 12:05:54 -0800 Subject: [PATCH 11/13] Address review comments --- stl/inc/xmemory | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 082cae0c57b..ddf8d0f9d05 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1182,7 +1182,7 @@ private: _CONSTEXPR20_CONTAINER void _Orphan_me_unlocked() noexcept { _Iterator_base12** _Pnext = &_Myproxy->_Myfirstiter; while (*_Pnext && *_Pnext != this) { - const auto _Temp = *_Pnext; // TRANSITION: ASO-XXXXX + const auto _Temp = *_Pnext; // TRANSITION: VSO-1269037 _Pnext = &_Temp->_Mynextiter; } @@ -1531,7 +1531,7 @@ public: ++_Last; } - _CONSTEXPR20_DYNALLOC pointer _Release() { // suppress any exception handling backout and return _Last + constexpr pointer _Release() { // suppress any exception handling backout and return _Last _First = _Last; return _Last; } @@ -1564,14 +1564,13 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_copy( return _Dest; } } + _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; for (; _UFirst != _ULast; ++_UFirst) { _Backout._Emplace_back(*_UFirst); } - _Dest = _Backout._Release(); - - return _Dest; + return _Backout._Release(); } // FUNCTION TEMPLATE uninitialized_copy @@ -1579,7 +1578,7 @@ template _CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_copy_unchecked( _InIt _First, const _InIt _Last, _NoThrowFwdIt _Dest) { // copy [_First, _Last) to raw [_Dest, ...) - if constexpr (_Ptr_move_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) { + if constexpr (_Ptr_copy_cat<_InIt, _NoThrowFwdIt>::_Really_trivial) { #ifdef __cpp_lib_constexpr_dynamic_alloc if (!_STD is_constant_evaluated()) #endif // __cpp_lib_constexpr_dynamic_alloc @@ -1587,14 +1586,13 @@ _CONSTEXPR20_DYNALLOC _NoThrowFwdIt _Uninitialized_copy_unchecked( return _Copy_memmove(_First, _Last, _Dest); } } + _Uninitialized_backout<_NoThrowFwdIt> _Backout{_Dest}; for (; _First != _Last; ++_First) { _Backout._Emplace_back(*_First); } - _Dest = _Backout._Release(); - - return _Dest; + return _Backout._Release(); } template @@ -1627,6 +1625,7 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_move( return _Dest + (_ULast - _UFirst); } } + _Uninitialized_backout_al<_Alloc> _Backout{_Dest, _Al}; for (; _UFirst != _ULast; ++_UFirst) { _Backout._Emplace_back(_STD move(*_UFirst)); @@ -1660,8 +1659,8 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_fill_n( } } } - _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; + _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; for (; 0 < _Count; --_Count) { _Backout._Emplace_back(_Val); } @@ -1685,6 +1684,7 @@ void uninitialized_fill(const _NoThrowFwdIt _First, const _NoThrowFwdIt _Last, c return; } } + _Uninitialized_backout<_Unwrapped_t> _Backout{_UFirst}; while (_Backout._Last != _ULast) { _Backout._Emplace_back(_Val); @@ -1723,6 +1723,7 @@ _CONSTEXPR20_DYNALLOC _Alloc_ptr_t<_Alloc> _Uninitialized_value_construct_n( return _First + _Count; } } + _Uninitialized_backout_al<_Alloc> _Backout{_First, _Al}; for (; 0 < _Count; --_Count) { _Backout._Emplace_back(); From 490d015acb6699379142688b4c3d776dd411b3aa Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 2 Feb 2021 17:04:20 -0800 Subject: [PATCH 12/13] Use comma in TRANSITION comment --- stl/inc/xmemory | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/xmemory b/stl/inc/xmemory index ddf8d0f9d05..81f9729d118 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -1182,7 +1182,7 @@ private: _CONSTEXPR20_CONTAINER void _Orphan_me_unlocked() noexcept { _Iterator_base12** _Pnext = &_Myproxy->_Myfirstiter; while (*_Pnext && *_Pnext != this) { - const auto _Temp = *_Pnext; // TRANSITION: VSO-1269037 + const auto _Temp = *_Pnext; // TRANSITION, VSO-1269037 _Pnext = &_Temp->_Mynextiter; } From 075dfaf2c3aed15291bcd2f205e905ec94fa4166 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 3 Feb 2021 01:37:30 -0800 Subject: [PATCH 13/13] Perma-workaround DevCom-1328628 "SFINAE bug when a default argument is protected". --- stl/inc/xutility | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 8c223caa7a9..eb2a04cadf3 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -131,10 +131,10 @@ _NODISCARD constexpr void* _Voidify_iter(_Iter _It) noexcept { // FUNCTION TEMPLATE construct_at #if _HAS_CXX20 -template -_CONSTEXPR20_DYNALLOC auto construct_at(_Ty* const _Location, _Types&&... _Args) noexcept( - noexcept(::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...))) // strengthened - -> decltype(::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...)) { +template ()) _Ty(_STD declval<_Types>()...))>> +_CONSTEXPR20_DYNALLOC _Ty* construct_at(_Ty* const _Location, _Types&&... _Args) noexcept( + noexcept(::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...))) /* strengthened */ { return ::new (_Voidify_iter(_Location)) _Ty(_STD forward<_Types>(_Args)...); } #endif // _HAS_CXX20