diff --git a/stl/inc/coroutine b/stl/inc/coroutine index c41e6b36f59..94933610fbe 100644 --- a/stl/inc/coroutine +++ b/stl/inc/coroutine @@ -92,12 +92,12 @@ private: void* _Ptr = nullptr; }; -_EXPORT_STD template +_EXPORT_STD template struct coroutine_handle { constexpr coroutine_handle() noexcept = default; constexpr coroutine_handle(nullptr_t) noexcept {} - _NODISCARD static coroutine_handle from_promise(_Promise& _Prom) noexcept { // strengthened + _NODISCARD static coroutine_handle from_promise(_CoroPromise& _Prom) noexcept { // strengthened const auto _Prom_ptr = const_cast(static_cast(_STD addressof(_Prom))); const auto _Frame_ptr = __builtin_coro_promise(_Prom_ptr, 0, true); coroutine_handle _Result; @@ -144,8 +144,8 @@ struct coroutine_handle { __builtin_coro_destroy(_Ptr); } - _NODISCARD _Promise& promise() const noexcept { // strengthened - return *reinterpret_cast<_Promise*>(__builtin_coro_promise(_Ptr, 0, false)); + _NODISCARD _CoroPromise& promise() const noexcept { // strengthened + return *reinterpret_cast<_CoroPromise*>(__builtin_coro_promise(_Ptr, 0, false)); } private: @@ -184,10 +184,10 @@ _NODISCARD constexpr bool operator>=(const coroutine_handle<> _Left, const corou } #endif // ^^^ !_HAS_CXX20 ^^^ -template -struct hash> { +template +struct hash> { _NODISCARD _STATIC_CALL_OPERATOR size_t operator()( - const coroutine_handle<_Promise>& _Coro) _CONST_CALL_OPERATOR noexcept { + const coroutine_handle<_CoroPromise>& _Coro) _CONST_CALL_OPERATOR noexcept { return _Hash_representation(_Coro.address()); } }; diff --git a/stl/inc/generator b/stl/inc/generator index 20a3b4d4046..10777a59e3e 100644 --- a/stl/inc/generator +++ b/stl/inc/generator @@ -49,9 +49,9 @@ private: return _Al.allocate(_Count); } else { // store stateful allocator - static constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block)); - const size_t _Count = (_Size + sizeof(_Alloc) + _Align - 1) / sizeof(_Aligned_block); - void* const _Ptr = _Al.allocate(_Count); + constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block)); + const size_t _Count = (_Size + sizeof(_Alloc) + _Align - 1) / sizeof(_Aligned_block); + void* const _Ptr = _Al.allocate(_Count); const auto _Al_address = (reinterpret_cast(_Ptr) + _Size + alignof(_Alloc) - 1) & ~(alignof(_Alloc) - 1); ::new (reinterpret_cast(_Al_address)) _Alloc(_STD move(_Al)); @@ -92,8 +92,8 @@ public: _Alloc _Al{_STD move(_Stored_al)}; _Stored_al.~_Alloc(); - static constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block)); - const size_t _Count = (_Size + sizeof(_Alloc) + _Align - 1) / sizeof(_Aligned_block); + constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block)); + const size_t _Count = (_Size + sizeof(_Alloc) + _Align - 1) / sizeof(_Aligned_block); _Al.deallocate(static_cast<_Aligned_block*>(_Ptr), _Count); } } @@ -102,7 +102,33 @@ public: template <> class _Promise_allocator { // type-erased allocator private: - using _Dealloc_fn = void (*)(void*, size_t); + using _Dealloc_fn = void(__stdcall*)(void*, size_t) _NOEXCEPT_FNPTR; + + template + static void __stdcall _Dealloc_stateless(void* const _Ptr, const size_t _Size) noexcept { + _Alloc _Al{}; + const size_t _Count = (_Size + sizeof(_Dealloc_fn) + sizeof(_Aligned_block) - 1) / sizeof(_Aligned_block); + _Al.deallocate(static_cast<_Aligned_block*>(_Ptr), _Count); + } + + template + static void __stdcall _Dealloc_stateful(void* const _Ptr, size_t _Size) noexcept { + constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block)); + + _Size += sizeof(_Dealloc_fn); + const auto _Al_address = + (reinterpret_cast(_Ptr) + _Size + alignof(_Alloc) - 1) & ~(alignof(_Alloc) - 1); + auto& _Stored_al = *reinterpret_cast<_Alloc*>(_Al_address); + _Alloc _Al{_STD move(_Stored_al)}; + _Stored_al.~_Alloc(); + + const size_t _Count = (_Size + sizeof(_Al) + _Align - 1) / sizeof(_Aligned_block); + _Al.deallocate(static_cast<_Aligned_block*>(_Ptr), _Count); + } + + static void __stdcall _Dealloc_delete(void* const _Ptr, const size_t _Size) noexcept { + ::operator delete[](_Ptr, _Size + sizeof(_Dealloc_fn)); + } template static void* _Allocate(const _ProtoAlloc& _Proto, size_t _Size) { @@ -111,12 +137,7 @@ private: if constexpr (default_initializable<_Alloc> && allocator_traits<_Alloc>::is_always_equal::value) { // don't store stateless allocator - const _Dealloc_fn _Dealloc = [](void* const _Ptr, const size_t _Size) { - _Alloc _Al{}; - const size_t _Count = - (_Size + sizeof(_Dealloc_fn) + sizeof(_Aligned_block) - 1) / sizeof(_Aligned_block); - _Al.deallocate(static_cast<_Aligned_block*>(_Ptr), _Count); - }; + const _Dealloc_fn _Dealloc = _Dealloc_stateless<_Alloc>; const size_t _Count = (_Size + sizeof(_Dealloc_fn) + sizeof(_Aligned_block) - 1) / sizeof(_Aligned_block); void* const _Ptr = _Al.allocate(_Count); @@ -124,19 +145,9 @@ private: return _Ptr; } else { // store stateful allocator - static constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block)); - - const _Dealloc_fn _Dealloc = [](void* const _Ptr, size_t _Size) { - _Size += sizeof(_Dealloc_fn); - const auto _Al_address = - (reinterpret_cast(_Ptr) + _Size + alignof(_Alloc) - 1) & ~(alignof(_Alloc) - 1); - auto& _Stored_al = *reinterpret_cast(_Al_address); - _Alloc _Al{_STD move(_Stored_al)}; - _Stored_al.~_Alloc(); + constexpr size_t _Align = (_STD max)(alignof(_Alloc), sizeof(_Aligned_block)); - const size_t _Count = (_Size + sizeof(_Al) + _Align - 1) / sizeof(_Aligned_block); - _Al.deallocate(static_cast<_Aligned_block*>(_Ptr), _Count); - }; + const _Dealloc_fn _Dealloc = _Dealloc_stateful<_Alloc>; const size_t _Count = (_Size + sizeof(_Dealloc_fn) + sizeof(_Al) + _Align - 1) / sizeof(_Aligned_block); void* const _Ptr = _Al.allocate(_Count); @@ -152,9 +163,7 @@ private: public: static void* operator new(const size_t _Size) { // default: new/delete void* const _Ptr = ::operator new[](_Size + sizeof(_Dealloc_fn)); - const _Dealloc_fn _Dealloc = [](void* const _Ptr, const size_t _Size) { - ::operator delete[](_Ptr, _Size + sizeof(_Dealloc_fn)); - }; + const _Dealloc_fn _Dealloc = _Dealloc_delete; _CSTD memcpy(static_cast(_Ptr) + _Size, &_Dealloc, sizeof(_Dealloc_fn)); return _Ptr; } @@ -231,7 +240,7 @@ public: requires same_as<_Gen_yield_t<_Gen_reference_t<_Rty, _Vty>>, _Yielded> _NODISCARD auto yield_value(_RANGES elements_of&&, _Unused> _Elem) noexcept { using _Nested_awaitable = _Nested_awaitable_provider<_Rty, _Vty, _Alloc>::_Awaitable; - return _Nested_awaitable{std::move(_Elem.range)}; + return _Nested_awaitable{_STD move(_Elem.range)}; } template <_RANGES input_range _Rng, class _Alloc> @@ -239,12 +248,15 @@ public: _NODISCARD auto yield_value(_RANGES elements_of<_Rng, _Alloc> _Elem) { using _Vty = _RANGES range_value_t<_Rng>; using _Nested_awaitable = _Nested_awaitable_provider<_Yielded, _Vty, _Alloc>::_Awaitable; - return _Nested_awaitable{[](allocator_arg_t, _Alloc, _RANGES iterator_t<_Rng> _It, - const _RANGES sentinel_t<_Rng> _Se) -> generator<_Yielded, _Vty, _Alloc> { + + auto _Lambda = [](allocator_arg_t, _Alloc, _RANGES iterator_t<_Rng> _It, + const _RANGES sentinel_t<_Rng> _Se) -> generator<_Yielded, _Vty, _Alloc> { for (; _It != _Se; ++_It) { co_yield static_cast<_Yielded>(*_It); } - }(allocator_arg, _Elem.allocator, _RANGES begin(_Elem.range), _RANGES end(_Elem.range))}; + }; + return _Nested_awaitable{ + _Lambda(allocator_arg, _Elem.allocator, _RANGES begin(_Elem.range), _RANGES end(_Elem.range))}; } void await_transform() = delete; @@ -255,7 +267,7 @@ public: if (_Info) { _Info->_Except = _STD current_exception(); } else { - throw; + _RERAISE; } } @@ -267,10 +279,10 @@ private: return false; } - template - constexpr void await_suspend(coroutine_handle<_Promise> _Handle) noexcept { + template + constexpr void await_suspend(coroutine_handle<_CoroPromise> _Handle) noexcept { #ifdef __cpp_lib_is_pointer_interconvertible // TRANSITION, LLVM-48860 - _STL_INTERNAL_STATIC_ASSERT(is_pointer_interconvertible_base_of_v<_Base, _Promise>); + _STL_INTERNAL_STATIC_ASSERT(is_pointer_interconvertible_base_of_v<_Base, _CoroPromise>); #endif // ^^^ no workaround ^^^ _Base& _Current = _Handle.promise(); @@ -291,10 +303,10 @@ private: return false; } - template - _NODISCARD coroutine_handle<> await_suspend(coroutine_handle<_Promise> _Handle) noexcept { + template + _NODISCARD coroutine_handle<> await_suspend(coroutine_handle<_CoroPromise> _Handle) noexcept { #ifdef __cpp_lib_is_pointer_interconvertible // TRANSITION, LLVM-48860 - _STL_INTERNAL_STATIC_ASSERT(is_pointer_interconvertible_base_of_v<_Base, _Promise>); + _STL_INTERNAL_STATIC_ASSERT(is_pointer_interconvertible_base_of_v<_Base, _CoroPromise>); #endif // ^^^ no workaround ^^^ _Base& _Current = _Handle.promise(); @@ -325,10 +337,10 @@ private: return !_Gen._Coro; } - template - _NODISCARD coroutine_handle<_Base> await_suspend(coroutine_handle<_Promise> _Current) noexcept { + template + _NODISCARD coroutine_handle<_Base> await_suspend(coroutine_handle<_CoroPromise> _Current) noexcept { #ifdef __cpp_lib_is_pointer_interconvertible // TRANSITION, LLVM-48860 - _STL_INTERNAL_STATIC_ASSERT(is_pointer_interconvertible_base_of_v<_Base, _Promise>); + _STL_INTERNAL_STATIC_ASSERT(is_pointer_interconvertible_base_of_v<_Base, _CoroPromise>); #endif // ^^^ no workaround ^^^ auto _Target = coroutine_handle<_Base>::from_address(_Gen._Coro.address()); _Nested._Parent = coroutine_handle<_Base>::from_address(_Current.address()); @@ -409,25 +421,27 @@ private: }; _EXPORT_STD template -class generator : public ranges::view_interface> { +class generator : public _RANGES view_interface> { private: using _Value = _Gen_value_t<_Rty, _Vty>; static_assert(same_as, _Value> && is_object_v<_Value>, - "generator's value type must be a cv-unqualified object type"); + "generator's value type must be a cv-unqualified object type (N4971 [coro.generator.class]/1.2)"); using _Ref = _Gen_reference_t<_Rty, _Vty>; static_assert( is_reference_v<_Ref> || (is_object_v<_Ref> && same_as, _Ref> && copy_constructible<_Ref>), - "generator's second argument must be a reference type or a cv-unqualified " - "copy-constructible object type"); + "generator's selected reference type must be an actual reference type " + "or a cv-unqualified copy-constructible object type (N4971 [coro.generator.class]/1.3)"); using _RRef = conditional_t, remove_reference_t<_Ref>&&, _Ref>; static_assert(common_reference_with<_Ref&&, _Value&> && common_reference_with<_Ref&&, _RRef&&> && common_reference_with<_RRef&&, const _Value&>, - "an iterator with the selected value and reference types cannot model indirectly_readable"); + "generator's iterator type must model indirectly_readable, " + "but that's impossible with the selected value and reference types (N4971 [coro.generator.class]/1.4)"); - static_assert(_Has_real_pointers<_Alloc>, "generator allocators must use raw pointers"); + static_assert(_Has_real_pointers<_Alloc>, "generator allocators must use raw pointers " + "(N4971 [coro.generator.class]/1.1)"); friend _Gen_promise_base<_Gen_yield_t<_Ref>>; diff --git a/tests/std/tests/P2502R2_generator/test.cpp b/tests/std/tests/P2502R2_generator/test.cpp index 75dcad61af8..ddc3af912ed 100644 --- a/tests/std/tests/P2502R2_generator/test.cpp +++ b/tests/std/tests/P2502R2_generator/test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include