ilya-biryukov updated this revision to Diff 517550.
ilya-biryukov marked 5 inline comments as done.
ilya-biryukov added a comment.

- Add a note when substituting into a lambda
- Quote the standard and add explanation for the test


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D148802/new/

https://reviews.llvm.org/D148802

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Frontend/FrontendActions.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
  clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
  clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
  clang/test/CXX/temp/temp.deduct/p9.cpp
  clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
  clang/test/PCH/cxx1y-init-captures.cpp
  clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
  clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
  clang/test/SemaCXX/cxx1y-init-captures.cpp
  clang/test/SemaCXX/cxx1z-lambda-star-this.cpp
  clang/test/SemaCXX/cxx20-decomposition.cpp
  clang/test/SemaCXX/lambda-expressions.cpp
  clang/test/SemaCXX/lambda-pack-expansion.cpp
  clang/test/SemaCXX/lambda-unevaluated.cpp
  clang/test/SemaCXX/vartemplate-lambda.cpp
  clang/test/SemaCXX/warn-unused-lambda-capture.cpp
  clang/test/SemaTemplate/concepts.cpp
  clang/test/SemaTemplate/cxx1z-using-declaration.cpp
  clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
  clang/test/SemaTemplate/instantiate-local-class.cpp
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1024,11 +1024,7 @@
     <tr>
       <td>Lambdas in unevaluated contexts</td>
       <td><a href="https://wg21.link/p0315r4";>P0315R4</a></td>
-      <td class="partial" align="center">
-        <details><summary>Partial</summary>
-          temp.deduct/9 is not implemented yet.
-        </details>
-      </td>
+      <td class="full" align="center">Clang 17</td>
     </tr>
     <!-- Jacksonville papers -->
     <tr>
Index: clang/test/SemaTemplate/instantiate-local-class.cpp
===================================================================
--- clang/test/SemaTemplate/instantiate-local-class.cpp
+++ clang/test/SemaTemplate/instantiate-local-class.cpp
@@ -473,7 +473,8 @@
   template <typename T> void bar() {
     auto lambda = [](T a = "") {}; // expected-error {{conversion function from 'const char[1]' to 'rdar23721638::A' invokes a deleted function}} \
                                    // expected-note  {{in instantiation of default function argument expression for 'operator()<rdar23721638::A>' required here}} \
-                                   // expected-note  {{passing argument to parameter 'a' here}}
+                                   // expected-note  {{passing argument to parameter 'a' here}} \
+                                   // expected-note {{while substituting into a lambda}}
     lambda();
   }
   template void bar<A>(); // expected-note {{in instantiation}}
@@ -496,6 +497,7 @@
   // expected-error@-1 {{cannot initialize a parameter of type 'int' with an rvalue of type 'std::nullptr_t'}}
   // expected-note@-2  {{in instantiation of default function argument expression for 'operator()<int>' required here}}
   // expected-note@-3  {{passing argument to parameter 'x' here}}
+  // expected-note@-4  {{while substituting into a lambda}}
 
   void g() { f<int>(); }
   // expected-note@-1 {{in instantiation of default function argument expression for 'f<int>' required here}}
