[clang] [libc] Add invoke / invoke_result type traits (PR #65750)

Guillaume Chatelet via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 14 04:48:14 PDT 2023


https://github.com/gchatelet updated https://github.com/llvm/llvm-project/pull/65750:

>From 5023264dce58aaa46b18404a4578b7a777962758 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Fri, 8 Sep 2023 13:10:05 +0000
Subject: [PATCH 1/4] [libc] add invoke / invoke_result type traits

---
 libc/src/__support/CPP/CMakeLists.txt         |  2 +
 libc/src/__support/CPP/type_traits.h          |  2 +
 libc/src/__support/CPP/type_traits/invoke.h   | 58 +++++++++++++
 .../__support/CPP/type_traits/invoke_result.h | 26 ++++++
 .../src/__support/CPP/type_traits_test.cpp    | 86 +++++++++++++++++++
 .../llvm-project-overlay/libc/BUILD.bazel     |  3 +
 6 files changed, 177 insertions(+)
 create mode 100644 libc/src/__support/CPP/type_traits/invoke.h
 create mode 100644 libc/src/__support/CPP/type_traits/invoke_result.h

diff --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt
index d24c023ec28ebc9..bb330a7b0ac5106 100644
--- a/libc/src/__support/CPP/CMakeLists.txt
+++ b/libc/src/__support/CPP/CMakeLists.txt
@@ -104,6 +104,8 @@ add_header_library(
     type_traits/enable_if.h
     type_traits/false_type.h
     type_traits/integral_constant.h
+    type_traits/invoke.h
+    type_traits/invoke_result.h
     type_traits/is_arithmetic.h
     type_traits/is_array.h
     type_traits/is_base_of.h
diff --git a/libc/src/__support/CPP/type_traits.h b/libc/src/__support/CPP/type_traits.h
index 9deb08b221593e1..3de2ca58903184c 100644
--- a/libc/src/__support/CPP/type_traits.h
+++ b/libc/src/__support/CPP/type_traits.h
@@ -18,6 +18,8 @@
 #include "src/__support/CPP/type_traits/enable_if.h"
 #include "src/__support/CPP/type_traits/false_type.h"
 #include "src/__support/CPP/type_traits/integral_constant.h"
+#include "src/__support/CPP/type_traits/invoke.h"
+#include "src/__support/CPP/type_traits/invoke_result.h"
 #include "src/__support/CPP/type_traits/is_arithmetic.h"
 #include "src/__support/CPP/type_traits/is_array.h"
 #include "src/__support/CPP/type_traits/is_base_of.h"
diff --git a/libc/src/__support/CPP/type_traits/invoke.h b/libc/src/__support/CPP/type_traits/invoke.h
new file mode 100644
index 000000000000000..e1f661339f349e7
--- /dev/null
+++ b/libc/src/__support/CPP/type_traits/invoke.h
@@ -0,0 +1,58 @@
+//===-- invoke type_traits --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_H
+#define LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_H
+
+#include "src/__support/CPP/type_traits/decay.h"
+#include "src/__support/CPP/type_traits/is_base_of.h"
+#include "src/__support/CPP/utility/forward.h"
+
+// BEWARE : this implementation is not fully conformant as it doesn't take
+// `cpp::reference_wrapper` into account.
+
+namespace __llvm_libc::cpp {
+
+namespace detail {
+
+// Catch all function types.
+template <class FunctionPtrType> struct invoke_dispatcher {
+  template <class... Args>
+  static auto call(FunctionPtrType &&fun, Args &&...args) {
+    return cpp::forward<FunctionPtrType>(fun)(cpp::forward<Args>(args)...);
+  }
+};
+
+// Catch pointer to member function types.
+template <class Class, class FunctionReturnType>
+struct invoke_dispatcher<FunctionReturnType Class::*> {
+  using FunctionPtrType = FunctionReturnType Class::*;
+
+  template <class T, class... Args, class DecayT = cpp::decay_t<T>>
+  static auto call(FunctionPtrType fun, T &&t1, Args &&...args) {
+    if constexpr (cpp::is_base_of_v<Class, DecayT>) {
+      // T is a (possibly cv ref) type.
+      return (cpp::forward<T>(t1).*fun)(cpp::forward<Args>(args)...);
+    } else {
+      // T is assumed to be a pointer type.
+      return (*cpp::forward<T>(t1).*fun)(cpp::forward<Args>(args)...);
+    }
+  }
+};
+
+} // namespace detail
+
+template <class Function, class... Args>
+auto invoke(Function &&fun, Args &&...args) {
+  return detail::invoke_dispatcher<cpp::decay_t<Function>>::call(
+      cpp::forward<Function>(fun), cpp::forward<Args>(args)...);
+}
+
+} // namespace __llvm_libc::cpp
+
+#endif // LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_H
diff --git a/libc/src/__support/CPP/type_traits/invoke_result.h b/libc/src/__support/CPP/type_traits/invoke_result.h
new file mode 100644
index 000000000000000..1a071f5cb94836f
--- /dev/null
+++ b/libc/src/__support/CPP/type_traits/invoke_result.h
@@ -0,0 +1,26 @@
+//===-- invoke_result type_traits -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_RESULT_H
+#define LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_RESULT_H
+
+#include "src/__support/CPP/type_traits/invoke.h"
+#include "src/__support/CPP/utility/declval.h"
+
+namespace __llvm_libc::cpp {
+
+template <class F, class... Args> struct invoke_result {
+  using type =
+      decltype(cpp::invoke(cpp::declval<F>(), cpp::declval<Args>()...));
+};
+
+template <class F, class... Args>
+using invoke_result_t = typename invoke_result<F, Args...>::type;
+
+} // namespace __llvm_libc::cpp
+
+#endif // LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_RESULT_H
diff --git a/libc/test/src/__support/CPP/type_traits_test.cpp b/libc/test/src/__support/CPP/type_traits_test.cpp
index cd025f588388d68..3c1a25b5a1033e9 100644
--- a/libc/test/src/__support/CPP/type_traits_test.cpp
+++ b/libc/test/src/__support/CPP/type_traits_test.cpp
@@ -145,6 +145,92 @@ TEST(LlvmLibcTypeTraitsTest, integral_constant) {
   EXPECT_EQ((integral_constant<int, 4>::value), 4);
 }
 
+namespace invoke_detail {
+
+enum State { INIT = 0, A_APPLY_CALLED, B_APPLY_CALLED };
+
+struct A {
+  State state = INIT;
+  virtual ~A() {}
+  virtual void apply() { state = A_APPLY_CALLED; }
+};
+
+struct B : public A {
+  virtual ~B() {}
+  virtual void apply() { state = B_APPLY_CALLED; }
+};
+
+void free_function() {}
+int free_function_return_5() { return 5; }
+int free_function_passtrough(int value) { return value; }
+
+struct Delegate {
+  int (*ptr)(int) = &free_function_passtrough;
+};
+
+} // namespace invoke_detail
+
+TEST(LlvmLibcTypeTraitsTest, invoke) {
+  using namespace invoke_detail;
+  { // member function call
+    A a;
+    EXPECT_EQ(a.state, INIT);
+    cpp::invoke(&A::apply, a);
+    EXPECT_EQ(a.state, A_APPLY_CALLED);
+  }
+  { // overriden member function call
+    B b;
+    EXPECT_EQ(b.state, INIT);
+    cpp::invoke(&A::apply, b);
+    EXPECT_EQ(b.state, B_APPLY_CALLED);
+  }
+  { // free function
+    cpp::invoke(&free_function);
+    EXPECT_EQ(cpp::invoke(&free_function_return_5), 5);
+    EXPECT_EQ(cpp::invoke(&free_function_passtrough, 1), 1);
+  }
+  { // pointer member function call
+    Delegate d;
+    EXPECT_EQ(cpp::invoke(&Delegate::ptr, d, 2), 2);
+  }
+  { // lambda
+    EXPECT_EQ(cpp::invoke([]() -> int { return 2; }), 2);
+    EXPECT_EQ(cpp::invoke([](int value) -> int { return value; }, 1), 1);
+  }
+}
+
+TEST(LlvmLibcTypeTraitsTest, invoke_result) {
+  using namespace invoke_detail;
+  EXPECT_TRUE(
+      (cpp::is_same_v<cpp::invoke_result_t<decltype(&A::apply), A>, void>));
+  EXPECT_TRUE(
+      (cpp::is_same_v<cpp::invoke_result_t<decltype(&A::apply), B>, void>));
+  EXPECT_TRUE(
+      (cpp::is_same_v<cpp::invoke_result_t<decltype(&free_function)>, void>));
+  EXPECT_TRUE(
+      (cpp::is_same_v<cpp::invoke_result_t<decltype(&free_function_return_5)>,
+                      int>));
+  EXPECT_TRUE((cpp::is_same_v<
+               cpp::invoke_result_t<decltype(&free_function_passtrough), int>,
+               int>));
+  EXPECT_TRUE(
+      (cpp::is_same_v<
+          cpp::invoke_result_t<decltype(&Delegate::ptr), Delegate, int>, int>));
+  {
+    auto lambda = []() {};
+    EXPECT_TRUE((cpp::is_same_v<cpp::invoke_result_t<decltype(lambda)>, void>));
+  }
+  {
+    auto lambda = []() { return 0; };
+    EXPECT_TRUE((cpp::is_same_v<cpp::invoke_result_t<decltype(lambda)>, int>));
+  }
+  {
+    auto lambda = [](int) -> double { return 0; };
+    EXPECT_TRUE(
+        (cpp::is_same_v<cpp::invoke_result_t<decltype(lambda), int>, double>));
+  }
+}
+
 using IntegralAndFloatingTypes =
     testing::TypeList<bool, char, short, int, long, long long, unsigned char,
                       unsigned short, unsigned int, unsigned long,
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 17e4913749d51c6..06cabc015decf30 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -295,6 +295,8 @@ libc_support_library(
         "src/__support/CPP/type_traits/enable_if.h",
         "src/__support/CPP/type_traits/false_type.h",
         "src/__support/CPP/type_traits/integral_constant.h",
+        "src/__support/CPP/type_traits/invoke.h",
+        "src/__support/CPP/type_traits/invoke_result.h",
         "src/__support/CPP/type_traits/is_arithmetic.h",
         "src/__support/CPP/type_traits/is_array.h",
         "src/__support/CPP/type_traits/is_base_of.h",
@@ -333,6 +335,7 @@ libc_support_library(
         "src/__support/CPP/type_traits/type_identity.h",
         "src/__support/CPP/type_traits/void_t.h",
         "src/__support/CPP/utility/declval.h",
+        "src/__support/CPP/utility/forward.h",
     ],
     deps = [
         ":__support_macros_attributes",

>From 61c3889d618fe9695d8ee86ecd8197555bdabb75 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Wed, 13 Sep 2023 13:11:19 +0000
Subject: [PATCH 2/4] Fix missing forwarding reference

---
 libc/src/__support/CPP/type_traits/invoke.h      | 15 ++++++++-------
 libc/test/src/__support/CPP/type_traits_test.cpp |  3 +++
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/libc/src/__support/CPP/type_traits/invoke.h b/libc/src/__support/CPP/type_traits/invoke.h
index e1f661339f349e7..0d66e5655594652 100644
--- a/libc/src/__support/CPP/type_traits/invoke.h
+++ b/libc/src/__support/CPP/type_traits/invoke.h
@@ -10,21 +10,22 @@
 #define LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_H
 
 #include "src/__support/CPP/type_traits/decay.h"
+#include "src/__support/CPP/type_traits/enable_if.h"
 #include "src/__support/CPP/type_traits/is_base_of.h"
+#include "src/__support/CPP/type_traits/is_same.h"
 #include "src/__support/CPP/utility/forward.h"
 
-// BEWARE : this implementation is not fully conformant as it doesn't take
-// `cpp::reference_wrapper` into account.
-
 namespace __llvm_libc::cpp {
 
 namespace detail {
 
-// Catch all function types.
+// Catch all function and functor types.
 template <class FunctionPtrType> struct invoke_dispatcher {
-  template <class... Args>
-  static auto call(FunctionPtrType &&fun, Args &&...args) {
-    return cpp::forward<FunctionPtrType>(fun)(cpp::forward<Args>(args)...);
+  template <class T, class... Args,
+            typename = cpp::enable_if_t<
+                cpp::is_same_v<cpp::decay_t<T>, FunctionPtrType>>>
+  static auto call(T &&fun, Args &&...args) {
+    return cpp::forward<T>(fun)(cpp::forward<Args>(args)...);
   }
 };
 
diff --git a/libc/test/src/__support/CPP/type_traits_test.cpp b/libc/test/src/__support/CPP/type_traits_test.cpp
index 3c1a25b5a1033e9..04ee3aba68e51ea 100644
--- a/libc/test/src/__support/CPP/type_traits_test.cpp
+++ b/libc/test/src/__support/CPP/type_traits_test.cpp
@@ -196,6 +196,9 @@ TEST(LlvmLibcTypeTraitsTest, invoke) {
   { // lambda
     EXPECT_EQ(cpp::invoke([]() -> int { return 2; }), 2);
     EXPECT_EQ(cpp::invoke([](int value) -> int { return value; }, 1), 1);
+
+    const auto lambda = [](int) { return 0; };
+    EXPECT_EQ(cpp::invoke(lambda, 1), 0);
   }
 }
 

>From 74d7f1b76a35967f61dc1a364576b39c11364285 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Wed, 13 Sep 2023 13:42:55 +0000
Subject: [PATCH 3/4] Enforce assumption

---
 libc/src/__support/CPP/CMakeLists.txt         |  1 +
 .../__support/CPP/type_traits/always_false.h  | 25 +++++++++++++++++++
 libc/src/__support/CPP/type_traits/invoke.h   |  8 ++++--
 libc/src/__support/CPP/utility/declval.h      |  8 ++----
 .../llvm-project-overlay/libc/BUILD.bazel     |  1 +
 5 files changed, 35 insertions(+), 8 deletions(-)
 create mode 100644 libc/src/__support/CPP/type_traits/always_false.h

diff --git a/libc/src/__support/CPP/CMakeLists.txt b/libc/src/__support/CPP/CMakeLists.txt
index bb330a7b0ac5106..a2d3bd7df9e9069 100644
--- a/libc/src/__support/CPP/CMakeLists.txt
+++ b/libc/src/__support/CPP/CMakeLists.txt
@@ -95,6 +95,7 @@ add_header_library(
   type_traits
   HDRS
     type_traits.h
+    type_traits/always_false.h
     type_traits/add_lvalue_reference.h
     type_traits/add_pointer.h
     type_traits/add_rvalue_reference.h
diff --git a/libc/src/__support/CPP/type_traits/always_false.h b/libc/src/__support/CPP/type_traits/always_false.h
new file mode 100644
index 000000000000000..84be58d16ec8da6
--- /dev/null
+++ b/libc/src/__support/CPP/type_traits/always_false.h
@@ -0,0 +1,25 @@
+//===-- convenient static_assert(false) helper ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_ALWAYS_FALSE_H
+#define LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_ALWAYS_FALSE_H
+
+#include "src/__support/macros/attributes.h"
+
+namespace __llvm_libc::cpp {
+
+// This is technically not part of the standard but it come often enough that
+// it's convenient to have around.
+//
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2593r0.html#valid-workaround
+
+template <typename...> LIBC_INLINE_VAR constexpr bool always_false = false;
+
+} // namespace __llvm_libc::cpp
+
+#endif // LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_ALWAYS_FALSE_H
diff --git a/libc/src/__support/CPP/type_traits/invoke.h b/libc/src/__support/CPP/type_traits/invoke.h
index 0d66e5655594652..5372a7f60980e23 100644
--- a/libc/src/__support/CPP/type_traits/invoke.h
+++ b/libc/src/__support/CPP/type_traits/invoke.h
@@ -9,9 +9,11 @@
 #ifndef LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_H
 #define LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_H
 
+#include "src/__support/CPP/type_traits/always_false.h"
 #include "src/__support/CPP/type_traits/decay.h"
 #include "src/__support/CPP/type_traits/enable_if.h"
 #include "src/__support/CPP/type_traits/is_base_of.h"
+#include "src/__support/CPP/type_traits/is_pointer.h"
 #include "src/__support/CPP/type_traits/is_same.h"
 #include "src/__support/CPP/utility/forward.h"
 
@@ -39,9 +41,11 @@ struct invoke_dispatcher<FunctionReturnType Class::*> {
     if constexpr (cpp::is_base_of_v<Class, DecayT>) {
       // T is a (possibly cv ref) type.
       return (cpp::forward<T>(t1).*fun)(cpp::forward<Args>(args)...);
-    } else {
-      // T is assumed to be a pointer type.
+    } else if constexpr (cpp::is_pointer_v<T>) {
+      // T is a pointer type.
       return (*cpp::forward<T>(t1).*fun)(cpp::forward<Args>(args)...);
+    } else {
+      static_assert(cpp::always_false<T>);
     }
   }
 };
diff --git a/libc/src/__support/CPP/utility/declval.h b/libc/src/__support/CPP/utility/declval.h
index 9261ceb9332d518..21bb973de0dd048 100644
--- a/libc/src/__support/CPP/utility/declval.h
+++ b/libc/src/__support/CPP/utility/declval.h
@@ -9,17 +9,13 @@
 #define LLVM_LIBC_SRC_SUPPORT_CPP_UTILITY_DECLVAL_H
 
 #include "src/__support/CPP/type_traits/add_rvalue_reference.h"
-#include "src/__support/macros/attributes.h"
+#include "src/__support/CPP/type_traits/always_false.h"
 
 namespace __llvm_libc::cpp {
 
 // declval
-namespace detail {
-template <typename T> LIBC_INLINE_VAR constexpr bool always_false = false;
-}
-
 template <typename T> cpp::add_rvalue_reference_t<T> declval() {
-  static_assert(detail::always_false<T>,
+  static_assert(cpp::always_false<T>,
                 "declval not allowed in an evaluated context");
 }
 
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 06cabc015decf30..80ea75ecd8760e0 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -289,6 +289,7 @@ libc_support_library(
         "src/__support/CPP/type_traits/add_lvalue_reference.h",
         "src/__support/CPP/type_traits/add_pointer.h",
         "src/__support/CPP/type_traits/add_rvalue_reference.h",
+        "src/__support/CPP/type_traits/always_false.h",
         "src/__support/CPP/type_traits/bool_constant.h",
         "src/__support/CPP/type_traits/conditional.h",
         "src/__support/CPP/type_traits/decay.h",

>From 485ecc2040819b0669cf1aa02743412745547c6a Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Thu, 14 Sep 2023 11:38:03 +0000
Subject: [PATCH 4/4] Add tests in the presence of several ref qualifiers

---
 .../__support/CPP/type_traits/invoke_result.h |  8 +--
 .../src/__support/CPP/type_traits_test.cpp    | 71 +++++++++++--------
 2 files changed, 47 insertions(+), 32 deletions(-)

diff --git a/libc/src/__support/CPP/type_traits/invoke_result.h b/libc/src/__support/CPP/type_traits/invoke_result.h
index 1a071f5cb94836f..20ebba4e4cf95cf 100644
--- a/libc/src/__support/CPP/type_traits/invoke_result.h
+++ b/libc/src/__support/CPP/type_traits/invoke_result.h
@@ -9,14 +9,14 @@
 #define LLVM_LIBC_SRC_SUPPORT_CPP_TYPE_TRAITS_INVOKE_RESULT_H
 
 #include "src/__support/CPP/type_traits/invoke.h"
+#include "src/__support/CPP/type_traits/type_identity.h"
 #include "src/__support/CPP/utility/declval.h"
 
 namespace __llvm_libc::cpp {
 
-template <class F, class... Args> struct invoke_result {
-  using type =
-      decltype(cpp::invoke(cpp::declval<F>(), cpp::declval<Args>()...));
-};
+template <class F, class... Args>
+struct invoke_result : cpp::type_identity<decltype(cpp::invoke(
+                           cpp::declval<F>(), cpp::declval<Args>()...))> {};
 
 template <class F, class... Args>
 using invoke_result_t = typename invoke_result<F, Args...>::type;
diff --git a/libc/test/src/__support/CPP/type_traits_test.cpp b/libc/test/src/__support/CPP/type_traits_test.cpp
index 04ee3aba68e51ea..e18004fa4bace0b 100644
--- a/libc/test/src/__support/CPP/type_traits_test.cpp
+++ b/libc/test/src/__support/CPP/type_traits_test.cpp
@@ -168,6 +168,17 @@ struct Delegate {
   int (*ptr)(int) = &free_function_passtrough;
 };
 
+template <int tag> struct Tag {
+  static int value() { return tag; }
+};
+
+struct Functor {
+  auto operator()() & { return Tag<0>(); }
+  auto operator()() const & { return Tag<1>(); }
+  auto operator()() && { return Tag<2>(); }
+  auto operator()() const && { return Tag<3>(); }
+};
+
 } // namespace invoke_detail
 
 TEST(LlvmLibcTypeTraitsTest, invoke) {
@@ -175,62 +186,66 @@ TEST(LlvmLibcTypeTraitsTest, invoke) {
   { // member function call
     A a;
     EXPECT_EQ(a.state, INIT);
-    cpp::invoke(&A::apply, a);
+    invoke(&A::apply, a);
     EXPECT_EQ(a.state, A_APPLY_CALLED);
   }
   { // overriden member function call
     B b;
     EXPECT_EQ(b.state, INIT);
-    cpp::invoke(&A::apply, b);
+    invoke(&A::apply, b);
     EXPECT_EQ(b.state, B_APPLY_CALLED);
   }
   { // free function
-    cpp::invoke(&free_function);
-    EXPECT_EQ(cpp::invoke(&free_function_return_5), 5);
-    EXPECT_EQ(cpp::invoke(&free_function_passtrough, 1), 1);
+    invoke(&free_function);
+    EXPECT_EQ(invoke(&free_function_return_5), 5);
+    EXPECT_EQ(invoke(&free_function_passtrough, 1), 1);
   }
   { // pointer member function call
     Delegate d;
-    EXPECT_EQ(cpp::invoke(&Delegate::ptr, d, 2), 2);
+    EXPECT_EQ(invoke(&Delegate::ptr, d, 2), 2);
+  }
+  { // Functor with several ref qualifier
+    Functor f;
+    const Functor cf;
+    EXPECT_EQ(invoke(f).value(), 0);
+    EXPECT_EQ(invoke(cf).value(), 1);
+    EXPECT_EQ(invoke(move(f)).value(), 2);
+    EXPECT_EQ(invoke(move(cf)).value(), 3);
   }
   { // lambda
-    EXPECT_EQ(cpp::invoke([]() -> int { return 2; }), 2);
-    EXPECT_EQ(cpp::invoke([](int value) -> int { return value; }, 1), 1);
+    EXPECT_EQ(invoke([]() -> int { return 2; }), 2);
+    EXPECT_EQ(invoke([](int value) -> int { return value; }, 1), 1);
 
     const auto lambda = [](int) { return 0; };
-    EXPECT_EQ(cpp::invoke(lambda, 1), 0);
+    EXPECT_EQ(invoke(lambda, 1), 0);
   }
 }
 
 TEST(LlvmLibcTypeTraitsTest, invoke_result) {
   using namespace invoke_detail;
-  EXPECT_TRUE(
-      (cpp::is_same_v<cpp::invoke_result_t<decltype(&A::apply), A>, void>));
-  EXPECT_TRUE(
-      (cpp::is_same_v<cpp::invoke_result_t<decltype(&A::apply), B>, void>));
-  EXPECT_TRUE(
-      (cpp::is_same_v<cpp::invoke_result_t<decltype(&free_function)>, void>));
-  EXPECT_TRUE(
-      (cpp::is_same_v<cpp::invoke_result_t<decltype(&free_function_return_5)>,
-                      int>));
-  EXPECT_TRUE((cpp::is_same_v<
-               cpp::invoke_result_t<decltype(&free_function_passtrough), int>,
-               int>));
-  EXPECT_TRUE(
-      (cpp::is_same_v<
-          cpp::invoke_result_t<decltype(&Delegate::ptr), Delegate, int>, int>));
+  EXPECT_TRUE((is_same_v<invoke_result_t<void (A::*)(), A>, void>));
+  EXPECT_TRUE((is_same_v<invoke_result_t<void (A::*)(), B>, void>));
+  EXPECT_TRUE((is_same_v<invoke_result_t<void (*)()>, void>));
+  EXPECT_TRUE((is_same_v<invoke_result_t<int (*)()>, int>));
+  EXPECT_TRUE((is_same_v<invoke_result_t<int (*)(int), int>, int>));
+  EXPECT_TRUE((
+      is_same_v<invoke_result_t<int (*Delegate::*)(int), Delegate, int>, int>));
+  // Functor with several ref qualifier
+  EXPECT_TRUE((is_same_v<invoke_result_t<Functor &>, Tag<0>>));
+  EXPECT_TRUE((is_same_v<invoke_result_t<Functor const &>, Tag<1>>));
+  EXPECT_TRUE((is_same_v<invoke_result_t<Functor &&>, Tag<2>>));
+  EXPECT_TRUE((is_same_v<invoke_result_t<Functor const &&>, Tag<3>>));
   {
     auto lambda = []() {};
-    EXPECT_TRUE((cpp::is_same_v<cpp::invoke_result_t<decltype(lambda)>, void>));
+    EXPECT_TRUE((is_same_v<invoke_result_t<decltype(lambda)>, void>));
   }
   {
     auto lambda = []() { return 0; };
-    EXPECT_TRUE((cpp::is_same_v<cpp::invoke_result_t<decltype(lambda)>, int>));
+    EXPECT_TRUE((is_same_v<invoke_result_t<decltype(lambda)>, int>));
   }
   {
     auto lambda = [](int) -> double { return 0; };
-    EXPECT_TRUE(
-        (cpp::is_same_v<cpp::invoke_result_t<decltype(lambda), int>, double>));
+    EXPECT_TRUE((is_same_v<invoke_result_t<decltype(lambda), int>, double>));
   }
 }
 



More information about the cfe-commits mailing list