[clang] 629170f - [Sema] Lambdas are not part of immediate context for deduction

Ilya Biryukov via cfe-commits cfe-commits at lists.llvm.org
Tue May 9 03:10:27 PDT 2023


Author: Ilya Biryukov
Date: 2023-05-09T12:06:33+02:00
New Revision: 629170fe452f4849c89fc289d6e2cf5f08534342

URL: https://github.com/llvm/llvm-project/commit/629170fe452f4849c89fc289d6e2cf5f08534342
DIFF: https://github.com/llvm/llvm-project/commit/629170fe452f4849c89fc289d6e2cf5f08534342.diff

LOG: [Sema] Lambdas are not part of immediate context for deduction

This commit implements [temp.deduct]p9.
Test updates include:
- New notes in `cxx1y-init-captures.cpp`, `lambda-expressions.cpp`
  and 'warn-unused-lambda-capture.cpp'.
  This seems to be caused by diagnosing errors earlier (during
  deduction) that were previously surfaced later (during
  instantiation).
- New error `lambda-unevaluated.cpp` is in line with [temp.deduct]p9.

Reviewed By: erichkeane, #clang-language-wg

Differential Revision: https://reviews.llvm.org/D148802

Added: 
    clang/test/CXX/temp/temp.deduct/p9.cpp

Modified: 
    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.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

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d3d731cf9d438..4ec4e4a49de6b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -91,6 +91,9 @@ C++20 Feature Support
   building of standard modules. This diagnostic may be strengthened into an
   error again in the future once there is a less fragile way to mark a module
   as being part of the implementation rather than a user module.