Index: clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
===================================================================
--- clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
+++ clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
@@ -160,7 +160,7 @@
     consume([]() noexcept(sizeof(T) == 4) {} ...);
   }
   template<bool ...B> void j() {
-    consume([](void (*p)() noexcept(B)) {
+    consume([](void (*p)() noexcept(B)) { // expected-note {{substituting into a lambda}}
       void (*q)() noexcept = p; // expected-error {{not superset of source}}
     } ...);
   }
Index: clang/test/SemaTemplate/cxx1z-using-declaration.cpp
===================================================================
--- clang/test/SemaTemplate/cxx1z-using-declaration.cpp
+++ clang/test/SemaTemplate/cxx1z-using-declaration.cpp
@@ -157,7 +157,7 @@
 
 // Test partial substitution into class-scope pack.
 template<typename ...T> auto lambda1() {
-  return [](auto x) {
+  return [](auto x) { // expected-note 1+{{substituting into a lambda}}
     struct A : T::template X<decltype(x)>... { // expected-note 1+{{instantiation of}}
       using T::template X<decltype(x)>::f ...;
       using typename T::template X<decltype(x)>::type ...;
Index: clang/test/SemaTemplate/concepts.cpp
===================================================================
--- clang/test/SemaTemplate/concepts.cpp
+++ clang/test/SemaTemplate/concepts.cpp
@@ -119,7 +119,7 @@
     []() -> C<T> auto{ return T(); }(); // expected-error {{expression contains unexpanded parameter pack 'T'}}
   }
   template<typename ...T> void g5() {
-    ([]() -> C<T> auto{ // expected-error-re {{deduced type {{.*}} does not satisfy}}
+    ([]() -> C<T> auto{ // expected-error-re {{deduced type {{.*}} does not satisfy}} expected-note {{while substituting into a lambda}}
      return T();
      }(), ...);
   }
Index: clang/test/SemaCXX/warn-unused-lambda-capture.cpp
===================================================================
--- clang/test/SemaCXX/warn-unused-lambda-capture.cpp
+++ clang/test/SemaCXX/warn-unused-lambda-capture.cpp
@@ -145,38 +145,38 @@
   auto explicit_by_value_used_generic = [i](auto c) { return i + 1; };
   auto explicit_by_value_used_void = [i] { (void)i; };
 
-  auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
-  auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
-  auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}}
-  auto explicit_by_value_unused_const = [k] { return k + 1; };         // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
-  auto explicit_by_value_unused_const_generic = [k](auto c) { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
+  auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}}
+  auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}} expected-note {{substituting into a lambda}}
+  auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}}
+  auto explicit_by_value_unused_const = [k] { return k + 1; };         // expected-warning{{lambda capture 'k' is not required to be captured for this use}} expected-note {{substituting into a lambda}}
+  auto explicit_by_value_unused_const_generic = [k](auto c) { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}} expected-note {{substituting into a lambda}}
 
   auto explicit_by_reference_used = [&i] { i++; };
-  auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}}
+  auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}}
 
   auto explicit_initialized_reference_used = [&j = i] { return j + 1; };
-  auto explicit_initialized_reference_unused = [&j = i]{}; // expected-warning{{lambda capture 'j' is not used}}
+  auto explicit_initialized_reference_unused = [&j = i]{}; // expected-warning{{lambda capture 'j' is not used}} expected-note {{substituting into a lambda}}
 
   auto explicit_initialized_value_used = [j = 1] { return j + 1; };
-  auto explicit_initialized_value_unused = [j = 1] {}; // expected-warning{{lambda capture 'j' is not used}}
+  auto explicit_initialized_value_unused = [j = 1] {}; // expected-warning{{lambda capture 'j' is not used}} expected-note {{substituting into a lambda}}
   auto explicit_initialized_value_non_trivial_constructor = [j = NonTrivialConstructor()]{};
   auto explicit_initialized_value_non_trivial_destructor = [j = NonTrivialDestructor()]{};
-  auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}}
+  auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}} expected-note {{substituting into a lambda}}
   auto explicit_initialized_value_non_trivial_init = [j = Trivial(42)]{};
   auto explicit_initialized_value_with_side_effect = [j = side_effect()]{};
   auto explicit_initialized_value_generic_used = [i = 1](auto c) mutable { i++; };
-  auto explicit_initialized_value_generic_unused = [i = 1](auto c) mutable {}; // expected-warning{{lambda capture 'i' is not used}}
+  auto explicit_initialized_value_generic_unused = [i = 1](auto c) mutable {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}}
 
-  auto nested = [&i] {
+  auto nested = [&i] { // expected-note {{substituting into a lambda}}
     auto explicit_by_value_used = [i] { return i + 1; };
-    auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
+    auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}}
   };
 
   Trivial trivial;
