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 @@ -193,9 +193,15 @@ template function_ref( Callable &&callable, + // This is not the copy-constructor. std::enable_if_t< !std::is_same>, - function_ref>::value> * = nullptr) + function_ref>::value> * = nullptr, + // Functor must be callable and return a suitable type. + std::enable_if_t::value || + std::is_convertible< + std::result_of_t, Ret>::value> + * = nullptr) : callback(callback_fn::type>), callable(reinterpret_cast(&callable)) {} diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h --- a/llvm/lib/AsmParser/LLParser.h +++ b/llvm/lib/AsmParser/LLParser.h @@ -166,8 +166,8 @@ : Context(Context), Lex(F, SM, Err, Context), M(M), Index(Index), Slots(Slots), BlockAddressPFS(nullptr) {} bool Run( - bool UpgradeDebugInfo, - DataLayoutCallbackTy DataLayoutCallback = [](Module *) {}); + bool UpgradeDebugInfo, DataLayoutCallbackTy DataLayoutCallback = + [](StringRef) { return None; }); bool parseStandaloneConstantValue(Constant *&C, const SlotMapping *Slots); diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -579,9 +579,7 @@ /// \returns true if an error occurred. Error parseBitcodeInto( Module *M, bool ShouldLazyLoadMetadata = false, bool IsImporting = false, - DataLayoutCallbackTy DataLayoutCallback = [](std::string) { - return None; - }); + DataLayoutCallbackTy DataLayoutCallback = [](StringRef) { return None; }); static uint64_t decodeSignRotatedValue(uint64_t V); 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