[libcxx-commits] [clang] [libcxx] [Clang] Add __builtin_invoke and use it in libc++ (PR #116709)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Jun 29 09:38:47 PDT 2025
================
@@ -0,0 +1,240 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s -std=c++23
+
+void func() { // expected-note {{'func' declared here}}
+ __builtin_invoke(); // expected-error {{too few arguments to function call, expected at least 1, have 0}}
+}
+
+void nfunc() noexcept {}
+
+struct S {};
+void argfunc(int, S) {} // expected-note {{'argfunc' declared here}}
+
+struct Callable {
+ void operator()() {}
+
+ void func() {}
+
+ int var;
+};
+
+void* malloc(decltype(sizeof(int)));
+
+template <class T>
+struct pointer_wrapper {
+ T* v;
+
+ T& operator*() {
+ return *v;
+ }
+};
+
+namespace std {
+ template <class T>
+ class reference_wrapper {
+ T* ptr;
+
+ public:
+ constexpr reference_wrapper(T& ref) : ptr(&ref) {}
+
+ constexpr T& get() { return *ptr; }
+ };
+
+ template <class T>
+ constexpr reference_wrapper<T> ref(T& v) {
+ return reference_wrapper<T>(v);
+ }
+} // namespace std
+
+struct InvalidSpecialization1 {
+ void func() {}
+
+ int var;
+};
+
+template <>
+class std::reference_wrapper<InvalidSpecialization1> {
+public:
+ reference_wrapper(InvalidSpecialization1&) {}
+};
+
+struct InvalidSpecialization2 {
+ void func() {}
+
+ int var;
+};
+
+template <>
+class std::reference_wrapper<InvalidSpecialization2> {
+public:
+ reference_wrapper(InvalidSpecialization2&) {}
+
+private:
+ InvalidSpecialization2& get(); // expected-note 2 {{declared private here}}
+};
+
+struct ExplicitObjectParam {
+ void func(this const ExplicitObjectParam& self) {}
+};
+
+struct Incomplete; // expected-note 2 {{forward declaration}}
+struct Incomplete2;
+
+void incomplete_by_val_test(Incomplete);
+
+void incomplete_test(Incomplete& incomplete) {
+ __builtin_invoke((int (Incomplete2::*)){}, incomplete); // expected-error {{incomplete type 'Incomplete' used in type trait expression}} \
+ expected-error {{indirection requires pointer operand ('Incomplete' invalid)}}
+ __builtin_invoke(incomplete_test, incomplete);
+ __builtin_invoke(incomplete_by_val_test, incomplete); // expected-error {{argument type 'Incomplete' is incomplete}}
+}
+
+void call() {
+ __builtin_invoke(func);
+ __builtin_invoke(nfunc);
+ static_assert(!noexcept(__builtin_invoke(func)));
+ static_assert(noexcept(__builtin_invoke(nfunc)));
+ __builtin_invoke(func, 1); // expected-error {{too many arguments to function call, expected 0, have 1}}
+ __builtin_invoke(argfunc, 1); // expected-error {{too few arguments to function call, expected 2, have 1}}
+ __builtin_invoke(Callable{});
+ __builtin_invoke(malloc, 0);
+ __builtin_invoke(__builtin_malloc, 0); // expected-error {{builtin functions must be directly called}}
+
+ // Variadic function
+ void variadic_func(int, ...); // expected-note {{declared here}}
+
+ __builtin_invoke(variadic_func); // expected-error {{too few arguments to function call, expected at least 1, have 0}}
+ __builtin_invoke(variadic_func, 1);
+ __builtin_invoke(variadic_func, 1, 2, 3);
+
+ // static member function
+ struct StaticMember {
+ static void func(int);
+ };
+
+ __builtin_invoke(StaticMember::func, 1);
+ StaticMember sm;
+ __builtin_invoke(sm.func, 1);
+
+ // lambda
+ __builtin_invoke([] {});
+ __builtin_invoke([](int) {}, 1);
+
+ // Member function pointer
+ __builtin_invoke(&Callable::func); // expected-error {{too few arguments to function call, expected at least 2, have 1}}
+ __builtin_invoke(&Callable::func, 1); // expected-error {{indirection requires pointer operand ('int' invalid)}}
+ __builtin_invoke(&Callable::func, Callable{});
+ __builtin_invoke(&Callable::func, Callable{}, 1); // expected-error {{too many arguments to function call, expected 0, have 1}}
+ __builtin_invoke(&ExplicitObjectParam::func, ExplicitObjectParam{});
+
+ Callable c;
+ __builtin_invoke(&Callable::func, &c);
+ __builtin_invoke(&Callable::func, std::ref(c));
+ __builtin_invoke(&Callable::func, &c);
+ __builtin_invoke(&Callable::func, &c, 2); // expected-error {{too many arguments to function call, expected 0, have 1}}
+ __builtin_invoke(&Callable::func, pointer_wrapper<Callable>{&c});
+ __builtin_invoke(&Callable::func, pointer_wrapper<Callable>{&c}, 2); // expected-error {{too many arguments to function call, expected 0, have 1}}
+
+ InvalidSpecialization1 is1;
+ InvalidSpecialization2 is2;
+ __builtin_invoke(&InvalidSpecialization1::func, std::ref(is1)); // expected-error {{no member named 'get' in 'std::reference_wrapper<InvalidSpecialization1>'}}
+ __builtin_invoke(&InvalidSpecialization2::func, std::ref(is2)); // expected-error {{'get' is a private member of 'std::reference_wrapper<InvalidSpecialization2>'}}
+
+ // Member data pointer
+ __builtin_invoke(&Callable::var); // expected-error {{too few arguments to function call, expected at least 2, have 1}}
+ __builtin_invoke(&Callable::var, 1); // expected-error {{indirection requires pointer operand ('int' invalid)}}
+ (void)__builtin_invoke(&Callable::var, Callable{});
+ __builtin_invoke(&Callable::var, Callable{}, 1); // expected-error {{too many arguments to function call, expected 2, have 3}}
+
+ (void)__builtin_invoke(&Callable::var, &c);
+ (void)__builtin_invoke(&Callable::var, std::ref(c));
+ (void)__builtin_invoke(&Callable::var, &c);
+ __builtin_invoke(&Callable::var, &c, 2); // expected-error {{too many arguments to function call, expected 2, have 3}}
+ (void)__builtin_invoke(&Callable::var, pointer_wrapper<Callable>{&c});
+ __builtin_invoke(&Callable::var, pointer_wrapper<Callable>{&c}, 2); // expected-error {{too many arguments to function call, expected 2, have 3}}
+
+ __builtin_invoke(&InvalidSpecialization1::var, std::ref(is1)); // expected-error {{no member named 'get' in 'std::reference_wrapper<InvalidSpecialization1>'}}
+ (void)__builtin_invoke(&InvalidSpecialization2::var, std::ref(is2)); // expected-error {{'get' is a private member of 'std::reference_wrapper<InvalidSpecialization2>'}}
+}
+
+[[nodiscard]] int diagnose_discard();
+int no_diagnose_discard();
+
+namespace std {
+ template <class... Args>
+ auto invoke(Args&&... args) -> decltype(__builtin_invoke(args...));
----------------
EricWF wrote:
Is this used anywhere in the tests?
https://github.com/llvm/llvm-project/pull/116709
More information about the libcxx-commits
mailing list