diff --git a/libcxx/include/__functional/bind.h b/libcxx/include/__functional/bind.h --- a/libcxx/include/__functional/bind.h +++ b/libcxx/include/__functional/bind.h @@ -80,7 +80,7 @@ #ifndef _LIBCPP_CXX03_LANG template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& __mu(reference_wrapper<_Tp> __t, _Uj&) { @@ -88,7 +88,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __invoke_of<_Ti&, _Uj...>::type __mu_expand(_Ti& __ti, tuple<_Uj...>& __uj, __tuple_indices<_Indx...>) { @@ -96,7 +96,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __enable_if_t < is_bind_expression<_Ti>::value, @@ -118,7 +118,7 @@ }; template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 typename enable_if < 0 < is_placeholder<_Ti>::value, @@ -131,7 +131,7 @@ } template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 typename enable_if < !is_bind_expression<_Ti>::value && @@ -249,7 +249,7 @@ }; template -inline _LIBCPP_INLINE_VISIBILITY +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 typename __bind_return<_Fp, _BoundArgs, _Args>::type __apply_functor(_Fp& __f, _BoundArgs& __bound_args, __tuple_indices<_Indx...>, _Args&& __args) diff --git a/libcxx/include/__functional/invoke.h b/libcxx/include/__functional/invoke.h --- a/libcxx/include/__functional/invoke.h +++ b/libcxx/include/__functional/invoke.h @@ -474,7 +474,7 @@ struct __invoke_void_return_wrapper { template - _LIBCPP_HIDE_FROM_ABI static _Ret __call(_Args&&... __args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static _Ret __call(_Args&&... __args) { return std::__invoke(std::forward<_Args>(__args)...); } }; @@ -483,7 +483,7 @@ struct __invoke_void_return_wrapper<_Ret, true> { template - _LIBCPP_HIDE_FROM_ABI static void __call(_Args&&... __args) { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 static void __call(_Args&&... __args) { std::__invoke(std::forward<_Args>(__args)...); } }; diff --git a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/PR23141_invoke_not_constexpr.pass.cpp b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/PR23141.pass.cpp rename from libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/PR23141_invoke_not_constexpr.pass.cpp rename to libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/PR23141.pass.cpp --- a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/PR23141_invoke_not_constexpr.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/PR23141.pass.cpp @@ -11,9 +11,9 @@ // // template -// unspecified bind(Fn, Types...); +// unspecified bind(Fn, Types...); // constexpr since C++20 // template -// unspecified bind(Fn, Types...); +// unspecified bind(Fn, Types...); // constexpr since C++20 // https://llvm.org/PR23141 #include @@ -21,18 +21,23 @@ #include "test_macros.h" -struct Fun -{ +struct Fun { template - void operator()(T &&, U &&) const - { + TEST_CONSTEXPR_CXX20 void operator()(T &&, U &&) const { static_assert(std::is_same::value, ""); } }; -int main(int, char**) -{ - std::bind(Fun{}, std::placeholders::_1, 42)("hello"); +TEST_CONSTEXPR_CXX20 bool test() { + std::bind(Fun{}, std::placeholders::_1, 42)("hello"); + return true; +} + +int main(int, char**) { + test(); +#if TEST_STD_VER >= 20 + static_assert(test()); +#endif return 0; } diff --git a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/invoke_int_0.pass.cpp b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/invoke_int_0.pass.cpp --- a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/invoke_int_0.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/invoke_int_0.pass.cpp @@ -11,9 +11,9 @@ // // template -// unspecified bind(Fn, Types...); +// unspecified bind(Fn, Types...); // constexpr since C++20 // template -// unspecified bind(Fn, Types...); +// unspecified bind(Fn, Types...); // constexpr since C++20 #include #include @@ -21,29 +21,25 @@ #include "test_macros.h" template -void -test(F f, R expected) -{ +TEST_CONSTEXPR_CXX20 +void test(F f, R expected) { assert(f() == expected); } template -void -test_const(const F& f, R expected) -{ +TEST_CONSTEXPR_CXX20 +void test_const(const F& f, R expected) { assert(f() == expected); } -int f() {return 1;} +TEST_CONSTEXPR_CXX20 int f() {return 1;} -struct A_int_0 -{ - int operator()() {return 4;} - int operator()() const {return 5;} +struct A_int_0 { + TEST_CONSTEXPR_CXX20 int operator()() {return 4;} + TEST_CONSTEXPR_CXX20 int operator()() const {return 5;} }; -int main(int, char**) -{ +TEST_CONSTEXPR_CXX20 bool test_all() { test(std::bind(f), 1); test(std::bind(&f), 1); test(std::bind(A_int_0()), 4); @@ -53,6 +49,14 @@ test(std::bind(&f), 1); test(std::bind(A_int_0()), 4); test_const(std::bind(A_int_0()), 5); + return true; +} + +int main(int, char**) { + test_all(); +#if TEST_STD_VER >= 20 + static_assert(test_all()); +#endif - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/invoke_lvalue.pass.cpp b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/invoke_lvalue.pass.cpp --- a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/invoke_lvalue.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/invoke_lvalue.pass.cpp @@ -11,9 +11,9 @@ // // template -// unspecified bind(Fn, Types...); +// unspecified bind(Fn, Types...); // constexpr since C++20 // template -// unspecified bind(Fn, Types...); +// unspecified bind(Fn, Types...); // constexpr since C++20 #include @@ -140,27 +140,22 @@ // 1 arg, return int -int f_int_1(int i) -{ +TEST_CONSTEXPR_CXX20 int f_int_1(int i) { return i + 1; } -struct A_int_1 -{ - A_int_1() : data_(5) {} - int operator()(int i) - { +struct A_int_1 { + TEST_CONSTEXPR_CXX20 A_int_1() : data_(5) {} + TEST_CONSTEXPR_CXX20 int operator()(int i) { return i - 1; } - int mem1() {return 3;} - int mem2() const {return 4;} + TEST_CONSTEXPR_CXX20 int mem1() { return 3; } + TEST_CONSTEXPR_CXX20 int mem2() const { return 4; } int data_; }; -void -test_int_1() -{ +TEST_CONSTEXPR_CXX20 bool test_int_1() { using namespace std::placeholders; // function { @@ -212,6 +207,8 @@ std::bind(&A_int_1::data_, _1)(ap) = 7; assert(std::bind(&A_int_1::data_, _1)(ap) == 7); } + + return true; } // 2 arg, return void @@ -263,31 +260,45 @@ } } -struct TFENode -{ - bool foo(unsigned long long) const - { +struct ConstQualifiedMemberFunction { + TEST_CONSTEXPR_CXX20 bool foo(unsigned long long) const { return true; } }; -void -test3() -{ +TEST_CONSTEXPR_CXX20 bool test_const_qualified_member() { using namespace std; using namespace std::placeholders; - const auto f = bind(&TFENode::foo, _1, 0UL); - const TFENode n = TFENode{}; + const auto f = bind(&ConstQualifiedMemberFunction::foo, _1, 0UL); + const ConstQualifiedMemberFunction n = ConstQualifiedMemberFunction{}; bool b = f(n); assert(b); + return true; } -int main(int, char**) -{ +TEST_CONSTEXPR_CXX20 bool test_many_args() { + using namespace std::placeholders; + auto f = [](int& a, char&, float&, long&) -> int& { return a; }; + auto bound = std::bind(f, _4, _3, _2, _1); + int a = 3; char b = '2'; float c = 1.0f; long d = 0l; + int& result = bound(d, c, b, a); + assert(&result == &a); + return true; +} + +int main(int, char**) { test_void_1(); test_int_1(); test_void_2(); - test3(); + test_const_qualified_member(); + test_many_args(); + + // The other tests are not constexpr-friendly since they need to use a global variable +#if TEST_STD_VER >= 20 + static_assert(test_int_1()); + static_assert(test_const_qualified_member()); + static_assert(test_many_args()); +#endif - return 0; + return 0; } diff --git a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/invoke_rvalue.pass.cpp b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/invoke_rvalue.pass.cpp --- a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/invoke_rvalue.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/invoke_rvalue.pass.cpp @@ -11,9 +11,9 @@ // // template -// unspecified bind(Fn, Types...); +// unspecified bind(Fn, Types...); // constexpr since C++20 // template -// unspecified bind(Fn, Types...); +// unspecified bind(Fn, Types...); // constexpr since C++20 #include @@ -130,27 +130,22 @@ // 1 arg, return int -int f_int_1(int i) -{ +TEST_CONSTEXPR_CXX20 int f_int_1(int i) { return i + 1; } -struct A_int_1 -{ - A_int_1() : data_(5) {} - int operator()(int i) - { +struct A_int_1 { + TEST_CONSTEXPR_CXX20 A_int_1() : data_(5) {} + TEST_CONSTEXPR_CXX20 int operator()(int i) { return i - 1; } - int mem1() {return 3;} - int mem2() const {return 4;} + TEST_CONSTEXPR_CXX20 int mem1() { return 3; } + TEST_CONSTEXPR_CXX20 int mem2() const { return 4; } int data_; }; -void -test_int_1() -{ +TEST_CONSTEXPR_CXX20 bool test_int_1() { using namespace std::placeholders; // function { @@ -196,6 +191,7 @@ std::bind(&A_int_1::data_, _1)(&a) = 7; assert(std::bind(&A_int_1::data_, _1)(&a) == 7); } + return true; } // 2 arg, return void @@ -244,28 +240,39 @@ } } -int f_nested(int i) -{ +TEST_CONSTEXPR_CXX20 int f_nested(int i) { return i+1; } -int g_nested(int i) -{ +TEST_CONSTEXPR_CXX20 int g_nested(int i) { return i*10; } -void test_nested() -{ +TEST_CONSTEXPR_CXX20 bool test_nested() { using namespace std::placeholders; assert(std::bind(f_nested, std::bind(g_nested, _1))(3) == 31); + return true; } -int main(int, char**) -{ +TEST_CONSTEXPR_CXX20 bool test_many_args() { + using namespace std::placeholders; + auto f = [](int a, char, float, long) { return a; }; + auto bound = std::bind(f, _4, _3, _2, _1); + assert(bound(0l, 1.0f, '2', 3) == 3); + return true; +} + +int main(int, char**) { test_void_1(); test_int_1(); test_void_2(); test_nested(); - return 0; + // The other tests are not constexpr-friendly since they need to use a global variable +#if TEST_STD_VER >= 20 + static_assert(test_int_1()); + static_assert(test_nested()); +#endif + + return 0; } diff --git a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/nested.pass.cpp b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/nested.pass.cpp --- a/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/nested.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/bind/func.bind/func.bind.bind/nested.pass.cpp @@ -11,45 +11,45 @@ // // template -// unspecified bind(Fn, Types...); +// unspecified bind(Fn, Types...); // constexpr since C++20 // template -// unspecified bind(Fn, Types...); +// unspecified bind(Fn, Types...); // constexpr since C++20 // https://llvm.org/PR16343 -#include #include #include #include "test_macros.h" -struct power -{ +struct multiply { template - T - operator()(T a, T b) - { - return static_cast(std::pow(a, b)); + TEST_CONSTEXPR_CXX20 T operator()(T a, T b) { + return a * b; } }; -struct plus_one -{ +struct plus_one { template - T - operator()(T a) - { + TEST_CONSTEXPR_CXX20 T operator()(T a) { return a + 1; } }; -int main(int, char**) -{ - using std::placeholders::_1; +TEST_CONSTEXPR_CXX20 bool test() { + using std::placeholders::_1; + auto g = std::bind(multiply(), 2, _1); + assert(g(5) == 10); + assert(std::bind(plus_one(), g)(5) == 11); - auto g = std::bind(power(), 2, _1); - assert(g(5) == 32); - assert(std::bind(plus_one(), g)(5) == 33); + return true; +} + +int main(int, char**) { + test(); +#if TEST_STD_VER >= 20 + static_assert(test()); +#endif return 0; }