+- Clang now implements `[temp.deduct]p9`. Substitution failures inside lambdas from
+  unevaluated contexts will be surfaced as errors. They were previously handled as
+  SFINAE.
 
 C++23 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index bade9ad5d5be3..e6b2e28a82ded 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5327,6 +5327,8 @@ def note_constraint_normalization_here : Note<
 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)">;

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f65f8e3f2b50b..5296d7000b5cc 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -9261,6 +9261,9 @@ class Sema final {
       /// 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.

diff  --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp
index c947772ec3e70..f62a29c02ee13 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -372,6 +372,8 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback {
       return "ExplicitTemplateArgumentSubstitution";
     case CodeSynthesisContext::DeducedTemplateArgumentSubstitution:
       return "DeducedTemplateArgumentSubstitution";
+    case CodeSynthesisContext::LambdaExpressionSubstitution:
+      return "LambdaExpressionSubstitution";
     case CodeSynthesisContext::PriorTemplateArgumentSubstitution:
       return "PriorTemplateArgumentSubstitution";
     case CodeSynthesisContext::DefaultTemplateArgumentChecking:

diff  --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 1582a5c4b6e44..a25f8175ebcdb 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -35,6 +35,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>
@@ -368,6 +369,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
   case InitializingStructuredBinding:
   case MarkingClassDllexported:
   case BuildingBuiltinDumpStructCall:
+  case LambdaExpressionSubstitution:
     return false;
 
   // This function should never be called when Kind's value is Memoization.
@@ -962,6 +964,10 @@ void Sema::PrintInstantiationStack() {
     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) {
@@ -1017,6 +1023,7 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
   if (InNonInstantiationSFINAEContext)
     return std::optional<TemplateDeductionInfo *>(nullptr);
 
+  bool SawLambdaSubstitution = false;
   for (SmallVectorImpl<CodeSynthesisContext>::const_reverse_iterator
          Active = CodeSynthesisContexts.rbegin(),
          ActiveEnd = CodeSynthesisContexts.rend();
@@ -1038,6 +1045,15 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
     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:
@@ -1050,12 +1066,17 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
 
     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;
 
@@ -1344,6 +1365,14 @@ namespace {
     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;

diff  --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
index 72265d77700aa..c5d08ec404a7c 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
@@ -35,7 +35,8 @@ struct NoDefaultCtor {
 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 void defargs_in_template_unused(NoDefaultCtor);  // expected-note{{in i
 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();
 }
 

diff  --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
index 67953c6a6f901..ed36a33850ce4 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
@@ -35,6 +35,7 @@ auto init_kind_2 = [ec = ExplicitCopy()] {}; // expected-error {{no matching con
 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 at -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_6 = [a{overload_fn}] {}; // expected-error {{cannot deduce type fo
 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 at -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 @@ auto s = [s(move(S()))] {};
 
 template<typename T> T instantiate_test(T t) {
   [x(&t)]() { *x = 1; } (); // expected-error {{assigning to 'const char *'}}
+                            // expected-note at -1 {{while substituting into a lambda expression here}}
   return t;
 }
 int instantiate_test_1 = instantiate_test(0);

diff  --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
index 028fcee5fda43..a5278c27bf25c 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
@@ -85,6 +85,7 @@ void init_capture_pack_err(Args ...args) {
 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 at -1 2{{while substituting into a lambda expression}}
 }
 template void init_capture_pack_multi(); // expected-note {{instantiation}}
 template void init_capture_pack_multi(int);

diff  --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
index 660f6091bb663..ffac9112491fe 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
@@ -54,6 +54,7 @@ void test_result_type(int N) {
 template <typename T>
 void test_result_type_tpl(int N) {
   auto l1 = []() -> T {}; // expected-error{{incomplete result type 'Incomplete' in lambda expression}}
+                          // expected-note at -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]')}}
 }

diff  --git a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
index 6579eb19a7596..0c357db764a92 100644
--- a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
+++ b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
@@ -80,6 +80,7 @@ namespace generic_lambda {
     [](auto x) {
       if constexpr (sizeof(T) == 1 && sizeof(x) == 1)
         T::error(); // expected-error 2{{'::'}}
+                    // expected-note at -3 2{{while substituting into a lambda expression here}}
     } (0);
   }
 
@@ -88,6 +89,7 @@ namespace generic_lambda {
       if constexpr (sizeof(T) == 1)
         if constexpr (sizeof(x) == 1)
           T::error(); // expected-error {{'::'}}
+                      // expected-note at -4 {{while substituting into a lambda expression here}}
     } (0);
   }
 

diff  --git a/clang/test/CXX/temp/temp.deduct/p9.cpp b/clang/test/CXX/temp/temp.deduct/p9.cpp
new file mode 100644
index 0000000000000..23bcd2a1892e7
--- /dev/null
+++ b/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 at -3 {{type 'int' cannot be used prior to '::'}}
+        // expected-note at -1 {{while substituting deduced template arguments}}
+        // expected-note at -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 at -4 {{type 'int' cannot be used prior to '::'}}
+        // expected-note at -4 {{in instantiation of default argument}}
+        // expected-note at -2 {{while substituting deduced template arguments}}
+        // expected-note at -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 at -3 {{type 'int' cannot be used prior to '::'}}
+        // expected-note at -1 {{while substituting deduced template arguments}}
+        // expected-note at -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 at -3 {{type 'int' cannot be used prior to '::'}}
+        // expected-note at -1 {{while substituting deduced template arguments}}
+        // expected-note at -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.
+}

diff  --git a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
index 63f56640b1ce9..83144a494937b 100644
--- a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
+++ b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
@@ -141,6 +141,7 @@ template<typename...Ts> struct A {
     B() {
       consume([]{
         int arr[Vs]; // expected-error {{negative size}}
+                     // expected-note at -2 {{while substituting into a lambda expression here}}
       }...);
     }
   };

diff  --git a/clang/test/PCH/cxx1y-init-captures.cpp b/clang/test/PCH/cxx1y-init-captures.cpp
index 7f8a9fa4b3c1d..c19dd90ac90be 100644
--- a/clang/test/PCH/cxx1y-init-captures.cpp
+++ b/clang/test/PCH/cxx1y-init-captures.cpp
@@ -25,6 +25,7 @@ int y = counter();
 void g() {
   f(0); // ok
   // expected-error at 18 {{lvalue of type 'const char *const'}}
+  // expected-note at 18 {{substituting into a lambda}}
   f("foo"); // expected-note {{here}}
 }
 

diff  --git a/clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp b/clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
index e9e2ecab8e028..dcc964cd60b34 100644
--- a/clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
+++ b/clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
@@ -563,8 +563,8 @@ struct X {
   
   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 @@ struct X {
   
   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 @@ struct X {
   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){}); 
         };

diff  --git a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
index 61dfd654f6d65..3c2d460ab9b4a 100644
--- a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
+++ b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
@@ -259,7 +259,7 @@ int test() {
 {
   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;
     };

diff  --git a/clang/test/SemaCXX/cxx1y-init-captures.cpp b/clang/test/SemaCXX/cxx1y-init-captures.cpp
index 1c1c93c757a0d..4cb53cc8bfc1c 100644
--- a/clang/test/SemaCXX/cxx1y-init-captures.cpp
+++ b/clang/test/SemaCXX/cxx1y-init-captures.cpp
@@ -21,17 +21,17 @@ namespace variadic_expansion {
                     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 @@ int test(T t = T{}) {
   }
   { // 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 @@ int test(T t = T{}) {
   }
   { // 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 @@ int test(T t = T{}) {
   return 0;
 }
 
-int run = test(); //expected-note {{instantiation}}
+int run = test(); //expected-note 2 {{instantiation}}
 
 }
 

diff  --git a/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp b/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp
index 95bc32b603ddf..0cee41ff5ed38 100644
--- a/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp
+++ b/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp
@@ -46,7 +46,7 @@ class B {
   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 @@ class B {
 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; };
     };

diff  --git a/clang/test/SemaCXX/cxx20-decomposition.cpp b/clang/test/SemaCXX/cxx20-decomposition.cpp
index 34f46f866c7df..430a158ff458e 100644
--- a/clang/test/SemaCXX/cxx20-decomposition.cpp
+++ b/clang/test/SemaCXX/cxx20-decomposition.cpp
@@ -177,7 +177,8 @@ namespace ODRUseTests {
     (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}}
   }

diff  --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp
index aeecf2109beff..b186583a7d82b 100644
--- a/clang/test/SemaCXX/lambda-expressions.cpp
+++ b/clang/test/SemaCXX/lambda-expressions.cpp
@@ -260,10 +260,11 @@ namespace VariadicPackExpansion {
     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 PR18128 {
 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 @@ namespace error_in_transform_prototype {
   void f(T t) {
     // expected-error at +2 {{type 'int' cannot be used prior to '::' because it has no members}}
     // expected-error at +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() {

diff  --git a/clang/test/SemaCXX/lambda-pack-expansion.cpp b/clang/test/SemaCXX/lambda-pack-expansion.cpp
index e3e968e2704ed..936e7c6b0e5c5 100644
--- a/clang/test/SemaCXX/lambda-pack-expansion.cpp
+++ b/clang/test/SemaCXX/lambda-pack-expansion.cpp
@@ -8,6 +8,7 @@ struct X {
 
 void take_by_copy(auto &...args) {
   [...args = args] {}(); // expected-error {{call to deleted constructor}}
+                         // expected-note at -1 {{substituting into a lambda}}
 }
 
 void take_by_ref(auto &...args) {

diff  --git a/clang/test/SemaCXX/lambda-unevaluated.cpp b/clang/test/SemaCXX/lambda-unevaluated.cpp
index 135c6f6bfc05e..179c7327ebdff 100644
--- a/clang/test/SemaCXX/lambda-unevaluated.cpp
+++ b/clang/test/SemaCXX/lambda-unevaluated.cpp
@@ -28,8 +28,11 @@ static_assert(&unique_test1<[](){}> != &unique_test1<[](){}>);
 
 template <class T>
 auto g(T) -> decltype([]() { T::invalid; } ());
-auto e = g(0); // expected-error{{no matching function for call}}
-// expected-note at -2 {{substitution failure}}
+auto e = g(0); // expected-error at -1{{type 'int' cannot be used prior to '::'}}
+               // expected-note at -1{{while substituting deduced template}}
+               // expected-note at -3{{while substituting into a lambda}}
+               // expected-error at -3 {{no matching function for call to 'g'}}
+               // expected-note at -5 {{substitution failure}}
 
 template <typename T>
 auto foo(decltype([] {
@@ -146,3 +149,36 @@ 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(); };
+};
+
+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 at -4 {{type 'int' cannot be used prior to '::'}}
+                      // expected-note at -1 {{while substituting deduced template arguments}}
+                      // expected-note at -6 {{while substituting into a lambda}}
+    bool x = requires { direct_lambda(0); }; // expected-error at -7 {{type 'int' cannot be used prior to '::'}}
+                                             // expected-note at -1 {{while substituting deduced template arguments}}
+                                             // expected-note at -9 {{while substituting into a lambda}}
+
+}
+}

diff  --git a/clang/test/SemaCXX/vartemplate-lambda.cpp b/clang/test/SemaCXX/vartemplate-lambda.cpp
index 8b232abe976b6..d2b53b53dcd49 100644
--- a/clang/test/SemaCXX/vartemplate-lambda.cpp
+++ b/clang/test/SemaCXX/vartemplate-lambda.cpp
@@ -8,6 +8,7 @@ template<typename T> auto v1 = [](int a = T()) { return a; }();
 // expected-error at -1{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}}
 // expected-note at -2{{in instantiation of default function argument expression for 'operator()<int *>' required here}}
 // expected-note at -3{{passing argument to parameter 'a' here}}
+// expected-note at -4{{substituting into a lambda}}
 
 struct S {
   template<class T>

diff  --git a/clang/test/SemaCXX/warn-unused-lambda-capture.cpp b/clang/test/SemaCXX/warn-unused-lambda-capture.cpp
index 52ec390b0bba6..67b8fc3b661c8 100644
--- a/clang/test/SemaCXX/warn-unused-lambda-capture.cpp
+++ b/clang/test/SemaCXX/warn-unused-lambda-capture.cpp
@@ -145,38 +145,38 @@ void test_templated() {
   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_templated() {
 }
 
 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 {

diff  --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index d28c2b22bd045..d348e7a7efaf9 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -119,7 +119,7 @@ namespace PackInTypeConstraint {
     []() -> 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();
      }(), ...);
   }

diff  --git a/clang/test/SemaTemplate/cxx1z-using-declaration.cpp b/clang/test/SemaTemplate/cxx1z-using-declaration.cpp
index 84e3bff159822..a1f1988efd608 100644
--- a/clang/test/SemaTemplate/cxx1z-using-declaration.cpp
+++ b/clang/test/SemaTemplate/cxx1z-using-declaration.cpp
@@ -157,7 +157,7 @@ template<typename ...T> void fn2() {
 
 // 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 ...;

diff  --git a/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp b/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
index c5290efafc1ab..d66e68dc9e9c8 100644
--- a/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
+++ b/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
@@ -160,7 +160,7 @@ namespace Variadic {
     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}}
     } ...);
   }

diff  --git a/clang/test/SemaTemplate/instantiate-local-class.cpp b/clang/test/SemaTemplate/instantiate-local-class.cpp
index f0f3d2b146b67..430516aaac5b5 100644
--- a/clang/test/SemaTemplate/instantiate-local-class.cpp
+++ b/clang/test/SemaTemplate/instantiate-local-class.cpp
@@ -473,7 +473,8 @@ namespace rdar23721638 {
   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 @@ namespace PR45000 {
   // expected-error at -1 {{cannot initialize a parameter of type 'int' with an rvalue of type 'std::nullptr_t'}}
   // expected-note at -2  {{in instantiation of default function argument expression for 'operator()<int>' required here}}
   // expected-note at -3  {{passing argument to parameter 'x' here}}
+  // expected-note at -4  {{while substituting into a lambda}}
 
   void g() { f<int>(); }
   // expected-note at -1 {{in instantiation of default function argument expression for 'f<int>' required here}}

diff  --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index e4ecb5f832e93..e43159aabaeba 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1024,11 +1024,7 @@ <h2 id="cxx20">C++20 implementation status</h2>
     <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>


        


More information about the cfe-commits mailing list