https://github.com/zyn0217 updated 
https://github.com/llvm/llvm-project/pull/210005

>From 3adf66a2cbc7808f5da7df049fb299562fd4affe Mon Sep 17 00:00:00 2001
From: Younan Zhang <[email protected]>
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    | 31 ++++++++++++++++++++++
 3 files changed, 52 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..bd9dff73cb640 100644
--- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
+++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
@@ -509,6 +509,37 @@ 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(... or !callable<S, B<N>>)
+// expected-note@-1 {{because '!callable<S, B<0>>' evaluated to false}} \
+// expected-note@-1 {{and '!callable<S, B<1>>' evaluated to false}} \
+// expected-note@-1 {{and '!callable<S, B<2>>' 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@-1 {{constraints not satisfied for class template 'Y'}}
+
+}
+
 namespace GH190169 {
 
 namespace _1 {

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

Reply via email to