https://github.com/a-tarasyuk updated 
https://github.com/llvm/llvm-project/pull/222987

>From af5b6ee39d4dfaed820c17f4303316e91302aa74 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <[email protected]>
Date: Fri, 11 Sep 2026 15:45:35 +0300
Subject: [PATCH 1/4] [Clang] fix crash with generic lambdas in function
 default args

---
 clang/docs/ReleaseNotes.md                |  2 +
 clang/lib/Parse/ParseDecl.cpp             |  6 +++
 clang/lib/Sema/SemaDeclCXX.cpp            |  9 ++++-
 clang/lib/Sema/SemaLambda.cpp             |  2 +-
 clang/lib/Sema/SemaTemplate.cpp           |  5 +--
 clang/test/SemaCXX/lambda-unevaluated.cpp | 47 +++++++++++++++++++++++
 6 files changed, 65 insertions(+), 6 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index ef694e1d0f5cc7..1d799c0ed0ba27 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -675,6 +675,8 @@ features cannot lower the translation-unit ABI level;
   class with an invalid non-static data member, such as one qualified with an
   address space. (#GH194605)
 
+- Fixed a crash with generic lambdas in default arguments of functions with 
`auto` parameters.
+
 #### Bug Fixes to AST Handling
 
 - Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 1d3789a10d9deb..bf42a04adf9652 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -7756,6 +7756,12 @@ void Parser::ParseParameterDeclarationClause(
           DelayTemplateIdDestructionRAII DontDestructTemplateIds(
               *this, /*DelayTemplateIdDestruction=*/true);
 
+          TemplateParameterDepthRAII CurTemplateDepthTracker(
+              TemplateParameterDepth);
+          unsigned Depth = Actions.getTemplateDepth(getCurScope());
+          if (Depth > TemplateParameterDepth)
+            CurTemplateDepthTracker.addDepth(Depth - TemplateParameterDepth);
+
           // The argument isn't actually potentially evaluated unless it is
           // used.
           EnterExpressionEvaluationContext Eval(
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index ea628f29d8a005..568bb4c7851401 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -165,12 +165,19 @@ bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr(
 }
 
 bool CheckDefaultArgumentVisitor::VisitLambdaExpr(const LambdaExpr *Lambda) {
+  bool Invalid = false;
+  for (NamedDecl *P : Lambda->getExplicitTemplateParameters()) {
+    const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P);
+    if (!NTTP || !NTTP->hasDefaultArgument())
+      continue;
+    Invalid |= Visit(NTTP->getDefaultArgument().getArgument().getAsExpr());
+  }
+
   // [expr.prim.lambda.capture]p9
   // a lambda-expression appearing in a default argument cannot implicitly or
   // explicitly capture any local entity. Such a lambda-expression can still
   // have an init-capture if any full-expression in its initializer satisfies
   // the constraints of an expression appearing in a default argument.
-  bool Invalid = false;
   for (const LambdaCapture &LC : Lambda->captures()) {
     if (!Lambda->isInitCapture(&LC))
       return S.Diag(LC.getLocation(), diag::err_lambda_capture_default_arg);
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 288f3c4f664cb4..ffbe5e72d4c516 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1143,7 +1143,7 @@ void 
Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
   // be dependent, because there are template parameters in scope.
   CXXRecordDecl::LambdaDependencyKind LambdaDependencyKind =
       CXXRecordDecl::LDK_Unknown;
-  if (CurScope->getTemplateParamParent() != nullptr) {
+  if (getTemplateDepth(CurScope) > 0) {
     LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent;
   } else if (Scope *ParentScope = CurScope->getParent()) {
     // Given a lambda defined inside a requires expression,
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index b8b0c71894daac..b800a433b3bf74 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -76,11 +76,8 @@ unsigned Sema::getTemplateDepth(Scope *S) const {
     if (auto *LSI = dyn_cast<LambdaScopeInfo>(FSI)) {
       if (!LSI->TemplateParams.empty()) {
         ParamsAtDepth(LSI->AutoTemplateParameterDepth);
-        break;
-      }
-      if (LSI->GLTemplateParameterList) {
+      } else if (LSI->GLTemplateParameterList) {
         ParamsAtDepth(LSI->GLTemplateParameterList->getDepth());
-        break;
       }
     }
   }
diff --git a/clang/test/SemaCXX/lambda-unevaluated.cpp 
b/clang/test/SemaCXX/lambda-unevaluated.cpp
index 9c723c6bc3b998..018d597e6831ba 100644
--- a/clang/test/SemaCXX/lambda-unevaluated.cpp
+++ b/clang/test/SemaCXX/lambda-unevaluated.cpp
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -std=c++20 %s -Wno-c++23-extensions -verify
 // RUN: %clang_cc1 -std=c++23 %s -verify
+// RUN: %clang_cc1 -std=c++26 %s -verify
 
 template <auto> struct Nothing {};
 Nothing<[]() { return 0; }()> nothing;
@@ -283,10 +284,21 @@ static_assert(__is_same_as(int, helper<int>));
 } // namespace GH138018
 
 namespace GH172814 {
+auto f() {
+  int x = 0;
+  return [](auto w = [&] { x += w(); }); // expected-error {{lambda expression 
in default argument cannot capture any entity}} \
+                                         // expected-error {{expected body of 
lambda expression}}
+}
+
 auto t() {
   int x = 0;
   return [](auto w = [&] { return x; }) { }; // expected-error {{lambda 
expression in default argument cannot capture any entity}}
 };
