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 @@ -186,16 +186,27 @@ std::forward(params)...); } + template ::type> + static constexpr bool IsCompatible = + std::is_void::value || std::is_convertible::value; + public: function_ref() = default; function_ref(std::nullptr_t) {} template + // Only allow this constructor if the object is actually callable + // and returns the correct type. function_ref( Callable &&callable, std::enable_if_t< + // This is not the copy-constructor. !std::is_same>, - function_ref>::value> * = nullptr) + function_ref>::value && + // Must be callable and return a suitable type. + IsCompatible> * = 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