-  auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}}
+  auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}} expected-note {{substituting into a lambda}}
 
   NonTrivialConstructor cons;
-  auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}}
+  auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}} expected-note {{substituting into a lambda}}
 
   NonTrivialCopyConstructor copy_cons;
   auto explicit_by_value_non_trivial_copy_constructor = [copy_cons] {};
@@ -189,7 +189,7 @@
 }
 
 void test_use_template() {
-  test_templated<int>(); // expected-note{{in instantiation of function template specialization 'test_templated<int>' requested here}}
+  test_templated<int>(); // expected-note 13{{in instantiation of function template specialization 'test_templated<int>' requested here}}
 }
 
 namespace pr35555 {
Index: clang/test/SemaCXX/vartemplate-lambda.cpp
===================================================================
--- clang/test/SemaCXX/vartemplate-lambda.cpp
+++ clang/test/SemaCXX/vartemplate-lambda.cpp
@@ -8,6 +8,7 @@
 // expected-error@-1{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}}
 // expected-note@-2{{in instantiation of default function argument expression for 'operator()<int *>' required here}}
 // expected-note@-3{{passing argument to parameter 'a' here}}
+// expected-note@-4{{substituting into a lambda}}
 
 struct S {
   template<class T>
Index: clang/test/SemaCXX/lambda-unevaluated.cpp
===================================================================
--- clang/test/SemaCXX/lambda-unevaluated.cpp
+++ clang/test/SemaCXX/lambda-unevaluated.cpp
@@ -28,8 +28,11 @@
 
 template <class T>
 auto g(T) -> decltype([]() { T::invalid; } ());
-auto e = g(0); // expected-error{{no matching function for call}}
-// expected-note@-2 {{substitution failure}}
+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([] {
@@ -146,3 +149,36 @@
 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(); };
+};
+
+static_assert(!lambda_works<int>);
+static_assert(lambda_works<WithFoo>);
+
+template <class T>
+int* func(T) requires requires { []() { T::foo(); }; };
+double* func(...);
+
+static_assert(__is_same(decltype(func(0)), double*));
+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}}
+
+}
+}
Index: clang/test/SemaCXX/lambda-pack-expansion.cpp
===================================================================
--- clang/test/SemaCXX/lambda-pack-expansion.cpp
+++ clang/test/SemaCXX/lambda-pack-expansion.cpp
@@ -8,6 +8,7 @@
 
 void take_by_copy(auto &...args) {
   [...args = args] {}(); // expected-error {{call to deleted constructor}}
+                         // expected-note@-1 {{substituting into a lambda}}
 }
 
 void take_by_ref(auto &...args) {
Index: clang/test/SemaCXX/lambda-expressions.cpp
===================================================================
--- clang/test/SemaCXX/lambda-expressions.cpp
+++ clang/test/SemaCXX/lambda-expressions.cpp
@@ -260,10 +260,11 @@
     f([&ts] { return (int)f(ts...); } ()...); // \
     // expected-error 2{{'ts' cannot be implicitly captured}} \
     // expected-note 2{{lambda expression begins here}} \
-    // expected-note 4 {{capture 'ts' by}}
+    // expected-note 4 {{capture 'ts' by}} \
+    // expected-note 2 {{while substituting into a lambda}}
   }
   template void nested2(int); // ok
