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 <[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 | 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@-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@-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
