llvm/clang/test/SemaCXX/lambda-unevaluated.cpp

// RUN: %clang_cc1 -std=c++20 %s -Wno-c++23-extensions -verify
// RUN: %clang_cc1 -std=c++23 %s -verify


template <auto> struct Nothing {};
Nothing<[]() { return 0; }()> nothing;

template <typename> struct NothingT {};
Nothing<[]() { return 0; }> nothingT;

template <typename T>
concept True = [] { return true; }();
static_assert(True<int>);

static_assert(sizeof([] { return 0; }));
static_assert(sizeof([] { return 0; }()));

void f()  noexcept(noexcept([] { return 0; }()));

using a = decltype([] { return 0; });
using b = decltype([] { return 0; }());
using c = decltype([]() noexcept(noexcept([] { return 0; }())) { return 0; });
using d = decltype(sizeof([] { return 0; }));

template <auto T>
int unique_test1();
static_assert(&unique_test1<[](){}> != &unique_test1<[](){}>);

template <class T>
auto g(T) -> decltype([]() { T::invalid; } ());
auto e = g(0); // expected-error@-1{{type 'int' cannot be used prior to '::'}}
               // expected-note@-1{{while substituting deduced template}}
               // expected-note@-3{{while substituting into a lambda}}
               // expected-error@-3 {{no matching function for call to 'g'}}
               // expected-note@-5 {{substitution failure}}

template <typename T>
auto foo(decltype([] {
  return [] { return T(); }();
})) {}

void test() {
  foo<int>({});
}

template <typename T>
struct C {
  template <typename U>
  auto foo(decltype([] {
    return [] { return T(); }();
  })) {}
};

void test2() {
  C<int>{}.foo<long>({});
}

namespace PR52073 {
// OK, these are distinct functions not redefinitions.
template<typename> void f(decltype([]{})) {} // expected-note {{candidate}}
template<typename> void f(decltype([]{})) {} // expected-note {{candidate}}
void use_f() { f<int>({}); } // expected-error {{ambiguous}}

// Same.
template<int N> void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}}
template<int N> void g(const char (*)[([]{ return N; })()]) {} // expected-note {{candidate}}
void use_g() { g<6>(&"hello"); } // expected-error {{ambiguous}}
}

namespace GH51416 {

template <class T>
struct A { // #defined-here-A
  void spam(decltype([] {}));
};

template <class T>
void A<T>::spam(decltype([] {})) // expected-error{{out-of-line definition of 'spam' does not match}}
                                 // expected-note@#defined-here-A{{defined here}}
{}

struct B { // #defined-here-B
  template <class T>
  void spam(decltype([] {}));
};

template <class T>
void B::spam(decltype([] {})) {} // expected-error{{out-of-line definition of 'spam' does not match}}
                                 // expected-note@#defined-here-B{{defined here}}

} // namespace GH51416

namespace GH50376 {

template <typename T, typename Fn>
struct foo_t {    // expected-note 2{{candidate constructor}}
  foo_t(T ptr) {} // expected-note{{candidate constructor}}
};

template <typename T>
using alias = foo_t<T, decltype([](int) { return 0; })>;

template <typename T>
auto fun(T const &t) -> alias<T> {
  return alias<T>{t}; // expected-error{{no viable conversion from returned value of type 'alias<...>'}}
}

void f() {
  int i;
  auto const error = fun(i); // expected-note{{in instantiation}}
}

} // namespace GH50376

namespace GH51414 {
template <class T> void spam(decltype([] {}) (*s)[sizeof(T)] = nullptr) {}
void foo() {
  spam<int>();
}
} // namespace GH51414

namespace GH51641 {
template <class T>
void foo(decltype(+[](T) {}) lambda, T param);
static_assert(!__is_same(decltype(foo<int>), void));
} // namespace GH51641

namespace StaticLambdas {
template <auto> struct Nothing {};
Nothing<[]() static { return 0; }()> nothing;

template <typename> struct NothingT {};
Nothing<[]() static { return 0; }> nothingT;

template <typename T>
concept True = [] static { return true; }();
static_assert(True<int>);

static_assert(sizeof([] static { return 0; }));
static_assert(sizeof([] static { return 0; }()));

void f()  noexcept(noexcept([] static { return 0; }()));

using a = decltype([] static { return 0; });
using b = decltype([] static { return 0; }());
using c = decltype([]() static noexcept(noexcept([] { return 0; }())) { return 0; });
using d = decltype(sizeof([] static { return 0; }));

}

namespace lambda_in_trailing_decltype {
auto x = ([](auto) -> decltype([] {}()) {}(0), 2);
}

