[clang] [Clang] Track constraint's SubstIndex only if it contains outer parameter packs (PR #191484)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Sat Apr 11 08:38:18 PDT 2026
https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/191484
>From c5f66b42960bfeaa8b7e12f1da783e3758266c35 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Fri, 10 Apr 2026 23:10:05 +0800
Subject: [PATCH 1/3] Revert "[Clang] Fix concept cache for normalized fold
expressions"
This reverts commit 257cc5ad89840cdfba4affcc8fe62cf9d02d9017.
---
clang/lib/Sema/SemaConcept.cpp | 29 +++++++++++++------------
clang/test/SemaCXX/cxx2c-fold-exprs.cpp | 14 ------------
2 files changed, 15 insertions(+), 28 deletions(-)
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 5cd2c3d326ff7..a58a3874149b7 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -493,12 +493,6 @@ class ConstraintSatisfactionChecker {
CachedTemplateArgs;
private:
- template <class Constraint>
- UnsignedOrNone getOuterPackIndex(const Constraint &C) const {
- return C.getPackSubstitutionIndex() ? C.getPackSubstitutionIndex()
- : PackSubstitutionIndex;
- }
-
ExprResult
EvaluateAtomicConstraint(const Expr *AtomicExpr,
const MultiLevelTemplateArgumentList &MLTAL);
@@ -812,11 +806,14 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
unsigned Size = Satisfaction.Details.size();
llvm::FoldingSetNodeID ID;
+ UnsignedOrNone OuterPackSubstIndex =
+ Constraint.getPackSubstitutionIndex()
+ ? Constraint.getPackSubstitutionIndex()
+ : PackSubstitutionIndex;
+
ID.AddPointer(Constraint.getConstraintExpr());
- ID.AddInteger(
- Constraint.getPackSubstitutionIndex().toInternalRepresentation());
- ID.AddInteger(PackSubstitutionIndex.toInternalRepresentation());
- HashParameterMapping(S, MLTAL, ID, getOuterPackIndex(Constraint))
+ ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
+ HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
.VisitConstraint(Constraint);
if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache.find(ID);
@@ -1045,6 +1042,12 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
const MultiLevelTemplateArgumentList &MLTAL) {
const ConceptReference *ConceptId = Constraint.getConceptId();
+
+ UnsignedOrNone OuterPackSubstIndex =
+ Constraint.getPackSubstitutionIndex()
+ ? Constraint.getPackSubstitutionIndex()
+ : PackSubstitutionIndex;
+
Sema::InstantiatingTemplate InstTemplate(
S, ConceptId->getBeginLoc(),
Sema::InstantiatingTemplate::ConstraintsCheck{},
@@ -1080,10 +1083,8 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
llvm::FoldingSetNodeID ID;
ID.AddPointer(Constraint.getConceptId());
- ID.AddInteger(
- Constraint.getPackSubstitutionIndex().toInternalRepresentation());
- ID.AddInteger(PackSubstitutionIndex.toInternalRepresentation());
- HashParameterMapping(S, MLTAL, ID, getOuterPackIndex(Constraint))
+ ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
+ HashParameterMapping(S, MLTAL, ID, OuterPackSubstIndex)
.VisitConstraint(Constraint);
if (auto Iter = S.UnsubstitutedConstraintSatisfactionCache.find(ID);
diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
index 5b993fead4877..89ddcbaf11583 100644
--- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
+++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
@@ -508,17 +508,3 @@ static_assert(!__callable<__mdispatch<int>>);
}
}
-
-namespace GH190169 {
-
-template <typename Type, typename... Choices>
-concept OneOf = (... || __is_same(Type, Choices));
-
-template <typename F, typename... Ts>
-using check = decltype((F{}(Ts{}), ...));
-
-using X = check<decltype([](auto val) {
- [](OneOf<int, char> auto) {}(val);
-}), char>;
-
-}
>From e9e59a9d4f3926a5b36dca944bb10a9c0d68fd16 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sat, 11 Apr 2026 02:30:32 +0800
Subject: [PATCH 2/3] [Clang] Track constraint's SubstIndex only if it contains
outer parameter packs
I believe that is the intent of SubstIndex in AssociatedConstraint.
So this applies the checking explicitly, in case nested SubstIndexes
confuses our poor constraint evaluator.
I reverted the previous fix 257cc5a because that was wrong.
No release note because this is a regression fix.
---
clang/lib/Sema/SemaTemplateInstantiate.cpp | 8 +++-
clang/lib/Sema/TreeTransform.h | 5 ++-
clang/test/SemaCXX/cxx2c-fold-exprs.cpp | 48 ++++++++++++++++++++++
3 files changed, 59 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 5381a5a6f110d..80e3b1a5b11f7 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -3085,7 +3085,13 @@ bool Sema::SubstTypeConstraint(
if (!EvaluateConstraints && !inParameterMappingSubstitution()) {
UnsignedOrNone Index = TC->getArgPackSubstIndex();
- if (!Index)
+ bool ContainsUnexpandedPack =
+ TemplArgInfo &&
+ llvm::any_of(
+ TemplArgInfo->arguments(), [](const TemplateArgumentLoc &TA) {
+ return TA.getArgument().containsUnexpandedParameterPack();
+ });
+ if (!Index && ContainsUnexpandedPack)
Index = SemaRef.ArgPackSubstIndex;
Inst->setTypeConstraint(TC->getConceptReference(),
TC->getImmediatelyDeclaredConstraint(), Index);
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 8ae5df367e0dd..4c941e234d78d 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -16004,7 +16004,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
assert(FPTL && "Not a FunctionProtoType?");
AssociatedConstraint TRC = E->getCallOperator()->getTrailingRequiresClause();
- if (!TRC.ArgPackSubstIndex)
+ // 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;
getSema().CompleteLambdaCallOperator(
diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
index 89ddcbaf11583..f681fc6f594c2 100644
--- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
+++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
@@ -508,3 +508,51 @@ static_assert(!__callable<__mdispatch<int>>);
}
}
+
+namespace GH190169 {
+
+namespace _1 {
+
+template <typename Type, typename... Choices>
+concept OneOf = (... || __is_same(Type, Choices));
+
+template <typename F, typename... Ts>
+using check = decltype((F{}(Ts{}), ...));
+
+using X = check<decltype([](auto val) {
+ [](OneOf<int, char> auto) {}(val);
+}), char>;
+
+}
+
+namespace _2 {
+
+template <typename T, typename U>
+concept Same = __is_same(T, U);
+
+template <typename Type, typename... Choices>
+concept OneOf = (... || Same<Type, Choices>);
+
+template <class... Ts>
+struct visitor : Ts... { using Ts::operator()...; };
+
+struct A {};
+struct B {};
+struct C {};
+
+template <typename F, typename T, typename = decltype(F{}(T{}))>
+struct check {};
+
+template <typename F, typename... Ts>
+struct check_all : check<F, Ts>... {};
+
+using F = decltype([](auto val) {
+ visitor{[](const A&) {},
+ [](const OneOf<B, C> auto&) {}}(val);
+});
+
+check_all<F, A, B, C> x;
+
+}
+
+}
>From 7b28c32b33dcf7951f8ff7ac38617aef871e970d Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sat, 11 Apr 2026 23:37:46 +0800
Subject: [PATCH 3/3] Add back getOuterPackIndex
---
clang/lib/Sema/SemaConcept.cpp | 27 ++++++++++-----------------
1 file changed, 10 insertions(+), 17 deletions(-)
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index a58a3874149b7..25b483b5e30b9 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -493,6 +493,12 @@ class ConstraintSatisfactionChecker {
CachedTemplateArgs;
private:
+ template <class Constraint>
+ UnsignedOrNone getOuterPackIndex(const Constraint &C) const {
+ return C.getPackSubstitutionIndex() ? C.getPackSubstitutionIndex()
+ : PackSubstitutionIndex;
+ }
+
ExprResult
EvaluateAtomicConstraint(const Expr *AtomicExpr,
const MultiLevelTemplateArgumentList &MLTAL);
@@ -658,10 +664,7 @@ ConstraintSatisfactionChecker::SubstitutionInTemplateArguments(
return std::nullopt;
TemplateArgumentListInfo SubstArgs;
- Sema::ArgPackSubstIndexRAII SubstIndex(
- S, Constraint.getPackSubstitutionIndex()
- ? Constraint.getPackSubstitutionIndex()
- : PackSubstitutionIndex);
+ Sema::ArgPackSubstIndexRAII SubstIndex(S, getOuterPackIndex(Constraint));
llvm::SaveAndRestore PushTemplateArgsCache(S.CurrentCachedTemplateArgs,
&CachedTemplateArgs);
@@ -806,10 +809,7 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
unsigned Size = Satisfaction.Details.size();
llvm::FoldingSetNodeID ID;
- UnsignedOrNone OuterPackSubstIndex =
- Constraint.getPackSubstitutionIndex()
- ? Constraint.getPackSubstitutionIndex()
- : PackSubstitutionIndex;
+ UnsignedOrNone OuterPackSubstIndex = getOuterPackIndex(Constraint);
ID.AddPointer(Constraint.getConstraintExpr());
ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
@@ -979,10 +979,7 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow(
return ExprError();
}
- Sema::ArgPackSubstIndexRAII SubstIndex(
- S, Constraint.getPackSubstitutionIndex()
- ? Constraint.getPackSubstitutionIndex()
- : PackSubstitutionIndex);
+ Sema::ArgPackSubstIndexRAII SubstIndex(S, getOuterPackIndex(Constraint));
const ASTTemplateArgumentListInfo *Ori =
ConceptId->getTemplateArgsAsWritten();
@@ -1043,11 +1040,6 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
const ConceptReference *ConceptId = Constraint.getConceptId();
- UnsignedOrNone OuterPackSubstIndex =
- Constraint.getPackSubstitutionIndex()
- ? Constraint.getPackSubstitutionIndex()
- : PackSubstitutionIndex;
-
Sema::InstantiatingTemplate InstTemplate(
S, ConceptId->getBeginLoc(),
Sema::InstantiatingTemplate::ConstraintsCheck{},
@@ -1081,6 +1073,7 @@ ExprResult ConstraintSatisfactionChecker::Evaluate(
if (Satisfaction.IsSatisfied)
return E;
+ UnsignedOrNone OuterPackSubstIndex = getOuterPackIndex(Constraint);
llvm::FoldingSetNodeID ID;
ID.AddPointer(Constraint.getConceptId());
ID.AddInteger(OuterPackSubstIndex.toInternalRepresentation());
More information about the cfe-commits
mailing list