From 4cae6228d129d4c4dfb156c043977bb6b5690031 Mon Sep 17 00:00:00 2001 From: Sam McCall Date: Tue, 6 Oct 2020 16:35:35 +0200 Subject: [PATCH] [ADT] function_ref's constructor is unavailable if the argument is not callable. This allows overload sets containing function_ref arguments to work correctly Otherwise they're ambiguous as anything "could be" converted to a function_ref. This matches proposed std::function_ref, absl::function_ref, etc. Differential Revision: https://reviews.llvm.org/D88901 --- llvm/include/llvm/ADT/STLExtras.h | 13 ++++++++++++- llvm/lib/AsmParser/LLParser.h | 4 ++-- llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 4 +--- llvm/unittests/ADT/FunctionRefTest.cpp | 11 +++++++++++ 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h index 4be016b795a0..b70a6f9fc381 100644 --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -186,16 +186,27 @@ class function_ref { 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 index a7fbcdd5abc5..5f581f0d4efb 100644 --- a/llvm/lib/AsmParser/LLParser.h +++ b/llvm/lib/AsmParser/LLParser.h @@ -166,8 +166,8 @@ namespace llvm { : 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 index 4d69dd7dcc5d..15ca3a54da2d 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -579,9 +579,7 @@ public: /// \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 index 669b87dbf8e4..f084aa7a660b 100644 --- a/llvm/unittests/ADT/FunctionRefTest.cpp +++ b/llvm/unittests/ADT/FunctionRefTest.cpp @@ -48,4 +48,15 @@ TEST(FunctionRefTest, BadCopy) { 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 -- GitLab