namespace lambda_in_constraints {
struct WithFoo { static void foo(); };

template <class T>
concept lambda_works = requires {
    []() { T::foo(); }; // expected-error{{type 'int' cannot be used prior to '::'}}
                        // expected-note@-1{{while substituting into a lambda expression here}}
                        // expected-note@-2{{in instantiation of requirement here}}
                        // expected-note@-4{{while substituting template arguments into constraint expression here}}
};

static_assert(!lambda_works<int>); // expected-note {{while checking the satisfaction of concept 'lambda_works<int>' requested here}}
static_assert(lambda_works<WithFoo>);

template <class T>
int* func(T) requires requires { []() { T::foo(); }; }; // expected-error{{type 'int' cannot be used prior to '::'}}
                                                        // expected-note@-1{{while substituting into a lambda expression here}}
                                                        // expected-note@-2{{in instantiation of requirement here}}
                                                        // expected-note@-3{{while substituting template arguments into constraint expression here}}
double* func(...);

static_assert(__is_same(decltype(func(0)), double*)); // expected-note {{while checking constraint satisfaction for template 'func<int>' required here}}
                                                      // expected-note@-1 {{in instantiation of function template specialization 'lambda_in_constraints::func<int>'}}
static_assert(__is_same(decltype(func(WithFoo())), int*));

template <class T>
auto direct_lambda(T) -> decltype([] { T::foo(); }) {}
void direct_lambda(...) {}

void recursive() {
    direct_lambda(0); // expected-error@-4 {{type 'int' cannot be used prior to '::'}}
                      // expected-note@-1 {{while substituting deduced template arguments}}
                      // expected-note@-6 {{while substituting into a lambda}}
    bool x = requires { direct_lambda(0); }; // expected-error@-7 {{type 'int' cannot be used prior to '::'}}
                                             // expected-note@-1 {{while substituting deduced template arguments}}
                                             // expected-note@-9 {{while substituting into a lambda}}

}
}

// GH63845: Test if we have skipped past RequiresExprBodyDecls in tryCaptureVariable().
namespace GH63845 {

template <bool> struct A {};

struct true_type {
  constexpr operator bool() noexcept { return true; }
};

constexpr bool foo() {
  true_type x{};
  return requires { typename A<x>; };
}

static_assert(foo());

} // namespace GH63845

// GH69307: Test if we can correctly handle param decls that have yet to get into the function scope.
namespace GH69307 {

constexpr auto ICE() {
  constexpr auto b = 1;
  return [=](auto c) -> int
           requires requires { b + c; }
  { return 1; };
};

constexpr auto Ret = ICE()(1);

} // namespace GH69307

// GH88081: Test if we evaluate the requires expression with lambda captures properly.
namespace GH88081 {

// Test that ActOnLambdaClosureQualifiers() is called only once.
void foo(auto value)
  requires requires { [&] -> decltype(value) {}; }
  // expected-error@-1 {{non-local lambda expression cannot have a capture-default}}
{}

struct S { //#S
  S(auto value) //#S-ctor
  requires requires { [&] -> decltype(value) { return 2; }; } {} // #S-requires

  static auto foo(auto value) -> decltype([&]() -> decltype(value) {}()) { return {}; } // #S-foo

  // FIXME: 'value' does not constitute an ODR use here. Add a diagnostic for it.
  static auto bar(auto value) -> decltype([&] { return value; }()) {
    return "a"; // #bar-body
  }
};

S s("a"); // #use
// expected-error@#S-requires {{cannot initialize return object of type 'decltype(value)' (aka 'const char *') with an rvalue of type 'int'}}
// expected-error@#use {{no matching constructor}}
// expected-note@#S-requires {{substituting into a lambda expression here}}
// expected-note@#S-requires {{substituting template arguments into constraint expression here}}
// expected-note@#S-requires {{in instantiation of requirement here}}
// expected-note@#use {{checking constraint satisfaction for template 'S<const char *>' required here}}
// expected-note@#use {{requested here}}
// expected-note-re@#S 2{{candidate constructor {{.*}} not viable}}
// expected-note@#S-ctor {{constraints not satisfied}}
// expected-note-re@#S-requires {{because {{.*}} would be invalid}}

void func() {
  S::foo(42);
  S::bar("str");
  S::bar(0.618);
  // expected-error-re@#bar-body {{cannot initialize return object of type {{.*}} (aka 'double') with an lvalue of type 'const char[2]'}}
  // expected-note@-2 {{requested here}}
}

} // namespace GH88081