-  template void nested2(int, int); // expected-note {{in instantiation of}}
+  template void nested2(int, int); // expected-note 2 {{in instantiation of}}
 }
 
 namespace PR13860 {
@@ -383,7 +384,7 @@
 namespace PR18473 {
   template<typename T> void f() {
     T t(0);
-    (void) [=]{ int n = t; }; // expected-error {{deleted}}
+    (void) [=]{ int n = t; }; // expected-error {{deleted}} expected-note {{while substituting into a lambda}}
   }
 
   template void f<int>();
@@ -466,7 +467,7 @@
   void f(T t) {
     // expected-error@+2 {{type 'int' cannot be used prior to '::' because it has no members}}
     // expected-error@+1 {{no member named 'ns' in 'error_in_transform_prototype::S'}}
-    auto x = [](typename T::ns::type &k) {};
+    auto x = [](typename T::ns::type &k) {}; // expected-note 2 {{while substituting into a lambda}}
   }
   class S {};
   void foo() {
Index: clang/test/SemaCXX/cxx20-decomposition.cpp
===================================================================
--- clang/test/SemaCXX/cxx20-decomposition.cpp
+++ clang/test/SemaCXX/cxx20-decomposition.cpp
@@ -177,7 +177,8 @@
     (void)[&b](auto c) { return b + [](auto) {   // expected-note 3{{lambda expression begins here}} \
                                                  // expected-note 6{{capture 'a'}} \
                                                  // expected-note 6{{default capture}} \
-                                                 // expected-note {{in instantiation}}
+                                                 // expected-note {{in instantiation}} \
+                                                 // expected-note {{while substituting into a lambda}}
         return a;  // expected-error 3{{variable 'a' cannot be implicitly captured}}
     }(0); }(0); // expected-note 2{{in instantiation}}
   }
Index: clang/test/SemaCXX/cxx1z-lambda-star-this.cpp
===================================================================
--- clang/test/SemaCXX/cxx1z-lambda-star-this.cpp
+++ clang/test/SemaCXX/cxx1z-lambda-star-this.cpp
@@ -46,7 +46,7 @@
   template <class T = int>
   void foo() {
     (void)[this] { return x; };
-    (void)[*this] { return x; }; //expected-error2{{call to deleted}}
+    (void)[*this] { return x; }; //expected-error2{{call to deleted}} expected-note {{while substituting into a lambda}}
   }
 
   B() = default;
@@ -63,7 +63,7 @@
 public:
   template <class T = int>
   auto foo() {
-    const auto &L = [*this](auto a) mutable { //expected-error{{call to deleted}}
+    const auto &L = [*this](auto a) mutable { //expected-error{{call to deleted}} expected-note {{while substituting into a lambda}}
       d += a;
       return [this](auto b) { return d += b; };
     };
Index: clang/test/SemaCXX/cxx1y-init-captures.cpp
===================================================================
--- clang/test/SemaCXX/cxx1y-init-captures.cpp
+++ clang/test/SemaCXX/cxx1y-init-captures.cpp
@@ -21,17 +21,17 @@
                     return a;
                   }() ...);
                 };                 
-    auto N2 = [x = y, //expected-note3{{begins here}} expected-note 6 {{default capture by}}
+    auto N2 = [x = y, //expected-note3{{begins here}} expected-note 6 {{default capture by}} expected-note 2 {{substituting into a lambda}}
                 &z = y, n = f(t...), 
                 o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...)](T& ... s) { // expected-note 6 {{capture 't' by}}
-                fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}}
+                fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}} expected-note 2{{substituting into a lambda}}
                     return a;
                   }() ...);
                 };                 
 
   }
 
-  void h(int i, char c) { g(i, c); } //expected-note{{in instantiation}}
+  void h(int i, char c) { g(i, c); } //expected-note 2{{in instantiation}}
 }
 
 namespace odr_use_within_init_capture {
@@ -117,7 +117,7 @@
   }
   { // will need to capture x in outer lambda
     const T x = 10; //expected-note {{declared}}
-    auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}}
+    auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}} expected-note {{substituting into a lambda}}
       auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}}
         return y;
       };
@@ -145,7 +145,7 @@
   }
   { // will need to capture x in outer lambda
     const int x = 10; //expected-note {{declared}}
-    auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}}
+    auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}} expected-note {{substituting into a lambda}}
       auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}}
         return y;
       };
@@ -164,7 +164,7 @@
   return 0;
 }
 
-int run = test(); //expected-note {{instantiation}}
+int run = test(); //expected-note 2 {{instantiation}}
 
 }
 
