[clang] [Clang] Fix evaluation of fold expanded constraints for NTTP (PR #210005)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 16 01:03:42 PDT 2026
https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/210005
This is a rework of #200185 and also reflects what we did for TTP in C++26 fold expression constraints (adc64c6e1745)
Fixes https://github.com/llvm/llvm-project/issues/199569
>From f3dec8c713a3e68068af176abb151b26dd799972 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Thu, 16 Jul 2026 16:00:15 +0800
Subject: [PATCH] [Clang] Fix evaluation of fold expanded constraints for NTTP
This is a rework of #200185 and also reflects what we did for TTP in
C++26 fold expression constraints (adc64c6e1745)
---
clang/lib/Sema/SemaConcept.cpp | 15 ++++++++---
clang/lib/Sema/SemaTemplateInstantiate.cpp | 12 ++++++---
clang/test/SemaCXX/cxx2c-fold-exprs.cpp | 29 ++++++++++++++++++++++
3 files changed, 50 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 8831a26224e7d..4e7ff0d930a97 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -293,12 +293,14 @@ class AdjustConstraints : public TreeTransform<AdjustConstraints> {
SemaRef.getASTContext(), NTTP->getDeclContext(),
NTTP->getInnerLocStart(), NTTP->getLocation(),
NTTP->getDepth() + TemplateDepth, NTTP->getPosition(),
- NTTP->getIdentifier(), TSI->getType(), NTTP->isParameterPack(), TSI);
+ NTTP->getIdentifier(), TSI->getType(),
+ RemoveNonPackExpansionPacks ? false : NTTP->isParameterPack(), TSI);
return DeclRefExpr::Create(
SemaRef.getASTContext(), E->getQualifierLoc(),
E->getTemplateKeywordLoc(), D, E->refersToEnclosingVariableOrCapture(),
- E->getNameInfo(), TSI->getType(), E->getValueKind(), D,
+ E->getNameInfo(), TSI->getType(), E->getValueKind(),
+ RemoveNonPackExpansionPacks ? NTTP : D,
/*TemplateArgs=*/nullptr, E->isNonOdrUse());
}
};
@@ -372,7 +374,14 @@ class HashParameterMapping : public RecursiveASTVisitor<HashParameterMapping> {
return true;
TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition());
- if (NTTP->isParameterPack() && SemaRef.ArgPackSubstIndex) {
+ // In concept parameter mapping for fold expressions, packs that aren't
+ // expanded in place are treated as having non-pack dependency, so that
+ // a PackExpansionType won't prevent expanding the packs outside the
+ // TreeTransform. However we still need to check the pack at this point.
+ if ((NTTP->isParameterPack() ||
+ (E->getFoundDecl() && E->getFoundDecl() != E->getDecl() &&
+ E->getFoundDecl()->isParameterPack())) &&
+ SemaRef.ArgPackSubstIndex) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
Arg = SemaRef.getPackSubstitutedTemplateArgument(Arg);
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index bad0cdd1b7067..513827aad29a1 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2247,9 +2247,15 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
auto [AssociatedDecl, Final] =
TemplateArgs.getAssociatedDecl(NTTP->getDepth());
UnsignedOrNone PackIndex = std::nullopt;
- if (NTTP->isParameterPack()) {
- assert(Arg.getKind() == TemplateArgument::Pack &&
- "Missing argument pack");
+ if (NTTP->isParameterPack() ||
+ // In concept parameter mapping for fold expressions, packs that aren't
+ // expanded in place are treated as having non-pack dependency, so that
+ // a PackExpansionType won't prevent expanding the packs outside the
+ // TreeTransform. However, we still need to unpack the arguments during
+ // any template argument substitution, so we also check its FoundDecl.
+ (E->getFoundDecl() && E->getFoundDecl() != E->getDecl() &&
+ E->getFoundDecl()->isParameterPack())) {
+ assert(Arg.getKind() == TemplateArgument::Pack && "Missing argument pack");
if (!getSema().ArgPackSubstIndex) {
// We have an argument pack, but we can't select a particular argument
diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
index 0312022912dca..b0e3eabd8ca24 100644
--- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
+++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
@@ -509,6 +509,35 @@ static_assert(!__callable<__mdispatch<int>>);
}
+namespace GH199569 {
+
+template<typename F, typename... A>
+concept callable = requires(F f, A... a) {
+ f(a...);
+};
+
+struct S {
+ void operator()(auto);
+};
+
+template<int> struct B {};
+
+template<int... N> requires(... and callable<S, B<N>>)
+struct X {};
+
+template<int... N> requires(... and !callable<S, B<N>>)
+// expected-note at -1 {{because '!callable<S, B<0>>' evaluated to false}}
+struct Y {};
+
+static_assert(callable<S, B<0>>);
+static_assert(callable<S, B<1>>);
+
+X<0, 1> x;
+Y<0, 1, 2> y;
+// expected-error at -1 {{constraints not satisfied for class template 'Y'}}
+
+}
+
namespace GH190169 {
namespace _1 {
More information about the cfe-commits
mailing list