+
+auto g() {
+  int x = 0;
+  return []<class T>(T w = [&] { return x; }) {}; // expected-error {{lambda 
expression in default argument cannot capture any entity}}
+}
 }
 
 namespace GH176534 {
@@ -318,3 +330,38 @@ struct S {
   void c(int x, int = sizeof([=] { return x; }));
 };
 }
+
+namespace GH48768 {
+
+auto a(auto x = 1, auto = []<auto = x> {}());               // expected-error 
{{default argument references parameter 'x'}}
+void b(auto x, auto = []<auto = x> {});                     // expected-error 
{{default argument references parameter 'x'}}
+auto c = [](auto x, int = []<auto = x> { return 0; }()) {}; // expected-error 
{{default argument references parameter 'x'}}
+
+constexpr int d(auto x, int n = []<auto N = sizeof(x)> { return N; }()) {
+  return n;
+}
+
+constexpr int e(auto x, int n = []<class T = decltype(x)> { return sizeof(T); 
}()) {
+  return n;
+}
+
+constexpr auto f = [](auto x, int n = []<auto N = sizeof(x)> { return N; }()) {
+  return n;
+};
+
+constexpr auto g = [](auto x, int n = []<class T = decltype(x)> { return 
sizeof(T); }()) {
+  return n;
+};
+
+constexpr auto h = [](auto x) {
+  return [](auto y, int n = []<auto N = sizeof(y)> { return N; }()) {
+    return n;
+  };
+};
+
+static_assert(d(0) == sizeof(int));
+static_assert(e(0) == sizeof(int));
+static_assert(f(0) == sizeof(int));
+static_assert(g(0) == sizeof(int));
+static_assert(h(0)('a') == 1);
+}

>From 123d67a77650fed1ad6b7ad8dc037e3f6e02e423 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <[email protected]>
Date: Mon, 14 Sep 2026 14:05:25 +0300
Subject: [PATCH 2/4] update release notes

