https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/86265
>From 6e7b38b3e3f781e11db2fa5d552fdfb6123609df Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Fri, 22 Mar 2024 17:34:08 +0800 Subject: [PATCH 1/2] [Sema] Preserve ContainsUnexpandedParameterPack in TransformLambdaExpr --- clang/docs/ReleaseNotes.rst | 2 + clang/include/clang/Sema/Sema.h | 8 +++ clang/lib/Sema/SemaTemplateVariadic.cpp | 16 +++++- clang/lib/Sema/TreeTransform.h | 18 ++++++ .../test/SemaTemplate/lambda-capture-pack.cpp | 57 +++++++++++++++++++ 5 files changed, 98 insertions(+), 3 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 690fc7ed271a3d..2d11a4b8c092a2 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -344,6 +344,8 @@ Bug Fixes to C++ Support when one of the function had more specialized templates. Fixes (`#82509 <https://github.com/llvm/llvm-project/issues/82509>`_) and (`#74494 <https://github.com/llvm/llvm-project/issues/74494>`_) +- Fixed a crash where template parameter packs were not expanded correctly in a lambda being + used as a pattern of a folded expression. (#GH56852), (#GH85667) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index cfc1c3b3494788..0d1a2e54840e52 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11201,6 +11201,14 @@ class Sema final { void collectUnexpandedParameterPacks( QualType T, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + /// Collect the set of unexpanded parameter packs from a lambda call operator. + /// + /// \param LambdaCall The lambda call operator that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacksFromLambda( + CXXMethodDecl *LambdaCall, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + /// Collect the set of unexpanded parameter packs within the given /// type. /// diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 903fbfd18e779c..638ceac4148aec 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -8,14 +8,15 @@ // This file implements semantic analysis for C++0x variadic templates. //===----------------------------------------------------------------------===/ -#include "clang/Sema/Sema.h" #include "TypeLocBuilder.h" +#include "clang/AST/ASTLambda.h" #include "clang/AST/Expr.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include <optional> @@ -61,8 +62,9 @@ namespace { public: explicit CollectUnexpandedParameterPacksVisitor( - SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) - : Unexpanded(Unexpanded) {} + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded, + bool InLambda = false) + : Unexpanded(Unexpanded), InLambda(InLambda) {} bool shouldWalkTypesOfTypeLocs() const { return false; } @@ -544,6 +546,14 @@ void Sema::collectUnexpandedParameterPacks(QualType T, CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(T); } +void Sema::collectUnexpandedParameterPacksFromLambda( + CXXMethodDecl *LambdaCall, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + assert(isLambdaCallOperator(LambdaCall) && "Expected a lambda call operator"); + CollectUnexpandedParameterPacksVisitor(Unexpanded, /*InLambda=*/true) + .TraverseDecl(LambdaCall); +} + void Sema::collectUnexpandedParameterPacks(TypeLoc TL, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(TL); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 2d22692f3ab750..f5a859c57034a5 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -13748,6 +13748,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { } NewVDs.push_back(NewVD); getSema().addInitCapture(LSI, NewVD, C->getCaptureKind() == LCK_ByRef); + LSI->ContainsUnexpandedParameterPack |= + Init.get()->containsUnexpandedParameterPack(); } if (Invalid) @@ -13936,6 +13938,22 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { /*IsInstantiation*/ true); SavedContext.pop(); + // The lambda may contain a pack that would be expanded by a fold expression + // outside. We should preserve the ContainsUnexpandedParameterPack flag here + // because CXXFoldExprs use it for the pattern. + // For example, + // + // []<class... Is>() { ([I = Is()]() {}, ...); } + // + // forgetting the flag will result in getPattern() of CXXFoldExpr returning + // null in terms of the inner lambda. + if (!LSICopy.ContainsUnexpandedParameterPack) { + llvm::SmallVector<UnexpandedParameterPack> UnexpandedPacks; + getSema().collectUnexpandedParameterPacksFromLambda(NewCallOperator, + UnexpandedPacks); + // Should we call DiagnoseUnexpandedParameterPacks() instead? + LSICopy.ContainsUnexpandedParameterPack = !UnexpandedPacks.empty(); + } return getSema().BuildLambdaExpr(E->getBeginLoc(), Body.get()->getEndLoc(), &LSICopy); } diff --git a/clang/test/SemaTemplate/lambda-capture-pack.cpp b/clang/test/SemaTemplate/lambda-capture-pack.cpp index 35b2ffcefea355..31d85e1689af15 100644 --- a/clang/test/SemaTemplate/lambda-capture-pack.cpp +++ b/clang/test/SemaTemplate/lambda-capture-pack.cpp @@ -23,3 +23,60 @@ namespace PR41576 { } static_assert(f(3, 4) == 6); // expected-note {{instantiation}} } + +namespace PR85667 { + +template <class T> +struct identity { + using type = T; +}; + +template <class = void> void f() { + + static_assert([]<class... Is>(Is... x) { + return ([I(x)] { + return I; + }() + ...); + }(1, 2) == 3); + + static_assert([]<class... Is>(Is... x) { + return ([](auto y = Is()) { return y + 1; } + ...); + }(0, 0, 0) == 3); + + []<class... Is>() { + return ([]() noexcept(Is()) { return 0; }() + ...); + }.template operator()<int, int>(); + + static_assert(__is_same(decltype([]<class... Is>() { + return ([]() -> decltype(Is()) { return {}; }(), + ...); + }.template operator()<int, char>()), + char)); + + []<class... Is>() { + return ([]<class... Ts>() -> decltype(Is()) { return Ts(); }() + ...); + // expected-error@-1 {{unexpanded parameter pack 'Ts'}} + }.template operator()<int, int>(); + + // Note that GCC and EDG reject this case currently. + // GCC says the fold expression "has no unexpanded parameter packs", while + // EDG says the constraint is not allowed on a non-template function. + // MSVC is happy with it. + []<class... Is>() { + ([]() + requires(Is()) + {}, + ...); + }.template operator()<bool, bool>(); + + // https://github.com/llvm/llvm-project/issues/56852 + []<class... Is>(Is...) { + ([] { + using T = identity<Is>::type; + }(), ...); + }(1, 2); +} + +template void f(); + +} >From e76fedd9fbe557f5c9a9f980a141c2ed31c24424 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Sat, 23 Mar 2024 19:39:37 +0800 Subject: [PATCH 2/2] Consider the captured pack variables - gh18873 --- clang/docs/ReleaseNotes.rst | 4 ++-- clang/lib/Sema/TreeTransform.h | 4 ++++ .../test/SemaTemplate/lambda-capture-pack.cpp | 21 +++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 2d11a4b8c092a2..41529cbc9bd9ad 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -344,8 +344,8 @@ Bug Fixes to C++ Support when one of the function had more specialized templates. Fixes (`#82509 <https://github.com/llvm/llvm-project/issues/82509>`_) and (`#74494 <https://github.com/llvm/llvm-project/issues/74494>`_) -- Fixed a crash where template parameter packs were not expanded correctly in a lambda being - used as a pattern of a folded expression. (#GH56852), (#GH85667) +- Fixed a crash where template parameter packs were not expanded correctly in a lambda used + as the pattern of a folded expression. (#GH56852), (#GH85667), and partially fixes (#GH18873). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index f5a859c57034a5..fb29e5111fc54f 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -13817,6 +13817,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { continue; } + if (auto *PVD = dyn_cast<VarDecl>(CapturedVar); + PVD && !C->isPackExpansion()) + LSI->ContainsUnexpandedParameterPack |= PVD->isParameterPack(); + // Capture the transformed variable. getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind, EllipsisLoc); diff --git a/clang/test/SemaTemplate/lambda-capture-pack.cpp b/clang/test/SemaTemplate/lambda-capture-pack.cpp index 31d85e1689af15..8a81417b6daeec 100644 --- a/clang/test/SemaTemplate/lambda-capture-pack.cpp +++ b/clang/test/SemaTemplate/lambda-capture-pack.cpp @@ -75,6 +75,27 @@ template <class = void> void f() { using T = identity<Is>::type; }(), ...); }(1, 2); + + // https://github.com/llvm/llvm-project/issues/18873 + [](auto ...y) { + ([y] { }, ...); + }(); + + [](auto ...x) { + ([&](auto ...y) { + // FIXME: This now hits the assertion with `PackIdx != -1 && "found declaration pack but not pack expanding"' + // in Sema::FindInstantiatedDecl. + // This is because the captured variable x has been expanded while transforming + // the outermost lambda call, but the expansion then gets holded off while transforming + // the folded expression. Then we would hit the assertion when instantiating the captured variable + // in TransformLambdaExpr. + // I think this is supposed to be ill-formed, but GCC and MSVC currently accept this. + // If x gets expanded with non-empty arguments, then GCC and MSVC will reject it - we probably + // miss a diagnostic for it. + // ([x, y] { }, ...); + ([x..., y] { }, ...); + })(); + }(); } template void f(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits