| // RUN: %clang_cc1 -std=c++20 -verify %s |
| // [temp.deduct.p9] |
| // A lambda-expression appearing in a function type or a template parameter is |
| // not considered part of the immediate context for the purposes of template |
| // argument deduction. |
| // [Note: The intent is to avoid requiring implementations to deal with |
| // substitution failure involving arbitrary statements.] |
| template <class T> |
| auto f(T) -> decltype([]() { T::invalid; } ()); |
| void f(...); |
| void test_f() { |
| f(0); // expected-error@-3 {{type 'int' cannot be used prior to '::'}} |
| // expected-note@-1 {{while substituting deduced template arguments}} |
| // expected-note@-5 {{while substituting into a lambda expression here}} |
| } |
| |
| template <class T, unsigned = sizeof([]() { T::invalid; })> |
| void g(T); |
| void g(...); |
| void test_g() { |
| g(0); // expected-error@-4 {{type 'int' cannot be used prior to '::'}} |
| // expected-note@-4 {{in instantiation of default argument}} |
| // expected-note@-2 {{while substituting deduced template arguments}} |
| // expected-note@-7 {{while substituting into a lambda expression here}} |
| } |
| |
| template <class T> |
| auto h(T) -> decltype([x = T::invalid]() { }); |
| void h(...); |
| void test_h() { |
| h(0); // expected-error@-3 {{type 'int' cannot be used prior to '::'}} |
| // expected-note@-1 {{while substituting deduced template arguments}} |
| // expected-note@-5 {{while substituting into a lambda expression here}} |
| } |
| |
| template <class T> |
| auto i(T) -> decltype([]() -> typename T::invalid { }); |
| void i(...); |
| void test_i() { |
| i(0); // expected-error@-3 {{type 'int' cannot be used prior to '::'}} |
| // expected-note@-1 {{while substituting deduced template arguments}} |
| // expected-note@-5 {{while substituting into a lambda expression here}} |
| } |
| |
| |
| // In this example, the lambda itself is not part of an immediate context, but |
| // substitution to the lambda expression succeeds, producing dependent |
| // `decltype(x.invalid)`. The call to the lambda, however, is in the immediate context |
| // and it produces a SFINAE failure. Hence, we pick the second overload |
| // and don't produce any errors. |
| template <class T> |
| auto j(T t) -> decltype([](auto x) -> decltype(x.invalid) { } (t)); // #1 |
| void j(...); // #2 |
| void test_j() { |
| j(0); // deduction fails on #1, calls #2. |
| } |