blob: d7694d619c692dd0b41792ca2592aae783ce08e8 [file] [log] [blame] [edit]
// 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...));
} // namespace std
template <class... Args>
concept invocable = requires(Args... args) { __builtin_invoke(args...); };
static_assert(!invocable<std::reference_wrapper<InvalidSpecialization1>>);
static_assert(!invocable<std::reference_wrapper<InvalidSpecialization2>>);
void test3() {
__builtin_invoke(diagnose_discard); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
__builtin_invoke(no_diagnose_discard);
}
template <class T>
auto test(T v) {
return __builtin_invoke(v);
}
auto call2() {
test(call);
}
template <class ClassT, class FuncT>
void func(ClassT& c, FuncT&& func) {
__builtin_invoke(func, c, 1, 2, 3); // expected-error {{too many arguments to function call, expected 0, have 3}}
}
struct DependentTest {
void func(int, int, int);
void bad_func();
};
void call3() {
DependentTest d;
func(d, &DependentTest::func);
func(d, &DependentTest::bad_func); // expected-note {{requested here}}
}
constexpr int constexpr_func() {
return 42;
}
struct ConstexprTestStruct {
int i;
constexpr int func() {
return 55;
}
};
// Make sure that constant evaluation works
static_assert([]() {
ConstexprTestStruct s;
if (__builtin_invoke(&ConstexprTestStruct::func, s) != 55) // [func.requires]/p1.1
return false;
if (__builtin_invoke(&ConstexprTestStruct::func, std::ref(s)) != 55) // [func.requires]/p1.2
return false;
if (__builtin_invoke(&ConstexprTestStruct::func, &s) != 55) // [func.requires]/p1.3
return false;
s.i = 22;
if (__builtin_invoke(&ConstexprTestStruct::i, s) != 22) // [func.requires]/p1.4
return false;
if (__builtin_invoke(&ConstexprTestStruct::i, std::ref(s)) != 22) // [func.requires]/p1.5
return false;
if (__builtin_invoke(&ConstexprTestStruct::i, &s) != 22) // [func.requires]/p1.6
return false;
// [func.requires]/p1.7
if (__builtin_invoke(constexpr_func) != 42)
return false;
if (__builtin_invoke([] { return 34; }) != 34)
return false;
return true;
}());