From 9390911f3eebf53c89925ad197e56b30bd9dd518 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Sat, 29 Feb 2020 10:19:02 -0800 Subject: [PATCH 01/16] Demacroize invoke. --- stl/inc/type_traits | 230 ++++++++++++++++++++------------------------ stl/inc/xatomic.h | 3 + 2 files changed, 105 insertions(+), 128 deletions(-) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 973aedab004..a343f099807 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1483,141 +1483,115 @@ class reference_wrapper; // 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)...); \ +// FUNCTION TEMPLATE invoke +struct _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)...)) { + return (_STD forward<_Ty1>(_Arg1).*_Pmf)(_STD forward<_Types2>(_Args2)...); } +}; + +struct _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)...)) { + return (_STD forward<_Ty1>(_Arg1).get().*_Pmf)(_STD forward<_Types2>(_Args2)...); + } +}; -_IMPLEMENT_INVOKE(_EMPTY_ARGUMENT, inline) +struct _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)...)) { + return ((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(_STD forward<_Types2>(_Args2)...); + } +}; + +struct _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) { + return _STD forward<_Ty1>(_Arg1).*_Pmd; + } +}; + +struct _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) { + return _STD forward<_Ty1>(_Arg1).get().*_Pmd; + } +}; + +struct _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) { + return (*_STD forward<_Ty1>(_Arg1)).*_Pmd; + } +}; + +struct _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)...))) { + 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 _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 {}; // function object + +template +struct _Invoker; + +template +struct _Invoker<_Callable> : _Invoker_functor {}; // zero arguments + +template +struct _Invoker<_Callable, _Ty1, _Types2...> : _Invoker1<_Callable, _Ty1> {}; // one or more arguments + +template +constexpr auto invoke(_Callable&& _Obj, _Types&&... _Args) noexcept( + noexcept(_Invoker<_Callable, _Types...>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...))) + -> decltype(_Invoker<_Callable, _Types...>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...)) { + return _Invoker<_Callable, _Types...>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...); +} #if _HAS_CXX17 // constexpr IMPLEMENTATION OF invoke -_IMPLEMENT_INVOKE(_C_, constexpr) +template +constexpr auto _C_invoke(_Callable&& _Obj, _Types&&... _Args) noexcept( + noexcept(_Invoker<_Callable, _Types...>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...))) + -> decltype(_Invoker<_Callable, _Types...>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...)) { + return _Invoker<_Callable, _Types...>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...); +} #endif // _HAS_CXX17 -#undef _IMPLEMENT_INVOKE - template > struct _Invoker_ret {}; // helper to give INVOKE an explicit return type; avoids undesirable Expression SFINAE 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 From 347160514a8f1b862bed355858210ee66d743789 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Mon, 2 Mar 2020 21:07:02 -0800 Subject: [PATCH 02/16] Avoid needless in Dev10_729003_bind_reference_wrapper. --- .../std/tests/Dev10_729003_bind_reference_wrapper/test.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) 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..ba54f1d0eb3 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(" + std::to_string(i + 9 * 9 * 9) + ")"; } }; From 623fe9ad4def208e5fa698a76c34a6b4c17c59ce Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Tue, 3 Mar 2020 21:08:14 -0800 Subject: [PATCH 03/16] if-constexpr-ize invoke so that there is at most one layer of forwards, working around DevCom-936694 and DevCom-936696. --- stl/inc/type_traits | 136 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 113 insertions(+), 23 deletions(-) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index a343f099807..0e75be9d335 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1484,7 +1484,30 @@ class reference_wrapper; // implementations. TRANSITION, P1065R2 // FUNCTION TEMPLATE invoke +enum class _Invoker_strategy { + _Functor, + _Pmf_object, + _Pmf_refwrap, + _Pmf_pointer, + _Pmd_object, + _Pmd_refwrap, + _Pmd_pointer +}; + +struct _Invoker_functor { // INVOKE a function object + static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Functor; + + 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)...)) { + return _STD forward<_Callable>(_Obj)(_STD forward<_Types>(_Args)...); + } +}; + struct _Invoker_pmf_object { // INVOKE a pointer to member function on an object + static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmf_object; + template static constexpr auto _Call(_Decayed _Pmf, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( noexcept((_STD forward<_Ty1>(_Arg1).*_Pmf)(_STD forward<_Types2>(_Args2)...))) @@ -1493,7 +1516,9 @@ struct _Invoker_pmf_object { // INVOKE a pointer to member function on an object } }; -struct _Invoker_pmf_refwrap { // INVOKE a pointer to member function on a reference_wrapper +struct _Invoker_pmf_refwrap { + static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmf_refwrap; + template static constexpr auto _Call(_Decayed _Pmf, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( noexcept((_STD forward<_Ty1>(_Arg1).get().*_Pmf)(_STD forward<_Types2>(_Args2)...))) @@ -1502,7 +1527,9 @@ struct _Invoker_pmf_refwrap { // INVOKE a pointer to member function on a refere } }; -struct _Invoker_pmf_pointer { // INVOKE a pointer to member function on a [smart] pointer +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(((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(_STD forward<_Types2>(_Args2)...))) @@ -1511,7 +1538,9 @@ struct _Invoker_pmf_pointer { // INVOKE a pointer to member function on a [smart } }; -struct _Invoker_pmd_object { // INVOKE a pointer to member data on an object +struct _Invoker_pmd_object { + static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmd_object; + template static constexpr auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept(noexcept(_STD forward<_Ty1>(_Arg1).*_Pmd)) -> decltype(_STD forward<_Ty1>(_Arg1).*_Pmd) { @@ -1519,7 +1548,9 @@ struct _Invoker_pmd_object { // INVOKE a pointer to member data on an object } }; -struct _Invoker_pmd_refwrap { // INVOKE a pointer to member data on a reference_wrapper +struct _Invoker_pmd_refwrap { + static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmd_refwrap; + template static constexpr auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept(noexcept(_STD forward<_Ty1>(_Arg1).get().*_Pmd)) -> decltype(_STD forward<_Ty1>(_Arg1).get().*_Pmd) { @@ -1527,7 +1558,9 @@ struct _Invoker_pmd_refwrap { // INVOKE a pointer to member data on a reference_ } }; -struct _Invoker_pmd_pointer { // INVOKE a pointer to member data on a [smart] pointer +struct _Invoker_pmd_pointer { + static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmd_pointer; + template static constexpr auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept(noexcept((*_STD forward<_Ty1>(_Arg1)).*_Pmd)) -> decltype((*_STD forward<_Ty1>(_Arg1)).*_Pmd) { @@ -1535,14 +1568,6 @@ struct _Invoker_pmd_pointer { // INVOKE a pointer to member data on a [smart] po } }; -struct _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)...))) { - 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>> @@ -1575,20 +1600,85 @@ struct _Invoker<_Callable> : _Invoker_functor {}; // zero arguments template struct _Invoker<_Callable, _Ty1, _Types2...> : _Invoker1<_Callable, _Ty1> {}; // one or more arguments -template -constexpr auto invoke(_Callable&& _Obj, _Types&&... _Args) noexcept( - noexcept(_Invoker<_Callable, _Types...>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...))) - -> decltype(_Invoker<_Callable, _Types...>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...)) { - return _Invoker<_Callable, _Types...>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...); +template +_CONSTEXPR20 auto invoke(_Callable&& _Obj) noexcept(noexcept(_STD forward<_Callable>(_Obj)())) + -> decltype(_STD forward<_Callable>(_Obj)()) { + return _STD forward<_Callable>(_Obj)(); +} + +template +_CONSTEXPR20 auto invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( + noexcept(_Invoker<_Callable, _Ty1, _Types2...>::_Call( + _STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...))) + -> decltype(_Invoker<_Callable, _Ty1, _Types2...>::_Call( + _STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...)) { +#if _HAS_IF_CONSTEXPR + if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Functor) { + return _STD forward<_Callable>(_Obj)(_STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...); + } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmf_object) { + auto _Pmf = _Obj; + return (_STD forward<_Ty1>(_Arg1).*_Pmf)(_STD forward<_Types2>(_Args2)...); + } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmf_refwrap) { + auto _Pmf = _Obj; + return (_STD forward<_Ty1>(_Arg1).get().*_Pmf)(_STD forward<_Types2>(_Args2)...); + } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmf_pointer) { + auto _Pmf = _Obj; + return ((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(_STD forward<_Types2>(_Args2)...); + } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmd_object) { + auto _Pmd = _Obj; + return _STD forward<_Ty1>(_Arg1).*_Pmd; + } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmd_refwrap) { + auto _Pmd = _Obj; + return _STD forward<_Ty1>(_Arg1).get().*_Pmd; + } else { + static_assert( + _Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in invoke"); + auto _Pmd = _Obj; + return (*_STD forward<_Ty1>(_Arg1)).*_Pmd; + } +#else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv + return _Invoker<_Callable, _Ty1, _Types2...>::_Call( + _STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...); +#endif // _HAS_IF_CONSTEXPR } #if _HAS_CXX17 // constexpr IMPLEMENTATION OF invoke -template -constexpr auto _C_invoke(_Callable&& _Obj, _Types&&... _Args) noexcept( - noexcept(_Invoker<_Callable, _Types...>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...))) - -> decltype(_Invoker<_Callable, _Types...>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...)) { - return _Invoker<_Callable, _Types...>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Types>(_Args)...); +template +constexpr auto _C_invoke(_Callable&& _Obj) noexcept(noexcept(_STD forward<_Callable>(_Obj)())) + -> decltype(_STD forward<_Callable>(_Obj)()) { + return _STD forward<_Callable>(_Obj)(); +} + +template +constexpr auto _C_invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( + noexcept(_Invoker<_Callable, _Ty1, _Types2...>::_Call( + _STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...))) + -> decltype(_Invoker<_Callable, _Ty1, _Types2...>::_Call( + _STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...)) { + if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Functor) { + return _STD forward<_Callable>(_Obj)(_STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...); + } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmf_object) { + auto _Pmf = _Obj; + return (_STD forward<_Ty1>(_Arg1).*_Pmf)(_STD forward<_Types2>(_Args2)...); + } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmf_refwrap) { + auto _Pmf = _Obj; + return (_STD forward<_Ty1>(_Arg1).get().*_Pmf)(_STD forward<_Types2>(_Args2)...); + } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmf_pointer) { + auto _Pmf = _Obj; + return ((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(_STD forward<_Types2>(_Args2)...); + } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmd_object) { + auto _Pmd = _Obj; + return _STD forward<_Ty1>(_Arg1).*_Pmd; + } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmd_refwrap) { + auto _Pmd = _Obj; + return _STD forward<_Ty1>(_Arg1).get().*_Pmd; + } else { + static_assert( + _Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in _C_invoke"); + auto _Pmd = _Obj; + return (*_STD forward<_Ty1>(_Arg1)).*_Pmd; + } } #endif // _HAS_CXX17 From 14f948eb0ca2b6a820ec1281c5e1c5979ad2d1cc Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 4 Mar 2020 00:06:56 -0800 Subject: [PATCH 04/16] _Invoker => _Invoker1 --- stl/inc/type_traits | 55 +++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 0e75be9d335..ebb771399a5 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1591,15 +1591,6 @@ struct _Invoker1<_Callable, _Ty1, _Removed_cvref, false, true> template struct _Invoker1<_Callable, _Ty1, _Removed_cvref, false, false> : _Invoker_functor {}; // function object -template -struct _Invoker; - -template -struct _Invoker<_Callable> : _Invoker_functor {}; // zero arguments - -template -struct _Invoker<_Callable, _Ty1, _Types2...> : _Invoker1<_Callable, _Ty1> {}; // one or more arguments - template _CONSTEXPR20 auto invoke(_Callable&& _Obj) noexcept(noexcept(_STD forward<_Callable>(_Obj)())) -> decltype(_STD forward<_Callable>(_Obj)()) { @@ -1608,36 +1599,34 @@ _CONSTEXPR20 auto invoke(_Callable&& _Obj) noexcept(noexcept(_STD forward<_Calla template _CONSTEXPR20 auto invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( - noexcept(_Invoker<_Callable, _Ty1, _Types2...>::_Call( - _STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...))) - -> decltype(_Invoker<_Callable, _Ty1, _Types2...>::_Call( - _STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...)) { + noexcept(_Invoker1<_Callable, _Ty1>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), + _STD forward<_Types2>(_Args2)...))) -> decltype(_Invoker1<_Callable, _Ty1>::_Call(_STD forward<_Callable>(_Obj), + _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...)) { #if _HAS_IF_CONSTEXPR - if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Functor) { + if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Functor) { return _STD forward<_Callable>(_Obj)(_STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...); - } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmf_object) { + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_object) { auto _Pmf = _Obj; return (_STD forward<_Ty1>(_Arg1).*_Pmf)(_STD forward<_Types2>(_Args2)...); - } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmf_refwrap) { + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_refwrap) { auto _Pmf = _Obj; return (_STD forward<_Ty1>(_Arg1).get().*_Pmf)(_STD forward<_Types2>(_Args2)...); - } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmf_pointer) { + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_pointer) { auto _Pmf = _Obj; return ((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(_STD forward<_Types2>(_Args2)...); - } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmd_object) { + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_object) { auto _Pmd = _Obj; return _STD forward<_Ty1>(_Arg1).*_Pmd; - } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmd_refwrap) { + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_refwrap) { auto _Pmd = _Obj; return _STD forward<_Ty1>(_Arg1).get().*_Pmd; } else { - static_assert( - _Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in invoke"); + static_assert(_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in invoke"); auto _Pmd = _Obj; return (*_STD forward<_Ty1>(_Arg1)).*_Pmd; } #else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv - return _Invoker<_Callable, _Ty1, _Types2...>::_Call( + return _Invoker1<_Callable, _Ty1>::_Call( _STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...); #endif // _HAS_IF_CONSTEXPR } @@ -1652,30 +1641,28 @@ constexpr auto _C_invoke(_Callable&& _Obj) noexcept(noexcept(_STD forward<_Calla template constexpr auto _C_invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( - noexcept(_Invoker<_Callable, _Ty1, _Types2...>::_Call( - _STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...))) - -> decltype(_Invoker<_Callable, _Ty1, _Types2...>::_Call( - _STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...)) { - if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Functor) { + noexcept(_Invoker1<_Callable, _Ty1>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), + _STD forward<_Types2>(_Args2)...))) -> decltype(_Invoker1<_Callable, _Ty1>::_Call(_STD forward<_Callable>(_Obj), + _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...)) { + if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Functor) { return _STD forward<_Callable>(_Obj)(_STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...); - } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmf_object) { + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_object) { auto _Pmf = _Obj; return (_STD forward<_Ty1>(_Arg1).*_Pmf)(_STD forward<_Types2>(_Args2)...); - } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmf_refwrap) { + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_refwrap) { auto _Pmf = _Obj; return (_STD forward<_Ty1>(_Arg1).get().*_Pmf)(_STD forward<_Types2>(_Args2)...); - } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmf_pointer) { + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_pointer) { auto _Pmf = _Obj; return ((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(_STD forward<_Types2>(_Args2)...); - } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmd_object) { + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_object) { auto _Pmd = _Obj; return _STD forward<_Ty1>(_Arg1).*_Pmd; - } else if constexpr (_Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmd_refwrap) { + } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_refwrap) { auto _Pmd = _Obj; return _STD forward<_Ty1>(_Arg1).get().*_Pmd; } else { - static_assert( - _Invoker<_Callable, _Ty1, _Types2...>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in _C_invoke"); + static_assert(_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in _C_invoke"); auto _Pmd = _Obj; return (*_STD forward<_Ty1>(_Arg1)).*_Pmd; } From c5af0896931b7fdd19294638ddbb84d1b15cea14 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 4 Mar 2020 00:26:52 -0800 Subject: [PATCH 05/16] de-forward invoke --- stl/inc/type_traits | 102 ++++++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index ebb771399a5..1d99fbda3c9 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1499,9 +1499,9 @@ struct _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)...)) { - return _STD forward<_Callable>(_Obj)(_STD forward<_Types>(_Args)...); + 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)...); } }; @@ -1510,9 +1510,9 @@ struct _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)...)) { - return (_STD forward<_Ty1>(_Arg1).*_Pmf)(_STD forward<_Types2>(_Args2)...); + 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)...); } }; @@ -1521,9 +1521,9 @@ struct _Invoker_pmf_refwrap { 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)...)) { - return (_STD forward<_Ty1>(_Arg1).get().*_Pmf)(_STD forward<_Types2>(_Args2)...); + noexcept((static_cast<_Ty1&&>(_Arg1).get().*_Pmf)(static_cast<_Types2&&>(_Args2)...))) + -> decltype((static_cast<_Ty1&&>(_Arg1).get().*_Pmf)(static_cast<_Types2&&>(_Args2)...)) { + return (static_cast<_Ty1&&>(_Arg1).get().*_Pmf)(static_cast<_Types2&&>(_Args2)...); } }; @@ -1532,9 +1532,9 @@ struct _Invoker_pmf_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)...)) { - return ((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(_STD forward<_Types2>(_Args2)...); + 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)...); } }; @@ -1542,9 +1542,9 @@ struct _Invoker_pmd_object { static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmd_object; template - static constexpr auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept(noexcept(_STD forward<_Ty1>(_Arg1).*_Pmd)) - -> decltype(_STD forward<_Ty1>(_Arg1).*_Pmd) { - return _STD forward<_Ty1>(_Arg1).*_Pmd; + 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; } }; @@ -1552,9 +1552,9 @@ struct _Invoker_pmd_refwrap { static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmd_refwrap; template - static constexpr auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept(noexcept(_STD forward<_Ty1>(_Arg1).get().*_Pmd)) - -> decltype(_STD forward<_Ty1>(_Arg1).get().*_Pmd) { - return _STD forward<_Ty1>(_Arg1).get().*_Pmd; + static constexpr auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept(noexcept(static_cast<_Ty1&&>(_Arg1).get().*_Pmd)) + -> decltype(static_cast<_Ty1&&>(_Arg1).get().*_Pmd) { + return static_cast<_Ty1&&>(_Arg1).get().*_Pmd; } }; @@ -1562,9 +1562,9 @@ struct _Invoker_pmd_pointer { static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmd_pointer; template - static constexpr auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept(noexcept((*_STD forward<_Ty1>(_Arg1)).*_Pmd)) - -> decltype((*_STD forward<_Ty1>(_Arg1)).*_Pmd) { - return (*_STD forward<_Ty1>(_Arg1)).*_Pmd; + 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; } }; @@ -1592,79 +1592,81 @@ template struct _Invoker1<_Callable, _Ty1, _Removed_cvref, false, false> : _Invoker_functor {}; // function object template -_CONSTEXPR20 auto invoke(_Callable&& _Obj) noexcept(noexcept(_STD forward<_Callable>(_Obj)())) - -> decltype(_STD forward<_Callable>(_Obj)()) { - return _STD forward<_Callable>(_Obj)(); +_CONSTEXPR20 auto invoke(_Callable&& _Obj) noexcept(noexcept(static_cast<_Callable&&>(_Obj)())) + -> decltype(static_cast<_Callable&&>(_Obj)()) { + return static_cast<_Callable&&>(_Obj)(); } template _CONSTEXPR20 auto invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( - noexcept(_Invoker1<_Callable, _Ty1>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), - _STD forward<_Types2>(_Args2)...))) -> decltype(_Invoker1<_Callable, _Ty1>::_Call(_STD forward<_Callable>(_Obj), - _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...)) { + 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 _STD forward<_Callable>(_Obj)(_STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...); + return static_cast<_Callable&&>(_Obj)(static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...); } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_object) { auto _Pmf = _Obj; - return (_STD forward<_Ty1>(_Arg1).*_Pmf)(_STD forward<_Types2>(_Args2)...); + return (static_cast<_Ty1&&>(_Arg1).*_Pmf)(static_cast<_Types2&&>(_Args2)...); } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_refwrap) { auto _Pmf = _Obj; - return (_STD forward<_Ty1>(_Arg1).get().*_Pmf)(_STD forward<_Types2>(_Args2)...); + return (static_cast<_Ty1&&>(_Arg1).get().*_Pmf)(static_cast<_Types2&&>(_Args2)...); } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_pointer) { auto _Pmf = _Obj; - return ((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(_STD forward<_Types2>(_Args2)...); + return ((*static_cast<_Ty1&&>(_Arg1)).*_Pmf)(static_cast<_Types2&&>(_Args2)...); } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_object) { auto _Pmd = _Obj; - return _STD forward<_Ty1>(_Arg1).*_Pmd; + return static_cast<_Ty1&&>(_Arg1).*_Pmd; } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_refwrap) { auto _Pmd = _Obj; - return _STD forward<_Ty1>(_Arg1).get().*_Pmd; + return static_cast<_Ty1&&>(_Arg1).get().*_Pmd; } else { static_assert(_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in invoke"); auto _Pmd = _Obj; - return (*_STD forward<_Ty1>(_Arg1)).*_Pmd; + return (*static_cast<_Ty1&&>(_Arg1)).*_Pmd; } #else // ^^^ _HAS_IF_CONSTEXPR // !_HAS_IF_CONSTEXPR vvv return _Invoker1<_Callable, _Ty1>::_Call( - _STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...); + static_cast<_Callable&&>(_Obj), static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...); #endif // _HAS_IF_CONSTEXPR } #if _HAS_CXX17 // constexpr IMPLEMENTATION OF invoke template -constexpr auto _C_invoke(_Callable&& _Obj) noexcept(noexcept(_STD forward<_Callable>(_Obj)())) - -> decltype(_STD forward<_Callable>(_Obj)()) { - return _STD forward<_Callable>(_Obj)(); +constexpr auto _C_invoke(_Callable&& _Obj) noexcept(noexcept(static_cast<_Callable&&>(_Obj)())) + -> decltype(static_cast<_Callable&&>(_Obj)()) { + return static_cast<_Callable&&>(_Obj)(); } template constexpr auto _C_invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( - noexcept(_Invoker1<_Callable, _Ty1>::_Call(_STD forward<_Callable>(_Obj), _STD forward<_Ty1>(_Arg1), - _STD forward<_Types2>(_Args2)...))) -> decltype(_Invoker1<_Callable, _Ty1>::_Call(_STD forward<_Callable>(_Obj), - _STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...)) { + 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 constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Functor) { - return _STD forward<_Callable>(_Obj)(_STD forward<_Ty1>(_Arg1), _STD forward<_Types2>(_Args2)...); + return static_cast<_Callable&&>(_Obj)(static_cast<_Ty1&&>(_Arg1), static_cast<_Types2&&>(_Args2)...); } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_object) { auto _Pmf = _Obj; - return (_STD forward<_Ty1>(_Arg1).*_Pmf)(_STD forward<_Types2>(_Args2)...); + return (static_cast<_Ty1&&>(_Arg1).*_Pmf)(static_cast<_Types2&&>(_Args2)...); } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_refwrap) { auto _Pmf = _Obj; - return (_STD forward<_Ty1>(_Arg1).get().*_Pmf)(_STD forward<_Types2>(_Args2)...); + return (static_cast<_Ty1&&>(_Arg1).get().*_Pmf)(static_cast<_Types2&&>(_Args2)...); } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_pointer) { auto _Pmf = _Obj; - return ((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(_STD forward<_Types2>(_Args2)...); + return ((*static_cast<_Ty1&&>(_Arg1)).*_Pmf)(static_cast<_Types2&&>(_Args2)...); } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_object) { auto _Pmd = _Obj; - return _STD forward<_Ty1>(_Arg1).*_Pmd; + return static_cast<_Ty1&&>(_Arg1).*_Pmd; } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_refwrap) { auto _Pmd = _Obj; - return _STD forward<_Ty1>(_Arg1).get().*_Pmd; + return static_cast<_Ty1&&>(_Arg1).get().*_Pmd; } else { static_assert(_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in _C_invoke"); auto _Pmd = _Obj; - return (*_STD forward<_Ty1>(_Arg1)).*_Pmd; + return (*static_cast<_Ty1&&>(_Arg1)).*_Pmd; } } #endif // _HAS_CXX17 @@ -1928,8 +1930,8 @@ public: } template - auto operator()(_Types&&... _Args) const -> decltype(_STD invoke(get(), _STD forward<_Types>(_Args)...)) { - return _STD invoke(get(), _STD forward<_Types>(_Args)...); + auto operator()(_Types&&... _Args) const -> decltype(_STD invoke(get(), static_cast<_Types&&>(_Args)...)) { + return _STD invoke(get(), static_cast<_Types&&>(_Args)...); } private: From 8f38b2f0cc89866f970261cc030ee48e85aa2efc Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 4 Mar 2020 00:35:28 -0800 Subject: [PATCH 06/16] Workaround DevCom-936696 again. --- stl/inc/type_traits | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 1d99fbda3c9..6647158c12c 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1484,6 +1484,8 @@ class reference_wrapper; // implementations. TRANSITION, P1065R2 // 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, @@ -1671,6 +1673,8 @@ constexpr auto _C_invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) no } #endif // _HAS_CXX17 +#pragma warning(pop) // TRANSITION, DevCom-936696 + template > struct _Invoker_ret {}; // helper to give INVOKE an explicit return type; avoids undesirable Expression SFINAE From df0bd58fc502455e9c9cede5c5d3327bd430c484 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 4 Mar 2020 00:58:07 -0800 Subject: [PATCH 07/16] git commit -am "Remove some comments and clang-format." --- stl/inc/type_traits | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 6647158c12c..f8bf020deb4 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1485,7 +1485,7 @@ class reference_wrapper; // FUNCTION TEMPLATE invoke #pragma warning(push) // TRANSITION, DevCom-936696 -#pragma warning(disable: 28278) // Function '%s' appears with no prototype in scope +#pragma warning(disable : 28278) // Function '%s' appears with no prototype in scope enum class _Invoker_strategy { _Functor, _Pmf_object, @@ -1496,7 +1496,7 @@ enum class _Invoker_strategy { _Pmd_pointer }; -struct _Invoker_functor { // INVOKE a function object +struct _Invoker_functor { static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Functor; template @@ -1507,7 +1507,7 @@ struct _Invoker_functor { // INVOKE a function object } }; -struct _Invoker_pmf_object { // INVOKE a pointer to member function on an object +struct _Invoker_pmf_object { static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmf_object; template @@ -1591,7 +1591,7 @@ struct _Invoker1<_Callable, _Ty1, _Removed_cvref, false, true> _Invoker_pmd_pointer>> {}; // pointer to member data template -struct _Invoker1<_Callable, _Ty1, _Removed_cvref, false, false> : _Invoker_functor {}; // function object +struct _Invoker1<_Callable, _Ty1, _Removed_cvref, false, false> : _Invoker_functor {}; template _CONSTEXPR20 auto invoke(_Callable&& _Obj) noexcept(noexcept(static_cast<_Callable&&>(_Obj)())) From ab1e8287a0af14260a037de146181f4da2b17ae0 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 4 Mar 2020 16:02:05 -0800 Subject: [PATCH 08/16] PR feedback: * de-std:: * _C_invoke => _STD invoke * Note that the LWG issue part of P1065R2 is implemented under '17. * Remove decay of _Pmf/_Pmd * PMD noexcept * Remove forwarding of reference_wrapper. * Strengthen noexcept and punch through reference_wrapper. --- stl/inc/tuple | 2 +- stl/inc/type_traits | 105 +++++------------- stl/inc/variant | 8 +- stl/inc/yvals_core.h | 2 + .../test.cpp | 2 +- 5 files changed, 37 insertions(+), 82 deletions(-) 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 f8bf020deb4..bf77837c92a 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1478,10 +1478,9 @@ _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 +// 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 @@ -1521,11 +1520,11 @@ struct _Invoker_pmf_object { struct _Invoker_pmf_refwrap { static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmf_refwrap; - template - static constexpr auto _Call(_Decayed _Pmf, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( - noexcept((static_cast<_Ty1&&>(_Arg1).get().*_Pmf)(static_cast<_Types2&&>(_Args2)...))) - -> decltype((static_cast<_Ty1&&>(_Arg1).get().*_Pmf)(static_cast<_Types2&&>(_Args2)...)) { - return (static_cast<_Ty1&&>(_Arg1).get().*_Pmf)(static_cast<_Types2&&>(_Args2)...); + 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)...); } }; @@ -1544,8 +1543,7 @@ struct _Invoker_pmd_object { static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmd_object; template - static constexpr auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept(noexcept(static_cast<_Ty1&&>(_Arg1).*_Pmd)) - -> decltype(static_cast<_Ty1&&>(_Arg1).*_Pmd) { + static constexpr auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept -> decltype(static_cast<_Ty1&&>(_Arg1).*_Pmd) { return static_cast<_Ty1&&>(_Arg1).*_Pmd; } }; @@ -1553,10 +1551,9 @@ struct _Invoker_pmd_object { struct _Invoker_pmd_refwrap { static constexpr _Invoker_strategy _Strategy = _Invoker_strategy::_Pmd_refwrap; - template - static constexpr auto _Call(_Decayed _Pmd, _Ty1&& _Arg1) noexcept(noexcept(static_cast<_Ty1&&>(_Arg1).get().*_Pmd)) - -> decltype(static_cast<_Ty1&&>(_Arg1).get().*_Pmd) { - return static_cast<_Ty1&&>(_Arg1).get().*_Pmd; + template + static constexpr auto _Call(_Decayed _Pmd, _Refwrap _Rw) noexcept -> decltype(_Rw.get().*_Pmd) { + return _Rw.get().*_Pmd; } }; @@ -1594,13 +1591,13 @@ template struct _Invoker1<_Callable, _Ty1, _Removed_cvref, false, false> : _Invoker_functor {}; template -_CONSTEXPR20 auto invoke(_Callable&& _Obj) noexcept(noexcept(static_cast<_Callable&&>(_Obj)())) +_CONSTEXPR17 auto invoke(_Callable&& _Obj) noexcept(noexcept(static_cast<_Callable&&>(_Obj)())) -> decltype(static_cast<_Callable&&>(_Obj)()) { return static_cast<_Callable&&>(_Obj)(); } template -_CONSTEXPR20 auto invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) noexcept( +_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( @@ -1609,70 +1606,24 @@ _CONSTEXPR20 auto invoke(_Callable&& _Obj, _Ty1&& _Arg1, _Types2&&... _Args2) no 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) { - auto _Pmf = _Obj; - return (static_cast<_Ty1&&>(_Arg1).*_Pmf)(static_cast<_Types2&&>(_Args2)...); + return (static_cast<_Ty1&&>(_Arg1).*_Obj)(static_cast<_Types2&&>(_Args2)...); } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_refwrap) { - auto _Pmf = _Obj; - return (static_cast<_Ty1&&>(_Arg1).get().*_Pmf)(static_cast<_Types2&&>(_Args2)...); + return (_Arg1.get().*_Obj)(static_cast<_Types2&&>(_Args2)...); } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_pointer) { - auto _Pmf = _Obj; - return ((*static_cast<_Ty1&&>(_Arg1)).*_Pmf)(static_cast<_Types2&&>(_Args2)...); + return ((*static_cast<_Ty1&&>(_Arg1)).*_Obj)(static_cast<_Types2&&>(_Args2)...); } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_object) { - auto _Pmd = _Obj; - return static_cast<_Ty1&&>(_Arg1).*_Pmd; + return static_cast<_Ty1&&>(_Arg1).*_Obj; } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_refwrap) { - auto _Pmd = _Obj; - return static_cast<_Ty1&&>(_Arg1).get().*_Pmd; + return _Arg1.get().*_Obj; } else { static_assert(_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in invoke"); - auto _Pmd = _Obj; - return (*static_cast<_Ty1&&>(_Arg1)).*_Pmd; + 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 } - -#if _HAS_CXX17 -// constexpr IMPLEMENTATION OF invoke -template -constexpr auto _C_invoke(_Callable&& _Obj) noexcept(noexcept(static_cast<_Callable&&>(_Obj)())) - -> decltype(static_cast<_Callable&&>(_Obj)()) { - return static_cast<_Callable&&>(_Obj)(); -} - -template -constexpr auto _C_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 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) { - auto _Pmf = _Obj; - return (static_cast<_Ty1&&>(_Arg1).*_Pmf)(static_cast<_Types2&&>(_Args2)...); - } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_refwrap) { - auto _Pmf = _Obj; - return (static_cast<_Ty1&&>(_Arg1).get().*_Pmf)(static_cast<_Types2&&>(_Args2)...); - } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmf_pointer) { - auto _Pmf = _Obj; - return ((*static_cast<_Ty1&&>(_Arg1)).*_Pmf)(static_cast<_Types2&&>(_Args2)...); - } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_object) { - auto _Pmd = _Obj; - return static_cast<_Ty1&&>(_Arg1).*_Pmd; - } else if constexpr (_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_refwrap) { - auto _Pmd = _Obj; - return static_cast<_Ty1&&>(_Arg1).get().*_Pmd; - } else { - static_assert(_Invoker1<_Callable, _Ty1>::_Strategy == _Invoker_strategy::_Pmd_pointer, "bug in _C_invoke"); - auto _Pmd = _Obj; - return (*static_cast<_Ty1&&>(_Arg1)).*_Pmd; - } -} -#endif // _HAS_CXX17 - #pragma warning(pop) // TRANSITION, DevCom-936696 template > @@ -1686,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)...); } }; @@ -1694,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)...); } }; @@ -1702,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)...); } }; @@ -1921,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); } @@ -1934,8 +1885,10 @@ public: } template - auto operator()(_Types&&... _Args) const -> decltype(_STD invoke(get(), static_cast<_Types&&>(_Args)...)) { - return _STD invoke(get(), static_cast<_Types&&>(_Args)...); + auto operator()(_Types&&... _Args) const + noexcept(noexcept(_STD invoke(*this->_Ptr, static_cast<_Types&&>(_Args)...))) + -> decltype(_STD invoke(*this->_Ptr, static_cast<_Types&&>(_Args)...)) { + return _STD invoke(*this->_Ptr, static_cast<_Types&&>(_Args)...); } private: 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/yvals_core.h b/stl/inc/yvals_core.h index 1e167b67ad5..31f5437d54d 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/std/tests/Dev10_729003_bind_reference_wrapper/test.cpp b/tests/std/tests/Dev10_729003_bind_reference_wrapper/test.cpp index ba54f1d0eb3..ea7f59a476a 100644 --- a/tests/std/tests/Dev10_729003_bind_reference_wrapper/test.cpp +++ b/tests/std/tests/Dev10_729003_bind_reference_wrapper/test.cpp @@ -9,7 +9,7 @@ using namespace std; struct A { string meow(int i) { - return "A::meow(" + std::to_string(i + 9 * 9 * 9) + ")"; + return "A::meow(" + to_string(i + 9 * 9 * 9) + ")"; } }; From 47ec84ba512cc0f9ae2fb89fece3ae256c51406d Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 4 Mar 2020 18:22:08 -0800 Subject: [PATCH 09/16] Fix declaration order problem for _Ptr in reference_wrapper, and add tests for the constexpr invoke function. --- stl/inc/type_traits | 13 +-- .../test.cpp | 95 +++++++++++++++++-- 2 files changed, 94 insertions(+), 14 deletions(-) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index bf77837c92a..6f7977dfcfa 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1884,15 +1884,16 @@ public: return *_Ptr; } +private: + _Ty* _Ptr; + +public: template auto operator()(_Types&&... _Args) const - noexcept(noexcept(_STD invoke(*this->_Ptr, static_cast<_Types&&>(_Args)...))) - -> decltype(_STD invoke(*this->_Ptr, static_cast<_Types&&>(_Args)...)) { - return _STD invoke(*this->_Ptr, static_cast<_Types&&>(_Args)...); + 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)...); } - -private: - _Ty* _Ptr; }; #if _HAS_CXX17 diff --git a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp index 7de6c1ff2f0..e8a13c9ea1f 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; } - int product(int z) const { + constexpr int sum_noexcept(int z) const noexcept { + return m_x + m_y + z; + } + + 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,72 @@ void test_reference_wrapper_invocation() { // Test C++17 invoke(). +#if _HAS_CXX17 +constexpr bool test_invoke_constexpr() { + // MSVC++ implements LWG-2894 as a DR back to C++17 + 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); + + assert(invoke(&Thing::sum, *p, 3) == 1023); + // assert(invoke(&Thing::sum, ref(*sp), 4) == 1024); TRANSITION, P1065R2 + assert(invoke(&Thing::sum, p, 5) == 1025); + + 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)); + + 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)); } From e58e3f7ce6d480e06ef57cbb130b0fc8994e7aec Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 4 Mar 2020 19:03:32 -0800 Subject: [PATCH 10/16] Workaround no noexcept in the type system in C++14 and DevCom-939490. --- tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp index e8a13c9ea1f..545fc8c618b 100644 --- a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp +++ b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp @@ -1070,9 +1070,11 @@ constexpr bool test_invoke_constexpr() { // 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); @@ -1122,10 +1124,12 @@ void test_invoke() { 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 } From ad44e886cb36076e19bb50ea2ed73d0645b3558c Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 4 Mar 2020 19:06:34 -0800 Subject: [PATCH 11/16] clang-format --- stl/inc/type_traits | 2 +- tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/type_traits b/stl/inc/type_traits index 6f7977dfcfa..a9a75cc679a 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1891,7 +1891,7 @@ 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)...)) { + -> decltype(_STD invoke(*_Ptr, static_cast<_Types&&>(_Args)...)) { return _STD invoke(*_Ptr, static_cast<_Types&&>(_Args)...); } }; diff --git a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp index 545fc8c618b..1f3533d428b 100644 --- a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp +++ b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp @@ -993,7 +993,7 @@ void test_reference_wrapper_invocation() { assert(i == 10); #ifndef __EDG__ // TRANSITION, DevCom-939485 - const auto noexcept_lambda = []() noexcept {}; + const auto noexcept_lambda = []() noexcept {}; const auto noexcept_lambda_ref = ref(noexcept_lambda); STATIC_ASSERT(noexcept(noexcept_lambda_ref())); // Strengthened #endif // __EDG__ From 45aa3e3a1e8524a41ec8317a3f2b752b1de5e36f Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 5 Mar 2020 01:11:33 -0800 Subject: [PATCH 12/16] More _C_invokes. --- stl/inc/algorithm | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) 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; } From 12913ab2f056c3466bb52f0388494060403e8b5b Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 5 Mar 2020 01:14:06 -0800 Subject: [PATCH 13/16] Strengthened => strengthened. MSVC++ => msvc. --- stl/inc/__msvc_all_public_headers.hpp | 2 +- stl/inc/type_traits | 2 +- tests/libcxx/skipped_tests.txt | 2 +- tests/std/tests/Dev09_158181_tr1_unordered_meow_swap/test.cpp | 2 +- tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp | 4 ++-- tests/std/tests/VSO_0000000_instantiate_containers/test.cpp | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) 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/type_traits b/stl/inc/type_traits index a9a75cc679a..8fb27de97e1 100644 --- a/stl/inc/type_traits +++ b/stl/inc/type_traits @@ -1890,7 +1890,7 @@ private: public: template auto operator()(_Types&&... _Args) const - noexcept(noexcept(_STD invoke(*_Ptr, static_cast<_Types&&>(_Args)...))) // Strengthened + 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)...); } 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..bb888cdd549 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/Dev11_0535636_functional_overhaul/test.cpp b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp index 1f3533d428b..2c1c8be4803 100644 --- a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp +++ b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp @@ -995,7 +995,7 @@ void test_reference_wrapper_invocation() { #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 + STATIC_ASSERT(noexcept(noexcept_lambda_ref())); // strengthened #endif // __EDG__ reference_wrapper rw_fxn(quadruple); @@ -1062,7 +1062,7 @@ void test_reference_wrapper_invocation() { // Test C++17 invoke(). #if _HAS_CXX17 constexpr bool test_invoke_constexpr() { - // MSVC++ implements LWG-2894 as a DR back to C++17 + // MSVC implements LWG-2894 as a DR back to C++17 Thing thing; auto p = &thing; diff --git a/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp b/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp index 786bc27df7c..13b6e5aabe8 100644 --- a/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp +++ b/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp @@ -339,9 +339,9 @@ 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&&)"); forward_list value{}; swap_test(value); From ff9e9f55f3326501310a71a74e9b42c8ce89e370 Mon Sep 17 00:00:00 2001 From: Billy O'Neal Date: Thu, 5 Mar 2020 12:53:40 -0800 Subject: [PATCH 14/16] Casey CR changes Co-Authored-By: Casey Carter --- tests/std/tests/Dev09_158181_tr1_unordered_meow_swap/test.cpp | 2 +- tests/std/tests/VSO_0000000_instantiate_containers/test.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) 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 bb888cdd549..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/VSO_0000000_instantiate_containers/test.cpp b/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp index 13b6e5aabe8..110f43d6728 100644 --- a/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp +++ b/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp @@ -342,6 +342,8 @@ void forward_list_test() { 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&&)"); +static_assert(is_nothrow_move_assignable_v>, + "strengthened noexcept on forward_list& forward_list::operator=(forward_list&&)"); forward_list value{}; swap_test(value); From 765672ae4c76693a5654dcd098d44504baca33d9 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 5 Mar 2020 13:19:37 -0800 Subject: [PATCH 15/16] One more nitpick. --- tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp index 2c1c8be4803..6a0f0f9c0d2 100644 --- a/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp +++ b/tests/std/tests/Dev11_0535636_functional_overhaul/test.cpp @@ -1062,7 +1062,7 @@ void test_reference_wrapper_invocation() { // Test C++17 invoke(). #if _HAS_CXX17 constexpr bool test_invoke_constexpr() { - // MSVC implements LWG-2894 as a DR back to C++17 + // MSVC implements LWG-2894 in C++17 and later Thing thing; auto p = &thing; From 96b9b44bbd3edd09ef79411ef0a1be493dfa6625 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Thu, 5 Mar 2020 13:19:58 -0800 Subject: [PATCH 16/16] clang-format --- tests/std/tests/VSO_0000000_instantiate_containers/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp b/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp index 110f43d6728..657e7b89659 100644 --- a/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp +++ b/tests/std/tests/VSO_0000000_instantiate_containers/test.cpp @@ -342,8 +342,8 @@ void forward_list_test() { 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&&)"); -static_assert(is_nothrow_move_assignable_v>, - "strengthened noexcept on forward_list& forward_list::operator=(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);