From 43bbf23bba13e24fdb96fe2031d5487d4daaa6ed Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 17 Mar 2023 02:06:21 +0800 Subject: [PATCH 1/4] Constrain functions used by `std::bind` --- stl/inc/functional | 41 ++++++++++++------ tests/std/test.lst | 1 + .../tests/GH_000952_bind_constraints/env.lst | 4 ++ .../test.compile.pass.cpp | 43 +++++++++++++++++++ 4 files changed, 77 insertions(+), 12 deletions(-) create mode 100644 tests/std/tests/GH_000952_bind_constraints/env.lst create mode 100644 tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp diff --git a/stl/inc/functional b/stl/inc/functional index 69954d4f9c6..dfe0116d628 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,12 @@ 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 +1242,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<_Rx>(static_cast<_VtInvQuals>(*_Self._Small_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + } else { + return _STD invoke<_Rx>(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<_Rx>(static_cast<_VtInvQuals>(*_Self._Large_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + } else { + return _STD invoke<_Rx>(static_cast<_VtInvQuals>(*_Self._Large_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + } } template @@ -1910,7 +1926,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 +1956,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 +1973,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 fc8574d2405..3699981a326 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 00000000000..19f025bd0e6 --- /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 00000000000..e07492f31e8 --- /dev/null +++ b/tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp @@ -0,0 +1,43 @@ +// 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>); + } +} From 31fb7cd392ea1252668aba748f4b2a3012aac2db Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 17 Mar 2023 02:13:49 +0800 Subject: [PATCH 2/4] Fix copy-pasta from unused `invoke_r<_Rx>` --- stl/inc/functional | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/functional b/stl/inc/functional index dfe0116d628..a2c58c0b48b 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -1243,18 +1243,18 @@ template template _NODISCARD _Rx __stdcall _Function_inv_small(const _Move_only_function_data& _Self, _Types&&... _Args) noexcept(_Noex) { if constexpr (is_void_v<_Rx>) { - (void) _STD invoke<_Rx>(static_cast<_VtInvQuals>(*_Self._Small_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + (void) _STD invoke(static_cast<_VtInvQuals>(*_Self._Small_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); } else { - return _STD invoke<_Rx>(static_cast<_VtInvQuals>(*_Self._Small_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + 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) { if constexpr (is_void_v<_Rx>) { - (void) _STD invoke<_Rx>(static_cast<_VtInvQuals>(*_Self._Large_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + (void) _STD invoke(static_cast<_VtInvQuals>(*_Self._Large_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); } else { - return _STD invoke<_Rx>(static_cast<_VtInvQuals>(*_Self._Large_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); + return _STD invoke(static_cast<_VtInvQuals>(*_Self._Large_fn_ptr<_Vt>()), _STD forward<_Types>(_Args)...); } } From a03165a9321f5bd1755cabb121a0b03e73315342 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Fri, 17 Mar 2023 02:28:25 +0800 Subject: [PATCH 3/4] Missed clang-format --- stl/inc/functional | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stl/inc/functional b/stl/inc/functional index a2c58c0b48b..f88728cca79 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -824,8 +824,7 @@ private: _Rx _Do_call(_Types&&... _Args) override { // call wrapped function if constexpr (is_void_v<_Rx>) { (void) _STD invoke(_Callee, _STD forward<_Types>(_Args)...); - } - else { + } else { return _STD invoke(_Callee, _STD forward<_Types>(_Args)...); } } From 7b6c06365ab30efda61a2785437ae43fb16479d3 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 24 Mar 2023 16:57:48 -0700 Subject: [PATCH 4/4] Fix repeated test lines, add a bit more coverage. --- .../tests/GH_000952_bind_constraints/test.compile.pass.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 index e07492f31e8..910117a97f3 100644 --- a/tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp +++ b/tests/std/tests/GH_000952_bind_constraints/test.compile.pass.cpp @@ -13,7 +13,7 @@ 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>); STATIC_ASSERT(!is_convertible_v>); } @@ -21,7 +21,7 @@ void test() { // COMPILE-ONLY 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>); STATIC_ASSERT(!is_convertible_v>); } @@ -38,6 +38,8 @@ void test() { // COMPILE-ONLY 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>); } }