Index: clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
===================================================================
--- clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
+++ clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
@@ -259,7 +259,7 @@
 {
   int i = 10; //expected-note 3{{declared here}}
   auto L = [](auto a) {
-    return [](auto b) { //expected-note 3{{begins here}} expected-note 6 {{capture 'i' by}} expected-note 6 {{default capture by}}
+    return [](auto b) { //expected-note 3{{begins here}} expected-note 6 {{capture 'i' by}} expected-note 6 {{default capture by}} expected-note {{while substituting into a lambda}}
       i = b;  //expected-error 3{{cannot be implicitly captured}}
       return b;
     };
Index: clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
===================================================================
--- clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
+++ clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
@@ -563,8 +563,8 @@
   
   int g() {
     auto L = [=](auto a) {
-      return [](int i) { // expected-note {{explicitly capture 'this'}}
-        return [=](auto b) {
+      return [](int i) { // expected-note {{explicitly capture 'this'}} expected-note {{while substituting into a lambda}}
+        return [=](auto b) { // expected-note {{while substituting into a lambda}}
           f(decltype(a){}); //expected-error{{this}}
           int x = i;
         };
@@ -587,8 +587,8 @@
   
   int g() {
     auto L = [=](auto a) {
-      return [](auto b) { // expected-note {{explicitly capture 'this'}}
-        return [=](int i) {
+      return [](auto b) { // expected-note {{explicitly capture 'this'}} expected-note {{while substituting into a lambda}}
+        return [=](int i) { // expected-note {{while substituting into a lambda}}
           f(b); 
           f(decltype(a){}); //expected-error{{this}}
         };
@@ -612,7 +612,7 @@
   int g() {
     auto L = [=](auto a) {
       return [](auto b) { // expected-note {{explicitly capture 'this'}}
-        return [=](int i) {
+        return [=](int i) { // expected-note {{while substituting into a lambda}}
           f(b); //expected-error{{this}}
           f(decltype(a){}); 
         };
Index: clang/test/PCH/cxx1y-init-captures.cpp
===================================================================
--- clang/test/PCH/cxx1y-init-captures.cpp
+++ clang/test/PCH/cxx1y-init-captures.cpp
@@ -25,6 +25,7 @@
 void g() {
   f(0); // ok
   // expected-error@18 {{lvalue of type 'const char *const'}}
+  // expected-note@18 {{substituting into a lambda}}
   f("foo"); // expected-note {{here}}
 }
 
Index: clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
===================================================================
--- clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
+++ clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
@@ -141,6 +141,7 @@
     B() {
       consume([]{
         int arr[Vs]; // expected-error {{negative size}}
+                     // expected-note@-2 {{while substituting into a lambda expression here}}
       }...);
     }
   };
Index: clang/test/CXX/temp/temp.deduct/p9.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/temp/temp.deduct/p9.cpp
@@ -0,0 +1,56 @@
+// 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.
+}
Index: clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
===================================================================
--- clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
+++ clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
@@ -80,6 +80,7 @@
     [](auto x) {
       if constexpr (sizeof(T) == 1 && sizeof(x) == 1)
         T::error(); // expected-error 2{{'::'}}
+                    // expected-note@-3 2{{while substituting into a lambda expression here}}
     } (0);
   }
 
@@ -88,6 +89,7 @@
       if constexpr (sizeof(T) == 1)
         if constexpr (sizeof(x) == 1)
           T::error(); // expected-error {{'::'}}
+                      // expected-note@-4 {{while substituting into a lambda expression here}}
     } (0);
   }
 
Index: clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
===================================================================
--- clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
@@ -54,6 +54,7 @@
 template <typename T>
 void test_result_type_tpl(int N) {
   auto l1 = []() -> T {}; // expected-error{{incomplete result type 'Incomplete' in lambda expression}}
+                          // expected-note@-1{{while substituting into a lambda expression here}}
   typedef int vla[N];
   auto l2 = []() -> vla {}; // expected-error{{function cannot return array type 'vla' (aka 'int[N]')}}
 }
Index: clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
===================================================================
--- clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
@@ -85,6 +85,7 @@
 template<typename ...Args>
 void init_capture_pack_multi(Args ...args) {
   [as(args...)] {} (); // expected-error {{initializer missing for lambda capture 'as'}} expected-error {{multiple}}
+                       // expected-note@-1 2{{while substituting into a lambda expression}}
 }
 template void init_capture_pack_multi(); // expected-note {{instantiation}}
 template void init_capture_pack_multi(int);
Index: clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
===================================================================
--- clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
@@ -35,6 +35,7 @@
 template<typename T> void init_kind_template() {
   auto init_kind_1 = [ec(T())] {};
   auto init_kind_2 = [ec = T()] {}; // expected-error {{no matching constructor}}
+                                    // expected-note@-1 {{while substituting into a lambda expression here}}
 }
 template void init_kind_template<int>();
 template void init_kind_template<ExplicitCopy>(); // expected-note {{instantiation of}}
@@ -52,6 +53,7 @@
 auto bad_init_7 = [a{{1}}] {}; // expected-error {{cannot deduce type for lambda capture 'a' from nested initializer list}}
 
 template<typename...T> void pack_1(T...t) { (void)[a(t...)] {}; } // expected-error {{initializer missing for lambda capture 'a'}}
+                                                                  // expected-note@-1 {{while substituting into a lambda expression here}}
 template void pack_1<>(); // expected-note {{instantiation of}}
 
 // No lifetime-extension of the temporary here.
@@ -74,6 +76,7 @@
 
 template<typename T> T instantiate_test(T t) {
   [x(&t)]() { *x = 1; } (); // expected-error {{assigning to 'const char *'}}
+                            // expected-note@-1 {{while substituting into a lambda expression here}}
   return t;
 }
 int instantiate_test_1 = instantiate_test(0);
Index: clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
===================================================================
--- clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
+++ clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
@@ -35,7 +35,8 @@
 template<typename T>
 void defargs_in_template_unused(T t) {
   auto l1 = [](const T& value = T()) { };  // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} \
-                                           // expected-note {{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' required here}}
+                                           // expected-note {{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' required here}} \
+                                           // expected-note {{while substituting into a lambda expression here}}
   l1(t);
 }
 
@@ -45,7 +46,8 @@
 template<typename T>
 void defargs_in_template_used() {
   auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} \
-                                          // expected-note {{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' required here}}
+                                          // expected-note {{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' required here}} \
+                                          // expected-note {{while substituting into a lambda expression here}}
   l1();
 }
 
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -34,6 +34,7 @@
 #include "clang/Sema/Template.h"
 #include "clang/Sema/TemplateDeduction.h"
 #include "clang/Sema/TemplateInstCallback.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/TimeProfiler.h"
 #include <optional>
@@ -367,6 +368,7 @@
   case InitializingStructuredBinding:
   case MarkingClassDllexported:
   case BuildingBuiltinDumpStructCall:
+  case LambdaExpressionSubstitution:
     return false;
 
   // This function should never be called when Kind's value is Memoization.
@@ -961,6 +963,10 @@
     case CodeSynthesisContext::Memoization:
       break;
 
+    case CodeSynthesisContext::LambdaExpressionSubstitution:
+      Diags.Report(Active->PointOfInstantiation,
+                   diag::note_lambda_substitution_here);
+      break;
     case CodeSynthesisContext::ConstraintsCheck: {
       unsigned DiagID = 0;
       if (!Active->Entity) {
@@ -1016,6 +1022,7 @@
   if (InNonInstantiationSFINAEContext)
     return std::optional<TemplateDeductionInfo *>(nullptr);
 
+  bool SawLambdaSubstitution = false;
   for (SmallVectorImpl<CodeSynthesisContext>::const_reverse_iterator
          Active = CodeSynthesisContexts.rbegin(),
          ActiveEnd = CodeSynthesisContexts.rend();
@@ -1037,6 +1044,15 @@
     case CodeSynthesisContext::NestedRequirementConstraintsCheck:
       // This is a template instantiation, so there is no SFINAE.
       return std::nullopt;
+    case CodeSynthesisContext::LambdaExpressionSubstitution:
+      // [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.
+
+      // We need to check parents.
+      SawLambdaSubstitution = true;
+      break;
 
     case CodeSynthesisContext::DefaultTemplateArgumentInstantiation:
     case CodeSynthesisContext::PriorTemplateArgumentSubstitution:
@@ -1049,12 +1065,17 @@
 
     case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution:
     case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
+      // We're either substituting explicitly-specified template arguments,
+      // deduced template arguments. SFINAE applies unless we are in a lambda
+      // expression, see [temp.deduct]p9.
+      if (SawLambdaSubstitution)
+        return std::nullopt;
+      [[fallthrough]];
     case CodeSynthesisContext::ConstraintSubstitution:
     case CodeSynthesisContext::RequirementInstantiation:
     case CodeSynthesisContext::RequirementParameterInstantiation:
-      // We're either substituting explicitly-specified template arguments,
-      // deduced template arguments, a constraint expression or a requirement
-      // in a requires expression, so SFINAE applies.
+      // SFINAE always applies in a constraint expression or a requirement
+      // in a requires expression.
       assert(Active->DeductionInfo && "Missing deduction info pointer");
       return Active->DeductionInfo;
 
@@ -1343,6 +1364,14 @@
     ExprResult TransformLambdaExpr(LambdaExpr *E) {
       LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
       Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
+
+      Sema::CodeSynthesisContext C;
+      C.Kind = clang::Sema::CodeSynthesisContext::LambdaExpressionSubstitution;
+      C.PointOfInstantiation = E->getBeginLoc();
+      SemaRef.pushCodeSynthesisContext(C);
+      auto PopCtx =
+          llvm::make_scope_exit([this] { SemaRef.popCodeSynthesisContext(); });
+
       ExprResult Result = inherited::TransformLambdaExpr(E);
       if (Result.isInvalid())
         return Result;
Index: clang/lib/Frontend/FrontendActions.cpp
===================================================================
--- clang/lib/Frontend/FrontendActions.cpp
+++ clang/lib/Frontend/FrontendActions.cpp
@@ -372,6 +372,8 @@
       return "ExplicitTemplateArgumentSubstitution";
     case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
       return "DeducedTemplateArgumentSubstitution";
+    case CodeSynthesisContext::LambdaExpressionSubstitution:
+      return "LambdaExpressionSubstitution";
     case CodeSynthesisContext::PriorTemplateArgumentSubstitution:
       return "PriorTemplateArgumentSubstitution";
     case CodeSynthesisContext::DefaultTemplateArgumentChecking:
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -9257,6 +9257,9 @@
       /// a TemplateDecl.
       DeducedTemplateArgumentSubstitution,
 
+      /// We are substituting into a lambda expression.
+      LambdaExpressionSubstitution,
+
       /// We are substituting prior template arguments into a new
       /// template parameter. The template parameter itself is either a
       /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl.
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5315,6 +5315,8 @@
 def note_parameter_mapping_substitution_here : Note<
   "while substituting into concept arguments here; substitution failures not "
   "allowed in concept arguments">;
+def note_lambda_substitution_here : Note<
+  "while substituting into a lambda expression here">;
 def note_instantiation_contexts_suppressed : Note<
   "(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to "
   "see all)">;
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -153,6 +153,10 @@
 - A new builtin type trait ``__is_trivially_equaltiy_comparable`` has been added,
   which checks whether comparing two instances of a type is equivalent to
   ``memcmp(&lhs, &rhs, sizeof(T)) == 0``.
+- Clang now implements `[temp.deduct]p9`, subsitution failures inside lambdas from
+  unevaluated contexts will be surfaced as errors. They were previously handled as
+  SFINAE.
+
 
 New Compiler Flags
 ------------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to