diff --git a/stl/inc/__msvc_all_public_headers.hpp b/stl/inc/__msvc_all_public_headers.hpp index cb3a06c6d71..680c38d4a38 100644 --- a/stl/inc/__msvc_all_public_headers.hpp +++ b/stl/inc/__msvc_all_public_headers.hpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// This file is intended as a test resource for tools that want to verify that they can parse all MSVC++ standard +// This file is intended as a test resource for tools that want to verify that they can parse all MSVC standard // library headers without warnings. This file disables deprecations, so it should not be included in programs directly. // // This file may be changed, renamed, or removed at any time. diff --git a/stl/inc/algorithm b/stl/inc/algorithm index beaf4b5891b..64aea9ef27c 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -304,7 +304,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped(_STD move(_First)); const auto _ULast = _Get_unwrapped(_STD move(_Last)); for (; _UFirst != _ULast; ++_UFirst) { - _C_invoke(_Func, _C_invoke(_Proj, *_UFirst)); + _STD invoke(_Func, _STD invoke(_Proj, *_UFirst)); } _Seek_wrapped(_First, _STD move(_UFirst)); @@ -336,7 +336,7 @@ namespace ranges { if (0 < _Count) { auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); do { - _C_invoke(_Func, _C_invoke(_Proj, *_UFirst)); + _STD invoke(_Func, _STD invoke(_Proj, *_UFirst)); --_Count; ++_UFirst; } while (0 < _Count); @@ -364,7 +364,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped(_STD move(_First)); const auto _ULast = _Get_unwrapped(_STD move(_Last)); for (; _UFirst != _ULast; ++_UFirst) { - if (_C_invoke(_Proj, *_UFirst) == _Val) { + if (_STD invoke(_Proj, *_UFirst) == _Val) { break; } } @@ -407,7 +407,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped(_STD move(_First)); const auto _ULast = _Get_unwrapped(_STD move(_Last)); for (; _UFirst != _ULast; ++_UFirst) { - if (_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_UFirst))) { break; } } @@ -465,7 +465,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped(_STD move(_First)); const auto _ULast = _Get_unwrapped(_STD move(_Last)); for (; _UFirst != _ULast; ++_UFirst) { - if (!_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) { + if (!_STD invoke(_Pred, _STD invoke(_Proj, *_UFirst))) { break; } } @@ -541,7 +541,7 @@ namespace ranges { iter_difference_t<_It> _Count = 0; for (; _UFirst != _ULast; ++_UFirst) { - if (_C_invoke(_Proj, *_UFirst) == _Val) { + if (_STD invoke(_Proj, *_UFirst) == _Val) { ++_Count; } } @@ -600,7 +600,7 @@ namespace ranges { const auto _ULast = _Get_unwrapped(_STD move(_Last)); iter_difference_t<_It> _Count = 0; for (; _UFirst != _ULast; ++_UFirst) { - if (_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_UFirst))) { ++_Count; } } @@ -811,7 +811,7 @@ namespace ranges { auto _UFirst2 = _Get_unwrapped(_STD move(_First2)); for (; _Count != 0; ++_UFirst1, (void) ++_UFirst2, --_Count) { - if (!_C_invoke(_Pred, _C_invoke(_Proj1, *_UFirst1), _C_invoke(_Proj2, *_UFirst2))) { + if (!_STD invoke(_Pred, _STD invoke(_Proj1, *_UFirst1), _STD invoke(_Proj2, *_UFirst2))) { break; } } @@ -830,7 +830,7 @@ namespace ranges { const auto _ULast2 = _Get_unwrapped(_STD move(_Last2)); for (; _UFirst1 != _ULast1 && _UFirst2 != _ULast2; ++_UFirst1, (void) ++_UFirst2) { - if (!_C_invoke(_Pred, _C_invoke(_Proj1, *_UFirst1), _C_invoke(_Proj2, *_UFirst2))) { + if (!_STD invoke(_Pred, _STD invoke(_Proj1, *_UFirst1), _STD invoke(_Proj2, *_UFirst2))) { break; } } @@ -899,7 +899,7 @@ namespace ranges { _NODISCARD static constexpr bool _Equal_count( _It1 _First1, _It2 _First2, _Size _Count, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) { for (; _Count != 0; ++_First1, (void) ++_First2, --_Count) { - if (!_C_invoke(_Pred, _C_invoke(_Proj1, *_First1), _C_invoke(_Proj2, *_First2))) { + if (!_STD invoke(_Pred, _STD invoke(_Proj1, *_First1), _STD invoke(_Proj2, *_First2))) { return false; } } @@ -917,7 +917,7 @@ namespace ranges { return false; } - if (!_C_invoke(_Pred, _C_invoke(_Proj1, *_First1), _C_invoke(_Proj2, *_First2))) { + if (!_STD invoke(_Pred, _STD invoke(_Proj1, *_First1), _STD invoke(_Proj2, *_First2))) { return false; } @@ -1017,7 +1017,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped(_STD move(_First)); const auto _ULast = _Get_unwrapped(_STD move(_Last)); for (; _UFirst != _ULast; ++_UFirst) { - if (!_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) { + if (!_STD invoke(_Pred, _STD invoke(_Proj, *_UFirst))) { return false; } } @@ -1071,7 +1071,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped(_STD move(_First)); const auto _ULast = _Get_unwrapped(_STD move(_Last)); for (; _UFirst != _ULast; ++_UFirst) { - if (_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_UFirst))) { return true; } } @@ -1125,7 +1125,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped(_STD move(_First)); const auto _ULast = _Get_unwrapped(_STD move(_Last)); for (; _UFirst != _ULast; ++_UFirst) { - if (_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_UFirst))) { return false; } } @@ -1280,7 +1280,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped(_STD move(_First)); const auto _ULast = _Get_unwrapped(_STD move(_Last)); for (; _UFirst != _ULast; ++_UFirst) { - if (_C_invoke(_Pred, _C_invoke(_Proj, *_UFirst))) { + if (_STD invoke(_Pred, _STD invoke(_Proj, *_UFirst))) { *_Result = *_UFirst; ++_Result; } diff --git a/stl/inc/tuple b/stl/inc/tuple index 073dafa9511..52f4c1223f6 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -949,7 +949,7 @@ _NODISCARD constexpr typename _Tuple_cat1<_Tuples...>::type tuple_cat(_Tuples&&. template constexpr decltype(auto) _Apply_impl( _Callable&& _Obj, _Tuple&& _Tpl, index_sequence<_Indices...>) { // invoke _Obj with the elements of _Tpl - return _C_invoke(_STD forward<_Callable>(_Obj), _STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...); + return _STD invoke(_STD forward<_Callable>(_Obj), _STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...); } #pragma warning(pop) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 973aedab004..8fb27de97e1 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1478,145 +1478,153 @@ _NODISCARD constexpr conditional_t && is_c template class reference_wrapper; -// std::invoke isn't constexpr in C++17, and implementers are forbidden from "strengthening" constexpr (WG21-N4842 -// [constexpr.functions]/1), yet both std::apply and std::visit are required to be constexpr and have invoke-like -// behavior. We solve this by using a macro to stamp out both public non-constexpr and internal constexpr -// implementations. TRANSITION, P1065R2 - -#define _CONCATX(x, y) x##y -#define _CONCAT(x, y) _CONCATX(x, y) - -#define _IMPLEMENT_INVOKE(NAME_PREFIX, CONSTEXPR) \ - /* FUNCTION TEMPLATE invoke */ \ - struct _CONCAT(NAME_PREFIX, _Invoker_pmf_object) { /* INVOKE a pointer to member function on an object */ \ - template \ - static CONSTEXPR auto _Call(_Decayed _Pmf, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( \ - noexcept((_STD forward<_Ty1>(_Arg1).*_Pmf)(_STD forward<_Types2>(_Args2)...))) \ - -> decltype((_STD forward<_Ty1>(_Arg1).*_Pmf)( \ - _STD forward<_Types2>(_Args2)...)) { /* INVOKE a pointer to member function on an object */ \ - return (_STD forward<_Ty1>(_Arg1).*_Pmf)(_STD forward<_Types2>(_Args2)...); \ - } \ - }; \ - \ - struct _CONCAT( \ - NAME_PREFIX, _Invoker_pmf_refwrap) { /* INVOKE a pointer to member function on a reference_wrapper */ \ - template \ - static CONSTEXPR auto _Call(_Decayed _Pmf, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( \ - noexcept((_STD forward<_Ty1>(_Arg1).get().*_Pmf)(_STD forward<_Types2>(_Args2)...))) \ - -> decltype((_STD forward<_Ty1>(_Arg1).get().*_Pmf)( \ - _STD forward<_Types2>(_Args2)...)) { /* INVOKE a pointer to member function on a reference_wrapper */ \ - return (_STD forward<_Ty1>(_Arg1).get().*_Pmf)(_STD forward<_Types2>(_Args2)...); \ - } \ - }; \ - \ - struct _CONCAT(NAME_PREFIX, _Invoker_pmf_pointer) { /* INVOKE a pointer to member function on a [smart] pointer */ \ - template \ - static CONSTEXPR auto _Call(_Decayed _Pmf, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( \ - noexcept(((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(_STD forward<_Types2>(_Args2)...))) \ - -> decltype(((*_STD forward<_Ty1>(_Arg1)).*_Pmf)( \ - _STD forward<_Types2>(_Args2)...)) { /* INVOKE a pointer to member function on a [smart] pointer */ \ - return ((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(_STD forward<_Types2>(_Args2)...); \ - } \ - }; \ - \ - struct _CONCAT(NAME_PREFIX, _Invoker_pmd_object) { /* INVOKE a pointer to member data on an object */ \ - template \ - static CONSTEXPR auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept(noexcept(_STD forward<_Ty1>(_Arg1).*_Pmd)) \ - -> decltype(_STD forward<_Ty1>(_Arg1).*_Pmd) { /* INVOKE a pointer to member data on an object */ \ - return _STD forward<_Ty1>(_Arg1).*_Pmd; \ - } \ - }; \ - \ - struct _CONCAT(NAME_PREFIX, _Invoker_pmd_refwrap) { /* INVOKE a pointer to member data on a reference_wrapper */ \ - template \ - static CONSTEXPR auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept( \ - noexcept(_STD forward<_Ty1>(_Arg1).get().*_Pmd)) \ - -> decltype( \ - _STD forward<_Ty1>(_Arg1).get().*_Pmd) { /* INVOKE a pointer to member data on a reference_wrapper */ \ - return _STD forward<_Ty1>(_Arg1).get().*_Pmd; \ - } \ - }; \ - \ - struct _CONCAT(NAME_PREFIX, _Invoker_pmd_pointer) { /* INVOKE a pointer to member data on a [smart] pointer */ \ - template \ - static CONSTEXPR auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept( \ - noexcept((*_STD forward<_Ty1>(_Arg1)).*_Pmd)) \ - -> decltype( \ - (*_STD forward<_Ty1>(_Arg1)).*_Pmd) { /* INVOKE a pointer to member data on a [smart] pointer */ \ - return (*_STD forward<_Ty1>(_Arg1)).*_Pmd; \ - } \ - }; \ - \ - struct _CONCAT(NAME_PREFIX, _Invoker_functor) { /* INVOKE a function object */ \ - template \ - static CONSTEXPR auto _Call(_Callable&& _Obj, _Types&&... _Args) noexcept( \ - noexcept(_STD forward<_Callable>(_Obj)(_STD forward<_Types>(_Args)...))) \ - -> decltype( \ - _STD forward<_Callable>(_Obj)(_STD forward<_Types>(_Args)...)) { /* INVOKE a function object */ \ - return _STD forward<_Callable>(_Obj)(_STD forward<_Types>(_Args)...); \ - } \ - }; \ - \ - template , \ - bool _Is_pmf = is_member_function_pointer_v<_Removed_cvref>, \ - bool _Is_pmd = is_member_object_pointer_v<_Removed_cvref>> \ - struct _CONCAT(NAME_PREFIX, _Invoker1); \ - \ - template \ - struct _CONCAT(NAME_PREFIX, _Invoker1)<_Callable, _Ty1, _Removed_cvref, true, false> \ - : conditional_t::_Class_type, remove_reference_t<_Ty1>>, \ - _CONCAT(NAME_PREFIX, _Invoker_pmf_object), \ - conditional_t<_Is_specialization_v<_Remove_cvref_t<_Ty1>, reference_wrapper>, \ - _CONCAT(NAME_PREFIX, _Invoker_pmf_refwrap), \ - _CONCAT(NAME_PREFIX, _Invoker_pmf_pointer)>> { /* pointer to member function */ \ - }; \ - \ - template \ - struct _CONCAT(NAME_PREFIX, _Invoker1)<_Callable, _Ty1, _Removed_cvref, false, true> \ - : conditional_t< \ - is_base_of_v::_Class_type, remove_reference_t<_Ty1>>, \ - _CONCAT(NAME_PREFIX, _Invoker_pmd_object), \ - conditional_t<_Is_specialization_v<_Remove_cvref_t<_Ty1>, reference_wrapper>, \ - _CONCAT(NAME_PREFIX, _Invoker_pmd_refwrap), \ - _CONCAT(NAME_PREFIX, _Invoker_pmd_pointer)>> { /* pointer to member data */ \ - }; \ - \ - template \ - struct _CONCAT(NAME_PREFIX, _Invoker1)<_Callable, _Ty1, _Removed_cvref, false, false> \ - : _CONCAT(NAME_PREFIX, _Invoker_functor) { /* function object */ \ - }; \ - \ - template \ - struct _CONCAT(NAME_PREFIX, _Invoker); \ - \ - template \ - struct _CONCAT(NAME_PREFIX, _Invoker)<_Callable> : _CONCAT(NAME_PREFIX, _Invoker_functor) { /* zero arguments */ \ - }; \ - \ - template \ - struct _CONCAT(NAME_PREFIX, _Invoker)<_Callable, _Ty1, _Types2...> \ - : _CONCAT(NAME_PREFIX, _Invoker1)<_Callable, _Ty1> { /* one or more arguments */ \ - }; \ - \ - template \ - CONSTEXPR auto _CONCAT(NAME_PREFIX, invoke)(_Callable && _Obj, _Types && ... _Args) noexcept( \ - noexcept(_CONCAT(NAME_PREFIX, _Invoker) < _Callable, \ - _Types... > ::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...))) \ - ->decltype(_CONCAT(NAME_PREFIX, _Invoker) < _Callable, \ - _Types... > ::_Call( \ - _STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...)) { /* INVOKE a callable object */ \ - return _CONCAT(NAME_PREFIX, _Invoker)<_Callable, _Types...>::_Call( \ - _STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...); \ +// std::invoke isn't constexpr in C++17, and normally implementers are forbidden from "strengthening" constexpr +// (WG21-N4842 [constexpr.functions]/1), yet both std::apply and std::visit are required to be constexpr and have +// invoke-like behavior. As a result, we've chosen to apply the part of P1065R2 resolving LWG-2894 as a defect report. + +// FUNCTION TEMPLATE invoke +#pragma warning(push) // TRANSITION, DevCom-936696 +#pragma warning(disable : 28278) // Function '%s' appears with no prototype in scope +enum class _Invoker_strategy { + _Functor, + _Pmf_object, + _Pmf_refwrap, + _Pmf_pointer, + _Pmd_object, + _Pmd_refwrap, + _Pmd_pointer +}; + +struct _Invoker_functor { + static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Functor; + + template + static constexpr auto _Call(_Callable&& _Obj, _Types&&... _Args) noexcept( + noexcept(static_cast<_Callable&&>(_Obj)(static_cast<_Types&&>(_Args)...))) + -> decltype(static_cast<_Callable&&>(_Obj)(static_cast<_Types&&>(_Args)...)) { + return static_cast<_Callable&&>(_Obj)(static_cast<_Types&&>(_Args)...); } +}; -_IMPLEMENT_INVOKE(_EMPTY_ARGUMENT, inline) +struct _Invoker_pmf_object { + static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmf_object; -#if _HAS_CXX17 -// constexpr IMPLEMENTATION OF invoke -_IMPLEMENT_INVOKE(_C_, constexpr) -#endif // _HAS_CXX17 + template + static constexpr auto _Call(_Decayed _Pmf, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( + noexcept((static_cast<_Ty1&&>(_Arg1).*_Pmf)(static_cast<_Types2&&>(_Args2)...))) + -> decltype((static_cast<_Ty1&&>(_Arg1).*_Pmf)(static_cast<_Types2&&>(_Args2)...)) { + return (static_cast<_Ty1&&>(_Arg1).*_Pmf)(static_cast<_Types2&&>(_Args2)...); + } +}; + +struct _Invoker_pmf_refwrap { + static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmf_refwrap; + + template + static constexpr auto _Call(_Decayed _Pmf, _Refwrap _Rw, _Types2&&... _Args2) noexcept( + noexcept((_Rw.get().*_Pmf)(static_cast<_Types2&&>(_Args2)...))) + -> decltype((_Rw.get().*_Pmf)(static_cast<_Types2&&>(_Args2)...)) { + return (_Rw.get().*_Pmf)(static_cast<_Types2&&>(_Args2)...); + } +}; + +struct _Invoker_pmf_pointer { + static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmf_pointer; + + template + static constexpr auto _Call(_Decayed _Pmf, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( + noexcept(((*static_cast<_Ty1&&>(_Arg1)).*_Pmf)(static_cast<_Types2&&>(_Args2)...))) + -> decltype(((*static_cast<_Ty1&&>(_Arg1)).*_Pmf)(static_cast<_Types2&&>(_Args2)...)) { + return ((*static_cast<_Ty1&&>(_Arg1)).*_Pmf)(static_cast<_Types2&&>(_Args2)...); + } +}; + +struct _Invoker_pmd_object { + static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmd_object; + + template + static constexpr auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept -> decltype(static_cast<_Ty1&&>(_Arg1).*_Pmd) { + return static_cast<_Ty1&&>(_Arg1).*_Pmd; + } +}; + +struct _Invoker_pmd_refwrap { + static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmd_refwrap; -#undef _IMPLEMENT_INVOKE + template + static constexpr auto _Call(_Decayed _Pmd, _Refwrap _Rw) noexcept -> decltype(_Rw.get().*_Pmd) { + return _Rw.get().*_Pmd; + } +}; + +struct _Invoker_pmd_pointer { + static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmd_pointer; + + template + static constexpr auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept(noexcept((*static_cast<_Ty1&&>(_Arg1)).*_Pmd)) + -> decltype((*static_cast<_Ty1&&>(_Arg1)).*_Pmd) { + return (*static_cast<_Ty1&&>(_Arg1)).*_Pmd; + } +}; + +template , + bool _Is_pmf = is_member_function_pointer_v<_Removed_cvref>, + bool _Is_pmd = is_member_object_pointer_v<_Removed_cvref>> +struct _Invoker1; + +template +struct _Invoker1<_Callable, _Ty1, _Removed_cvref, true, false> + : conditional_t::_Class_type, remove_reference_t<_Ty1>>, + _Invoker_pmf_object, + conditional_t<_Is_specialization_v<_Remove_cvref_t<_Ty1>, reference_wrapper>, _Invoker_pmf_refwrap, + _Invoker_pmf_pointer>> {}; // pointer to member function + +template +struct _Invoker1<_Callable, _Ty1, _Removed_cvref, false, true> + : conditional_t< + is_base_of_v::_Class_type, remove_reference_t<_Ty1>>, + _Invoker_pmd_object, + conditional_t<_Is_specialization_v<_Remove_cvref_t<_Ty1>, reference_wrapper>, _Invoker_pmd_refwrap, + _Invoker_pmd_pointer>> {}; // pointer to member data + +template +struct _Invoker1<_Callable, _Ty1, _Removed_cvref, false, false> : _Invoker_functor {}; + +template +_CONSTEXPR17 auto invoke(_Callable&& _Obj) noexcept(noexcept(static_cast<_Callable&&>(_Obj)())) + -> decltype(static_cast<_Callable&&>(_Obj)()) { + return static_cast<_Callable&&>(_Obj)(); +} + +template +_CONSTEXPR17 auto invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( + noexcept(_Invoker1<_Callable, _Ty1>::_Call( + static_cast<_Callable&&>(_Obj), static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...))) + -> decltype(_Invoker1<_Callable, _Ty1>::_Call( + static_cast<_Callable&&>(_Obj), static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...)) { +#if _HAS_IF_CONSTEXPR + if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Functor) { + return static_cast<_Callable&&>(_Obj)(static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...); + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_object) { + return (static_cast<_Ty1&&>(_Arg1).*_Obj)(static_cast<_Types2&&>(_Args2)...); + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_refwrap) { + return (_Arg1.get().*_Obj)(static_cast<_Types2&&>(_Args2)...); + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_pointer) { + return ((*static_cast<_Ty1&&>(_Arg1)).*_Obj)(static_cast<_Types2&&>(_Args2)...); + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_object) { + return static_cast<_Ty1&&>(_Arg1).*_Obj; + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_refwrap) { + return _Arg1.get().*_Obj; + } else { + static_assert(_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in invoke"); + return (*static_cast<_Ty1&&>(_Arg1)).*_Obj; + } +#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv + return _Invoker1<_Callable, _Ty1>::_Call( + static_cast<_Callable&&>(_Obj), static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...); +#endif // _HAS_IF_CONSTEXPR +} +#pragma warning(pop) // TRANSITION, DevCom-936696 template > struct _Invoker_ret {}; // helper to give INVOKE an explicit return type; avoids undesirable Expression SFINAE @@ -1629,7 +1637,7 @@ template struct _Invoker_ret<_Cv_void, true> { // selected for _Rx being cv void template static void _Call(_Valtys&&... _Vals) { // INVOKE, "implicitly" converted to void - _STD invoke(_STD forward<_Valtys>(_Vals)...); + _STD invoke(static_cast<_Valtys&&>(_Vals)...); } }; @@ -1637,7 +1645,7 @@ template struct _Invoker_ret<_Rx, false> { // selected for all _Rx other than cv void and _Unforced template static _Rx _Call(_Valtys&&... _Vals) { // INVOKE, implicitly converted to _Rx - return _STD invoke(_STD forward<_Valtys>(_Vals)...); + return _STD invoke(static_cast<_Valtys&&>(_Vals)...); } }; @@ -1645,8 +1653,8 @@ template <> struct _Invoker_ret<_Unforced, false> { // selected for _Rx being _Unforced template static auto _Call(_Valtys&&... _Vals) - -> decltype(_STD invoke(_STD forward<_Valtys>(_Vals)...)) { // INVOKE, unchanged - return _STD invoke(_STD forward<_Valtys>(_Vals)...); + -> decltype(_STD invoke(static_cast<_Valtys&&>(_Vals)...)) { // INVOKE, unchanged + return _STD invoke(static_cast<_Valtys&&>(_Vals)...); } }; @@ -1864,7 +1872,7 @@ public: _Refwrap_has_ctor_from<_Ty, _Uty>>, int> = 0> reference_wrapper(_Uty&& _Val) noexcept(noexcept(_Refwrap_ctor_fun<_Ty>(_STD declval<_Uty>()))) { - _Ty& _Ref = _STD forward<_Uty>(_Val); + _Ty& _Ref = static_cast<_Uty&&>(_Val); _Ptr = _STD addressof(_Ref); } @@ -1876,13 +1884,16 @@ public: return *_Ptr; } - template - auto operator()(_Types&&... _Args) const -> decltype(_STD invoke(get(), _STD forward<_Types>(_Args)...)) { - return _STD invoke(get(), _STD forward<_Types>(_Args)...); - } - private: _Ty* _Ptr; + +public: + template + auto operator()(_Types&&... _Args) const + noexcept(noexcept(_STD invoke(*_Ptr, static_cast<_Types&&>(_Args)...))) // strengthened + -> decltype(_STD invoke(*_Ptr, static_cast<_Types&&>(_Args)...)) { + return _STD invoke(*_Ptr, static_cast<_Types&&>(_Args)...); + } }; #if _HAS_CXX17 diff --git a/stl/inc/variant b/stl/inc/variant index 23801a1c6e5..2c051677a0e 100644 --- a/stl/inc/variant +++ b/stl/inc/variant @@ -1459,7 +1459,7 @@ _NODISCARD constexpr size_t _Variant_visit_index1(size_t _Acc, const _FirstTy& _ template using _Variant_visit_result_t = - decltype(_C_invoke(_STD declval<_Callable>(), _Variant_raw_get<0>(_STD declval<_Types>()._Storage())...)); + decltype(_STD invoke(_STD declval<_Callable>(), _Variant_raw_get<0>(_STD declval<_Types>()._Storage())...)); template struct _Variant_dispatcher; @@ -1475,12 +1475,12 @@ struct _Variant_dispatcher> { } #if _HAS_CXX20 else if constexpr (is_void_v<_Ret>) { - static_cast(_C_invoke( + static_cast(_STD invoke( static_cast<_Callable&&>(_Obj), _Variant_raw_get<_Is - 1>(static_cast<_Types&&>(_Args)._Storage())...)); } #endif // _HAS_CXX20 else { - return _C_invoke( + return _STD invoke( static_cast<_Callable&&>(_Obj), _Variant_raw_get<_Is - 1>(static_cast<_Types&&>(_Args)._Storage())...); } } @@ -1504,7 +1504,7 @@ template struct _Variant_single_visit_result<_Callable, index_sequence<_Idxs...>, _Variants...> { // result type/category from invoking _Callable with the elements of // _Variants... at (_Idxs - 1)... - using type = decltype(_C_invoke(_STD declval<_Callable>(), + using type = decltype(_STD invoke(_STD declval<_Callable>(), _Variant_raw_get<_Idxs == 0 ? 0 : _Idxs - 1>(_STD declval<_Variants>()._Storage())...)); }; diff --git a/stl/inc/xatomic.h b/stl/inc/xatomic.h index 632b5c1cceb..6af55a96696 100644 --- a/stl/inc/xatomic.h +++ b/stl/inc/xatomic.h @@ -19,6 +19,9 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new +#define _CONCATX(x, y) x##y +#define _CONCAT(x, y) _CONCATX(x, y) + // Interlocked intrinsic mapping for _nf/_acq/_rel #if defined(_M_CEE_PURE) || defined(_M_IX86) || defined(_M_X64) #define _INTRIN_RELAXED(x) x diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index 2ace2274054..28f23efe16f 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -109,6 +109,8 @@ // P0682R1 Repairing Elementary String Conversions // P0739R0 Improving Class Template Argument Deduction For The STL // P0858R0 Constexpr Iterator Requirements +// P1065R2 constexpr INVOKE +// (the std::invoke function only; other components like bind and reference_wrapper will be C++20 only) // _HAS_CXX17 indirectly controls: // N4190 Removing auto_ptr, random_shuffle(), And Old Stuff diff --git a/tests/libcxx/skipped_tests.txt b/tests/libcxx/skipped_tests.txt index d77870969ff..0e692b9aa18 100644 --- a/tests/libcxx/skipped_tests.txt +++ b/tests/libcxx/skipped_tests.txt @@ -759,7 +759,7 @@ diagnostics\syserr\syserr.syserr\syserr.syserr.members\ctor_int_error_category_c diagnostics\syserr\syserr.syserr\syserr.syserr.members\ctor_int_error_category_string.pass.cpp diagnostics\syserr\syserr.syserr\syserr.syserr.members\ctor_int_error_category.pass.cpp -# libc++ disagrees with libstdc++ and MSVC++ on whether setstate calls during I/O that throw set failbit; see open issue LWG-2349 +# libc++ disagrees with libstdc++ and MSVC on whether setstate calls during I/O that throw set failbit; see open issue LWG-2349 input.output\iostream.format\input.streams\istream.unformatted\get_pointer_size_chart.pass.cpp input.output\iostream.format\input.streams\istream.unformatted\get_pointer_size.pass.cpp diff --git a/tests/std/tests/Dev09_158181_tr1_unordered_meow_swap/test.cpp b/tests/std/tests/Dev09_158181_tr1_unordered_meow_swap/test.cpp index 15401c46f56..9696d173537 100644 --- a/tests/std/tests/Dev09_158181_tr1_unordered_meow_swap/test.cpp +++ b/tests/std/tests/Dev09_158181_tr1_unordered_meow_swap/test.cpp @@ -104,7 +104,7 @@ void test_LWG_2156() { x.max_load_factor(5.0f); for (int i = 0; i < 100; ++i) { x.emplace(i); - assert_is_pow2(x.bucket_count()); // MSVC++ specific invariant + assert_is_pow2(x.bucket_count()); // MSVC-specific invariant } const auto afterEmplaceBuckets = x.bucket_count(); diff --git a/tests/std/tests/Dev10_729003_bind_reference_wrapper/test.cpp b/tests/std/tests/Dev10_729003_bind_reference_wrapper/test.cpp index 18b16b12512..ea7f59a476a 100644 --- a/tests/std/tests/Dev10_729003_bind_reference_wrapper/test.cpp +++ b/tests/std/tests/Dev10_729003_bind_reference_wrapper/test.cpp @@ -3,18 +3,13 @@ #include #include -#include #include using namespace std; struct A { string meow(int i) { - ostringstream oss; - - oss << "A::meow(" << i + 9 * 9 * 9 << ")"; - - return oss.str(); + return "A::meow(" + to_string(i + 9 * 9 * 9) + ")"; } }; diff --git a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp index 7de6c1ff2f0..6a0f0f9c0d2 100644 --- a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp +++ b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp @@ -683,22 +683,39 @@ using FuncRef = int (&)(float, double); STATIC_ASSERT(is_same_v, int>); -int triple(int n) { +constexpr int triple(int n) { return n * 3; } -int quadruple(int n) { +constexpr int quadruple(int n) { return n * 4; } +// separate constexpr and non-constexpr functions are TRANSITION, CWG-1129 int square(int n) { return n * n; } +constexpr int square_constexpr(int n) { + return n * n; +} + +int square_noexcept(int n) noexcept { + return n * n; +} + int cube(int n) { return n * n * n; } +constexpr int cube_constexpr(int n) { + return n * n * n; +} + +int cube_noexcept(int n) noexcept { + return n * n * n; +} + void test_dev11_391117(); void test_dev11_535636(); void test_dev11_794227(); @@ -907,11 +924,15 @@ struct Thing { int m_x = 1000; int m_y = 20; - int sum(int z) const { + constexpr int sum(int z) const { + return m_x + m_y + z; + } + + constexpr int sum_noexcept(int z) const noexcept { return m_x + m_y + z; } - int product(int z) const { + constexpr int product(int z) const { return m_x * m_y * z; } }; @@ -922,18 +943,18 @@ class UnaryBinary { // "reference_wrapper: Doesn't handle classes that derive from both unary_function and binary_function". // The typedefs are tested elsewhere here (see SameResults and DifferentResults). - UnaryBinary() : m_i(0) {} + constexpr UnaryBinary() : m_i(0) {} - int val() const { + constexpr int val() const { return m_i; } - int operator()(const int n) { + constexpr int operator()(const int n) { m_i += 7; return n * 10; } - int operator()(const int x, const int y) { + constexpr int operator()(const int x, const int y) { m_i += 40; return x + y; } @@ -959,6 +980,8 @@ void test_reference_wrapper_invocation() { auto rw_lambda = ref(lambda); + STATIC_ASSERT(!noexcept(rw_lambda(x))); + assert(rw_lambda(x) == 126 && x == 9); assert(rw_lambda(x) == 150 && x == 10); assert(rw_lambda(x) == 176 && x == 11); @@ -969,6 +992,11 @@ void test_reference_wrapper_invocation() { assert(i == 10); +#ifndef __EDG__ // TRANSITION, DevCom-939485 + const auto noexcept_lambda = []() noexcept {}; + const auto noexcept_lambda_ref = ref(noexcept_lambda); + STATIC_ASSERT(noexcept(noexcept_lambda_ref())); // strengthened +#endif // __EDG__ reference_wrapper rw_fxn(quadruple); assert(rw_fxn(9) == 36); @@ -1032,21 +1060,76 @@ void test_reference_wrapper_invocation() { // Test C++17 invoke(). +#if _HAS_CXX17 +constexpr bool test_invoke_constexpr() { + // MSVC implements LWG-2894 in C++17 and later + Thing thing; + auto p = &thing; + + assert(&invoke(&Thing::m_x, *p) == &p->m_x); + // assert(&invoke(&Thing::m_x, ref(*sp)) == &sp->m_x); TRANSITION, P1065R2 + assert(&invoke(&Thing::m_x, p) == &p->m_x); + +#ifndef _M_CEE // TRANSITION, DevCom-939490 + assert(invoke(&Thing::sum, *p, 3) == 1023); + // assert(invoke(&Thing::sum, ref(*sp), 4) == 1024); TRANSITION, P1065R2 + assert(invoke(&Thing::sum, p, 5) == 1025); +#endif // _M_CEE + + assert(invoke(square_constexpr, 6) == 36); + assert(invoke(&cube_constexpr, 7) == 343); + return true; +} +#endif // _HAS_CXX17 + void test_invoke() { +#if _HAS_CXX17 + assert(test_invoke_constexpr()); + STATIC_ASSERT(test_invoke_constexpr()); +#endif // _HAS_CXX17 + auto sp = make_shared(); assert(&invoke(&Thing::m_x, *sp) == &sp->m_x); + STATIC_ASSERT(noexcept(&invoke(&Thing::m_x, *sp) == &sp->m_x)); assert(&invoke(&Thing::m_x, ref(*sp)) == &sp->m_x); + STATIC_ASSERT(noexcept(&invoke(&Thing::m_x, ref(*sp)) == &sp->m_x)); assert(&invoke(&Thing::m_x, sp.get()) == &sp->m_x); + STATIC_ASSERT(noexcept(&invoke(&Thing::m_x, sp.get()) == &sp->m_x)); assert(&invoke(&Thing::m_x, sp) == &sp->m_x); + STATIC_ASSERT(noexcept(&invoke(&Thing::m_x, sp) == &sp->m_x)); assert(invoke(&Thing::sum, *sp, 3) == 1023); + STATIC_ASSERT(!noexcept(invoke(&Thing::sum, *sp, 3) == 1023)); assert(invoke(&Thing::sum, ref(*sp), 4) == 1024); + STATIC_ASSERT(!noexcept(invoke(&Thing::sum, ref(*sp), 4) == 1024)); assert(invoke(&Thing::sum, sp.get(), 5) == 1025); + STATIC_ASSERT(!noexcept(invoke(&Thing::sum, sp.get(), 5) == 1025)); assert(invoke(&Thing::sum, sp, 6) == 1026); + STATIC_ASSERT(!noexcept(invoke(&Thing::sum, sp, 6) == 1026)); + +#if _HAS_CXX17 + assert(invoke(&Thing::sum_noexcept, *sp, 3) == 1023); + STATIC_ASSERT(noexcept(invoke(&Thing::sum_noexcept, *sp, 3) == 1023)); + assert(invoke(&Thing::sum_noexcept, ref(*sp), 4) == 1024); + STATIC_ASSERT(noexcept(invoke(&Thing::sum_noexcept, ref(*sp), 4) == 1024)); + assert(invoke(&Thing::sum_noexcept, sp.get(), 5) == 1025); + STATIC_ASSERT(noexcept(invoke(&Thing::sum_noexcept, sp.get(), 5) == 1025)); + assert(invoke(&Thing::sum_noexcept, sp, 6) == 1026); + STATIC_ASSERT(noexcept(invoke(&Thing::sum_noexcept, sp, 6) == 1026)); +#endif // _HAS_CXX17 assert(invoke(square, 6) == 36); + STATIC_ASSERT(!noexcept(invoke(square, 6) == 36)); assert(invoke(&cube, 7) == 343); + STATIC_ASSERT(!noexcept(invoke(&cube, 7) == 343)); + +#if _HAS_CXX17 + assert(invoke(square_noexcept, 6) == 36); + STATIC_ASSERT(noexcept(invoke(square_noexcept, 6) == 36)); + assert(invoke(&cube_noexcept, 7) == 343); + STATIC_ASSERT(noexcept(invoke(&cube_noexcept, 7) == 343)); +#endif // _HAS_CXX17 } diff --git a/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp b/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp index 786bc27df7c..657e7b89659 100644 --- a/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp +++ b/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp @@ -339,9 +339,11 @@ void deque_test() { void forward_list_test() { static_assert( - is_nothrow_default_constructible_v>, "Strengthened noexcept on forward_list::forward_list()"); + is_nothrow_default_constructible_v>, "strengthened noexcept on forward_list::forward_list()"); static_assert(is_nothrow_move_constructible_v>, - "Strengthened noexcept on forward_list::forward_list(forward_list&&)"); + "strengthened noexcept on forward_list::forward_list(forward_list&&)"); + static_assert(is_nothrow_move_assignable_v>, + "strengthened noexcept on forward_list& forward_list::operator=(forward_list&&)"); forward_list value{}; swap_test(value);