https://github.com/zyn0217 updated 
https://github.com/llvm/llvm-project/pull/207966

>From 10729a86948f4ad8e7d3f3d518cf909e9702c93a Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Tue, 7 Jul 2026 14:06:24 +0800
Subject: [PATCH 1/7] Reapply "[Clang] Transform lambda's constraints when
 instantiating parameter mapping"

This reverts commit 4ad14a07f5704b950131f361edf05b96a871dfa2.
---
 clang/lib/Parse/ParseTemplate.cpp             |  6 ---
 clang/lib/Sema/SemaConcept.cpp                | 19 +++++-----
 clang/lib/Sema/SemaTemplate.cpp               |  2 +-
 clang/lib/Sema/SemaTemplateDeduction.cpp      | 14 -------
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 37 ++++++++++++++++---
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  7 ++++
 clang/lib/Sema/TreeTransform.h                | 14 ++++++-
 clang/test/SemaTemplate/concepts-lambda.cpp   | 36 ++++++++++++++++--
 clang/test/SemaTemplate/concepts.cpp          |  3 ++
 9 files changed, 97 insertions(+), 41 deletions(-)

diff --git a/clang/lib/Parse/ParseTemplate.cpp 
b/clang/lib/Parse/ParseTemplate.cpp
index 735a9bd1f9f1c..1529da187614f 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -533,12 +533,6 @@ bool Parser::isTypeConstraintAnnotation() {
 bool Parser::TryAnnotateTypeConstraint() {
   if (!getLangOpts().CPlusPlus20)
     return false;
-  // The type constraint may declare template parameters, notably
-  // if it contains a generic lambda, so we need to increment
-  // the template depth as these parameters would not be instantiated
-  // at the current depth.
-  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
-  ++CurTemplateDepthTracker;
   CXXScopeSpec SS;
   bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
   if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index f41f37b8a3d19..fc52d1c4b83bb 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -746,17 +746,8 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
   // i.e they should not have access to the current class object or its
   // non-public members.
   std::optional<Sema::ContextRAII> ConceptContext;
-  if (ParentConcept) {
+  if (ParentConcept)
     ConceptContext.emplace(S, ParentConcept->getDeclContext());
-    // FIXME: the evaluation context should learn to track template arguments
-    // separately from a Decl.
-    EvaluationContext.emplace(
-        S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
-        /*LambdaContextDecl=*/
-        ImplicitConceptSpecializationDecl::Create(
-            S.Context, ParentConcept->getDeclContext(),
-            ParentConcept->getBeginLoc(), SubstitutedOutermost));
-  }
 
   Sema::ArgPackSubstIndexRAII SubstIndex(S, PackSubstitutionIndex);
   ExprResult SubstitutedAtomicExpr = EvaluateAtomicConstraint(
@@ -2319,6 +2310,14 @@ bool 
SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
     }
     assert(!ArgsAsWritten);
     const ConceptSpecializationExpr *CSE = CC.getConceptSpecializationExpr();
+    // Make sure that lambdas within template arguments live in a
+    // dependent context such that they are assured to be transformed during
+    // constraint evaluation.
+    EnterExpressionEvaluationContext EECtx(
+        SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+        /*LambdaContextDecl=*/
+        const_cast<ImplicitConceptSpecializationDecl *>(
+            CSE->getSpecializationDecl()));
     SmallVector<TemplateArgument> InnerArgs(CSE->getTemplateArguments());
     ConceptDecl *Concept = CSE->getNamedConcept();
     if (RemovePacksForFoldExpr) {
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index a7f252be1cb39..7286a0c2f6fbf 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4939,7 +4939,7 @@ ExprResult Sema::CheckConceptTemplateId(
     LocalInstantiationScope Scope(*this);
 
     EnterExpressionEvaluationContext EECtx{
-        *this, ExpressionEvaluationContext::Unevaluated, CSD};
+        *this, ExpressionEvaluationContext::Unevaluated};
 
     Error = CheckConstraintSatisfaction(
         NamedConcept, AssociatedConstraint(Concept->getConstraintExpr()), 
MLTAL,
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index d93b528facbcc..078cd0717bb25 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5180,20 +5180,6 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, 
const AutoType &Type,
     return true;
   MultiLevelTemplateArgumentList MLTAL(Concept, CTAI.SugaredConverted,
                                        /*Final=*/true);
-  // Build up an EvaluationContext with an ImplicitConceptSpecializationDecl so
-  // that the template arguments of the constraint can be preserved. For
-  // example:
-  //
-  //  template <class T>
-  //  concept C = []<D U = void>() { return true; }();
-  //
-  // We need the argument for T while evaluating type constraint D in
-  // building the CallExpr to the lambda.
-  EnterExpressionEvaluationContext EECtx(
-      S, Sema::ExpressionEvaluationContext::Unevaluated,
-      ImplicitConceptSpecializationDecl::Create(
-          S.getASTContext(), Concept->getDeclContext(), Concept->getLocation(),
-          CTAI.SugaredConverted));
   if (S.CheckConstraintSatisfaction(
           Concept, AssociatedConstraint(Concept->getConstraintExpr()), MLTAL,
           TypeLoc.getLocalSourceRange(), Satisfaction))
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp 
b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 990e52eb27d39..210c970902f6a 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1753,9 +1753,24 @@ namespace {
           if (TA.isDependent())
             return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
       }
+      if (auto *CD = dyn_cast_if_present<ImplicitConceptSpecializationDecl>(
+              LSI->Lambda->getLambdaContextDecl())) {
+        if (llvm::any_of(CD->getTemplateArguments(),
+                         [](const auto &TA) { return TA.isDependent(); }))
+          return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
+      }
       return inherited::ComputeLambdaDependency(LSI);
     }
 
+    ExprResult TransformConstraint(Expr *AC) {
+      // We don't want the template argument substitution into parameter
+      // mappings to preserve the outer depths.
+      if (AC && SemaRef.inConstraintSubstitution())
+        return TransformExpr(const_cast<Expr *>(AC));
+
+      return AC;
+    }
+
     ExprResult TransformLambdaExpr(LambdaExpr *E) {
       // Do not rebuild lambdas to avoid creating a new type.
       // Lambdas have already been processed inside their eval contexts.
@@ -1866,12 +1881,24 @@ namespace {
                               TemplateParameterList *OrigTPL)  {
       if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
 
+      std::optional<MultiLevelTemplateArgumentList> OldMLTAL;
+      // We need to preserve the lambda depth in parameter mapping.
+      // Otherwise the template argument deduction would fail, if we reduced 
the
+      // depth too early.
+      if (SemaRef.inParameterMappingSubstitution() &&
+          OrigTPL->getDepth() >= TemplateArgs.getNumSubstitutedLevels())
+        OldMLTAL = ForgetSubstitution();
+
       DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
-      TemplateDeclInstantiator DeclInstantiator(getSema(),
-                                                /* DeclContext *Owner */ Owner,
-                                                TemplateArgs);
-      DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
-      return DeclInstantiator.SubstTemplateParams(OrigTPL);
+      TemplateDeclInstantiator DeclInstantiator(getSema(), Owner, 
TemplateArgs);
+      // We don't want the template argument substitution into parameter
+      // mappings to preserve the outer depths.
+      DeclInstantiator.setEvaluateConstraints(
+          SemaRef.inConstraintSubstitution() || EvaluateConstraints);
+      auto *Transformed = DeclInstantiator.SubstTemplateParams(OrigTPL);
+      if (OldMLTAL)
+        RememberSubstitution(std::move(*OldMLTAL));
+      return Transformed;
     }
 
     concepts::TypeRequirement *
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index a787d537f02f8..f0593e9bb1788 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4848,6 +4848,13 @@ 
TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
     return nullptr;
 
   Expr *InstRequiresClause = L->getRequiresClause();
+  if (InstRequiresClause && EvaluateConstraints) {
+    ExprResult E =
+        SemaRef.SubstConstraintExpr(InstRequiresClause, TemplateArgs);
+    if (E.isInvalid())
+      return nullptr;
+    InstRequiresClause = E.get();
+  }
 
   TemplateParameterList *InstL
     = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 3c8fcbe582b43..477acaaea8576 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -837,6 +837,8 @@ class TreeTransform {
         LSI->Lambda->getLambdaDependencyKind());
   }
 
+  ExprResult TransformConstraint(Expr *AC) { return AC; }
+
   QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
 
   StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
@@ -16095,8 +16097,16 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr 
*E) {
   assert(FPTL && "Not a FunctionProtoType?");
 
   AssociatedConstraint TRC = E->getCallOperator()->getTrailingRequiresClause();
-  // If the concept refers to any outer parameter packs, we track the 
SubstIndex
-  // for evaluation.
+  if (TRC) {
+    ExprResult E = getDerived().TransformConstraint(
+        const_cast<Expr *>(TRC.ConstraintExpr));
+    if (E.isInvalid())
+      return E;
+    TRC.ConstraintExpr = E.get();
+  }
+  // If the concept refers to any outer parameter packs, we track the
+  // SubstIndex for evaluation.
+  // FIXME: This seems unnecessary after transforming lambda constraints.
   if (TRC && TRC.ConstraintExpr->containsUnexpandedParameterPack() &&
       !TRC.ArgPackSubstIndex)
     TRC.ArgPackSubstIndex = SemaRef.ArgPackSubstIndex;
diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp 
b/clang/test/SemaTemplate/concepts-lambda.cpp
index 2349953736c4f..840cd7cdb4d47 100644
--- a/clang/test/SemaTemplate/concepts-lambda.cpp
+++ b/clang/test/SemaTemplate/concepts-lambda.cpp
@@ -56,9 +56,7 @@ namespace GH57971 {
   function_ptr ptr = f<void>;
 }
 
-// GH58368: A lambda defined in a concept requires we store
-// the concept as a part of the lambda context.
-namespace LambdaInConcept {
+namespace GH58368 {
 using size_t = unsigned long;
 
 template<size_t...Ts>
@@ -407,3 +405,35 @@ void test() {
     f<42>();
 }
 }
+
+namespace GH193944 {
+
+template<auto L, typename... Ts>
+concept pass_a_concept_inside_a_lambda = requires { L.template 
operator()<Ts...>(); }; // #requires_pass_a_concept_inside_a_lambda
+
+template<auto Pred, typename... Ts>
+concept PredicateFor_bad = pass_a_concept_inside_a_lambda<[]<typename... Xs> 
// #pass_a_concept_inside_a_lambda
+                                          
requires(__is_same(decltype(Pred.template operator()<Xs>()), bool) and ...)
+                                      {},
+                                      Ts...>;
+
+template<auto Pred, typename... Ts>
+    requires PredicateFor_bad<Pred, Ts...> // #PredicateFor_bad
+constexpr const unsigned count_if_v_bad =
+        [] { return (Pred.template operator()<Ts>() + ... + 0); }();
+
+constexpr const auto L = []<typename T>
+{ return __is_same(T, long); };
+
+constexpr const auto L2 = []<typename T>
+{ return 114514; };
+
+static_assert(count_if_v_bad<L, double, int, long, void> == 1);
+
+static_assert(count_if_v_bad<L2, double> == 1);
+// expected-error@-1 {{constraints not satisfied}}
+// expected-note@#PredicateFor_bad {{evaluated to false}}
+// expected-note@#pass_a_concept_inside_a_lambda {{evaluated to false}}
+// expected-note@#requires_pass_a_concept_inside_a_lambda {{no matching member 
function}}
+
+}
diff --git a/clang/test/SemaTemplate/concepts.cpp 
b/clang/test/SemaTemplate/concepts.cpp
index f2478e1a22a6a..1ea97e5582374 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1567,9 +1567,12 @@ template<generic_range_value<[]<
    >() {}> T>
 void x() {}
 
+// FIXME: Crashes because it produces a template type parameter with invalid 
depth
+#if 0
 void foo() {
   x<vector<int>>();
 }
+#endif
 }
 
 namespace GH162770 {

>From 03c1087c2168d193a1e2cd993b076920117f0067 Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Tue, 7 Jul 2026 18:36:34 +0800
Subject: [PATCH 2/7] Fix regressions

---
 clang/include/clang/Sema/Sema.h             |  2 +-
 clang/lib/Parse/ParseTemplate.cpp           |  6 ++++
 clang/lib/Sema/SemaConcept.cpp              | 40 ++++++++++++++-------
 clang/lib/Sema/SemaTemplateInstantiate.cpp  | 37 ++++++++++++-------
 clang/lib/Sema/TreeTransform.h              |  4 +--
 clang/test/SemaTemplate/concepts-lambda.cpp | 37 +++++++++++++++++--
 clang/test/SemaTemplate/concepts.cpp        |  3 --
 7 files changed, 95 insertions(+), 34 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f7d0d493e7081..7c0b13335fc2b 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13567,7 +13567,7 @@ class Sema final : public SemaBase {
   bool SubstTemplateArgumentsInParameterMapping(
       ArrayRef<TemplateArgumentLoc> Args, SourceLocation BaseLoc,
       const MultiLevelTemplateArgumentList &TemplateArgs,
-      TemplateArgumentListInfo &Out);
+      bool TransformLambdaConstraint, TemplateArgumentListInfo &Out);
 
   /// Retrieve the template argument list(s) that should be used to
   /// instantiate the definition of the given declaration.
diff --git a/clang/lib/Parse/ParseTemplate.cpp 
b/clang/lib/Parse/ParseTemplate.cpp
index 1529da187614f..735a9bd1f9f1c 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -533,6 +533,12 @@ bool Parser::isTypeConstraintAnnotation() {
 bool Parser::TryAnnotateTypeConstraint() {
   if (!getLangOpts().CPlusPlus20)
     return false;
+  // The type constraint may declare template parameters, notably
+  // if it contains a generic lambda, so we need to increment
+  // the template depth as these parameters would not be instantiated
+  // at the current depth.
+  TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+  ++CurTemplateDepthTracker;
   CXXScopeSpec SS;
   bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope);
   if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index fc52d1c4b83bb..d683ac31850a8 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -491,6 +491,7 @@ class HashParameterMapping : public 
RecursiveASTVisitor<HashParameterMapping> {
 class ConstraintSatisfactionChecker {
   Sema &S;
   const NamedDecl *Template;
+  const ConceptReference *TopLevelConceptId;
   SourceLocation TemplateNameLoc;
   UnsignedOrNone PackSubstitutionIndex;
   ConstraintSatisfaction &Satisfaction;
@@ -549,11 +550,13 @@ class ConstraintSatisfactionChecker {
 
 public:
   ConstraintSatisfactionChecker(Sema &SemaRef, const NamedDecl *Template,
+                                const ConceptReference *TopLevelConceptId,
                                 SourceLocation TemplateNameLoc,
                                 UnsignedOrNone PackSubstitutionIndex,
                                 ConstraintSatisfaction &Satisfaction,
                                 bool BuildExpression)
-      : S(SemaRef), Template(Template), TemplateNameLoc(TemplateNameLoc),
+      : S(SemaRef), Template(Template), TopLevelConceptId(TopLevelConceptId),
+        TemplateNameLoc(TemplateNameLoc),
         PackSubstitutionIndex(PackSubstitutionIndex),
         Satisfaction(Satisfaction), BuildExpression(BuildExpression) {}
 
@@ -681,9 +684,11 @@ 
ConstraintSatisfactionChecker::SubstitutionInTemplateArguments(
   llvm::SaveAndRestore PushTemplateArgsCache(S.CurrentCachedTemplateArgs,
                                              &CachedTemplateArgs);
 
+  // We don't want the template argument substitution into parameter
+  // mappings to preserve the outer depths.
   if (S.SubstTemplateArgumentsInParameterMapping(
           Constraint.getParameterMapping(), Constraint.getBeginLoc(), MLTAL,
-          SubstArgs)) {
+          /*TransformLambdaConstraint=*/true, SubstArgs)) {
     Satisfaction.IsSatisfied = false;
     return std::nullopt;
   }
@@ -906,8 +911,9 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
     Satisfaction.IsSatisfied = false;
     Satisfaction.ContainsErrors = false;
     ExprResult Expr =
-        ConstraintSatisfactionChecker(S, Template, TemplateNameLoc,
-                                      UnsignedOrNone(I), Satisfaction,
+        ConstraintSatisfactionChecker(S, Template, TopLevelConceptId,
+                                      TemplateNameLoc, UnsignedOrNone(I),
+                                      Satisfaction,
                                       /*BuildExpression=*/false)
             .Evaluate(Constraint.getNormalizedPattern(), *SubstitutedArgs);
     if (BuildExpression) {
@@ -993,8 +999,13 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
       const_cast<NamedDecl *>(Template), Constraint.getSourceRange());
 
   TemplateArgumentListInfo OutArgs(Ori->LAngleLoc, Ori->RAngleLoc);
-  if (S.SubstTemplateArguments(Ori->arguments(), *SubstitutedArgs, OutArgs) ||
-      Trap.hasErrorOccurred()) {
+
+  if (ConceptId == TopLevelConceptId) {
+    for (auto &A : Ori->arguments())
+      OutArgs.addArgument(A);
+  } else if (S.SubstTemplateArguments(Ori->arguments(), *SubstitutedArgs,
+                                      OutArgs) ||
+             Trap.hasErrorOccurred()) {
     Satisfaction.IsSatisfied = false;
     if (!Trap.hasErrorOccurred())
       return ExprError();
@@ -1232,11 +1243,12 @@ static bool CheckConstraintSatisfaction(
                                     Template, /*CSE=*/nullptr,
                                     S.ArgPackSubstIndex);
 
-  ExprResult Res = ConstraintSatisfactionChecker(
-                       S, Template, TemplateIDRange.getBegin(),
-                       S.ArgPackSubstIndex, Satisfaction,
-                       /*BuildExpression=*/ConvertedExpr != nullptr)
-                       .Evaluate(*C, TemplateArgsLists);
+  ExprResult Res =
+      ConstraintSatisfactionChecker(
+          S, Template, TopLevelConceptId, TemplateIDRange.getBegin(),
+          S.ArgPackSubstIndex, Satisfaction,
+          /*BuildExpression=*/ConvertedExpr != nullptr)
+          .Evaluate(*C, TemplateArgsLists);
 
   if (Res.isInvalid())
     return true;
@@ -2192,7 +2204,8 @@ bool SubstituteParameterMappings::substitute(
   llvm::SaveAndRestore<decltype(SemaRef.CurrentCachedTemplateArgs)>
       DoNotCacheDependentArgs(SemaRef.CurrentCachedTemplateArgs, nullptr);
   if (SemaRef.SubstTemplateArgumentsInParameterMapping(
-          N.getParameterMapping(), N.getBeginLoc(), *MLTAL, SubstArgs))
+          N.getParameterMapping(), N.getBeginLoc(), *MLTAL,
+          /*TransformLambdaConstraint=*/false, SubstArgs))
     return true;
   Sema::CheckTemplateArgumentInfo CTAI;
   auto *TD =
@@ -2264,7 +2277,8 @@ bool 
SubstituteParameterMappings::substitute(ConceptIdConstraint &CC) {
   const ASTTemplateArgumentListInfo *ArgsAsWritten =
       CSE->getTemplateArgsAsWritten();
   if (SemaRef.SubstTemplateArgumentsInParameterMapping(
-          ArgsAsWritten->arguments(), CC.getBeginLoc(), *MLTAL, Out))
+          ArgsAsWritten->arguments(), CC.getBeginLoc(), *MLTAL,
+          /*TransformLambdaConstraint=*/false, Out))
     return true;
   Sema::CheckTemplateArgumentInfo CTAI;
   if (SemaRef.CheckTemplateArgumentList(CSE->getNamedConcept(),
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp 
b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 210c970902f6a..208d0693b94e5 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1308,6 +1308,7 @@ namespace {
     DeclarationName Entity;
     // Whether to evaluate the C++20 constraints or simply substitute into 
them.
     bool EvaluateConstraints = true;
+    bool EvaluateLambdaConstraint = false;
     // Whether Substitution was Incomplete, that is, we tried to substitute in
     // any user provided template arguments which were null.
     bool IsIncomplete = false;
@@ -1346,10 +1347,14 @@ namespace {
     inline static struct ForParameterMappingSubstitution_t {
     } ForParameterMappingSubstitution;
 
+    inline static struct ForConstraintSubstitution_t {
+    } ForConstraintSubstitution;
+
     TemplateInstantiator(ForParameterMappingSubstitution_t, Sema &SemaRef,
-                         SourceLocation Loc,
+                         SourceLocation Loc, bool TransformLambdaConstraint,
                          const MultiLevelTemplateArgumentList &TemplateArgs)
         : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+          EvaluateLambdaConstraint(TransformLambdaConstraint),
           BailOutOnIncomplete(false) {
       if (!SemaRef.CurrentCachedTemplateArgs)
         return;
@@ -1359,6 +1364,13 @@ namespace {
           Arg.Profile(V, SemaRef.Context);
     }
 
+    TemplateInstantiator(ForConstraintSubstitution_t, Sema &SemaRef,
+                         const MultiLevelTemplateArgumentList &TemplateArgs,
+                         SourceLocation Loc, DeclarationName Entity,
+                         bool BailOutOnIncomplete = false)
+        : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
+          EvaluateLambdaConstraint(true), BailOutOnIncomplete(false) {}
+
     /// Determine whether the given type \p T has already been
     /// transformed.
     ///
@@ -1762,10 +1774,8 @@ namespace {
       return inherited::ComputeLambdaDependency(LSI);
     }
 
-    ExprResult TransformConstraint(Expr *AC) {
-      // We don't want the template argument substitution into parameter
-      // mappings to preserve the outer depths.
-      if (AC && SemaRef.inConstraintSubstitution())
+    ExprResult TransformLambdaConstraint(Expr *AC) {
+      if (AC && EvaluateLambdaConstraint)
         return TransformExpr(const_cast<Expr *>(AC));
 
       return AC;
@@ -1885,8 +1895,7 @@ namespace {
       // We need to preserve the lambda depth in parameter mapping.
       // Otherwise the template argument deduction would fail, if we reduced 
the
       // depth too early.
-      if (SemaRef.inParameterMappingSubstitution() &&
-          OrigTPL->getDepth() >= TemplateArgs.getNumSubstitutedLevels())
+      if (SemaRef.inParameterMappingSubstitution())
         OldMLTAL = ForgetSubstitution();
 
       DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
@@ -4442,10 +4451,10 @@ bool Sema::SubstTemplateArguments(
 bool Sema::SubstTemplateArgumentsInParameterMapping(
     ArrayRef<TemplateArgumentLoc> Args, SourceLocation BaseLoc,
     const MultiLevelTemplateArgumentList &TemplateArgs,
-    TemplateArgumentListInfo &Out) {
+    bool TransformLambdaConstraint, TemplateArgumentListInfo &Out) {
   TemplateInstantiator Instantiator(
       TemplateInstantiator::ForParameterMappingSubstitution, *this, BaseLoc,
-      TemplateArgs);
+      TransformLambdaConstraint, TemplateArgs);
   return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), 
Out);
 }
 
@@ -4474,9 +4483,13 @@ Sema::SubstCXXIdExpr(Expr *E,
 ExprResult
 Sema::SubstConstraintExpr(Expr *E,
                           const MultiLevelTemplateArgumentList &TemplateArgs) {
-  // FIXME: should call SubstExpr directly if this function is equivalent or
-  //        should it be different?
-  return SubstExpr(E, TemplateArgs);
+  if (!E)
+    return E;
+
+  TemplateInstantiator Instantiator(
+      TemplateInstantiator::ForConstraintSubstitution, *this, TemplateArgs,
+      SourceLocation(), DeclarationName());
+  return Instantiator.TransformExpr(E);
 }
 
 ExprResult Sema::SubstConstraintExprWithoutSatisfaction(
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 477acaaea8576..07f2dcf496f4b 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -837,7 +837,7 @@ class TreeTransform {
         LSI->Lambda->getLambdaDependencyKind());
   }
 
-  ExprResult TransformConstraint(Expr *AC) { return AC; }
+  ExprResult TransformLambdaConstraint(Expr *AC) { return AC; }
 
   QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
 
@@ -16098,7 +16098,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr 
*E) {
 
   AssociatedConstraint TRC = E->getCallOperator()->getTrailingRequiresClause();
   if (TRC) {
-    ExprResult E = getDerived().TransformConstraint(
+    ExprResult E = getDerived().TransformLambdaConstraint(
         const_cast<Expr *>(TRC.ConstraintExpr));
     if (E.isInvalid())
       return E;
diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp 
b/clang/test/SemaTemplate/concepts-lambda.cpp
index 840cd7cdb4d47..19c0769833480 100644
--- a/clang/test/SemaTemplate/concepts-lambda.cpp
+++ b/clang/test/SemaTemplate/concepts-lambda.cpp
@@ -160,13 +160,10 @@ static_assert(E<int>);  // previously Asserted.
 namespace DIsFalse {
 template<auto Q> concept C = requires { Q.template operator()<float>(); }; // 
#GH60642-C
 template<class> concept D = false;
-// FIXME: Crashes because it produces a template type parameter with invalid 
depth
-#if 0
 static_assert(C<[]<D>{}>);
 // expected-error@-1{{static assertion failed}}
 // expected-note@-2{{does not satisfy 'C'}}
 // expected-note@-5{{because 'Q.template operator()<float>()' would be 
invalid: no matching member function for call to 'operator()'}}
-#endif
 template<class> concept E = C<[]<D>{}>;
 static_assert(E<int>);
 // expected-error@-1{{static assertion failed}}
@@ -406,6 +403,40 @@ void test() {
 }
 }
 
+namespace GH199209 {
+
+template <class T> auto declval() -> T &&;
+struct Id {
+  template <class T> using f = T;
+};
+template <class... Ts> concept Ok = (__is_same(Ts, Ts) && ...);
+template <bool> struct I;
+template <class F, class... Ts>
+using minvoke = I<Ok<Ts...>>::template f<F>::template f<Ts...>;
+template <> struct I<true> {
+  template <template <class...> class F, class... Ts>
+  using g = F<Ts...>;
+  template <class F> using f = F;
+};
+template <template <class...> class F> struct Q {
+  template <class... Ts> using f = I<Ok<Ts...>>::template g<F, Ts...>;
+};
+template <class S> concept has_env = requires { declval<S>().get_env(); };
+struct Desc {
+  template <class F> using f = minvoke<F, int>;
+};
+template <class... C> auto captures(C...) {
+  return []<class Cv>(Cv) -> int requires Ok<minvoke<Cv, C>...> {};
+}
+template <class D> using captures_t = decltype(captures(declval<D>));
+template <class D> struct Sexpr {
+  minvoke<D, Q<captures_t>> impl;
+  auto get_env() -> decltype(impl(Id()));
+};
+static_assert(has_env<Sexpr<Desc>>);
+
+}
+
 namespace GH193944 {
 
 template<auto L, typename... Ts>
diff --git a/clang/test/SemaTemplate/concepts.cpp 
b/clang/test/SemaTemplate/concepts.cpp
index 1ea97e5582374..f2478e1a22a6a 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1567,12 +1567,9 @@ template<generic_range_value<[]<
    >() {}> T>
 void x() {}
 
-// FIXME: Crashes because it produces a template type parameter with invalid 
depth
-#if 0
 void foo() {
   x<vector<int>>();
 }
-#endif
 }
 
 namespace GH162770 {

>From 0ad7ab95cf210351384aa941f1731117921b747f Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Wed, 8 Jul 2026 19:50:03 +0800
Subject: [PATCH 3/7] Really fix the lambda depths issue

---
 clang/lib/Sema/SemaConcept.cpp       | 12 +++++++++---
 clang/lib/Sema/SemaLambda.cpp        |  3 ++-
 clang/test/SemaTemplate/concepts.cpp | 11 ++++++++++-
 3 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index d683ac31850a8..8e94945c48e71 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -735,9 +735,15 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
     const AtomicConstraint &Constraint,
     const MultiLevelTemplateArgumentList &MLTAL) {
   std::optional<EnterExpressionEvaluationContext> EvaluationContext;
-  EvaluationContext.emplace(
-      S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
-      Sema::ReuseLambdaContextDecl);
+  // The ConceptDecl as a ContextDecl ensures that, when evaluating constraints
+  // on transformed lambdas, we don't have extra outer template arguments.
+  if (ParentConcept)
+    EvaluationContext.emplace(
+        S, Sema::ExpressionEvaluationContext::ConstantEvaluated, 
ParentConcept);
+  else
+    EvaluationContext.emplace(
+        S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+        Sema::ReuseLambdaContextDecl);
 
   llvm::SmallVector<TemplateArgument> SubstitutedOutermost;
   std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs =
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 8572e3a742a6c..463163a31bca6 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -327,7 +327,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
       }
     } else if (isa<FieldDecl>(ManglingContextDecl)) {
       return DataMember;
-    } else if (isa<ImplicitConceptSpecializationDecl>(ManglingContextDecl)) {
+    } else if (isa<ImplicitConceptSpecializationDecl, ConceptDecl>(
+                   ManglingContextDecl)) {
       return Concept;
     }
 
diff --git a/clang/test/SemaTemplate/concepts.cpp 
b/clang/test/SemaTemplate/concepts.cpp
index f2478e1a22a6a..b37e856fe84d0 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -1556,9 +1556,12 @@ struct vector;
 template <typename T, typename U>
 concept C = __is_same_as(T, U);
 
+template <typename T, typename U>
+concept D = false && __is_same_as(T, U);
+
 template<class T, auto Cpt>
 concept generic_range_value = requires {
-    Cpt.template operator()<int>();
+    Cpt.template operator()<int>(); // expected-note {{would be invalid}}
 };
 
 
@@ -1567,8 +1570,14 @@ template<generic_range_value<[]<
    >() {}> T>
 void x() {}
 
+template<generic_range_value<[]< // expected-note {{evaluated to false}}
+   D<int>
+   >() {}> T>
+void y() {} // expected-note {{ignored}}
+
 void foo() {
   x<vector<int>>();
+  y<vector<int>>(); // expected-error {{no matching function}}
 }
 }
 

>From 680f9f82bb5f5d47f389a8d29a8b4d12e2bbb3a9 Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Fri, 10 Jul 2026 14:56:48 +0800
Subject: [PATCH 4/7] Fix another regression in 22

---
 clang/include/clang/Sema/Sema.h               | 17 +--------
 clang/include/clang/Sema/Template.h           |  6 +++
 clang/lib/Sema/SemaConcept.cpp                |  9 ++---
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 37 +++++++------------
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 11 ++++--
 clang/lib/Sema/TreeTransform.h                |  6 ---
 clang/test/SemaTemplate/concepts-lambda.cpp   | 25 +++++++++++++
 7 files changed, 57 insertions(+), 54 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 7c0b13335fc2b..e80b4bed2c89d 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13567,7 +13567,7 @@ class Sema final : public SemaBase {
   bool SubstTemplateArgumentsInParameterMapping(
       ArrayRef<TemplateArgumentLoc> Args, SourceLocation BaseLoc,
       const MultiLevelTemplateArgumentList &TemplateArgs,
-      bool TransformLambdaConstraint, TemplateArgumentListInfo &Out);
+      TemplateArgumentListInfo &Out);
 
   /// Retrieve the template argument list(s) that should be used to
   /// instantiate the definition of the given declaration.
@@ -13872,21 +13872,6 @@ class Sema final : public SemaBase {
   ExprResult SubstCXXIdExpr(Expr *E,
                             const MultiLevelTemplateArgumentList 
&TemplateArgs);
 
-  // A RAII type used by the TemplateDeclInstantiator and TemplateInstantiator
-  // to disable constraint evaluation, then restore the state.
-  template <typename InstTy> struct ConstraintEvalRAII {
-    InstTy &TI;
-    bool OldValue;
-
-    ConstraintEvalRAII(InstTy &TI)
-        : TI(TI), OldValue(TI.getEvaluateConstraints()) {
-      TI.setEvaluateConstraints(false);
-    }
-    ~ConstraintEvalRAII() { TI.setEvaluateConstraints(OldValue); }
-    ConstraintEvalRAII(const ConstraintEvalRAII &) = delete;
-    ConstraintEvalRAII &operator=(const ConstraintEvalRAII &) = delete;
-  };
-
   // Must be used instead of SubstExpr at 'constraint checking' time.
   ExprResult
   SubstConstraintExpr(Expr *E,
diff --git a/clang/include/clang/Sema/Template.h 
b/clang/include/clang/Sema/Template.h
index b0170c21feb1a..a3340d2f4a044 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -97,6 +97,8 @@ enum class TemplateSubstitutionKind : char {
     /// The kind of substitution described by this argument list.
     TemplateSubstitutionKind Kind = TemplateSubstitutionKind::Specialization;
 
+    bool RetainInnerDepths = false;
+
   public:
     /// Construct an empty set of template argument lists.
     MultiLevelTemplateArgumentList() = default;
@@ -108,6 +110,10 @@ enum class TemplateSubstitutionKind : char {
 
     void setKind(TemplateSubstitutionKind K) { Kind = K; }
 
+    void setRetainInnerDepths() { RetainInnerDepths = true; }
+
+    bool retainInnerDepths() const { return RetainInnerDepths; }
+
     /// Determine the kind of template substitution being performed.
     TemplateSubstitutionKind getKind() const { return Kind; }
 
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 8e94945c48e71..4d030d5115fc1 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -688,7 +688,7 @@ 
ConstraintSatisfactionChecker::SubstitutionInTemplateArguments(
   // mappings to preserve the outer depths.
   if (S.SubstTemplateArgumentsInParameterMapping(
           Constraint.getParameterMapping(), Constraint.getBeginLoc(), MLTAL,
-          /*TransformLambdaConstraint=*/true, SubstArgs)) {
+          SubstArgs)) {
     Satisfaction.IsSatisfied = false;
     return std::nullopt;
   }
@@ -2210,8 +2210,7 @@ bool SubstituteParameterMappings::substitute(
   llvm::SaveAndRestore<decltype(SemaRef.CurrentCachedTemplateArgs)>
       DoNotCacheDependentArgs(SemaRef.CurrentCachedTemplateArgs, nullptr);
   if (SemaRef.SubstTemplateArgumentsInParameterMapping(
-          N.getParameterMapping(), N.getBeginLoc(), *MLTAL,
-          /*TransformLambdaConstraint=*/false, SubstArgs))
+          N.getParameterMapping(), N.getBeginLoc(), *MLTAL, SubstArgs))
     return true;
   Sema::CheckTemplateArgumentInfo CTAI;
   auto *TD =
@@ -2283,8 +2282,7 @@ bool 
SubstituteParameterMappings::substitute(ConceptIdConstraint &CC) {
   const ASTTemplateArgumentListInfo *ArgsAsWritten =
       CSE->getTemplateArgsAsWritten();
   if (SemaRef.SubstTemplateArgumentsInParameterMapping(
-          ArgsAsWritten->arguments(), CC.getBeginLoc(), *MLTAL,
-          /*TransformLambdaConstraint=*/false, Out))
+          ArgsAsWritten->arguments(), CC.getBeginLoc(), *MLTAL, Out))
     return true;
   Sema::CheckTemplateArgumentInfo CTAI;
   if (SemaRef.CheckTemplateArgumentList(CSE->getNamedConcept(),
@@ -2366,6 +2364,7 @@ bool 
SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
         /*RelativeToPrimary=*/true,
         /*Pattern=*/nullptr,
         /*ForConstraintInstantiation=*/true);
+    MLTAL.setRetainInnerDepths();
 
     return SubstituteParameterMappings(SemaRef, &MLTAL,
                                        CSE->getTemplateArgsAsWritten(),
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp 
b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 208d0693b94e5..15acc6bf9caee 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1351,11 +1351,10 @@ namespace {
     } ForConstraintSubstitution;
 
     TemplateInstantiator(ForParameterMappingSubstitution_t, Sema &SemaRef,
-                         SourceLocation Loc, bool TransformLambdaConstraint,
+                         SourceLocation Loc,
                          const MultiLevelTemplateArgumentList &TemplateArgs)
         : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc),
-          EvaluateLambdaConstraint(TransformLambdaConstraint),
-          BailOutOnIncomplete(false) {
+          EvaluateLambdaConstraint(true), BailOutOnIncomplete(false) {
       if (!SemaRef.CurrentCachedTemplateArgs)
         return;
       auto &V = TemplateArgsHashValue.emplace();
@@ -1788,7 +1787,7 @@ namespace {
         return E;
       LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
                                     /*InstantiatingLambdaOrBlock=*/true);
-      Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
+      llvm::SaveAndRestore RAII(EvaluateConstraints, EvaluateLambdaConstraint);
 
       return inherited::TransformLambdaExpr(E);
     }
@@ -1891,23 +1890,10 @@ namespace {
                               TemplateParameterList *OrigTPL)  {
       if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
 
-      std::optional<MultiLevelTemplateArgumentList> OldMLTAL;
-      // We need to preserve the lambda depth in parameter mapping.
-      // Otherwise the template argument deduction would fail, if we reduced 
the
-      // depth too early.
-      if (SemaRef.inParameterMappingSubstitution())
-        OldMLTAL = ForgetSubstitution();
-
       DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
       TemplateDeclInstantiator DeclInstantiator(getSema(), Owner, 
TemplateArgs);
-      // We don't want the template argument substitution into parameter
-      // mappings to preserve the outer depths.
-      DeclInstantiator.setEvaluateConstraints(
-          SemaRef.inConstraintSubstitution() || EvaluateConstraints);
-      auto *Transformed = DeclInstantiator.SubstTemplateParams(OrigTPL);
-      if (OldMLTAL)
-        RememberSubstitution(std::move(*OldMLTAL));
-      return Transformed;
+      DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
+      return DeclInstantiator.SubstTemplateParams(OrigTPL);
     }
 
     concepts::TypeRequirement *
@@ -2202,6 +2188,9 @@ 
TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
 ExprResult
 TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
                                                NonTypeTemplateParmDecl *NTTP) {
+  if (TemplateArgs.retainInnerDepths() &&
+      NTTP->getDepth() >= TemplateArgs.getNumLevels())
+    return E;
   // If the corresponding template argument is NULL or non-existent, it's
   // because we are performing instantiation from explicitly-specified
   // template arguments in a function template, but there were some
@@ -2610,8 +2599,10 @@ 
TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
     NewTTPDecl = cast_or_null<TemplateTypeParmDecl>(
         TransformDecl(TL.getNameLoc(), OldTTPDecl));
   QualType Result = getSema().Context.getTemplateTypeParmType(
-      T->getDepth() - TemplateArgs.getNumSubstitutedLevels(), T->getIndex(),
-      T->isParameterPack(), NewTTPDecl);
+      T->getDepth() - (TemplateArgs.retainInnerDepths()
+                           ? 0
+                           : TemplateArgs.getNumSubstitutedLevels()),
+      T->getIndex(), T->isParameterPack(), NewTTPDecl);
   TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result);
   NewTL.setNameLoc(TL.getNameLoc());
   return Result;
@@ -4451,10 +4442,10 @@ bool Sema::SubstTemplateArguments(
 bool Sema::SubstTemplateArgumentsInParameterMapping(
     ArrayRef<TemplateArgumentLoc> Args, SourceLocation BaseLoc,
     const MultiLevelTemplateArgumentList &TemplateArgs,
-    bool TransformLambdaConstraint, TemplateArgumentListInfo &Out) {
+    TemplateArgumentListInfo &Out) {
   TemplateInstantiator Instantiator(
       TemplateInstantiator::ForParameterMappingSubstitution, *this, BaseLoc,
-      TransformLambdaConstraint, TemplateArgs);
+      TemplateArgs);
   return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), 
Out);
 }
 
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f0593e9bb1788..2461c5ae700da 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -33,6 +33,7 @@
 #include "clang/Sema/SemaSwift.h"
 #include "clang/Sema/Template.h"
 #include "clang/Sema/TemplateInstCallback.h"
+#include "llvm/Support/SaveAndRestore.h"
 #include "llvm/Support/TimeProfiler.h"
 #include <optional>
 
@@ -2547,7 +2548,7 @@ 
TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
   // merged with the local instantiation scope for the function template
   // itself.
   LocalInstantiationScope Scope(SemaRef);
-  Sema::ConstraintEvalRAII<TemplateDeclInstantiator> RAII(*this);
+  llvm::SaveAndRestore RAII(EvaluateConstraints, false);
 
   TemplateParameterList *TempParams = D->getTemplateParameters();
   TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
@@ -3577,9 +3578,11 @@ Decl 
*TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
 
   TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create(
       SemaRef.Context, Owner, D->getBeginLoc(), D->getLocation(),
-      D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(),
-      D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack(),
-      D->hasTypeConstraint(), NumExpanded);
+      D->getDepth() - (TemplateArgs.retainInnerDepths()
+                           ? 0
+                           : TemplateArgs.getNumSubstitutedLevels()),
+      D->getIndex(), D->getIdentifier(), D->wasDeclaredWithTypename(),
+      D->isParameterPack(), D->hasTypeConstraint(), NumExpanded);
 
   Inst->setAccess(AS_public);
   Inst->setImplicit(D->isImplicit());
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 07f2dcf496f4b..0069a62ce184e 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -16104,12 +16104,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr 
*E) {
       return E;
     TRC.ConstraintExpr = E.get();
   }
-  // If the concept refers to any outer parameter packs, we track the
-  // SubstIndex for evaluation.
-  // FIXME: This seems unnecessary after transforming lambda constraints.
-  if (TRC && TRC.ConstraintExpr->containsUnexpandedParameterPack() &&
-      !TRC.ArgPackSubstIndex)
-    TRC.ArgPackSubstIndex = SemaRef.ArgPackSubstIndex;
 
   getSema().CompleteLambdaCallOperator(
       NewCallOperator, E->getCallOperator()->getLocation(),
diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp 
b/clang/test/SemaTemplate/concepts-lambda.cpp
index 19c0769833480..2010a028fce4a 100644
--- a/clang/test/SemaTemplate/concepts-lambda.cpp
+++ b/clang/test/SemaTemplate/concepts-lambda.cpp
@@ -467,4 +467,29 @@ static_assert(count_if_v_bad<L2, double> == 1);
 // expected-note@#pass_a_concept_inside_a_lambda {{evaluated to false}}
 // expected-note@#requires_pass_a_concept_inside_a_lambda {{no matching member 
function}}
 
+template <typename ...Ts>
+concept test = ((sizeof(Ts) < 2) && ...);
+
+template<auto L, typename... Ts>
+concept pass_a_concept_inside_a_lambda_2 = requires {
+  L.template operator()<Ts...>(Ts()...);  // 
#requires_pass_a_concept_inside_a_lambda_2
+};
+
+template<auto Pred, typename... Ts>
+concept PredicateFor_bad_2 = pass_a_concept_inside_a_lambda_2<[]<typename... 
Xs> // #pass_a_concept_inside_a_lambda_2
+                                          
requires(__is_same(decltype(Pred.template operator()<Xs>()), bool) and ...)
+                                      (test auto...){},
+                                      Ts...>;
+
+template<auto Pred, typename... Ts>
+    requires PredicateFor_bad_2<Pred, Ts...> // #PredicateFor_bad_2
+constexpr const unsigned count_if_v_bad_2 = 111;
+
+static_assert(count_if_v_bad_2<L, double> == 111);
+// expected-error@-1 {{constraints not satisfied}}
+// expected-note@#PredicateFor_bad_2 {{false}}
+// expected-note@#pass_a_concept_inside_a_lambda_2 {{false}}
+// expected-note@#requires_pass_a_concept_inside_a_lambda_2 {{no matching 
member function}}
+static_assert(count_if_v_bad_2<L, char> == 111);
+
 }

>From 7fd35dcdf0e6ef3d4fbae7d42184836da2bd154f Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Fri, 10 Jul 2026 15:39:27 +0800
Subject: [PATCH 5/7] revert format changes

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp 
b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 15acc6bf9caee..3fede2b7c1d2f 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1891,7 +1891,9 @@ namespace {
       if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
 
       DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext();
-      TemplateDeclInstantiator DeclInstantiator(getSema(), Owner, 
TemplateArgs);
+      TemplateDeclInstantiator DeclInstantiator(getSema(),
+                                                /* DeclContext *Owner */ Owner,
+                                                TemplateArgs);
       DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
       return DeclInstantiator.SubstTemplateParams(OrigTPL);
     }

>From c96ec40de0a8edecca8e72c2308c13ca039109c5 Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Fri, 10 Jul 2026 19:27:42 +0800
Subject: [PATCH 6/7] [Clang] Ensure correct template parameter depth for
 abbreviated templates

---
 clang/test/SemaTemplate/concepts-lambda.cpp | 37 +++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp 
b/clang/test/SemaTemplate/concepts-lambda.cpp
index 2010a028fce4a..f5eed4d993c27 100644
--- a/clang/test/SemaTemplate/concepts-lambda.cpp
+++ b/clang/test/SemaTemplate/concepts-lambda.cpp
@@ -403,6 +403,43 @@ void test() {
 }
 }
 
+namespace GH200682 {
+
+template <typename... Args> struct A {
+  template <auto F> constexpr static bool B = F(42);
+};
+
+template <typename T>
+concept c = true;
+
+template <typename T>
+concept d = false;
+
+void f(auto &&...args)
+  requires(
+      A<decltype(args)...>::template B<[](auto x) { return c<decltype(x)>; }>);
+
+template <class>
+void g(auto &&...args)
+  requires(
+      A<decltype(args)...>::template B<[](auto x) { return c<decltype(x)>; }>);
+
+void h(auto &&...args) // expected-note {{constraints not satisfied}}
+  requires(
+      A<decltype(args)...>::template B<[](auto x) { // expected-note 
{{evaluated to false}}
+        return d<decltype(x)>;
+      }>);
+
+void main() {
+  f();
+  g<int>();
+
+  h(42);
+  // expected-error@-1 {{no matching}}
+}
+
+}
+
 namespace GH199209 {
 
 template <class T> auto declval() -> T &&;

>From 1bb3570a49cabb51baeccc5afebb8628de3ab7f6 Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Fri, 10 Jul 2026 23:05:18 +0800
Subject: [PATCH 7/7] Address feedback

---
 clang/lib/Sema/SemaConcept.cpp              |  5 ++-
 clang/test/SemaTemplate/concepts-lambda.cpp | 37 ---------------------
 2 files changed, 4 insertions(+), 38 deletions(-)

diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 4d030d5115fc1..476910a9db528 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -1006,7 +1006,10 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
 
   TemplateArgumentListInfo OutArgs(Ori->LAngleLoc, Ori->RAngleLoc);
 
-  if (ConceptId == TopLevelConceptId) {
+  // There's a concern that even with the same concept, they may not have the
+  // same ConceptReference, if they come from modules.
+  if (TopLevelConceptId &&
+      ConceptId->getNamedConcept() == TopLevelConceptId->getNamedConcept()) {
     for (auto &A : Ori->arguments())
       OutArgs.addArgument(A);
   } else if (S.SubstTemplateArguments(Ori->arguments(), *SubstitutedArgs,
diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp 
b/clang/test/SemaTemplate/concepts-lambda.cpp
index f5eed4d993c27..2010a028fce4a 100644
--- a/clang/test/SemaTemplate/concepts-lambda.cpp
+++ b/clang/test/SemaTemplate/concepts-lambda.cpp
@@ -403,43 +403,6 @@ void test() {
 }
 }
 
-namespace GH200682 {
-
-template <typename... Args> struct A {
-  template <auto F> constexpr static bool B = F(42);
-};
-
-template <typename T>
-concept c = true;
-
-template <typename T>
-concept d = false;
-
-void f(auto &&...args)
-  requires(
-      A<decltype(args)...>::template B<[](auto x) { return c<decltype(x)>; }>);
-
-template <class>
-void g(auto &&...args)
-  requires(
-      A<decltype(args)...>::template B<[](auto x) { return c<decltype(x)>; }>);
-
-void h(auto &&...args) // expected-note {{constraints not satisfied}}
-  requires(
-      A<decltype(args)...>::template B<[](auto x) { // expected-note 
{{evaluated to false}}
-        return d<decltype(x)>;
-      }>);
-
-void main() {
-  f();
-  g<int>();
-
-  h(42);
-  // expected-error@-1 {{no matching}}
-}
-
-}
-
 namespace GH199209 {
 
 template <class T> auto declval() -> T &&;

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

Reply via email to