[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/zyn0217 closed https://github.com/llvm/llvm-project/pull/195995 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
llvm-ci wrote: LLVM Buildbot has detected a new failure on builder `clang-aarch64-global-isel` running on `linaro-clang-aarch64-global-isel` while building `clang` at step 14 "test-suite". Full details are available at: https://lab.llvm.org/buildbot/#/builders/125/builds/14554 Here is the relevant piece of the build log for the reference ``` Step 14 (test-suite) failure: test (failure) TEST 'test-suite :: tools/test/alloc_mem.test' FAILED /home/tcwg-buildbot/worker/clang-aarch64-global-isel/test/sandbox/build/tools/timeit-target --timeout 7200 --limit-core 0 --limit-cpu 7200 --limit-file-size 209715200 --limit-rss-size 838860800 --redirect-input /dev/null --summary /home/tcwg-buildbot/worker/clang-aarch64-global-isel/test/sandbox/build/tools/test/Output/alloc_mem.test.time /usr/bin/python3.10 /home/tcwg-buildbot/worker/clang-aarch64-global-isel/test/sandbox/build/tools/test/test_maxrss.py /home/tcwg-buildbot/worker/clang-aarch64-global-isel/test/sandbox/build/tools/timeit-target /home/tcwg-buildbot/worker/clang-aarch64-global-isel/test/sandbox/build/tools/test/alloc_mem maxrss too low: 132120576 < 134217728 + /home/tcwg-buildbot/worker/clang-aarch64-global-isel/test/sandbox/build/tools/timeit-target --timeout 7200 --limit-core 0 --limit-cpu 7200 --limit-file-size 209715200 --limit-rss-size 838860800 --redirect-input /dev/null --summary /home/tcwg-buildbot/worker/clang-aarch64-global-isel/test/sandbox/build/tools/test/Output/alloc_mem.test.time /usr/bin/python3.10 /home/tcwg-buildbot/worker/clang-aarch64-global-isel/test/sandbox/build/tools/test/test_maxrss.py /home/tcwg-buildbot/worker/clang-aarch64-global-isel/test/sandbox/build/tools/timeit-target /home/tcwg-buildbot/worker/clang-aarch64-global-isel/test/sandbox/build/tools/test/alloc_mem ``` https://github.com/llvm/llvm-project/pull/195995 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/zyn0217 edited https://github.com/llvm/llvm-project/pull/195995 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
@@ -1876,11 +1901,25 @@ namespace {
TemplateParameterList *OrigTPL) {
if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
+ std::optional 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() &&
+ getDepthAndIndex(OrigTPL->getParam(0)).first >=
+ TemplateArgs.getNumSubstitutedLevels())
+OldMLTAL = ForgetSubstitution();
mizvekov wrote:
Okay, I think I understand now what you are trying to do. I initially
misunderstood the problem as you trying to avoid getting the lambda's depth to
go below zero.
I am not sure I understand why changing the depth is a problem for deduction,
because deduction accepts the template depth as a parameter and this should be
easy to figure out for the lambda since it has template parameters.
Anyway, you can use the `getDepth` method on the template parameter list
directly:
```suggestion
std::optional 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();
```
https://github.com/llvm/llvm-project/pull/195995
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
github-actions[bot] wrote:
:warning: C/C++ code formatter, clang-format found issues in your code.
:warning:
You can test this locally with the following command:
``bash
git-clang-format --diff origin/main HEAD --extensions h,cpp --
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 --diff_from_common_commit
``
:warning:
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing `origin/main` to the base branch/commit you want to compare against.
:warning:
View the diff from clang-format here.
``diff
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 97b4f709d..444795c3b 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -16069,8 +16069,8 @@ TreeTransform::TransformLambdaExpr(LambdaExpr
*E) {
AssociatedConstraint TRC = E->getCallOperator()->getTrailingRequiresClause();
if (TRC) {
-ExprResult E =
-getDerived().TransformConstraint(const_cast(TRC.ConstraintExpr));
+ExprResult E = getDerived().TransformConstraint(
+const_cast(TRC.ConstraintExpr));
if (E.isInvalid())
return E;
TRC.ConstraintExpr = E.get();
``
https://github.com/llvm/llvm-project/pull/195995
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/mizvekov approved this pull request. Thanks, this looks better! https://github.com/llvm/llvm-project/pull/195995 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/zyn0217 updated
https://github.com/llvm/llvm-project/pull/195995
>From 6271200c059ff757333247e286b85538735ffe74 Mon Sep 17 00:00:00 2001
From: Younan Zhang
Date: Wed, 6 May 2026 12:04:13 +0800
Subject: [PATCH 1/3] [Clang] Transform lambda's constraints when instantiating
parameter mapping
This way we can remove a few workarounds of lambda expressions where
outer template arguments of concepts have to be preserved through
ImplicitConceptSpecializationDecls.
---
clang/lib/Parse/ParseTemplate.cpp | 6 ---
clang/lib/Sema/SemaConcept.cpp| 30
clang/lib/Sema/SemaTemplate.cpp | 2 +-
clang/lib/Sema/SemaTemplateDeduction.cpp | 14 --
clang/lib/Sema/SemaTemplateInstantiate.cpp| 47 +--
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 7 +++
clang/lib/Sema/TreeTransform.h| 12 ++---
clang/test/SemaTemplate/concepts-lambda.cpp | 34 +-
8 files changed, 97 insertions(+), 55 deletions(-)
diff --git a/clang/lib/Parse/ParseTemplate.cpp
b/clang/lib/Parse/ParseTemplate.cpp
index 330a9c6aea0c5..dbc7cbc6cdc0c 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 3f04922a5647e..8bd3a8f6e1a45 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -482,11 +482,6 @@ class ConstraintSatisfactionChecker {
ConstraintSatisfaction &Satisfaction;
bool BuildExpression;
- // The most closest concept declaration when evaluating atomic constriants.
- // This is to make sure that lambdas in the atomic expression live in the
- // right context.
- ConceptDecl *ParentConcept = nullptr;
-
// This is for TemplateInstantiator to not instantiate the same template
// parameter mapping many times, in order to improve substitution
performance.
llvm::DenseMap
@@ -730,20 +725,6 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
return ExprEmpty();
}
- // Note that generic lambdas inside requires body require a lambda context
- // decl from which to fetch correct template arguments. But we don't have any
- // proper decls because the constraints are already normalized.
- if (ParentConcept) {
-// 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(
Constraint.getConstraintExpr(), *SubstitutedArgs);
@@ -1052,9 +1033,6 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
if (InstTemplate.isInvalid())
return ExprError();
- llvm::SaveAndRestore PushConceptDecl(
- ParentConcept, cast(ConceptId->getNamedConcept()));
-
unsigned Size = Satisfaction.Details.size();
ExprResult E = Evaluate(Constraint.getNormalizedConstraint(), MLTAL);
@@ -2291,6 +2269,14 @@ bool
SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
}
assert(!ArgsAsWritten);
const ConceptSpecializationExpr *CSE = CC.getConceptSpecializationExpr();
+// This is to make sure that lambdas within template arguments live in a
+// dependent context such that they are assured to be transformed in
+// evaluation.
+EnterExpressionEvaluationContext EECtx(
+SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+/*LambdaContextDecl=*/
+const_cast(
+CSE->getSpecializationDecl()));
SmallVector InnerArgs(CSE->getTemplateArguments());
ConceptDecl *Concept = CSE->getNamedConcept();
if (RemovePacksForFoldExpr) {
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index c436b7018a2bd..6b7dadcf123a7 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4912,7 +4912,7 @@ ExprResult Sema::CheckConceptTemplateId(
LocalInstantiationScope Scope(*this);
EnterExpression
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
@@ -1876,11 +1901,25 @@ namespace {
TemplateParameterList *OrigTPL) {
if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
+ std::optional 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() &&
+ getDepthAndIndex(OrigTPL->getParam(0)).first >=
+ TemplateArgs.getNumSubstitutedLevels())
+OldMLTAL = ForgetSubstitution();
zyn0217 wrote:
> I am not sure I understand why changing the depth is a problem for deduction,
> because deduction accepts the template depth as a parameter and this should
> be easy to figure out for the lambda since it has template parameters.
It's all about the collection of explicit template arguments:
`PackDeductionScope::finishConstruction` requires a depth-level-match of
template parameters.
And I don't think we can add template depth to deduction to the code path that
performs a deduction on a function call? we seem to always assume their depths
are 0.
https://github.com/llvm/llvm-project/pull/195995
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/zyn0217 updated
https://github.com/llvm/llvm-project/pull/195995
>From 6271200c059ff757333247e286b85538735ffe74 Mon Sep 17 00:00:00 2001
From: Younan Zhang
Date: Wed, 6 May 2026 12:04:13 +0800
Subject: [PATCH 1/3] [Clang] Transform lambda's constraints when instantiating
parameter mapping
This way we can remove a few workarounds of lambda expressions where
outer template arguments of concepts have to be preserved through
ImplicitConceptSpecializationDecls.
---
clang/lib/Parse/ParseTemplate.cpp | 6 ---
clang/lib/Sema/SemaConcept.cpp| 30
clang/lib/Sema/SemaTemplate.cpp | 2 +-
clang/lib/Sema/SemaTemplateDeduction.cpp | 14 --
clang/lib/Sema/SemaTemplateInstantiate.cpp| 47 +--
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 7 +++
clang/lib/Sema/TreeTransform.h| 12 ++---
clang/test/SemaTemplate/concepts-lambda.cpp | 34 +-
8 files changed, 97 insertions(+), 55 deletions(-)
diff --git a/clang/lib/Parse/ParseTemplate.cpp
b/clang/lib/Parse/ParseTemplate.cpp
index 330a9c6aea0c5..dbc7cbc6cdc0c 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 3f04922a5647e..8bd3a8f6e1a45 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -482,11 +482,6 @@ class ConstraintSatisfactionChecker {
ConstraintSatisfaction &Satisfaction;
bool BuildExpression;
- // The most closest concept declaration when evaluating atomic constriants.
- // This is to make sure that lambdas in the atomic expression live in the
- // right context.
- ConceptDecl *ParentConcept = nullptr;
-
// This is for TemplateInstantiator to not instantiate the same template
// parameter mapping many times, in order to improve substitution
performance.
llvm::DenseMap
@@ -730,20 +725,6 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
return ExprEmpty();
}
- // Note that generic lambdas inside requires body require a lambda context
- // decl from which to fetch correct template arguments. But we don't have any
- // proper decls because the constraints are already normalized.
- if (ParentConcept) {
-// 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(
Constraint.getConstraintExpr(), *SubstitutedArgs);
@@ -1052,9 +1033,6 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
if (InstTemplate.isInvalid())
return ExprError();
- llvm::SaveAndRestore PushConceptDecl(
- ParentConcept, cast(ConceptId->getNamedConcept()));
-
unsigned Size = Satisfaction.Details.size();
ExprResult E = Evaluate(Constraint.getNormalizedConstraint(), MLTAL);
@@ -2291,6 +2269,14 @@ bool
SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
}
assert(!ArgsAsWritten);
const ConceptSpecializationExpr *CSE = CC.getConceptSpecializationExpr();
+// This is to make sure that lambdas within template arguments live in a
+// dependent context such that they are assured to be transformed in
+// evaluation.
+EnterExpressionEvaluationContext EECtx(
+SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+/*LambdaContextDecl=*/
+const_cast(
+CSE->getSpecializationDecl()));
SmallVector InnerArgs(CSE->getTemplateArguments());
ConceptDecl *Concept = CSE->getNamedConcept();
if (RemovePacksForFoldExpr) {
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index c436b7018a2bd..6b7dadcf123a7 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4912,7 +4912,7 @@ ExprResult Sema::CheckConceptTemplateId(
LocalInstantiationScope Scope(*this);
EnterExpression
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/zyn0217 updated
https://github.com/llvm/llvm-project/pull/195995
>From 6271200c059ff757333247e286b85538735ffe74 Mon Sep 17 00:00:00 2001
From: Younan Zhang
Date: Wed, 6 May 2026 12:04:13 +0800
Subject: [PATCH 1/3] [Clang] Transform lambda's constraints when instantiating
parameter mapping
This way we can remove a few workarounds of lambda expressions where
outer template arguments of concepts have to be preserved through
ImplicitConceptSpecializationDecls.
---
clang/lib/Parse/ParseTemplate.cpp | 6 ---
clang/lib/Sema/SemaConcept.cpp| 30
clang/lib/Sema/SemaTemplate.cpp | 2 +-
clang/lib/Sema/SemaTemplateDeduction.cpp | 14 --
clang/lib/Sema/SemaTemplateInstantiate.cpp| 47 +--
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 7 +++
clang/lib/Sema/TreeTransform.h| 12 ++---
clang/test/SemaTemplate/concepts-lambda.cpp | 34 +-
8 files changed, 97 insertions(+), 55 deletions(-)
diff --git a/clang/lib/Parse/ParseTemplate.cpp
b/clang/lib/Parse/ParseTemplate.cpp
index 330a9c6aea0c5..dbc7cbc6cdc0c 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 3f04922a5647e..8bd3a8f6e1a45 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -482,11 +482,6 @@ class ConstraintSatisfactionChecker {
ConstraintSatisfaction &Satisfaction;
bool BuildExpression;
- // The most closest concept declaration when evaluating atomic constriants.
- // This is to make sure that lambdas in the atomic expression live in the
- // right context.
- ConceptDecl *ParentConcept = nullptr;
-
// This is for TemplateInstantiator to not instantiate the same template
// parameter mapping many times, in order to improve substitution
performance.
llvm::DenseMap
@@ -730,20 +725,6 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
return ExprEmpty();
}
- // Note that generic lambdas inside requires body require a lambda context
- // decl from which to fetch correct template arguments. But we don't have any
- // proper decls because the constraints are already normalized.
- if (ParentConcept) {
-// 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(
Constraint.getConstraintExpr(), *SubstitutedArgs);
@@ -1052,9 +1033,6 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
if (InstTemplate.isInvalid())
return ExprError();
- llvm::SaveAndRestore PushConceptDecl(
- ParentConcept, cast(ConceptId->getNamedConcept()));
-
unsigned Size = Satisfaction.Details.size();
ExprResult E = Evaluate(Constraint.getNormalizedConstraint(), MLTAL);
@@ -2291,6 +2269,14 @@ bool
SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
}
assert(!ArgsAsWritten);
const ConceptSpecializationExpr *CSE = CC.getConceptSpecializationExpr();
+// This is to make sure that lambdas within template arguments live in a
+// dependent context such that they are assured to be transformed in
+// evaluation.
+EnterExpressionEvaluationContext EECtx(
+SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+/*LambdaContextDecl=*/
+const_cast(
+CSE->getSpecializationDecl()));
SmallVector InnerArgs(CSE->getTemplateArguments());
ConceptDecl *Concept = CSE->getNamedConcept();
if (RemovePacksForFoldExpr) {
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index c436b7018a2bd..6b7dadcf123a7 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4912,7 +4912,7 @@ ExprResult Sema::CheckConceptTemplateId(
LocalInstantiationScope Scope(*this);
EnterExpression
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/zyn0217 edited https://github.com/llvm/llvm-project/pull/195995 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/zyn0217 edited https://github.com/llvm/llvm-project/pull/195995 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
@@ -1876,11 +1901,25 @@ namespace {
TemplateParameterList *OrigTPL) {
if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
+ std::optional 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() &&
+ getDepthAndIndex(OrigTPL->getParam(0)).first >=
+ TemplateArgs.getNumSubstitutedLevels())
+OldMLTAL = ForgetSubstitution();
zyn0217 wrote:
Hmm, isn't that what I am doing now?
`getDepthAndIndex(OrigTPL->getParam(0)).first >=
TemplateArgs.getNumSubstitutedLevels()` so the outer levels == the whole thing?
https://github.com/llvm/llvm-project/pull/195995
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
@@ -1876,11 +1901,25 @@ namespace {
TemplateParameterList *OrigTPL) {
if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
+ std::optional 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() &&
+ getDepthAndIndex(OrigTPL->getParam(0)).first >=
+ TemplateArgs.getNumSubstitutedLevels())
+OldMLTAL = ForgetSubstitution();
zyn0217 wrote:
the decl instantiator reduces the depth by getNumSubstitutedLevels(), I don't
know how we can clamp MLTAL without forgetting the outer template arguments?
Are you concerning about associated type constraints getting untransformed, I
guess?
https://github.com/llvm/llvm-project/pull/195995
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/zyn0217 edited https://github.com/llvm/llvm-project/pull/195995 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
@@ -1876,11 +1901,25 @@ namespace {
TemplateParameterList *OrigTPL) {
if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
+ std::optional 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() &&
+ getDepthAndIndex(OrigTPL->getParam(0)).first >=
+ TemplateArgs.getNumSubstitutedLevels())
+OldMLTAL = ForgetSubstitution();
zyn0217 wrote:
> Also, I don't see how the level check is necessary.
@mizvekov
The fact is that we will transform the lambda expression in both building and
substitution of parameter mapping.
Say we have
```cpp
template
concept PredicateFor_bad = pass_a_concept_inside_a_lambda<[]
requires(__is_same(decltype(Pred.template operator()()), bool) and ...)
{},
Ts...>;
```
When building, we only have outer template arguments `>`, and
since the transform of parameter list will reduce the depth of anyway
if only partial template arguments are provided, depth of will be
converted to 0.
And in the second transform where we started to substitute real template
arguments into parameter mapping (i.e. when we have `>`), the depth of `Xs` is reduced before deduction happens. This
results in a -1 depth during argument deduction and thus we won't have a
correct template argument list when checking the inner constraint.
Note that we didn't transform the lambda expression in the second transfrom,
because the lambda was seen as non-dependent. I do want the lambda to have a
second transform, because otherwise we don't have a way to get substituted
`Pred` in constraint evaluation. (`Pred` is normalized and we have to evaluate
the lambda's inner constraint during parameter mapping substitution, when we
dont have any proper template arguments at that moment, which is an
egg-and-chicken problem though)
https://github.com/llvm/llvm-project/pull/195995
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
@@ -1763,9 +1763,34 @@ namespace {
if (TA.isDependent())
return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
}
+ if (auto *CD = dyn_cast_if_present(
+ LSI->Lambda->getLambdaContextDecl())) {
+if (llvm::any_of(CD->getTemplateArguments(),
+ [](const auto &TA) { return TA.isDependent(); }))
+ return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
+ }
return inherited::ComputeLambdaDependency(LSI);
}
+AssociatedConstraint TransformConstraint(AssociatedConstraint AC) {
+ // If the concept refers to any outer parameter packs, we track the
+ // SubstIndex for evaluation.
+ if (AC && AC.ConstraintExpr->containsUnexpandedParameterPack() &&
+ !AC.ArgPackSubstIndex)
+AC.ArgPackSubstIndex = SemaRef.ArgPackSubstIndex;
zyn0217 wrote:
I made the default behavior no-op in TreeTransform. We want the transfrom of
constraints in template instantiator.
https://github.com/llvm/llvm-project/pull/195995
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
@@ -1876,11 +1901,25 @@ namespace {
TemplateParameterList *OrigTPL) {
if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
+ std::optional 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() &&
+ getDepthAndIndex(OrigTPL->getParam(0)).first >=
+ TemplateArgs.getNumSubstitutedLevels())
+OldMLTAL = ForgetSubstitution();
zyn0217 wrote:
> Would look cleaner if this used ForgetSubstitutionRAII.
Oh thanks, I wasn't aware of that
https://github.com/llvm/llvm-project/pull/195995
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
@@ -1876,11 +1901,25 @@ namespace {
TemplateParameterList *OrigTPL) {
if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
+ std::optional 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() &&
+ getDepthAndIndex(OrigTPL->getParam(0)).first >=
+ TemplateArgs.getNumSubstitutedLevels())
+OldMLTAL = ForgetSubstitution();
mizvekov wrote:
I am talking about forgetting just the outer levels, instead of the whole
thing, yes.
https://github.com/llvm/llvm-project/pull/195995
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/zyn0217 edited https://github.com/llvm/llvm-project/pull/195995 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/zyn0217 edited https://github.com/llvm/llvm-project/pull/195995 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
@@ -1876,11 +1901,25 @@ namespace {
TemplateParameterList *OrigTPL) {
if (!OrigTPL || !OrigTPL->size()) return OrigTPL;
+ std::optional 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() &&
+ getDepthAndIndex(OrigTPL->getParam(0)).first >=
+ TemplateArgs.getNumSubstitutedLevels())
+OldMLTAL = ForgetSubstitution();
mizvekov wrote:
Would look cleaner if this used `ForgetSubstitutionRAII`.
Also, I don't see how the level check is necessary. The comment doesn't explain
it either.
https://github.com/llvm/llvm-project/pull/195995
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
@@ -1763,9 +1763,34 @@ namespace {
if (TA.isDependent())
return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
}
+ if (auto *CD = dyn_cast_if_present(
+ LSI->Lambda->getLambdaContextDecl())) {
+if (llvm::any_of(CD->getTemplateArguments(),
+ [](const auto &TA) { return TA.isDependent(); }))
+ return CXXRecordDecl::LambdaDependencyKind::LDK_AlwaysDependent;
+ }
return inherited::ComputeLambdaDependency(LSI);
}
+AssociatedConstraint TransformConstraint(AssociatedConstraint AC) {
+ // If the concept refers to any outer parameter packs, we track the
+ // SubstIndex for evaluation.
+ if (AC && AC.ConstraintExpr->containsUnexpandedParameterPack() &&
+ !AC.ArgPackSubstIndex)
+AC.ArgPackSubstIndex = SemaRef.ArgPackSubstIndex;
mizvekov wrote:
As far as I remember when I implemented this, this `ArgPackSubstIndex` should
track what index was used to expand this constraint, so I think it only makes
sense to change this when the constraint is actually transformed.
https://github.com/llvm/llvm-project/pull/195995
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
@@ -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;
mizvekov wrote:
Yeah, this certainly looked wrong, this is not a place in the grammar you would
see an increase in template depth, so props for getting rid of this.
https://github.com/llvm/llvm-project/pull/195995
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/zyn0217 updated
https://github.com/llvm/llvm-project/pull/195995
>From 6271200c059ff757333247e286b85538735ffe74 Mon Sep 17 00:00:00 2001
From: Younan Zhang
Date: Wed, 6 May 2026 12:04:13 +0800
Subject: [PATCH 1/2] [Clang] Transform lambda's constraints when instantiating
parameter mapping
This way we can remove a few workarounds of lambda expressions where
outer template arguments of concepts have to be preserved through
ImplicitConceptSpecializationDecls.
---
clang/lib/Parse/ParseTemplate.cpp | 6 ---
clang/lib/Sema/SemaConcept.cpp| 30
clang/lib/Sema/SemaTemplate.cpp | 2 +-
clang/lib/Sema/SemaTemplateDeduction.cpp | 14 --
clang/lib/Sema/SemaTemplateInstantiate.cpp| 47 +--
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 7 +++
clang/lib/Sema/TreeTransform.h| 12 ++---
clang/test/SemaTemplate/concepts-lambda.cpp | 34 +-
8 files changed, 97 insertions(+), 55 deletions(-)
diff --git a/clang/lib/Parse/ParseTemplate.cpp
b/clang/lib/Parse/ParseTemplate.cpp
index 330a9c6aea0c5..dbc7cbc6cdc0c 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 3f04922a5647e..8bd3a8f6e1a45 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -482,11 +482,6 @@ class ConstraintSatisfactionChecker {
ConstraintSatisfaction &Satisfaction;
bool BuildExpression;
- // The most closest concept declaration when evaluating atomic constriants.
- // This is to make sure that lambdas in the atomic expression live in the
- // right context.
- ConceptDecl *ParentConcept = nullptr;
-
// This is for TemplateInstantiator to not instantiate the same template
// parameter mapping many times, in order to improve substitution
performance.
llvm::DenseMap
@@ -730,20 +725,6 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
return ExprEmpty();
}
- // Note that generic lambdas inside requires body require a lambda context
- // decl from which to fetch correct template arguments. But we don't have any
- // proper decls because the constraints are already normalized.
- if (ParentConcept) {
-// 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(
Constraint.getConstraintExpr(), *SubstitutedArgs);
@@ -1052,9 +1033,6 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
if (InstTemplate.isInvalid())
return ExprError();
- llvm::SaveAndRestore PushConceptDecl(
- ParentConcept, cast(ConceptId->getNamedConcept()));
-
unsigned Size = Satisfaction.Details.size();
ExprResult E = Evaluate(Constraint.getNormalizedConstraint(), MLTAL);
@@ -2291,6 +2269,14 @@ bool
SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
}
assert(!ArgsAsWritten);
const ConceptSpecializationExpr *CSE = CC.getConceptSpecializationExpr();
+// This is to make sure that lambdas within template arguments live in a
+// dependent context such that they are assured to be transformed in
+// evaluation.
+EnterExpressionEvaluationContext EECtx(
+SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+/*LambdaContextDecl=*/
+const_cast(
+CSE->getSpecializationDecl()));
SmallVector InnerArgs(CSE->getTemplateArguments());
ConceptDecl *Concept = CSE->getNamedConcept();
if (RemovePacksForFoldExpr) {
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index c436b7018a2bd..6b7dadcf123a7 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4912,7 +4912,7 @@ ExprResult Sema::CheckConceptTemplateId(
LocalInstantiationScope Scope(*this);
EnterExpression
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/erichkeane approved this pull request. Not sure I am completely understanding the consequences of this, but I think this makes sense? I'd love to see @mizvekov take a look though if possible before merging. https://github.com/llvm/llvm-project/pull/195995 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
@@ -2312,6 +2269,14 @@ bool
SubstituteParameterMappings::substitute(NormalizedConstraint &N) {
}
assert(!ArgsAsWritten);
const ConceptSpecializationExpr *CSE = CC.getConceptSpecializationExpr();
+// This is to make sure that lambdas within template arguments live in a
+// dependent context such that they are assured to be transformed in
+// evaluation.
cor3ntin wrote:
```suggestion
// Make sure that lambdas within template arguments live in a
// dependent context such that they are assured to be transformed during
constraint
// evaluation.
```
https://github.com/llvm/llvm-project/pull/195995
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/cor3ntin edited https://github.com/llvm/llvm-project/pull/195995 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Clang] Transform lambda's constraints when instantiating parameter mapping (PR #195995)
https://github.com/cor3ntin commented: Thanks. I think i need more time to think about that but it looks cleaner than the previous approach https://github.com/llvm/llvm-project/pull/195995 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
