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

This reapplies https://github.com/llvm/llvm-project/pull/195995

The last approach caused a regression because sometimes we transformed the 
constraints of lambda expression too aggressively when we should have preserved 
it.

The basic idea of this patch is to transform constraints of lambda expressions 
when we instantiate the parameter mapping, thus the evaluation can be 
emancipated from preserving outer template arguments.

Fixes https://github.com/llvm/llvm-project/issues/193944
Fixes https://github.com/llvm/llvm-project/issues/202957


>From ec8174b26e15369e97a0a069bfad2b11e5d863da Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Tue, 7 Jul 2026 14:06:24 +0800
Subject: [PATCH 1/2] 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 32a07b6266666..41a1f3d2bff40 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -741,17 +741,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(
@@ -2253,6 +2244,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 1591cea9286ae..f0d7e03c7ee4e 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4926,7 +4926,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 f57f60eb527ae..dd208d78063e6 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5159,20 +5159,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 31d2a7d763c9e..6b9c59da454c9 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1519,9 +1519,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.
@@ -1632,12 +1647,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 aad0d7da9420a..d3002e15e188b 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4926,6 +4926,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 5a19105a5bf51..a08cd52843c73 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>
@@ -370,3 +368,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 6f7f00bf12e61..1d12badda88d8 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 289df1f8bac61652a582d390dcd94f8694d3467d Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
Date: Tue, 7 Jul 2026 18:36:34 +0800
Subject: [PATCH 2/2] Fix regressions

---
 clang/include/clang/Sema/Sema.h               |   2 +-
 clang/lib/Sema/SemaConcept.cpp                |  92 +++++++------
 clang/lib/Sema/SemaTemplateInstantiate.cpp    |  34 +++--
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |   2 +-
 clang/lib/Sema/TreeTransform.h                |   4 +-
 .../SemaTemplate/concepts-lambda-GH199209.cpp | 123 ++++++++++++++++++
 clang/test/SemaTemplate/concepts-lambda.cpp   |   3 -
 clang/test/SemaTemplate/concepts.cpp          |   3 -
 8 files changed, 204 insertions(+), 59 deletions(-)
 create mode 100644 clang/test/SemaTemplate/concepts-lambda-GH199209.cpp

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 631a680727fee..2629b7b0a8679 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13520,7 +13520,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/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 41a1f3d2bff40..cbbe9b57a38b9 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -486,6 +486,7 @@ class HashParameterMapping : public 
RecursiveASTVisitor<HashParameterMapping> {
 class ConstraintSatisfactionChecker {
   Sema &S;
   const NamedDecl *Template;
+  const ConceptReference *TopLevelConceptId;
   SourceLocation TemplateNameLoc;
   UnsignedOrNone PackSubstitutionIndex;
   ConstraintSatisfaction &Satisfaction;
@@ -544,11 +545,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) {}
 
@@ -676,9 +679,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;
   }
@@ -901,8 +906,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) {
@@ -978,37 +984,42 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
   }
 
   Sema::ArgPackSubstIndexRAII SubstIndex(S, getOuterPackIndex(Constraint));
-
   const ASTTemplateArgumentListInfo *Ori =
       ConceptId->getTemplateArgsAsWritten();
-  TemplateDeductionInfo Info(TemplateNameLoc);
-  Sema::SFINAETrap Trap(S, Info);
-  Sema::InstantiatingTemplate _2(
-      S, TemplateNameLoc, 
Sema::InstantiatingTemplate::ConstraintSubstitution{},
-      const_cast<NamedDecl *>(Template), Constraint.getSourceRange());
-
   TemplateArgumentListInfo OutArgs(Ori->LAngleLoc, Ori->RAngleLoc);
