diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -190,9 +190,17 @@ function_ref() = default; function_ref(std::nullptr_t) {} - template + template ::value || + std::is_convertible< + typename std::result_of::type, + Ret>::value>::type> function_ref( Callable &&callable, + // This is not a copy-constructor. std::enable_if_t< !std::is_same>, function_ref>::value> * = nullptr) 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 @@ -48,4 +48,15 @@ ASSERT_EQ(1, X()); } +// Test that overloads on function_refs are resolved as expected. +const char *returns(StringRef) { return "not a function"; } +const char *returns(function_ref F) { return "number"; } +const char *returns(function_ref F) { return "string"; } + +TEST(FunctionRefTest, SFINAE) { + EXPECT_EQ("not a function", returns("boo!")); + EXPECT_EQ("number", returns([] { return 42; })); + EXPECT_EQ("string", returns([] { return "hello"; })); +} + } // namespace