[llvm] 9ebc837 - [ADT] Add SFINAE guards to unique_function constructor.

Sam McCall via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 17 01:36:28 PST 2021


Author: Sam McCall
Date: 2021-02-17T10:36:07+01:00
New Revision: 9ebc837f555249759c538338ffdbf7463e1b6a77

URL: https://github.com/llvm/llvm-project/commit/9ebc837f555249759c538338ffdbf7463e1b6a77
DIFF: https://github.com/llvm/llvm-project/commit/9ebc837f555249759c538338ffdbf7463e1b6a77.diff

LOG: [ADT] Add SFINAE guards to unique_function constructor.

We can't construct a working unique_function from an object that's not callable
with the right types, so don't allow deduction to succeed.
This avoids some ambiguous conversion cases, e.g. allowing to overload
on different unique_function types, and to conversion operators to
unique_function.

std::function and the any_invocable proposal have these.
This was added to llvm::function_ref in D88901 and followups

Differential Revision: https://reviews.llvm.org/D96794

Added: 
    

Modified: 
    llvm/include/llvm/ADT/FunctionExtras.h
    llvm/unittests/ADT/FunctionExtrasTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ADT/FunctionExtras.h b/llvm/include/llvm/ADT/FunctionExtras.h
index c0a05bfc09db..da19d14e464b 100644
--- a/llvm/include/llvm/ADT/FunctionExtras.h
+++ b/llvm/include/llvm/ADT/FunctionExtras.h
@@ -59,6 +59,15 @@ template <typename T>
 using EnableIfTrivial =
     std::enable_if_t<llvm::is_trivially_move_constructible<T>::value &&
                      std::is_trivially_destructible<T>::value>;
+template <typename CallableT, typename ThisT>
+using EnableUnlessSameType = std::enable_if_t<!std::is_same<
+    std::remove_cv_t<std::remove_reference_t<CallableT>>, ThisT>::value>;
+template <typename CallableT, typename Ret, typename... Params>
+using EnableIfCallable =
+    std::enable_if_t<std::is_void<Ret>::value ||
+                     std::is_convertible<decltype(std::declval<CallableT>()(
+                                             std::declval<Params>()...)),
+                                         Ret>::value>;
 
 template <typename ReturnT, typename... ParamTs> class UniqueFunctionBase {
 protected:
@@ -346,7 +355,10 @@ class unique_function<R(P...)> : public detail::UniqueFunctionBase<R, P...> {
   unique_function &operator=(const unique_function &) = delete;
 
   template <typename CallableT>
-  unique_function(CallableT Callable)
+  unique_function(
+      CallableT Callable,
+      detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
+      detail::EnableIfCallable<CallableT, R, P...> * = nullptr)
       : Base(std::forward<CallableT>(Callable),
              typename Base::template CalledAs<CallableT>{}) {}
 
@@ -369,7 +381,10 @@ class unique_function<R(P...) const>
   unique_function &operator=(const unique_function &) = delete;
 
   template <typename CallableT>
-  unique_function(CallableT Callable)
+  unique_function(
+      CallableT Callable,
+      detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
+      detail::EnableIfCallable<const CallableT, R, P...> * = nullptr)
       : Base(std::forward<CallableT>(Callable),
              typename Base::template CalledAs<const CallableT>{}) {}
 

diff  --git a/llvm/unittests/ADT/FunctionExtrasTest.cpp b/llvm/unittests/ADT/FunctionExtrasTest.cpp
index 2ae0d1813858..8eb0d9be7d93 100644
--- a/llvm/unittests/ADT/FunctionExtrasTest.cpp
+++ b/llvm/unittests/ADT/FunctionExtrasTest.cpp
@@ -262,4 +262,15 @@ TEST(UniqueFunctionTest, Const) {
   EXPECT_EQ("const", X());
 }
 
+// Test that overloads on unique_functions are resolved as expected.
+std::string returns(StringRef) { return "not a function"; }
+std::string returns(unique_function<double()> F) { return "number"; }
+std::string returns(unique_function<StringRef()> F) { return "string"; }
+
+TEST(UniqueFunctionTest, SFINAE) {
+  EXPECT_EQ("not a function", returns("boo!"));
+  EXPECT_EQ("number", returns([] { return 42; }));
+  EXPECT_EQ("string", returns([] { return "hello"; }));
+}
+
 } // anonymous namespace


        


More information about the llvm-commits mailing list