-  if (S.SubstTemplateArguments(Ori->arguments(), *SubstitutedArgs, OutArgs) ||
-      Trap.hasErrorOccurred()) {
-    Satisfaction.IsSatisfied = false;
-    if (!Trap.hasErrorOccurred())
-      return ExprError();
+  if (Constraint.hasParameterMapping() || ConceptId != TopLevelConceptId) {
+    TemplateDeductionInfo Info(TemplateNameLoc);
+    Sema::SFINAETrap Trap(S, Info);
+    Sema::InstantiatingTemplate _2(
+        S, TemplateNameLoc,
+        Sema::InstantiatingTemplate::ConstraintSubstitution{},
+        const_cast<NamedDecl *>(Template), Constraint.getSourceRange());
 
-    PartialDiagnosticAt SubstDiag{SourceLocation(),
-                                  PartialDiagnostic::NullDiagnostic()};
-    Info.takeSFINAEDiagnostic(SubstDiag);
-    // FIXME: This is an unfortunate consequence of there
-    //  being no serialization code for PartialDiagnostics and the fact
-    //  that serializing them would likely take a lot more storage than
-    //  just storing them as strings. We would still like, in the
-    //  future, to serialize the proper PartialDiagnostic as serializing
-    //  it as a string defeats the purpose of the diagnostic mechanism.
-    Satisfaction.Details.insert(
-        Satisfaction.Details.begin() + Size,
-        new (S.Context) ConstraintSubstitutionDiagnostic{
-            SubstDiag.first,
-            allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
-    return ExprError();
+    if (S.SubstTemplateArguments(Ori->arguments(), *SubstitutedArgs, OutArgs) 
||
+        Trap.hasErrorOccurred()) {
+      Satisfaction.IsSatisfied = false;
+      if (!Trap.hasErrorOccurred())
+        return ExprError();
+
+      PartialDiagnosticAt SubstDiag{SourceLocation(),
+                                    PartialDiagnostic::NullDiagnostic()};
+      Info.takeSFINAEDiagnostic(SubstDiag);
+      // FIXME: This is an unfortunate consequence of there
+      //  being no serialization code for PartialDiagnostics and the fact
+      //  that serializing them would likely take a lot more storage than
+      //  just storing them as strings. We would still like, in the
+      //  future, to serialize the proper PartialDiagnostic as serializing
+      //  it as a string defeats the purpose of the diagnostic mechanism.
+      Satisfaction.Details.insert(
+          Satisfaction.Details.begin() + Size,
+          new (S.Context) ConstraintSubstitutionDiagnostic{
+              SubstDiag.first,
+              allocateStringFromConceptDiagnostic(S, SubstDiag.second)});
+      return ExprError();
+    }
+  } else {
+    for (auto &A : Ori->arguments())
+      OutArgs.addArgument(A);
   }
 
   CXXScopeSpec SS;
@@ -1019,7 +1030,7 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
       ConceptId->getFoundDecl(), ConceptId->getNamedConcept(), &OutArgs,
       /*DoCheckConstraintSatisfaction=*/false);
 
-  if (SubstitutedConceptId.isInvalid() || Trap.hasErrorOccurred())
+  if (SubstitutedConceptId.isInvalid())
     return ExprError();
 
   if (Size != Satisfaction.Details.size()) {
@@ -1227,11 +1238,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;
@@ -2126,7 +2138,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 =
@@ -2198,7 +2211,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 6b9c59da454c9..309835b610a6e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1076,6 +1076,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;
@@ -1114,10 +1115,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;
@@ -1127,6 +1132,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.
     ///
@@ -1528,10 +1540,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;
@@ -4211,10 +4221,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);
 }
 
@@ -4243,9 +4253,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/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d3002e15e188b..0cc7795e5d62e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3632,7 +3632,7 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
 
   TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create(
       SemaRef.Context, Owner, D->getBeginLoc(), D->getLocation(),
-      D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(),
+      TemplateArgs.getNewDepth(D->getDepth()), D->getIndex(),
       D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack(),
       D->hasTypeConstraint(), NumExpanded);
 
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-GH199209.cpp 
b/clang/test/SemaTemplate/concepts-lambda-GH199209.cpp
new file mode 100644
index 0000000000000..9dd52242580f0
--- /dev/null
+++ b/clang/test/SemaTemplate/concepts-lambda-GH199209.cpp
@@ -0,0 +1,123 @@
+// RUN: %clang_cc1 -std=c++2a -verify %s
+// RUN: %clang_cc1 -std=c++2b -verify %s
+// RUN: %clang_cc1 -std=c++2c -verify %s
+
+// expected-no-diagnostics
+
+template <class _Tp> auto __declval() -> _Tp &&;
+struct __cp {
+  template <class _Tp> using __f = _Tp;
+};
+template <class> __cp __cpcvr;
+template <class _Tp> using __copy_cvref_fn = decltype(__cpcvr<_Tp>);
+template <class... _As>
+concept __callable = requires(_As...) { 0; };
+struct __ignore {
+  __ignore(auto);
+};
+template <auto _Value> using __mtypeof = decltype(_Value);
+template <class> int __v;
+template <class...> int __ok_v;
+template <class> using __ok_t = decltype(__ok_v<>);
+template <class... _Args>
+concept _Ok = (__is_same(__ok_t<_Args>, int) && ...);
+template <bool> struct __i;
+template <class _Fn, class... _Args>
+using __minvoke = __i<_Ok<_Args...>>::template __f<_Fn>::template 
__f<_Args...>;
+template <> struct __i<true> {
+  template <template <class...> class _Fn, class... _Args>
+  using __g = _Fn<_Args...>;
+  template <class _Fn> using __f = _Fn;
+};
+template <template <class...> class _Fn> struct __q {
+  template <class... _Args>
+  using __f = __i<_Ok<_Args...>>::template __g<_Fn, _Args...>;
+};
+template <class _Fun, class... _As>
+using __call_result_t = decltype(__declval<_Fun>()(__declval<_As>()...));
+template <auto &_Fun, class... _As>
+using __result_of = decltype(_Fun(__declval<_As>()...));
+struct get_env_t;
+template <class _EnvProvider>
+using env_of_t = __call_result_t<get_env_t, _EnvProvider>;
+template <class _Tag, class... _Args>
+concept tag_invocable =
+    requires(_Tag __tag, _Args... __args) { tag_invoke(__tag, __args...); };
+template <class _Tag, class... _Args>
+using tag_invoke_result_t =
+    decltype(tag_invoke(__declval<_Tag>(), __declval<_Args>()...));
+struct aft {
+  void operator()(int);
+};
+struct get_env_t {
+  template <class _EnvProvider>
+  friend auto tag_invoke(get_env_t, _EnvProvider __env_provider)
+      -> decltype(__env_provider.get_env());
+  template <class _EnvProvider>
+  auto operator()(_EnvProvider) -> tag_invoke_result_t<get_env_t, 
_EnvProvider>;
+};
+template <class _Sender>
+concept aff = requires { __v<__call_result_t<aft, env_of_t<_Sender>>>; };
+struct {
+  template <class _Sender, class _ApplyFn>
+  auto operator()(_Sender __sndr, _ApplyFn __fun)
+      -> decltype(__sndr.apply(__sndr, __fun));
+} __sexpr_apply;
+struct __desc {
+  using __tag = int;
+  template <class _Fn> using __f = __minvoke<_Fn, int, int>;
+};
+template <class _Sender>
+using __impl_of = decltype(__declval<_Sender>().__impl_);
+template <class _Descriptor, auto _DescriptorFn = [] { return _Descriptor(); }>
+auto __descriptor_fn_v = _DescriptorFn;
+template <class> struct __sexpr_impl;
+auto __drop_front = []<class _Fn>(_Fn) {
+  return
+      []<class... _Rest>(auto, _Rest...) -> __call_result_t<_Fn, _Rest...> {};
+};
+template <class... _Captures> auto __captures(_Captures...) {
+  return []<class _Cvref, class _Fun>(_Cvref, _Fun)
+             -> __call_result_t<_Fun, int, __minvoke<_Cvref, _Captures>...>
+           requires __callable<__minvoke<_Cvref, _Captures>...>
+  {};
+}
+template <class, class _Data>
+using __captures_t = decltype(__captures(__declval<_Data>));
+template <class _Tag>
+using __get_attrs_fn =
+    __result_of<__drop_front, __mtypeof<__sexpr_impl<_Tag>::get_attrs>>;
+template <auto _DescriptorFn> struct __sexpr {
+  using __desc_t = decltype(_DescriptorFn());
+  using __tag_t = __desc_t::__tag;
+  __minvoke<__desc_t, __q<__captures_t>> __impl_;
+  template <class _Tag, class _Data> __sexpr(_Tag, _Data) {}
+  template <class _Self = __sexpr>
+  auto get_env() -> __result_of<__sexpr_apply, _Self, __get_attrs_fn<__tag_t>>;
+  template <class _Sender, class _ApplyFn>
+  auto apply(_Sender, _ApplyFn)
+      -> __call_result_t<__impl_of<_Sender>, __copy_cvref_fn<_Sender>,
+                         _ApplyFn>;
+};
+template <class, class> using __sexpr_t = __sexpr<__descriptor_fn_v<__desc>>;
+template <class _Tag> struct __make_sexpr_t {
+  auto operator()() { return __sexpr_t<_Tag, int>{_Tag(), 0}; }
+};
+template <class _Tag> __make_sexpr_t<_Tag> __make_sexpr;
+struct sc {
+  template <class T>
+    requires tag_invocable<sc, T>
+  auto operator()(T s) {
+    return tag_invoke({}, s);
+  }
+};
+template <class T> using res = __call_result_t<sc, T>;
+struct S {
+  template <class _Tag = int> friend auto tag_invoke(sc, S) {
+    return __make_sexpr<_Tag>();
+  }
+};
+template <> struct __sexpr_impl<int> {
+  static constexpr auto get_attrs = [](__ignore) { return int(); };
+};
+static_assert(aff<res<S>>);
diff --git a/clang/test/SemaTemplate/concepts-lambda.cpp 
b/clang/test/SemaTemplate/concepts-lambda.cpp
index a08cd52843c73..a143260f6d568 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}}
diff --git a/clang/test/SemaTemplate/concepts.cpp 
b/clang/test/SemaTemplate/concepts.cpp
index 1d12badda88d8..6f7f00bf12e61 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 {

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

Reply via email to