diff --git a/stl/inc/functional b/stl/inc/functional index 69954d4f9c..f88728cca7 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -647,7 +647,8 @@ struct _Unforced { // tag to distinguish bind() from bind() // helper to give INVOKE an explicit return type; avoids undesirable Expression SFINAE template struct _Invoker_ret { // selected for all _Rx other than _Unforced - template + template ::template _Is_invocable_r<_Rx>::value, int> = 0> static _CONSTEXPR20 _Rx _Call(_Fx&& _Func, _Valtys&&... _Vals) noexcept(_Select_invoke_traits<_Fx, _Valtys...>::template _Is_nothrow_invocable_r<_Rx>::value) { // INVOKE, implicitly converted if constexpr (is_void_v<_Rx>) { @@ -760,7 +761,11 @@ private: } _Rx _Do_call(_Types&&... _Args) override { // call wrapped function - return _Invoker_ret<_Rx>::_Call(_Mypair._Myval2, _STD forward<_Types>(_Args)...); + if constexpr (is_void_v<_Rx>) { + (void) _STD invoke(_Mypair._Myval2, _STD forward<_Types>(_Args)...); + } else { + return _STD invoke(_Mypair._Myval2, _STD forward<_Types>(_Args)...); + } } const type_info& _Target_type() const noexcept override { @@ -817,7 +822,11 @@ private: } _Rx _Do_call(_Types&&... _Args) override { // call wrapped function - return _Invoker_ret<_Rx>::_Call(_Callee, _STD forward<_Types>(_Args)...); + if constexpr (is_void_v<_Rx>) { + (void) _STD invoke(_Callee, _STD forward<_Types>(_Args)...); + } else { + return _STD invoke(_Callee, _STD forward<_Types>(_Args)...); + } } const type_info& _Target_type() const noexcept override { @@ -1232,14 +1241,20 @@ template template _NODISCARD _Rx __stdcall _Function_inv_small(const _Move_only_function_data& _Self, _Types&&... _Args) noexcept(_Noex) { - return _Invoker_ret<_Rx>::_Call( - static_cast<_VtInvQuals>(*_Self._Small_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + if constexpr (is_void_v<_Rx>) { + (void) _STD invoke(static_cast<_VtInvQuals>(*_Self._Small_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + } else { + return _STD invoke(static_cast<_VtInvQuals>(*_Self._Small_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + } } template _NODISCARD _Rx __stdcall _Function_inv_large(const _Move_only_function_data& _Self, _Types&&... _Args) noexcept(_Noex) { - return _Invoker_ret<_Rx>::_Call( - static_cast<_VtInvQuals>(*_Self._Large_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + if constexpr (is_void_v<_Rx>) { + (void) _STD invoke(static_cast<_VtInvQuals>(*_Self._Large_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + } else { + return _STD invoke(static_cast<_VtInvQuals>(*_Self._Large_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + } } template @@ -1910,7 +1925,8 @@ struct _Select_fixer<_Cv_TiD, true, false, 0> { // reference_wrapper fixer template struct _Select_fixer<_Cv_TiD, false, true, 0> { // nested bind fixer - template + template )>...>, int> = 0> static constexpr auto _Apply(_Cv_TiD& _Tid, _Untuple&& _Ut, index_sequence<_Jx...>) noexcept( noexcept(_Tid(_STD get<_Jx>(_STD move(_Ut))...))) -> decltype(_Tid(_STD get<_Jx>(_STD move(_Ut))...)) { // call a nested bind expression @@ -1939,7 +1955,7 @@ template struct _Select_fixer<_Cv_TiD, false, false, _Jx> { // placeholder fixer static_assert(_Jx > 0, "invalid is_placeholder value"); - template + template ), int> = 0> static constexpr auto _Fix(_Cv_TiD&, _Untuple&& _Ut) noexcept -> decltype(_STD get<_Jx - 1>(_STD move(_Ut))) { // choose the Jth unbound argument (1-based indexing) return _STD get<_Jx - 1>(_STD move(_Ut)); @@ -1956,10 +1972,10 @@ constexpr auto _Fix_arg(_Cv_TiD& _Tid, _Untuple&& _Ut) noexcept( template _CONSTEXPR20 auto _Call_binder(_Invoker_ret<_Ret>, index_sequence<_Ix...>, _Cv_FD& _Obj, _Cv_tuple_TiD& _Tpl, _Untuple&& _Ut) noexcept(noexcept(_Invoker_ret<_Ret>::_Call(_Obj, - _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...))) - -> decltype(_Invoker_ret<_Ret>::_Call(_Obj, _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...)) { + _STD _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...))) + -> decltype(_Invoker_ret<_Ret>::_Call(_Obj, _STD _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...)) { // bind() and bind() invocation - return _Invoker_ret<_Ret>::_Call(_Obj, _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...); + return _Invoker_ret<_Ret>::_Call(_Obj, _STD _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...); } template diff --git a/tests/std/test.lst b/tests/std/test.lst index fc8574d240..3699981a32 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -174,6 +174,7 @@ tests\GH_000690_overaligned_function tests\GH_000890_pow_template tests\GH_000935_complex_numerical_accuracy tests\GH_000940_missing_valarray_copy +tests\GH_000952_bind_constraints tests\GH_000990_any_link_without_exceptions tests\GH_001001_random_rejection_rounding tests\GH_001010_filesystem_error_encoding diff --git a/tests/std/tests/GH_000952_bind_constraints/env.lst b/tests/std/tests/GH_000952_bind_constraints/env.lst new file mode 100644 index 0000000000..19f025bd0e --- /dev/null +++ b/tests/std/tests/GH_000952_bind_constraints/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp b/tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp new file mode 100644 index 0000000000..910117a97f --- /dev/null +++ b/tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) + +using namespace std; + +void test() { // COMPILE-ONLY + { + auto lambda = [](int) {}; + auto f = bind(lambda, placeholders::_1); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(is_convertible_v>); + STATIC_ASSERT(!is_convertible_v>); + } + { + auto lambda = [](int) { return 42; }; + auto f = bind(lambda, placeholders::_1); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(is_convertible_v>); + STATIC_ASSERT(!is_convertible_v>); + } + { + auto lambda = [](int) { return 42; }; + auto f = bind(lambda, placeholders::_1); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(is_convertible_v>); + STATIC_ASSERT(is_convertible_v>); + } + { + auto lambda0 = [](int, int) { return true; }; + auto lambda1 = [](const char*) { return 0; }; + auto f = bind(lambda0, placeholders::_1, bind(lambda1, placeholders::_2)); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(!is_convertible_v>); + STATIC_ASSERT(is_convertible_v>); + STATIC_ASSERT(is_convertible_v>); + } +}