---
 clang/docs/ReleaseNotes.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 1d799c0ed0ba27..f497d38ca1dd2a 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -675,7 +675,7 @@ features cannot lower the translation-unit ABI level;
   class with an invalid non-static data member, such as one qualified with an
   address space. (#GH194605)
 
-- Fixed a crash with generic lambdas in default arguments of functions with 
`auto` parameters.
+- Fixed a crash with generic lambdas in default arguments of functions with 
`auto` parameters. (#GH48768)
 
 #### Bug Fixes to AST Handling
 

>From 7f9612bfd2d1b1699d547deeecb6bc2422b96837 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <[email protected]>
Date: Mon, 14 Sep 2026 14:08:51 +0300
Subject: [PATCH 3/4] explain default argument tpl depth

---
 clang/lib/Parse/ParseDecl.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index bf42a04adf9652..9834293a0d09b6 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -7756,6 +7756,10 @@ void Parser::ParseParameterDeclarationClause(
           DelayTemplateIdDestructionRAII DontDestructTemplateIds(
               *this, /*DelayTemplateIdDestruction=*/true);
 
+          // Include the template level introduced by 'auto' parameters:
+          //   void f(auto x, int = []<auto N = sizeof(x)>() { return N; }());
+          // The type parameter for x has depth 0, so N starts at depth 1.
+          // Otherwise, instantiation would reduce N's depth to -1.
           TemplateParameterDepthRAII CurTemplateDepthTracker(
               TemplateParameterDepth);
           unsigned Depth = Actions.getTemplateDepth(getCurScope());

>From 7f107d45fc18f27d68bf49b93de0caf1abfb93c0 Mon Sep 17 00:00:00 2001
From: Oleksandr Tarasiuk <[email protected]>
Date: Wed, 23 Sep 2026 22:47:38 +0300
Subject: [PATCH 4/4] fix implicit tpl scope handling for auto parameters

---
 clang/include/clang/Parse/Parser.h        | 21 ++++----
 clang/include/clang/Sema/Scope.h          |  2 +
 clang/include/clang/Sema/Sema.h           | 19 +------
 clang/lib/Parse/ParseCXXInlineMethods.cpp | 17 +-----
 clang/lib/Parse/ParseDecl.cpp             | 25 ++++-----
 clang/lib/Parse/ParseDeclCXX.cpp          |  7 +--
 clang/lib/Parse/ParseExprCXX.cpp          | 22 ++++----
 clang/lib/Parse/ParseTemplate.cpp         | 19 +++++++
 clang/lib/Parse/Parser.cpp                | 11 +---
 clang/lib/Sema/Scope.cpp                  | 14 +++++
 clang/lib/Sema/Sema.cpp                   | 11 ----
 clang/lib/Sema/SemaDecl.cpp               | 10 +---
 clang/lib/Sema/SemaDeclCXX.cpp            | 23 ++++++---
 clang/lib/Sema/SemaLambda.cpp             | 29 +----------
 clang/lib/Sema/SemaTemplate.cpp           | 28 +---------
 clang/lib/Sema/SemaType.cpp               |  3 ++
 clang/test/SemaCXX/lambda-unevaluated.cpp | 63 ++++++++++++++++-------
 17 files changed, 139 insertions(+), 185 deletions(-)

diff --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index 6913c42884a367..fbbbf2dfaec32a 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1339,10 +1339,6 @@ class Parser : public CodeCompletionHandler {
   typedef SmallVector<LateParsedDeclaration *, 2>
       LateParsedDeclarationsContainer;
 
-  /// Utility to re-enter a possibly-templated scope while parsing its
-  /// late-parsed components.
-  struct ReenterTemplateScopeRAII;
-
   /// Utility to re-enter a class scope while parsing its late-parsed
   /// components.
   struct ReenterClassScopeRAII;
@@ -7941,13 +7937,18 @@ class Parser : public CodeCompletionHandler {
       Depth += D;
       AddedLevels += D;
     }
-    void setAddedDepth(unsigned D) {
-      Depth = Depth - AddedLevels + D;
-      AddedLevels = D;
-    }
-
     unsigned getDepth() const { return Depth; }
-    unsigned getOriginalDepth() const { return Depth - AddedLevels; }
+  };
+
+  /// Utility to re-enter a possibly-templated scope while parsing its
+  /// late-parsed components.
+  struct ReenterTemplateScopeRAII {
+    MultiParseScope Scopes;
+    TemplateParameterDepthRAII CurTemplateDepthTracker;
+
+    ReenterTemplateScopeRAII(Parser &P, Decl *MaybeTemplated,
+                             bool Enter = true);
+    ReenterTemplateScopeRAII(Parser &P, const Declarator &D);
   };
 
   /// Gathers and cleans up TemplateIdAnnotations when parsing of a
diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h
index 58ca2c0738f3c7..ff153a198bc9f4 100644
--- a/clang/include/clang/Sema/Scope.h
+++ b/clang/include/clang/Sema/Scope.h
@@ -270,6 +270,8 @@ class Scope {
 
   void setFlags(unsigned F) { setFlags(getParent(), F); }
 
+  void EnterTemplateParameterScope();
+
   /// Get the label that precedes this scope.
   LabelDecl *getPrecedingLabel() const { return PrecedingLabel; }
 
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index fc8da0ed560054..493b8014a4c2e0 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1118,9 +1118,6 @@ class Sema final : public SemaBase {
   sema::LambdaScopeInfo *
   getCurLambda(bool IgnoreNonLambdaCapturingScope = false);
 
-  /// Retrieve the current generic lambda info, if any.
-  sema::LambdaScopeInfo *getCurGenericLambda();
-
   /// Retrieve the current captured region, if any.
   sema::CapturedRegionScopeInfo *getCurCapturedRegion();
 
@@ -3524,10 +3521,6 @@ class Sema final : public SemaBase {
 public:
   IdentifierResolver IdResolver;
 
-  /// The index of the first InventedParameterInfo that refers to the current
-  /// context.
-  unsigned InventedParameterInfosStart = 0;
-
   /// A RAII object to temporarily push a declaration context.
   class ContextRAII {
   private:
@@ -3536,22 +3529,19 @@ class Sema final : public SemaBase {
     ProcessingContextState SavedContextState;
     QualType SavedCXXThisTypeOverride;
     unsigned SavedFunctionScopesStart;
-    unsigned SavedInventedParameterInfosStart;
 
   public:
     ContextRAII(Sema &S, DeclContext *ContextToPush, bool NewThisContext = 
true)
         : S(S), SavedContext(S.CurContext),
           SavedContextState(S.DelayedDiagnostics.pushUndelayed()),
           SavedCXXThisTypeOverride(S.CXXThisTypeOverride),
-          SavedFunctionScopesStart(S.FunctionScopesStart),
-          SavedInventedParameterInfosStart(S.InventedParameterInfosStart) {
+          SavedFunctionScopesStart(S.FunctionScopesStart) {
       assert(ContextToPush && "pushing null context");
       S.CurContext = ContextToPush;
       if (NewThisContext)
         S.CXXThisTypeOverride = QualType();
       // Any saved FunctionScopes do not refer to this context.
       S.FunctionScopesStart = S.FunctionScopes.size();
-      S.InventedParameterInfosStart = S.InventedParameterInfos.size();
     }
 
     void pop() {
@@ -3561,7 +3551,6 @@ class Sema final : public SemaBase {
       S.DelayedDiagnostics.popUndelayed(SavedContextState);
       S.CXXThisTypeOverride = SavedCXXThisTypeOverride;
       S.FunctionScopesStart = SavedFunctionScopesStart;
-      S.InventedParameterInfosStart = SavedInventedParameterInfosStart;
       SavedContext = nullptr;
     }
 
@@ -11445,12 +11434,6 @@ class Sema final : public SemaBase {
     FpPragmaStack.CurrentValue = FPO.getChangesFrom(FPOptions(LangOpts));
   }
 
-  ArrayRef<InventedTemplateParameterInfo> getInventedParameterInfos() const {
-    return llvm::ArrayRef(InventedParameterInfos.begin() +
-                              InventedParameterInfosStart,
-                          InventedParameterInfos.end());
-  }
-
   ArrayRef<sema::FunctionScopeInfo *> getFunctionScopes() const {
     return llvm::ArrayRef(FunctionScopes.begin() + FunctionScopesStart,
                           FunctionScopes.end());
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp 
b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index e472628dd36bc8..43e73249baa340 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -318,27 +318,14 @@ void Parser::LateParsedPragma::ParseLexedPragmas() {
   Self->ParseLexedPragma(*this);
 }
 
-struct Parser::ReenterTemplateScopeRAII {
-  Parser &P;
-  MultiParseScope Scopes;
-  TemplateParameterDepthRAII CurTemplateDepthTracker;
-
-  ReenterTemplateScopeRAII(Parser &P, Decl *MaybeTemplated, bool Enter = true)
-      : P(P), Scopes(P), CurTemplateDepthTracker(P.TemplateParameterDepth) {
-    if (Enter) {
-      CurTemplateDepthTracker.addDepth(
-          P.ReenterTemplateScopes(Scopes, MaybeTemplated));
-    }
-  }
-};
-
 struct Parser::ReenterClassScopeRAII : ReenterTemplateScopeRAII {
+  Parser &P;
   ParsingClass &Class;
 
   ReenterClassScopeRAII(Parser &P, ParsingClass &Class)
       : ReenterTemplateScopeRAII(P, Class.TagOrTemplate,
                                  /*Enter=*/!Class.TopLevelClass),
-        Class(Class) {
+        P(P), Class(Class) {
     // If this is the top-level class, we're still within its scope.
     if (Class.TopLevelClass)
       return;
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 9834293a0d09b6..c1511a5f0cb93f 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2187,11 +2187,7 @@ Parser::DeclGroupPtrTy 
Parser::ParseDeclGroup(ParsingDeclSpec &DS,
       ;
 
   if (Tok.is(tok::kw_requires)) {
-    TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
-    // With abbreviated function templates - we need to explicitly add depth to
-    // account for the implicit template parameter list induced by the 
template.
-    if (!TemplateInfo.TemplateParams && D.getInventedTemplateParameterList())
-      ++CurTemplateDepthTracker;
+    ReenterTemplateScopeRAII InTemplateScope(*this, D);
     ParseTrailingRequiresClauseWithScope(D);
   }
 
@@ -6943,6 +6939,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
   while (true) {
     if (Tok.is(tok::l_paren)) {
       bool IsFunctionDeclaration = 
D.isFunctionDeclaratorAFunctionDeclaration();
+      ParseScope ImplicitTemplateScope(this, Scope::NoScope,
+                                       getLangOpts().CPlusPlus &&
+                                           IsFunctionDeclaration);
+
       // Enter function-declaration scope, limiting any declarators to the
       // function prototype scope, including parameter declarators.
       ParseScope PrototypeScope(
@@ -7280,6 +7280,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
                                      BalancedDelimiterTracker &Tracker,
                                      bool IsAmbiguous,
                                      bool RequiresArg) {
+  llvm::SaveAndRestore<unsigned> SavedTemplateDepth(TemplateParameterDepth);
   assert(getCurScope()->isFunctionPrototypeScope() &&
          "Should call from a Function scope");
   // lparen is already consumed!
@@ -7723,8 +7724,12 @@ void Parser::ParseParameterDeclarationClause(
 
       // Inform the actions module about the parameter declarator, so it gets
       // added to the current scope.
+      Scope *TemplateScope = getCurScope()->getTemplateParamParent();
       Decl *Param =
           Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator, ThisLoc);
+
+      if (getCurScope()->getTemplateParamParent() != TemplateScope)
+        ++TemplateParameterDepth;
       // Parse the default argument, if any. We parse the default
       // arguments in all dialects; the semantic analysis in
       // ActOnParamDefaultArgument will reject the default argument in
@@ -7756,16 +7761,6 @@ void Parser::ParseParameterDeclarationClause(
           DelayTemplateIdDestructionRAII DontDestructTemplateIds(
               *this, /*DelayTemplateIdDestruction=*/true);
 
-          // Include the template level introduced by 'auto' parameters:
-          //   void f(auto x, int = []<auto N = sizeof(x)>() { return N; }());
-          // The type parameter for x has depth 0, so N starts at depth 1.
-          // Otherwise, instantiation would reduce N's depth to -1.
-          TemplateParameterDepthRAII CurTemplateDepthTracker(
-              TemplateParameterDepth);
-          unsigned Depth = Actions.getTemplateDepth(getCurScope());
-          if (Depth > TemplateParameterDepth)
-            CurTemplateDepthTracker.addDepth(Depth - TemplateParameterDepth);
-
           // The argument isn't actually potentially evaluated unless it is
           // used.
           EnterExpressionEvaluationContext Eval(
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index dbc1b85acd1433..2f26d2299a68fd 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -2600,12 +2600,7 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer(
     if (BitfieldSize.isInvalid())
       SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch);
   } else if (Tok.is(tok::kw_requires)) {
-    TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
-    // With abbreviated function templates - we need to explicitly add depth to
-    // account for the implicit template parameter list induced by the 
template.
-    if (DeclaratorInfo.getTemplateParameterLists().empty() &&
-        DeclaratorInfo.getInventedTemplateParameterList())
-      ++CurTemplateDepthTracker;
+    ReenterTemplateScopeRAII InTemplateScope(*this, DeclaratorInfo);
     ParseTrailingRequiresClauseWithScope(DeclaratorInfo);
   } else {
     ParseOptionalCXX11VirtSpecifierSeq(
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 860c069e18fcaf..ce6633bbcfdb9d 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1215,7 +1215,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
   // Parse lambda-declarator[opt].
   DeclSpec DS(AttrFactory);
   Declarator D(DS, ParsedAttributesView::none(), 
DeclaratorContext::LambdaExpr);
-  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+  llvm::SaveAndRestore<unsigned> SavedTemplateDepth(TemplateParameterDepth);
 
   ParseScope LambdaScope(this, Scope::LambdaScope | Scope::DeclScope |
                                    Scope::FunctionDeclarationScope |
@@ -1255,8 +1255,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
 
     SmallVector<NamedDecl*, 4> TemplateParams;
     SourceLocation LAngleLoc, RAngleLoc;
-    if (ParseTemplateParameters(TemplateParamScope,
-                                CurTemplateDepthTracker.getDepth(),
+    if (ParseTemplateParameters(TemplateParamScope, TemplateParameterDepth,
                                 TemplateParams, LAngleLoc, RAngleLoc)) {
       Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope());
       return ExprError();
@@ -1275,7 +1274,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
       // This way, abbreviated generic lambdas could have different template
       // depths, avoiding substitution into the wrong template parameters 
during
       // constraint satisfaction check.
-      ++CurTemplateDepthTracker;
+      ++TemplateParameterDepth;
       ExprResult RequiresClause;
       if (TryConsumeToken(tok::kw_requires)) {
         RequiresClause =
@@ -1311,6 +1310,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
   bool HasSpecifiers = false;
   SourceLocation MutableLoc;
 
+  ParseScope ImplicitTemplateScope(
+      this, Scope::NoScope,
+      Actions.getCurLambda()->NumExplicitTemplateParams == 0);
+
   ParseScope Prototype(this, Scope::FunctionPrototypeScope |
                                  Scope::FunctionDeclarationScope |
                                  Scope::DeclScope);
@@ -1325,17 +1328,9 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
     LParenLoc = T.getOpenLocation();
 
     if (Tok.isNot(tok::r_paren)) {
-      Actions.RecordParsingTemplateParameterDepth(
-          CurTemplateDepthTracker.getOriginalDepth());
+      Actions.RecordParsingTemplateParameterDepth(SavedTemplateDepth.get());
 
       ParseParameterDeclarationClause(D, Attributes, ParamInfo, EllipsisLoc);
-      // For a generic lambda, each 'auto' within the parameter declaration
-      // clause creates a template type parameter, so increment the depth.
-      // If we've parsed any explicit template parameters, then the depth will
-      // have already been incremented. So we make sure that at most a single
-      // depth level is added.
-      if (Actions.getCurGenericLambda())
-        CurTemplateDepthTracker.setAddedDepth(1);
     }
 
     T.consumeClose();
@@ -1480,6 +1475,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
 
   StmtResult Stmt(ParseCompoundStatementBody());
   BodyScope.Exit();
+  ImplicitTemplateScope.Exit();
   TemplateParamScope.Exit();
   LambdaScope.Exit();
 
diff --git a/clang/lib/Parse/ParseTemplate.cpp 
b/clang/lib/Parse/ParseTemplate.cpp
index 1e5aa55338309e..a60e47e70d24cf 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -22,6 +22,25 @@
 #include "clang/Sema/Scope.h"
 using namespace clang;
 
+Parser::ReenterTemplateScopeRAII::ReenterTemplateScopeRAII(Parser &P,
+                                                           Decl 
*MaybeTemplated,
+                                                           bool Enter)
+    : Scopes(P), CurTemplateDepthTracker(P.TemplateParameterDepth) {
+  if (Enter)
+    CurTemplateDepthTracker.addDepth(
+        P.ReenterTemplateScopes(Scopes, MaybeTemplated));
+}
+
+Parser::ReenterTemplateScopeRAII::ReenterTemplateScopeRAII(Parser &P,
+                                                           const Declarator &D)
+    : Scopes(P), CurTemplateDepthTracker(P.TemplateParameterDepth) {
+  const auto *Params = D.getInventedTemplateParameterList();
+  if (Params && Params->getParam(0)->isImplicit()) {
+    Scopes.Enter(Scope::TemplateParamScope);
+    ++CurTemplateDepthTracker;
+  }
+}
+
 unsigned Parser::ReenterTemplateScopes(MultiParseScope &S, Decl *D) {
   return Actions.ActOnReenterTemplateScope(D, [&] {
     S.Enter(Scope::TemplateParamScope);
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 8ca118cd89ec46..dd95b1ca0b6711 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1185,7 +1185,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator 
&D,
   // Poison SEH identifiers so they are flagged as illegal in function bodies.
   PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
   const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
-  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+  ReenterTemplateScopeRAII InTemplateScope(*this, D);
 
   // If this is C89 and the declspecs were completely missing, fudge in an
   // implicit int.  We do this here because this is the only place where
@@ -1371,15 +1371,6 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator 
&D,
     return Res;
   }
 
-  // With abbreviated function templates - we need to explicitly add depth to
-  // account for the implicit template parameter list induced by the template.
-  if (const auto *Template = dyn_cast_if_present<FunctionTemplateDecl>(Res);
-      Template && Template->isAbbreviated() &&
-      Template->getTemplateParameters()->getParam(0)->isImplicit())
-    // First template parameter is implicit - meaning no explicit template
-    // parameter list was specified.
-    CurTemplateDepthTracker.addDepth(1);
-
   // Late attributes are parsed in the same scope as the function body.
   if (LateParsedAttrs)
     ParseLexedAttributeList(*LateParsedAttrs, Res, /*EnterScope=*/false,
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index fc79b1a056ed9e..ca5886f88e9a96 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -103,6 +103,20 @@ void Scope::Init(Scope *parent, unsigned flags) {
   NRVO = std::nullopt;
 }
 
+void Scope::EnterTemplateParameterScope() {
+  assert(isFunctionPrototypeScope() && isFunctionDeclarationScope());
+
+  Scope *Parent = getParent();
+  assert(Parent && !Parent->Entity && Parent->DeclsInScope.empty() &&
+         Parent->UsingDirectives.empty());
+  assert((Parent->getFlags() &
+          ~(OpenMPSimdDirectiveScope | OpenMPOrderClauseScope)) == NoScope &&
+         "expected a reserved, inactive template scope");
+
+  Parent->setFlags(TemplateParamScope);
+  TemplateParamParent = Parent;
+}
+
 bool Scope::containedInPrototypeScope() const {
   const Scope *S = this;
   while (S) {
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 21f71d7f8b40e2..10ee85c33441de 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -2739,17 +2739,6 @@ LambdaScopeInfo *Sema::getCurLambda(bool 
IgnoreNonLambdaCapturingScope) {
   return CurLSI;
 }
 
-// We have a generic lambda if we parsed auto parameters, or we have
-// an associated template parameter list.
-LambdaScopeInfo *Sema::getCurGenericLambda() {
-  if (LambdaScopeInfo *LSI =  getCurLambda()) {
-    return (LSI->TemplateParams.size() ||
-                    LSI->GLTemplateParameterList) ? LSI : nullptr;
-  }
-  return nullptr;
-}
-
-
 void Sema::ActOnComment(SourceRange Comment) {
   if (!LangOpts.RetainCommentsFromSystemHeaders &&
       SourceMgr.isInSystemHeader(Comment.getBegin()))
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 5de5821fe263e5..f23fe78d537b7a 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16399,14 +16399,8 @@ LambdaScopeInfo 
*Sema::RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator) {
   LSI->AfterParameterList = CurContext == CallOperator;
   LSI->BeforeCompoundStatement = false;
 
-  // GLTemplateParameterList is necessary for getCurGenericLambda() which is
-  // used at the point of dealing with potential captures.
-  //
-  // We don't use LambdaClass->isGenericLambda() because this value doesn't
-  // flip for instantiated generic lambdas, where no FunctionTemplateDecls are
-  // associated. (Technically, we could recover that list from their
-  // instantiation patterns, but for now, the GLTemplateParameterList seems
-  // unnecessary in these cases.)
+  // A generic lambda's call operator specialization has no template parameter
+  // list, even though the closure is still marked as generic.
   if (FunctionTemplateDecl *FTD = CallOperator->getDescribedFunctionTemplate())
     LSI->GLTemplateParameterList = FTD->getTemplateParameters();
   const LambdaCaptureDefault LCD = LambdaClass->getLambdaCaptureDefault();
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 568bb4c7851401..58818167b69e69 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -81,6 +81,7 @@ class CheckDefaultArgumentVisitor
   bool VisitExpr(const Expr *Node);
   bool VisitDeclRefExpr(const DeclRefExpr *DRE);
   bool VisitCXXThisExpr(const CXXThisExpr *ThisE);
+  bool VisitTemplateParameters(ArrayRef<NamedDecl *> Parameters);
   bool VisitLambdaExpr(const LambdaExpr *Lambda);
   bool VisitPseudoObjectExpr(const PseudoObjectExpr *POE);
   bool VisitCoawaitExpr(const CoawaitExpr *E);
@@ -164,14 +165,24 @@ bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr(
   return Invalid;
 }
 
-bool CheckDefaultArgumentVisitor::VisitLambdaExpr(const LambdaExpr *Lambda) {
+bool CheckDefaultArgumentVisitor::VisitTemplateParameters(
+    ArrayRef<NamedDecl *> Parameters) {
   bool Invalid = false;
-  for (NamedDecl *P : Lambda->getExplicitTemplateParameters()) {
-    const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P);
-    if (!NTTP || !NTTP->hasDefaultArgument())
-      continue;
-    Invalid |= Visit(NTTP->getDefaultArgument().getArgument().getAsExpr());
+  for (NamedDecl *P : Parameters) {
+    if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
+      if (NTTP->hasDefaultArgument())
+        Invalid |= Visit(NTTP->getDefaultArgument().getArgument().getAsExpr());
+    } else if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(P)) {
+      Invalid |=
+          VisitTemplateParameters(TTP->getTemplateParameters()->asArray());
+    }
   }
+  return Invalid;
+}
+
+bool CheckDefaultArgumentVisitor::VisitLambdaExpr(const LambdaExpr *Lambda) {
+  bool Invalid =
+      VisitTemplateParameters(Lambda->getExplicitTemplateParameters());
 
   // [expr.prim.lambda.capture]p9
   // a lambda-expression appearing in a default argument cannot implicitly or
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index ffbe5e72d4c516..dfa46ed19a7751 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1064,6 +1064,7 @@ void Sema::AddTemplateParametersToLambdaCallOperator(
       TemplateParams, CallOperator);
   TemplateMethod->setAccess(AS_public);
   CallOperator->setDescribedFunctionTemplate(TemplateMethod);
+  Class->setLambdaIsGeneric(true);
 }
 
 void Sema::CompleteLambdaCallOperator(
@@ -1097,7 +1098,6 @@ void Sema::CompleteLambdaCallOperator(
   } else {
     LSI->Lambda->addDecl(Method);
   }
-  LSI->Lambda->setLambdaIsGeneric(TemplateParams);
   LSI->Lambda->setLambdaTypeInfo(MethodTyInfo);
 
   Method->setLexicalDeclContext(DC);
@@ -1143,32 +1143,8 @@ void 
Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
   // be dependent, because there are template parameters in scope.
   CXXRecordDecl::LambdaDependencyKind LambdaDependencyKind =
       CXXRecordDecl::LDK_Unknown;
-  if (getTemplateDepth(CurScope) > 0) {
+  if (CurrentScope->getTemplateParamParent())
     LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent;
-  } else if (Scope *ParentScope = CurScope->getParent()) {
-    // Given a lambda defined inside a requires expression,
-    //
-    // struct S {
-    //   S(auto var) requires requires { [&] -> decltype(var) { }; }
-    //   {}
-    // };
-    //
-    // The parameter var is not injected into the function Decl at the point of
-    // parsing lambda. In such scenarios, perceiving it as dependent could
-    // result in the constraint being evaluated, which matches what GCC does.
-    Scope *LookupScope = ParentScope;
-    while (LookupScope->getEntity() &&
-           LookupScope->getEntity()->isRequiresExprBody())
-      LookupScope = LookupScope->getParent();
-
-    if (LookupScope != ParentScope &&
-        LookupScope->isFunctionDeclarationScope() &&
-        llvm::any_of(LookupScope->decls(), [](Decl *D) {
-          return isa<ParmVarDecl>(D) &&
-                 cast<ParmVarDecl>(D)->getType()->isTemplateTypeParmType();
-        }))
-      LambdaDependencyKind = CXXRecordDecl::LDK_AlwaysDependent;
-  }
 
   CXXRecordDecl *Class = createLambdaClosureType(
       Intro.Range, /*Info=*/nullptr, LambdaDependencyKind, Intro.Default);
@@ -1448,7 +1424,6 @@ void Sema::ActOnLambdaClosureParameters(
   if (TemplateParams) {
     AddTemplateParametersToLambdaCallOperator(LSI->CallOperator, LSI->Lambda,
                                               TemplateParams);
-    LSI->Lambda->setLambdaIsGeneric(true);
     LSI->ContainsUnexpandedParameterPack |=
         TemplateParams->containsUnexpandedParameterPack();
   }
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index b800a433b3bf74..238b0073cdca1a 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -63,34 +63,8 @@ unsigned Sema::getTemplateDepth(Scope *S) const {
   // Each template parameter scope represents one level of template parameter
   // depth.
   for (Scope *TempParamScope = S->getTemplateParamParent(); TempParamScope;
-       TempParamScope = TempParamScope->getParent()->getTemplateParamParent()) 
{
+       TempParamScope = TempParamScope->getParent()->getTemplateParamParent())
     ++Depth;
-  }
-
-  // Note that there are template parameters with the given depth.
-  auto ParamsAtDepth = [&](unsigned D) { Depth = std::max(Depth, D + 1); };
-
-  // Look for parameters of an enclosing generic lambda. We don't create a
-  // template parameter scope for these.
-  for (FunctionScopeInfo *FSI : getFunctionScopes()) {
-    if (auto *LSI = dyn_cast<LambdaScopeInfo>(FSI)) {
-      if (!LSI->TemplateParams.empty()) {
-        ParamsAtDepth(LSI->AutoTemplateParameterDepth);
-      } else if (LSI->GLTemplateParameterList) {
-        ParamsAtDepth(LSI->GLTemplateParameterList->getDepth());
-      }
-    }
-  }
-
-  // Look for parameters of an enclosing terse function template. We don't
-  // create a template parameter scope for these either.
-  for (const InventedTemplateParameterInfo &Info :
-       getInventedParameterInfos()) {
-    if (!Info.TemplateParams.empty()) {
-      ParamsAtDepth(Info.AutoTemplateParameterDepth);
-      break;
-    }
-  }
 
   return Depth;
 }
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 9de4f12aabf684..bf56cbc88a0735 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -3099,6 +3099,9 @@ InventTemplateParameter(TypeProcessingState &state, 
QualType T,
   InventedTemplateParam->setImplicit();
   Info.TemplateParams.push_back(InventedTemplateParam);
 
+  if (AutoParameterPosition == 0)
+    S.getCurScope()->EnterTemplateParameterScope();
+
   // Attach type constraints to the new parameter.
   if (Auto->isConstrained()) {
     if (TrailingTSI) {
diff --git a/clang/test/SemaCXX/lambda-unevaluated.cpp 
b/clang/test/SemaCXX/lambda-unevaluated.cpp
index 018d597e6831ba..ac0b09f787894c 100644
--- a/clang/test/SemaCXX/lambda-unevaluated.cpp
+++ b/clang/test/SemaCXX/lambda-unevaluated.cpp
@@ -284,18 +284,18 @@ static_assert(__is_same_as(int, helper<int>));
 } // namespace GH138018
 
 namespace GH172814 {
-auto f() {
+auto a() {
   int x = 0;
   return [](auto w = [&] { x += w(); }); // expected-error {{lambda expression 
in default argument cannot capture any entity}} \
                                          // expected-error {{expected body of 
lambda expression}}
 }
 
-auto t() {
+auto b() {
   int x = 0;
   return [](auto w = [&] { return x; }) { }; // expected-error {{lambda 
expression in default argument cannot capture any entity}}
 };
 
-auto g() {
+auto c() {
   int x = 0;
   return []<class T>(T w = [&] { return x; }) {}; // expected-error {{lambda 
expression in default argument cannot capture any entity}}
 }
@@ -332,36 +332,61 @@ struct S {
 }
 
 namespace GH48768 {
-
 auto a(auto x = 1, auto = []<auto = x> {}());               // expected-error 
{{default argument references parameter 'x'}}
 void b(auto x, auto = []<auto = x> {});                     // expected-error 
{{default argument references parameter 'x'}}
 auto c = [](auto x, int = []<auto = x> { return 0; }()) {}; // expected-error 
{{default argument references parameter 'x'}}
+void d(auto x, auto = []<template<auto = x> class> {});     // expected-error 
{{default argument references parameter 'x'}}
 
-constexpr int d(auto x, int n = []<auto N = sizeof(x)> { return N; }()) {
-  return n;
+constexpr int e(int x, auto y, auto z, int n = [](auto x) { return sizeof(x); 
}(123)) {
+  return x + y + z + n;
 }
+static_assert(e(1, 2, char(3)) == 6 + sizeof(int));
 
-constexpr int e(auto x, int n = []<class T = decltype(x)> { return sizeof(T); 
}()) {
+constexpr int f(auto *x, int n = []<class T = decltype(*x), auto N = 
sizeof(T)> { return N; }()) noexcept([]<class T = decltype(*x)> { return 
sizeof(T) == 1; }()) {
   return n;
 }
+static_assert(f(static_cast<int *>(nullptr)) == sizeof(int));
+static_assert(f(static_cast<char *>(nullptr)) == 1);
+static_assert(noexcept(f(static_cast<char *>(nullptr), 0)));
+static_assert(!noexcept(f(static_cast<int *>(nullptr), 0)));
 
-constexpr auto f = [](auto x, int n = []<auto N = sizeof(x)> { return N; }()) {
+constexpr int g(auto, int n = []<class T, unsigned N>(const T (&)[N]) { return 
sizeof(T) + N; }("abc")) {
   return n;
-};
+}
+static_assert(g(0) == 5);
 
-constexpr auto g = [](auto x, int n = []<class T = decltype(x)> { return 
sizeof(T); }()) {
+template <class T>
+constexpr int h(T x, auto y, int n = []<auto N = sizeof(x) + sizeof(y)> { 
return N; }()) {
   return n;
+}
+static_assert(h('a', 0) == 1 + sizeof(int));
+
+auto i = [](auto x) {
+  return [](auto y, int n = []<class T = decltype(y), auto N = 2 * sizeof(x) + 
sizeof(T)> { return N; }()) { return n; };
 };
+static_assert(i(0)('a') == 2 * sizeof(int) + 1);
+static_assert(i('a')(0) == 2 + sizeof(int));
+
+template <auto> struct A {};
+template <class> constexpr auto j() noexcept {
+  return [](auto x, int n = [](auto) noexcept { return 0; }(123)) 
noexcept([]<class T = decltype(x)> { return sizeof(T) == 1; }()) -> A<[]<auto N 
= sizeof(x)> { return N; }()> { return {}; };
+}
+static_assert(__is_same(decltype(j<void>()('a')), A<sizeof(char)>));
+static_assert(__is_same(decltype(j<void>()(0)), A<sizeof(int)>));
+static_assert(noexcept(j<void>()('a')) && !noexcept(j<void>()(0)));
 
-constexpr auto h = [](auto x) {
-  return [](auto y, int n = []<auto N = sizeof(y)> { return N; }()) {
-    return n;
-  };
+template <class T> struct B { // expected-note {{B defined here}}
+  static constexpr int a(auto x);
+  void b(auto) requires ([](auto) { return true; }(T{}));
 };
+template <class T> constexpr int B<T>::a(auto x) {
+  return [](auto y) { return sizeof(y) + sizeof(T); }(x);
+}
+static_assert(B<char>::a(0) == 1 + sizeof(int));
+
+template <class T>
+void B<T>::b(auto) requires ([](auto) { return true; }(T{})) {} // 
expected-error {{out-of-line definition of 'b' does not match any declaration}}
 
-static_assert(d(0) == sizeof(int));
-static_assert(e(0) == sizeof(int));
-static_assert(f(0) == sizeof(int));
-static_assert(g(0) == sizeof(int));
-static_assert(h(0)('a') == 1);
+template <template <class T> requires requires(T t) { t; } class> struct C {};
+static_assert([](auto x) { return x; }(1) == 1);
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to