diff --git a/llvm/include/llvm/ADT/STLFunctionalExtras.h b/llvm/include/llvm/ADT/STLFunctionalExtras.h --- a/llvm/include/llvm/ADT/STLFunctionalExtras.h +++ b/llvm/include/llvm/ADT/STLFunctionalExtras.h @@ -56,6 +56,8 @@ // This is not the copy-constructor. std::enable_if_t, function_ref>::value> * = nullptr, + // callable is not convertible to bool + std::enable_if_t::value> * = nullptr, // Functor must be callable and return a suitable type. std::enable_if_t::value || std::is_convertible()( @@ -64,6 +66,28 @@ : callback(callback_fn::type>), callable(reinterpret_cast(&callable)) {} + template + function_ref( + Callable &&callable, + // This is not the copy-constructor. + std::enable_if_t, + function_ref>::value> * = nullptr, + // callable is convertible to bool + std::enable_if_t::value> * = nullptr, + // Functor must be callable and return a suitable type. + std::enable_if_t::value || + std::is_convertible()( + std::declval()...)), + Ret>::value> * = nullptr) + : callback(callback_fn::type>), + callable(reinterpret_cast(&callable)) { + // Handles construction from an empty callable (for example a default + // constructed std::function) and ensure that bool conversion to `false` is + // propagated. + if (!callable) + callback = nullptr; + } + Ret operator()(Params ...params) const { return callback(callable, std::forward(params)...); } diff --git a/llvm/unittests/ADT/FunctionRefTest.cpp b/llvm/unittests/ADT/FunctionRefTest.cpp --- a/llvm/unittests/ADT/FunctionRefTest.cpp +++ b/llvm/unittests/ADT/FunctionRefTest.cpp @@ -59,4 +59,11 @@ EXPECT_EQ("string", returns([] { return "hello"; })); } +TEST(FunctionRefTest, std_function) { + // Check that function_ref constructed from an empty std::function is empty. + std::function f; + function_ref f_ref(f); + ASSERT_FALSE((bool)f_ref); +} + } // namespace