Author: Alexander Kornienko
Date: 2026-05-22T17:10:06Z
New Revision: 4ad14a07f5704b950131f361edf05b96a871dfa2

URL: 
https://github.com/llvm/llvm-project/commit/4ad14a07f5704b950131f361edf05b96a871dfa2
DIFF: 
https://github.com/llvm/llvm-project/commit/4ad14a07f5704b950131f361edf05b96a871dfa2.diff

LOG: Revert "[Clang] Transform lambda's constraints when instantiating 
parameter mapping (#195995)" (#199228)

This reverts commit 7e2821e025f8ee4add31693ddf462947d7618016, which
causes a crash-on-valid in clang:
https://github.com/llvm/llvm-project/issues/199209

Added: 
    

Modified: 
    clang/lib/Parse/ParseTemplate.cpp
    clang/lib/Sema/SemaConcept.cpp
    clang/lib/Sema/SemaTemplate.cpp
    clang/lib/Sema/SemaTemplateDeduction.cpp
    clang/lib/Sema/SemaTemplateInstantiate.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/lib/Sema/TreeTransform.h
    clang/test/SemaTemplate/concepts-lambda.cpp
    clang/test/SemaTemplate/concepts.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Parse/ParseTemplate.cpp 
b/clang/lib/Parse/ParseTemplate.cpp
index dbc7cbc6cdc0c..330a9c6aea0c5 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 ac1c716b5c385..ea03c3f408986 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -732,8 +732,17 @@ 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(
@@ -2296,14 +2305,6 @@ 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 e2aecd21bed70..5667cf53fee0b 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4932,7 +4932,7 @@ ExprResult Sema::CheckConceptTemplateId(
     LocalInstantiationScope Scope(*this);
 
     EnterExpressionEvaluationContext EECtx{
-        *this, ExpressionEvaluationContext::Unevaluated};
+        *this, ExpressionEvaluationContext::Unevaluated, CSD};
 
     Error = CheckConstraintSatisfaction(
         NamedConcept, AssociatedConstraint(Concept->getConstraintExpr()), 
MLTAL,

diff  --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index c04fff6cbd964..1544fd56b82ae 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -5161,6 +5161,20 @@ 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 3c9ffdb42eeec..f168c99d1ac1a 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1753,24 +1753,9 @@ 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.
@@ -1881,24 +1866,12 @@ 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(), 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;
+      TemplateDeclInstantiator DeclInstantiator(getSema(),
+                                                /* DeclContext *Owner */ Owner,
+                                                TemplateArgs);
+      DeclInstantiator.setEvaluateConstraints(EvaluateConstraints);
+      return DeclInstantiator.SubstTemplateParams(OrigTPL);
     }
 
     concepts::TypeRequirement *

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index ce0e390e371e1..c9bc613a7c4ea 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4862,13 +4862,6 @@ 
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 9c0479fe8aa4f..c3bf71dbf10df 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -836,8 +836,6 @@ class TreeTransform {
         LSI->Lambda->getLambdaDependencyKind());
   }
 
-  ExprResult TransformConstraint(Expr *AC) { return AC; }
-
   QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
 
   StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
@@ -16069,16 +16067,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr 
*E) {
   assert(FPTL && "Not a FunctionProtoType?");
 
   AssociatedConstraint TRC = E->getCallOperator()->getTrailingRequiresClause();
-  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 the concept refers to any outer parameter packs, we track the 
SubstIndex
+  // for evaluation.
   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 a08cd52843c73..5a19105a5bf51 100644
--- a/clang/test/SemaTemplate/concepts-lambda.cpp
+++ b/clang/test/SemaTemplate/concepts-lambda.cpp
@@ -56,7 +56,9 @@ namespace GH57971 {
   function_ptr ptr = f<void>;
 }
 
-namespace GH58368 {
+// GH58368: A lambda defined in a concept requires we store
+// the concept as a part of the lambda context.
+namespace LambdaInConcept {
 using size_t = unsigned long;
 
 template<size_t...Ts>
@@ -368,35 +370,3 @@ 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 0e9fefdc081ed..1a0834452cbdb 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