[clang] [libc] Add invoke / invoke_result type traits (PR #65750)
Clement Courbet via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 14 05:53:38 PDT 2023
================
@@ -145,6 +145,110 @@ 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;
+};
+
+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) {
+ using namespace invoke_detail;
+ { // member function call
+ A a;
+ EXPECT_EQ(a.state, INIT);
+ invoke(&A::apply, a);
+ EXPECT_EQ(a.state, A_APPLY_CALLED);
+ }
+ { // overriden member function call
+ B b;
+ EXPECT_EQ(b.state, INIT);
+ invoke(&A::apply, b);
+ EXPECT_EQ(b.state, B_APPLY_CALLED);
+ }
+ { // free function
+ 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(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(invoke([]() -> int { return 2; }), 2);
+ EXPECT_EQ(invoke([](int value) -> int { return value; }, 1), 1);
+
+ const auto lambda = [](int) { return 0; };
+ EXPECT_EQ(invoke(lambda, 1), 0);
+ }
+}
+
+TEST(LlvmLibcTypeTraitsTest, invoke_result) {
+ using namespace invoke_detail;
+ 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((is_same_v<invoke_result_t<decltype(lambda)>, void>));
+ }
+ {
+ auto lambda = []() { return 0; };
+ EXPECT_TRUE((is_same_v<invoke_result_t<decltype(lambda)>, int>));
+ }
+ {
+ auto lambda = [](int) -> double { return 0; };
+ EXPECT_TRUE((is_same_v<invoke_result_t<decltype(lambda), int>, double>));
+ }
+}
----------------
legrosbuffle wrote:
We're missing tests for a functor with overloaded types:
```
auto lambda = [](auto a) { return a; };
EXPECT_TRUE((is_same_v<invoke_result_t<decltype(lambda), int>, int>));
EXPECT_TRUE((is_same_v<invoke_result_t<decltype(lambda), double>, double>));
```
maybe also with `auto&` and `auto&&`.
https://github.com/llvm/llvm-project/pull/65750
More information about the cfe-commits
mailing list