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 01/23] [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 690fc7ed271a3..2d11a4b8c092a 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 cfc1c3b349478..0d1a2e54840e5 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 903fbfd18e779..638ceac4148ae 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 2d22692f3ab75..f5a859c57034a 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 35b2ffcefea35..31d85e1689af1 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 02/23] 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 2d11a4b8c092a..41529cbc9bd9a 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 f5a859c57034a..fb29e5111fc54 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 31d85e1689af1..8a81417b6daee 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(); >From faf5d8710ba0177685cd65c6b81cf79b97223e4b Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Sat, 23 Mar 2024 23:00:51 +0800 Subject: [PATCH 03/23] comments --- clang/lib/Sema/TreeTransform.h | 4 ++++ clang/test/SemaTemplate/lambda-capture-pack.cpp | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 0e2ea13d64d46..31592e6557f0d 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -13786,6 +13786,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { } NewVDs.push_back(NewVD); getSema().addInitCapture(LSI, NewVD, C->getCaptureKind() == LCK_ByRef); + // The initializer might be expanded later. This may happen + // if the lambda is within a folded expression. LSI->ContainsUnexpandedParameterPack |= Init.get()->containsUnexpandedParameterPack(); } @@ -13855,6 +13857,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { continue; } + // The captured variable might be expanded later. This may happen + // if the lambda is within a folded expression. if (auto *PVD = dyn_cast<VarDecl>(CapturedVar); PVD && !C->isPackExpansion()) LSI->ContainsUnexpandedParameterPack |= PVD->isParameterPack(); diff --git a/clang/test/SemaTemplate/lambda-capture-pack.cpp b/clang/test/SemaTemplate/lambda-capture-pack.cpp index 8a81417b6daee..506902bc99dc6 100644 --- a/clang/test/SemaTemplate/lambda-capture-pack.cpp +++ b/clang/test/SemaTemplate/lambda-capture-pack.cpp @@ -83,15 +83,15 @@ template <class = void> void f() { [](auto ...x) { ([&](auto ...y) { - // FIXME: This now hits the assertion with `PackIdx != -1 && "found declaration pack but not pack expanding"' + // FIXME: This now hits assertion `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. + // the outermost lambda call, but the expansion is held 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. + // However, if x gets expanded with non-empty arguments, then GCC and MSVC will reject it - + // we probably need a diagnostic for it. // ([x, y] { }, ...); ([x..., y] { }, ...); })(); >From c5765ec62f1d32b1cd817c8c78ef7b2d21bf296e Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Sun, 24 Mar 2024 00:15:14 +0800 Subject: [PATCH 04/23] format --- clang/lib/Sema/TreeTransform.h | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 31592e6557f0d..e2ec9b7085737 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -13786,8 +13786,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { } NewVDs.push_back(NewVD); getSema().addInitCapture(LSI, NewVD, C->getCaptureKind() == LCK_ByRef); - // The initializer might be expanded later. This may happen - // if the lambda is within a folded expression. + // If the lambda is written within a fold expression, the initializer + // may be expanded later. Preserve the ContainsUnexpandedParameterPack + // flag because CXXFoldExpr uses it for the pattern. LSI->ContainsUnexpandedParameterPack |= Init.get()->containsUnexpandedParameterPack(); } @@ -13848,6 +13849,17 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { EllipsisLoc = C->getEllipsisLoc(); } +#if 0 + else if (auto *PVD = cast<VarDecl>(C->getCapturedVar()); PVD->isParameterPack()) { + // If the lambda is written within a fold expression, the captured + // variable may be expanded later. Preserve the + // ContainsUnexpandedParameterPack flag because CXXFoldExpr uses it for the + // pattern. + LSI->ContainsUnexpandedParameterPack |= true; + getSema().tryCaptureVariable(PVD, C->getLocation(), Kind, EllipsisLoc); + continue; + } +#endif // Transform the captured variable. auto *CapturedVar = cast_or_null<ValueDecl>( @@ -13857,11 +13869,15 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { continue; } - // The captured variable might be expanded later. This may happen - // if the lambda is within a folded expression. + // If the lambda is written within a fold expression, the captured + // variable may be expanded later. Preserve the + // ContainsUnexpandedParameterPack flag because CXXFoldExpr uses it for the + // pattern. +#if 1 if (auto *PVD = dyn_cast<VarDecl>(CapturedVar); PVD && !C->isPackExpansion()) LSI->ContainsUnexpandedParameterPack |= PVD->isParameterPack(); +#endif // Capture the transformed variable. getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind, @@ -13984,12 +14000,10 @@ 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, + // The lambda function might contain a pack that would be expanded by a fold + // expression outside. For example, // - // []<class... Is>() { ([I = Is()]() {}, ...); } + // []<class... Is>() { ([](auto P = Is()) {}, ...); } // // forgetting the flag will result in getPattern() of CXXFoldExpr returning // null in terms of the inner lambda. @@ -13997,7 +14011,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { llvm::SmallVector<UnexpandedParameterPack> UnexpandedPacks; getSema().collectUnexpandedParameterPacksFromLambda(NewCallOperator, UnexpandedPacks); - // Should we call DiagnoseUnexpandedParameterPacks() instead? + // FIXME: Should we call DiagnoseUnexpandedParameterPacks() instead? LSICopy.ContainsUnexpandedParameterPack = !UnexpandedPacks.empty(); } return getSema().BuildLambdaExpr(E->getBeginLoc(), Body.get()->getEndLoc(), >From 6c2d311938839092f8fd1c5334673c6e35fe4651 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Fri, 3 May 2024 21:50:42 +0800 Subject: [PATCH 05/23] Retain the 'unexpanded' Decls --- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 ++++++ .../test/SemaTemplate/lambda-capture-pack.cpp | 26 +++++++++---------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 787a485e0b2f8..ac96449221384 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -6221,6 +6221,14 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, return cast<NamedDecl>(FD); int PackIdx = ArgumentPackSubstitutionIndex; + // FIXME: Move it elsewhere e.g. TreeTransform::TransformDecl. + // This is for #18873. + if (PackIdx == -1) { + LocalInstantiationScope LIS(*this, /*CombineWithOuterScope=*/false); + MultiLevelTemplateArgumentList FakeArgs; + FakeArgs.addOuterRetainedLevels(D->getTemplateDepth() + 1); + return cast_if_present<NamedDecl>(SubstDecl(D, CurContext, FakeArgs)); + } assert(PackIdx != -1 && "found declaration pack but not pack expanding"); typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; diff --git a/clang/test/SemaTemplate/lambda-capture-pack.cpp b/clang/test/SemaTemplate/lambda-capture-pack.cpp index 506902bc99dc6..12cb2ba6cb86e 100644 --- a/clang/test/SemaTemplate/lambda-capture-pack.cpp +++ b/clang/test/SemaTemplate/lambda-capture-pack.cpp @@ -83,21 +83,21 @@ template <class = void> void f() { [](auto ...x) { ([&](auto ...y) { - // FIXME: This now hits assertion `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 is held 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. - // However, if x gets expanded with non-empty arguments, then GCC and MSVC will reject it - - // we probably need a diagnostic for it. - // ([x, y] { }, ...); ([x..., y] { }, ...); - })(); - }(); + })(1); + }(2, 'b'); + + [](auto ...x) { // #outer + ([&](auto ...y) { // #inner + ([x, y] { }, ...); + // expected-error@-1 {{parameter pack 'y' that has a different length (4 vs. 3) from outer parameter packs}} + // expected-note-re@#inner {{function template specialization {{.*}} requested here}} + // expected-note-re@#outer {{function template specialization {{.*}} requested here}} + // expected-note-re@#instantiate-f {{function template specialization {{.*}} requested here}} + })('a', 'b', 'c'); + }(0, 1, 2, 3); } -template void f(); +template void f(); // #instantiate-f } >From 1ac5ca73a1dd6084cae9ec54546f56fc18d7e0bc Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Fri, 3 May 2024 22:11:49 +0800 Subject: [PATCH 06/23] Update ReleaseNotes --- clang/docs/ReleaseNotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 81a6d67f42f7e..dd488f7ec17d1 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -561,7 +561,7 @@ Bug Fixes to C++ Support - Fixed a crash when trying to evaluate a user-defined ``static_assert`` message whose ``size()`` function returns a large or negative value. Fixes (#GH89407). - 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 fixed (#GH18873). + as the pattern of a folded expression. (#GH56852), (#GH85667) and (#GH18873). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ >From db36bc87d2a5bb64a918a53636f3f97524f883ad Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Wed, 8 May 2024 09:50:01 +0800 Subject: [PATCH 07/23] Cleanup & silence the unused-expression warning --- clang/lib/Sema/TreeTransform.h | 18 ++---------------- .../test/SemaTemplate/lambda-capture-pack.cpp | 12 +++++++++--- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index ec14129259f83..e765d25ee606f 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -14092,17 +14092,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { EllipsisLoc = C->getEllipsisLoc(); } -#if 0 - else if (auto *PVD = cast<VarDecl>(C->getCapturedVar()); PVD->isParameterPack()) { - // If the lambda is written within a fold expression, the captured - // variable may be expanded later. Preserve the - // ContainsUnexpandedParameterPack flag because CXXFoldExpr uses it for the - // pattern. - LSI->ContainsUnexpandedParameterPack |= true; - getSema().tryCaptureVariable(PVD, C->getLocation(), Kind, EllipsisLoc); - continue; - } -#endif // Transform the captured variable. auto *CapturedVar = cast_or_null<ValueDecl>( @@ -14116,11 +14105,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { // variable may be expanded later. Preserve the // ContainsUnexpandedParameterPack flag because CXXFoldExpr uses it for the // pattern. -#if 1 - if (auto *PVD = dyn_cast<VarDecl>(CapturedVar); - PVD && !C->isPackExpansion()) - LSI->ContainsUnexpandedParameterPack |= PVD->isParameterPack(); -#endif + LSI->ContainsUnexpandedParameterPack |= + cast<VarDecl>(CapturedVar)->isParameterPack(); // Capture the transformed variable. getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind, diff --git a/clang/test/SemaTemplate/lambda-capture-pack.cpp b/clang/test/SemaTemplate/lambda-capture-pack.cpp index 12cb2ba6cb86e..7b22c724eb20e 100644 --- a/clang/test/SemaTemplate/lambda-capture-pack.cpp +++ b/clang/test/SemaTemplate/lambda-capture-pack.cpp @@ -78,18 +78,24 @@ template <class = void> void f() { // https://github.com/llvm/llvm-project/issues/18873 [](auto ...y) { - ([y] { }, ...); + ([y] { }(), ...); }(); [](auto ...x) { ([&](auto ...y) { - ([x..., y] { }, ...); + ([x..., y] { }(), ...); })(1); }(2, 'b'); + [](auto ...x) { + ([&](auto ...y) { + ([x, y] { }(), ...); + })(1, 'a'); + }(2, 'b'); + [](auto ...x) { // #outer ([&](auto ...y) { // #inner - ([x, y] { }, ...); + ([x, y] { }(), ...); // expected-error@-1 {{parameter pack 'y' that has a different length (4 vs. 3) from outer parameter packs}} // expected-note-re@#inner {{function template specialization {{.*}} requested here}} // expected-note-re@#outer {{function template specialization {{.*}} requested here}} >From 66acffb605aa724f59a2667bc3e542a23163e1e3 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Fri, 24 May 2024 13:33:20 +0800 Subject: [PATCH 08/23] Fix the CI --- clang/lib/Sema/TreeTransform.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index e765d25ee606f..3be68d8d251f3 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -14105,8 +14105,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { // variable may be expanded later. Preserve the // ContainsUnexpandedParameterPack flag because CXXFoldExpr uses it for the // pattern. - LSI->ContainsUnexpandedParameterPack |= - cast<VarDecl>(CapturedVar)->isParameterPack(); + if (auto *VD = dyn_cast<VarDecl>(CapturedVar); VD && !C->isPackExpansion()) + LSI->ContainsUnexpandedParameterPack |= VD->isParameterPack(); // Capture the transformed variable. getSema().tryCaptureVariable(CapturedVar, C->getLocation(), Kind, >From 5285c104ed526311edc4a54842ca7844410d4780 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Fri, 24 May 2024 13:34:00 +0800 Subject: [PATCH 09/23] Fix typos --- clang/lib/Sema/SemaTemplateDeduction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 0b6375001f532..2af3c44f49b3c 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -4296,7 +4296,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( // Deduce an argument of type ParamType from an expression with index ArgIdx. auto DeduceCallArgument = [&](QualType ParamType, unsigned ArgIdx, - bool ExplicitObjetArgument) { + bool ExplicitObjectArgument) { // C++ [demp.deduct.call]p1: (DR1391) // Template argument deduction is done by comparing each function template // parameter that contains template-parameters that participate in @@ -4304,7 +4304,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments( if (!hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) return TemplateDeductionResult::Success; - if (ExplicitObjetArgument) { + if (ExplicitObjectArgument) { // ... with the type of the corresponding argument return DeduceTemplateArgumentsFromCallArgument( *this, TemplateParams, FirstInnerIndex, ParamType, ObjectType, >From b2d28364d1729b3f90b37905b91554b9a5d75423 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Thu, 18 Jul 2024 14:28:52 +0800 Subject: [PATCH 10/23] Fixup --- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 ----- clang/lib/Sema/TreeTransform.h | 25 +++++++--------- .../test/SemaTemplate/lambda-capture-pack.cpp | 29 +++++++++++++++---- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 896e38d45326e..01432301633ed 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -6113,14 +6113,6 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, return cast<NamedDecl>(FD); int PackIdx = ArgumentPackSubstitutionIndex; - // FIXME: Move it elsewhere e.g. TreeTransform::TransformDecl. - // This is for #18873. - if (PackIdx == -1) { - LocalInstantiationScope LIS(*this, /*CombineWithOuterScope=*/false); - MultiLevelTemplateArgumentList FakeArgs; - FakeArgs.addOuterRetainedLevels(D->getTemplateDepth() + 1); - return cast_if_present<NamedDecl>(SubstDecl(D, CurContext, FakeArgs)); - } assert(PackIdx != -1 && "found declaration pack but not pack expanding"); typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index ba074bc636361..1afe05d9ad524 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -14443,9 +14443,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { } NewVDs.push_back(NewVD); getSema().addInitCapture(LSI, NewVD, C->getCaptureKind() == LCK_ByRef); - // If the lambda is written within a fold expression, the initializer - // may be expanded later. Preserve the ContainsUnexpandedParameterPack - // flag because CXXFoldExpr uses it for the pattern. + // The Init expression might be expanded by an outer fold expression. LSI->ContainsUnexpandedParameterPack |= Init.get()->containsUnexpandedParameterPack(); } @@ -14515,10 +14513,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { continue; } - // If the lambda is written within a fold expression, the captured - // variable may be expanded later. Preserve the - // ContainsUnexpandedParameterPack flag because CXXFoldExpr uses it for the - // pattern. + // The captured pack might be expanded by an outer fold expression. if (auto *VD = dyn_cast<VarDecl>(CapturedVar); VD && !C->isPackExpansion()) LSI->ContainsUnexpandedParameterPack |= VD->isParameterPack(); @@ -14574,6 +14569,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { if (NewCallOpType.isNull()) return ExprError(); + LSI->ContainsUnexpandedParameterPack |= + NewCallOpType->containsUnexpandedParameterPack(); NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType); } @@ -14648,18 +14645,18 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { /*IsInstantiation*/ true); SavedContext.pop(); - // The lambda function might contain a pack that would be expanded by a fold - // expression outside. For example, + // Parts other than the capture e.g. the lambda body might still contain a + // pattern that an outer fold expression would expand. // - // []<class... Is>() { ([](auto P = Is()) {}, ...); } - // - // forgetting the flag will result in getPattern() of CXXFoldExpr returning - // null in terms of the inner lambda. + // We don't have a way to propagate up the ContainsUnexpandedParameterPack + // flag from a Stmt, so we have to revisit the lambda. if (!LSICopy.ContainsUnexpandedParameterPack) { llvm::SmallVector<UnexpandedParameterPack> UnexpandedPacks; getSema().collectUnexpandedParameterPacksFromLambda(NewCallOperator, UnexpandedPacks); - // FIXME: Should we call DiagnoseUnexpandedParameterPacks() instead? + // FIXME: Should we call Sema::DiagnoseUnexpandedParameterPacks() instead? + // Unfortunately, that requires the LambdaScopeInfo to exist, which has been + // removed by ActOnFinishFunctionBody(). LSICopy.ContainsUnexpandedParameterPack = !UnexpandedPacks.empty(); } // Recompute the dependency of the lambda so that we can defer the lambda call diff --git a/clang/test/SemaTemplate/lambda-capture-pack.cpp b/clang/test/SemaTemplate/lambda-capture-pack.cpp index 7b22c724eb20e..6d2ab50827759 100644 --- a/clang/test/SemaTemplate/lambda-capture-pack.cpp +++ b/clang/test/SemaTemplate/lambda-capture-pack.cpp @@ -76,7 +76,6 @@ template <class = void> void f() { }(), ...); }(1, 2); - // https://github.com/llvm/llvm-project/issues/18873 [](auto ...y) { ([y] { }(), ...); }(); @@ -87,11 +86,28 @@ template <class = void> void f() { })(1); }(2, 'b'); - [](auto ...x) { - ([&](auto ...y) { - ([x, y] { }(), ...); - })(1, 'a'); - }(2, 'b'); +#if 0 + // https://github.com/llvm/llvm-project/issues/18873 + [](auto ...x) { // #1 + ([&](auto ...y) { // #2 + ([x, y] { }(), ...); // #3 + })(1, 'a'); // #4 + }(2, 'b'); // #5 + + // We run into another crash for the above lambda because of the absence of a + // mechanism that rebuilds an unexpanded pack from an expanded Decls. + // + // Basically, this happens after `x` at #1 being expanded when the template + // arguments at #5, deduced as <int, char>, are ready. When we want to + // instantiate the body of #1, we first instantiate the CallExpr at #4, which + // boils down to the lambda's instantiation at #2. To that end, we have to + // instantiate the body of it, which turns out to be #3. #3 is a CXXFoldExpr, + // and we immediately have to hold off on the expansion because we don't have + // corresponding template arguments for it. Therefore, we want to rebuild a + // CXXFoldExpr, which requires another pattern transformation of the lambda + // inside #3. Then we need to find an unexpanded form of such a Decl of x at + // the time of transforming the capture, which is impossible because the + // instantiated form has been expanded at #1! [](auto ...x) { // #outer ([&](auto ...y) { // #inner @@ -102,6 +118,7 @@ template <class = void> void f() { // expected-note-re@#instantiate-f {{function template specialization {{.*}} requested here}} })('a', 'b', 'c'); }(0, 1, 2, 3); +#endif } template void f(); // #instantiate-f >From 26872a6fecbc4ac4f83f6b694ef241a9bf17c4ed Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Thu, 18 Jul 2024 15:28:36 +0800 Subject: [PATCH 11/23] Fix release notes --- clang/docs/ReleaseNotes.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9e5bee1e7989b..02cf2e1919d7f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1034,13 +1034,13 @@ Bug Fixes to C++ Support - Fixed a CTAD substitution bug involving type aliases that reference outer template parameters. (#GH94614). - Clang now correctly handles unexpanded packs in the template parameter list of a generic lambda expression (#GH48937) +- Clang now correctly handles unexpanded packs in a lambda used as the pattern of a folded expression. (#GH56852), + (#GH85667). - Fix a crash when parsing an invalid type-requirement in a requires expression. (#GH51868) - Fix parsing of built-in type-traits such as ``__is_pointer`` in libstdc++ headers. (#GH95598) - Fixed failed assertion when resolving context of defaulted comparison method outside of struct. (#GH96043). - Clang now diagnoses explicit object parameters in member pointers and other contexts where they should not appear. Fixes (#GH85992). -- 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 (#GH18873). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ >From 10b9d8b1e74a741cb23c9b4b207519a2f38da95e Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Thu, 18 Jul 2024 15:31:52 +0800 Subject: [PATCH 12/23] clarify a bit more --- clang/test/SemaTemplate/lambda-capture-pack.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/test/SemaTemplate/lambda-capture-pack.cpp b/clang/test/SemaTemplate/lambda-capture-pack.cpp index 6d2ab50827759..ebfec69e19a7a 100644 --- a/clang/test/SemaTemplate/lambda-capture-pack.cpp +++ b/clang/test/SemaTemplate/lambda-capture-pack.cpp @@ -103,11 +103,11 @@ template <class = void> void f() { // boils down to the lambda's instantiation at #2. To that end, we have to // instantiate the body of it, which turns out to be #3. #3 is a CXXFoldExpr, // and we immediately have to hold off on the expansion because we don't have - // corresponding template arguments for it. Therefore, we want to rebuild a - // CXXFoldExpr, which requires another pattern transformation of the lambda - // inside #3. Then we need to find an unexpanded form of such a Decl of x at - // the time of transforming the capture, which is impossible because the - // instantiated form has been expanded at #1! + // corresponding template arguments (arguments at #4 are not transformed yet) for it. + // Therefore, we want to rebuild a CXXFoldExpr, which requires another pattern + // transformation of the lambda inside #3. Then we need to find an unexpanded form + // of such a Decl of x at the time of transforming the capture, which is impossible + // because the instantiated form has been expanded at #1! [](auto ...x) { // #outer ([&](auto ...y) { // #inner >From 54af6a1cdcdedebe1f3c218d9defc06a74965f06 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Mon, 22 Jul 2024 13:41:40 +0800 Subject: [PATCH 13/23] Typo --- clang/docs/ReleaseNotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 02cf2e1919d7f..8d520e859bee4 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1034,7 +1034,7 @@ Bug Fixes to C++ Support - Fixed a CTAD substitution bug involving type aliases that reference outer template parameters. (#GH94614). - Clang now correctly handles unexpanded packs in the template parameter list of a generic lambda expression (#GH48937) -- Clang now correctly handles unexpanded packs in a lambda used as the pattern of a folded expression. (#GH56852), +- Clang now correctly handles unexpanded packs in a lambda used as the pattern of a fold expression. (#GH56852), (#GH85667). - Fix a crash when parsing an invalid type-requirement in a requires expression. (#GH51868) - Fix parsing of built-in type-traits such as ``__is_pointer`` in libstdc++ headers. (#GH95598) >From 81fd4c9bdf768c268386b68c2d5d32e6f000351a Mon Sep 17 00:00:00 2001 From: Ilya Biryukov <ibiryu...@google.com> Date: Mon, 22 Jul 2024 15:19:07 +0200 Subject: [PATCH 14/23] [Sema] Default arguments for template parameters affect ContainsUnexpandedPacks This addresses the FIXME in the code. There are tests for the new behavior in a follow up fix for #99877, which also addresses other bugs that prevent exposing the wrong results of `ContainsUnexpandedPacks` in the outputs of the compiler without crashes. --- clang/lib/AST/DeclTemplate.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 722c7fcf0b0df..5a47b4e646355 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -44,6 +44,13 @@ using namespace clang; // TemplateParameterList Implementation //===----------------------------------------------------------------------===// +namespace { +template <class TemplateParam> +bool DefaultArgumentContainsUnexpandedPack(const TemplateParam &P) { + return P.hasDefaultArgument() && + P.getDefaultArgument().getArgument().containsUnexpandedParameterPack(); +} +} // namespace TemplateParameterList::TemplateParameterList(const ASTContext& C, SourceLocation TemplateLoc, @@ -61,27 +68,30 @@ TemplateParameterList::TemplateParameterList(const ASTContext& C, bool IsPack = P->isTemplateParameterPack(); if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) { - if (!IsPack && NTTP->getType()->containsUnexpandedParameterPack()) + if (!IsPack && (NTTP->getType()->containsUnexpandedParameterPack() || + DefaultArgumentContainsUnexpandedPack(*NTTP))) ContainsUnexpandedParameterPack = true; if (NTTP->hasPlaceholderTypeConstraint()) HasConstrainedParameters = true; } else if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(P)) { if (!IsPack && - TTP->getTemplateParameters()->containsUnexpandedParameterPack()) + (TTP->getTemplateParameters()->containsUnexpandedParameterPack() || + DefaultArgumentContainsUnexpandedPack(*TTP))) { ContainsUnexpandedParameterPack = true; + } } else if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(P)) { - if (const TypeConstraint *TC = TTP->getTypeConstraint()) { - if (TC->getImmediatelyDeclaredConstraint() - ->containsUnexpandedParameterPack()) - ContainsUnexpandedParameterPack = true; + if (!IsPack && DefaultArgumentContainsUnexpandedPack(*TTP)) { + ContainsUnexpandedParameterPack = true; + } else if (const TypeConstraint *TC = TTP->getTypeConstraint(); + TC && TC->getImmediatelyDeclaredConstraint() + ->containsUnexpandedParameterPack()) { + ContainsUnexpandedParameterPack = true; } if (TTP->hasTypeConstraint()) HasConstrainedParameters = true; } else { llvm_unreachable("unexpected template parameter type"); } - // FIXME: If a default argument contains an unexpanded parameter pack, the - // template parameter list does too. } if (HasRequiresClause) { >From 97372b6820ccba9263cee4ee3fbd87e6edb2e6c3 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Tue, 23 Jul 2024 23:06:07 +0800 Subject: [PATCH 15/23] Merge tests from ilya's 99882 and handle template parameter cases Co-authored-by: Ilya Biryukov <ibiryu...@google.com> --- clang/lib/Sema/TreeTransform.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 1afe05d9ad524..cd72bff376e9a 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -14528,9 +14528,14 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { auto TPL = getDerived().TransformTemplateParameterList( E->getTemplateParameterList()); LSI->GLTemplateParameterList = TPL; - if (TPL) + if (TPL) { getSema().AddTemplateParametersToLambdaCallOperator(NewCallOperator, Class, TPL); + // The parameter list might reference to a pack that an outer fold + // expression would expand. + LSI->ContainsUnexpandedParameterPack |= + TPL->containsUnexpandedParameterPack(); + } // Transform the type of the original lambda's call operator. // The transformation MUST be done in the CurrentInstantiationScope since >From d1cc8a89b58327e1318b33c9add6b51a9980f110 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Thu, 25 Jul 2024 21:48:35 +0800 Subject: [PATCH 16/23] Handle more cases e.g. constraints, DeclStmt, etc. --- clang/include/clang/Sema/Sema.h | 17 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 40 ++-- clang/lib/Sema/SemaTemplateVariadic.cpp | 55 ++++- clang/lib/Sema/TreeTransform.h | 93 ++++++-- .../SemaCXX/fold_lambda_with_variadics.cpp | 201 ++++++++++++++++++ .../test/SemaTemplate/lambda-capture-pack.cpp | 101 --------- 6 files changed, 350 insertions(+), 157 deletions(-) create mode 100644 clang/test/SemaCXX/fold_lambda_with_variadics.cpp diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 74cde2bcff1c2..6712392c2b03c 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14035,6 +14035,15 @@ class Sema final : public SemaBase { TemplateArgument Arg, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + /// Collect the set of unexpanded parameter packs within the given + /// template argument. + /// + /// \param Arg The template argument that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacksForFoldExprs( + Expr *E, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded, + SmallVectorImpl<UnexpandedParameterPack> &UnexpandedFromConstraints); + /// Collect the set of unexpanded parameter packs within the given /// template argument. /// @@ -14052,14 +14061,6 @@ class Sema final : public SemaBase { 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/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index a7bc6749c5852..13f6d6cbeb757 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -39,6 +39,7 @@ #include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/TimeProfiler.h" #include <optional> @@ -1394,7 +1395,22 @@ namespace { SourceRange PatternRange, ArrayRef<UnexpandedParameterPack> Unexpanded, bool &ShouldExpand, bool &RetainExpansion, - std::optional<unsigned> &NumExpansions) { + std::optional<unsigned> &NumExpansions, + bool ForConstraints = false) { + if (ForConstraints) { + LambdaScopeInfo *LSI = getSema().getCurLambda(); + if (LSI) { + MultiLevelTemplateArgumentList MLTAL = + getSema().getTemplateInstantiationArgs( + LSI->CallOperator, /*DC=*/nullptr, /*Final=*/false, + /*Innermost=*/std::nullopt, /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true); + return getSema().CheckParameterPacksForExpansion( + EllipsisLoc, PatternRange, Unexpanded, MLTAL, ShouldExpand, + RetainExpansion, NumExpansions); + } + } + return getSema().CheckParameterPacksForExpansion(EllipsisLoc, PatternRange, Unexpanded, TemplateArgs, @@ -1656,11 +1672,12 @@ namespace { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this); - ExprResult Result = inherited::TransformLambdaExpr(E); - if (Result.isInvalid()) - return Result; + return inherited::TransformLambdaExpr(E); + } - CXXMethodDecl *MD = Result.getAs<LambdaExpr>()->getCallOperator(); + void RebuildLambdaExprImpl(SourceLocation StartLoc, SourceLocation EndLoc, + LambdaScopeInfo *LSI) { + CXXMethodDecl *MD = LSI->CallOperator; for (ParmVarDecl *PVD : MD->parameters()) { assert(PVD && "null in a parameter list"); if (!PVD->hasDefaultArg()) @@ -1673,14 +1690,12 @@ namespace { // RecoveryExpr that wraps the uninstantiated default argument so // that downstream diagnostics are omitted. ExprResult ErrorResult = SemaRef.CreateRecoveryExpr( - UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), - { UninstExpr }, UninstExpr->getType()); + UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), {UninstExpr}, + UninstExpr->getType()); if (ErrorResult.isUsable()) PVD->setDefaultArg(ErrorResult.get()); } } - - return Result; } StmtResult TransformLambdaBody(LambdaExpr *E, Stmt *Body) { @@ -1693,11 +1708,8 @@ namespace { // `true` to temporarily fix this issue. // FIXME: This temporary fix can be removed after fully implementing // p0588r1. - bool Prev = EvaluateConstraints; - EvaluateConstraints = true; - StmtResult Stmt = inherited::TransformLambdaBody(E, Body); - EvaluateConstraints = Prev; - return Stmt; + llvm::SaveAndRestore _(EvaluateConstraints, true); + return inherited::TransformLambdaBody(E, Body); } ExprResult TransformRequiresExpr(RequiresExpr *E) { diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 9a92fd682133f..7c7f5d233cbbc 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -19,6 +19,7 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" +#include "llvm/Support/SaveAndRestore.h" #include <optional> using namespace clang; @@ -40,6 +41,10 @@ namespace { bool InLambda = false; unsigned DepthLimit = (unsigned)-1; + FunctionDecl *CurrentFunction = nullptr; + bool InConstraint = false; + SmallVectorImpl<UnexpandedParameterPack> *UnexpandedFromConstraints; + void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) { if (auto *VD = dyn_cast<VarDecl>(ND)) { // For now, the only problematic case is a generic lambda's templated @@ -52,19 +57,31 @@ namespace { } else if (getDepthAndIndex(ND).first >= DepthLimit) return; + if (InConstraint && UnexpandedFromConstraints) { + UnexpandedFromConstraints->push_back({ND, Loc}); + return; + } + Unexpanded.push_back({ND, Loc}); } void addUnexpanded(const TemplateTypeParmType *T, SourceLocation Loc = SourceLocation()) { - if (T->getDepth() < DepthLimit) + if (T->getDepth() < DepthLimit) { + if (InConstraint && UnexpandedFromConstraints) { + UnexpandedFromConstraints->push_back({T, Loc}); + return; + } Unexpanded.push_back({T, Loc}); + } } public: explicit CollectUnexpandedParameterPacksVisitor( SmallVectorImpl<UnexpandedParameterPack> &Unexpanded, - bool InLambda = false) - : Unexpanded(Unexpanded), InLambda(InLambda) {} + SmallVectorImpl<UnexpandedParameterPack> *UnexpandedFromConstraints = + nullptr) + : Unexpanded(Unexpanded), + UnexpandedFromConstraints(UnexpandedFromConstraints) {} bool shouldWalkTypesOfTypeLocs() const { return false; } @@ -138,6 +155,11 @@ namespace { /// do not contain unexpanded parameter packs. bool TraverseStmt(Stmt *S) { Expr *E = dyn_cast_or_null<Expr>(S); + + llvm::SaveAndRestore _(InConstraint); + if (CurrentFunction && CurrentFunction->getTrailingRequiresClause() == S) + InConstraint = true; + if ((E && E->containsUnexpandedParameterPack()) || InLambda) return inherited::TraverseStmt(S); @@ -172,6 +194,17 @@ namespace { if (D && D->isParameterPack()) return true; + if (D && D->isFunctionOrFunctionTemplate()) { + FunctionDecl *FD; + if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) + FD = FTD->getTemplatedDecl(); + else + FD = cast<FunctionDecl>(D); + + llvm::SaveAndRestore _(CurrentFunction, FD); + return inherited::TraverseDecl(D); + } + return inherited::TraverseDecl(D); } @@ -538,6 +571,14 @@ void Sema::collectUnexpandedParameterPacks(TemplateArgument Arg, .TraverseTemplateArgument(Arg); } +void Sema::collectUnexpandedParameterPacksForFoldExprs( + Expr *E, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded, + SmallVectorImpl<UnexpandedParameterPack> &UnexpandedFromConstraints) { + CollectUnexpandedParameterPacksVisitor Visitor(Unexpanded, + &UnexpandedFromConstraints); + Visitor.TraverseTemplateArgument(E); +} + void Sema::collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded) @@ -549,14 +590,6 @@ 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 cd72bff376e9a..8280e166706b2 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -288,7 +288,8 @@ class TreeTransform { SourceRange PatternRange, ArrayRef<UnexpandedParameterPack> Unexpanded, bool &ShouldExpand, bool &RetainExpansion, - std::optional<unsigned> &NumExpansions) { + std::optional<unsigned> &NumExpansions, + bool ForConstraints = false) { ShouldExpand = false; return false; } @@ -4006,6 +4007,37 @@ class TreeTransform { NumExpansions); } + void RebuildLambdaExprImpl(SourceLocation StartLoc, SourceLocation EndLoc, + LambdaScopeInfo *LSI) {} + + ExprResult RebuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, + LambdaScopeInfo *LSI) { + CXXRecordDecl *Class = LSI->Lambda; + CXXMethodDecl *CallOperator = LSI->CallOperator; + CallOperator->setLexicalDeclContext(Class); + Decl *TemplateOrNonTemplateCallOperatorDecl = + CallOperator->getDescribedFunctionTemplate() + ? CallOperator->getDescribedFunctionTemplate() + : cast<Decl>(CallOperator); + // FIXME: Is this really the best choice? Keeping the lexical decl context + // set as CurContext seems more faithful to the source. + TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class); + + getDerived().RebuildLambdaExprImpl(StartLoc, EndLoc, LSI); + + // Default arguments might contain unexpanded packs that would expand later. + for (ParmVarDecl *PVD : LSI->CallOperator->parameters()) { + if (Expr *Init = PVD->getInit()) + LSI->ContainsUnexpandedParameterPack |= + Init->containsUnexpandedParameterPack(); + else if (PVD->hasUninstantiatedDefaultArg()) + LSI->ContainsUnexpandedParameterPack |= + PVD->getUninstantiatedDefaultArg() + ->containsUnexpandedParameterPack(); + } + return getSema().BuildLambdaExpr(StartLoc, EndLoc, LSI); + } + /// Build an empty C++1z fold-expression with the given operator. /// /// By default, produces the fallback value for the fold-expression, or @@ -8257,6 +8289,7 @@ StmtResult TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) { bool DeclChanged = false; SmallVector<Decl *, 4> Decls; + LambdaScopeInfo *LSI = getSema().getCurLambda(); for (auto *D : S->decls()) { Decl *Transformed = getDerived().TransformDefinition(D->getLocation(), D); if (!Transformed) @@ -8265,6 +8298,15 @@ TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) { if (Transformed != D) DeclChanged = true; + if (LSI && isa<TypeDecl>(Transformed)) + LSI->ContainsUnexpandedParameterPack |= + getSema() + .getASTContext() + .getTypeDeclType(cast<TypeDecl>(Transformed)) + .getCanonicalType() + .getTypePtr() + ->containsUnexpandedParameterPack(); + Decls.push_back(Transformed); } @@ -14588,11 +14630,20 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { Params = FPTL.getParams(); } + Expr *TrailingRequiresExpr = + E->getCallOperator()->getTrailingRequiresClause(); + if (TrailingRequiresExpr) { + // If we're in an expansion, do not propagate up this flag. Otherwise we + // would fail to unexpand the surrounding CXXFoldExpr. + if (getSema().ArgumentPackSubstitutionIndex == -1) + LSI->ContainsUnexpandedParameterPack |= + TrailingRequiresExpr->containsUnexpandedParameterPack(); + } + getSema().CompleteLambdaCallOperator( NewCallOperator, E->getCallOperator()->getLocation(), - E->getCallOperator()->getInnerLocStart(), - E->getCallOperator()->getTrailingRequiresClause(), NewCallOpTSI, - E->getCallOperator()->getConstexprKind(), + E->getCallOperator()->getInnerLocStart(), TrailingRequiresExpr, + NewCallOpTSI, E->getCallOperator()->getConstexprKind(), E->getCallOperator()->getStorageClass(), Params, E->hasExplicitResultType()); @@ -14650,20 +14701,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { /*IsInstantiation*/ true); SavedContext.pop(); - // Parts other than the capture e.g. the lambda body might still contain a - // pattern that an outer fold expression would expand. - // - // We don't have a way to propagate up the ContainsUnexpandedParameterPack - // flag from a Stmt, so we have to revisit the lambda. - if (!LSICopy.ContainsUnexpandedParameterPack) { - llvm::SmallVector<UnexpandedParameterPack> UnexpandedPacks; - getSema().collectUnexpandedParameterPacksFromLambda(NewCallOperator, - UnexpandedPacks); - // FIXME: Should we call Sema::DiagnoseUnexpandedParameterPacks() instead? - // Unfortunately, that requires the LambdaScopeInfo to exist, which has been - // removed by ActOnFinishFunctionBody(). - LSICopy.ContainsUnexpandedParameterPack = !UnexpandedPacks.empty(); - } // Recompute the dependency of the lambda so that we can defer the lambda call // construction until after we have all the necessary template arguments. For // example, given @@ -14704,8 +14741,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { Class->setTypeForDecl(nullptr); getSema().Context.getTypeDeclType(Class); - return getSema().BuildLambdaExpr(E->getBeginLoc(), Body.get()->getEndLoc(), - &LSICopy); + return RebuildLambdaExpr(E->getBeginLoc(), Body.get()->getEndLoc(), &LSICopy); } template<typename Derived> @@ -15244,9 +15280,11 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) { Expr *Pattern = E->getPattern(); - SmallVector<UnexpandedParameterPack, 2> Unexpanded; - getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); - assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); + SmallVector<UnexpandedParameterPack, 2> Unexpanded, UnexpandedFromConstraints; + getSema().collectUnexpandedParameterPacksForFoldExprs( + Pattern, Unexpanded, UnexpandedFromConstraints); + assert((!Unexpanded.empty() || !UnexpandedFromConstraints.empty()) && + "Pack expansion without parameter packs?"); // Determine whether the set of unexpanded parameter packs can and should // be expanded. @@ -15261,6 +15299,15 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) { NumExpansions)) return true; + // Only constraints contain unexpanded packs. + if (Unexpanded.empty() && !UnexpandedFromConstraints.empty()) { + if (getDerived().TryExpandParameterPacks( + E->getEllipsisLoc(), Pattern->getSourceRange(), + UnexpandedFromConstraints, Expand, RetainExpansion, NumExpansions, + /*ForConstraints=*/true)) + return true; + } + if (!Expand) { // Do not expand any packs here, just transform and rebuild a fold // expression. diff --git a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp new file mode 100644 index 0000000000000..f4ecfe9807e5d --- /dev/null +++ b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp @@ -0,0 +1,201 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s + +namespace GH85667 { + +template <class T> +struct identity { + using type = T; +}; + +template <class... T> +concept C = false; // #concept-C + +template <class = void> void f() { + + static_assert([]<class... Is>(Is... x) { + return ([I(x)] { + return I; + }() + ...); + }(1, 2) == 3); + + []<class... Is>(Is... x) { + return ([](auto y = Is()) { return y + 1; }() + ...); // expected-error {{no matching function}} \ + // expected-note {{couldn't infer template argument 'y:auto'}} \ + // expected-note@-1 {{requested here}} + // expected-note@#instantiate-f {{requested here}} + }(1); + + []<class... Is>() { + ([]() // expected-error {{no matching function}} + requires C<Is> // expected-note {{because 'float' does not satisfy 'C'}} \ + // expected-note@-1 {{constraints not satisfied}} \ + // expected-note@#concept-C {{evaluated to false}} \ + // expected-note@#instantiate-f {{requested here}} + {}(), + ...); + }.template operator()<char, int, float>(); // expected-note {{requested here}} + + []<class... Is>() { + ([](Is) + requires (!C<Is>) + {}(Is()), + ...); + }.template operator()<char, int, float>(); + + []<class... Is>() { + ([]<class = Is>(Is) + noexcept(bool(Is())) requires (!C<Is>) + {}(Is()), + ...); + }.template operator()<char, int, float>(); + + 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>(); + + // https://github.com/llvm/llvm-project/issues/56852 + []<class... Is>(Is...) { + ([] { + using T = identity<Is>::type; + }(), ...); + }(1, 2); + + [](auto ...y) { + ([y] { }(), ...); + }(); + + [](auto ...x) { + ([&](auto ...y) { + ([x..., y] { }(), ...); + })(1); + }(2, 'b'); + +#if 0 + // https://github.com/llvm/llvm-project/issues/18873 + [](auto ...x) { // #1 + ([&](auto ...y) { // #2 + ([x, y] { }(), ...); // #3 + })(1, 'a'); // #4 + }(2, 'b'); // #5 + + // We run into another crash for the above lambda because of the absence of a + // mechanism that rebuilds an unexpanded pack from an expanded Decls. + // + // Basically, this happens after `x` at #1 being expanded when the template + // arguments at #5, deduced as <int, char>, are ready. When we want to + // instantiate the body of #1, we first instantiate the CallExpr at #4, which + // boils down to the lambda's instantiation at #2. To that end, we have to + // instantiate the body of it, which turns out to be #3. #3 is a CXXFoldExpr, + // and we immediately have to hold off on the expansion because we don't have + // corresponding template arguments (arguments at #4 are not transformed yet) for it. + // Therefore, we want to rebuild a CXXFoldExpr, which requires another pattern + // transformation of the lambda inside #3. Then we need to find an unexpanded form + // of such a Decl of x at the time of transforming the capture, which is impossible + // because the instantiated form has been expanded at #1! + + [](auto ...x) { // #outer + ([&](auto ...y) { // #inner + ([x, y] { }(), ...); + // expected-error@-1 {{parameter pack 'y' that has a different length (4 vs. 3) from outer parameter packs}} + // expected-note-re@#inner {{function template specialization {{.*}} requested here}} + // expected-note-re@#outer {{function template specialization {{.*}} requested here}} + // expected-note-re@#instantiate-f {{function template specialization {{.*}} requested here}} + })('a', 'b', 'c'); + }(0, 1, 2, 3); +#endif +} + +template void f(); // #instantiate-f + +} // namespace GH85667 + +namespace GH99877 { + +struct tuple { + int x[3]; +}; + +template <class F> int apply(F f, tuple v) { return f(v.x[0], v.x[1], v.x[2]); } + +int Cartesian1(auto x, auto y) { + return apply( + [&](auto... xs) { + return (apply([xs](auto... ys) { return (ys + ...); }, y) + ...); + }, + x); +} + +int Cartesian2(auto x, auto y) { + return apply( + [&](auto... xs) { + return (apply([zs = xs](auto... ys) { return (ys + ...); }, y) + ...); + }, + x); +} + +template <int...> struct Ints {}; +template <int> struct Choose { + template <class> struct Templ; +}; +template <int... x> int Cartesian3(auto y) { + return [&]<int... xs>(Ints<xs...>) { + // check in default template arguments for + // - type template parameters, + (void)(apply([]<class = decltype(xs)>(auto... ys) { return (ys + ...); }, + y) + + ...); + // - template template parameters. + (void)(apply([]<template <class> class = Choose<xs>::template Templ>( + auto... ys) { return (ys + ...); }, + y) + + ...); + // - non-type template parameters, + return (apply([]<int = xs>(auto... ys) { return (ys + ...); }, y) + ...); + }(Ints<x...>()); +} + +template <int... x> int Cartesian4(auto y) { + return [&]<int... xs>(Ints<xs...>) { + return ( + apply([]<decltype(xs) xx = 1>(auto... ys) { return (ys + ...); }, y) + + ...); + }(Ints<x...>()); +} + +// FIXME: Attributes should preserve the ContainsUnexpandedPack flag. +#if 0 + +int Cartesian5(auto x, auto y) { + return apply( + [&](auto... xs) { + return (apply([](auto... ys) __attribute__(( + diagnose_if(!__is_same(decltype(xs), int), "message", + "error"))) { return (ys + ...); }, + y) + + ...); + }, + x); +} + +#endif + +void foo() { + auto x = tuple({1, 2, 3}); + auto y = tuple({4, 5, 6}); + Cartesian1(x, y); + Cartesian2(x, y); + Cartesian3<1, 2, 3>(y); + Cartesian4<1, 2, 3>(y); +#if 0 + Cartesian5(x, y); +#endif +} + +} // namespace GH99877 diff --git a/clang/test/SemaTemplate/lambda-capture-pack.cpp b/clang/test/SemaTemplate/lambda-capture-pack.cpp index ebfec69e19a7a..35b2ffcefea35 100644 --- a/clang/test/SemaTemplate/lambda-capture-pack.cpp +++ b/clang/test/SemaTemplate/lambda-capture-pack.cpp @@ -23,104 +23,3 @@ 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); - - [](auto ...y) { - ([y] { }(), ...); - }(); - - [](auto ...x) { - ([&](auto ...y) { - ([x..., y] { }(), ...); - })(1); - }(2, 'b'); - -#if 0 - // https://github.com/llvm/llvm-project/issues/18873 - [](auto ...x) { // #1 - ([&](auto ...y) { // #2 - ([x, y] { }(), ...); // #3 - })(1, 'a'); // #4 - }(2, 'b'); // #5 - - // We run into another crash for the above lambda because of the absence of a - // mechanism that rebuilds an unexpanded pack from an expanded Decls. - // - // Basically, this happens after `x` at #1 being expanded when the template - // arguments at #5, deduced as <int, char>, are ready. When we want to - // instantiate the body of #1, we first instantiate the CallExpr at #4, which - // boils down to the lambda's instantiation at #2. To that end, we have to - // instantiate the body of it, which turns out to be #3. #3 is a CXXFoldExpr, - // and we immediately have to hold off on the expansion because we don't have - // corresponding template arguments (arguments at #4 are not transformed yet) for it. - // Therefore, we want to rebuild a CXXFoldExpr, which requires another pattern - // transformation of the lambda inside #3. Then we need to find an unexpanded form - // of such a Decl of x at the time of transforming the capture, which is impossible - // because the instantiated form has been expanded at #1! - - [](auto ...x) { // #outer - ([&](auto ...y) { // #inner - ([x, y] { }(), ...); - // expected-error@-1 {{parameter pack 'y' that has a different length (4 vs. 3) from outer parameter packs}} - // expected-note-re@#inner {{function template specialization {{.*}} requested here}} - // expected-note-re@#outer {{function template specialization {{.*}} requested here}} - // expected-note-re@#instantiate-f {{function template specialization {{.*}} requested here}} - })('a', 'b', 'c'); - }(0, 1, 2, 3); -#endif -} - -template void f(); // #instantiate-f - -} >From ce2bf931b07ab95f0f7da5e5923bd74578385544 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Thu, 25 Jul 2024 22:15:21 +0800 Subject: [PATCH 17/23] Co-author Co-authored-by: Ilya Biryukov <809452+ilya-biryu...@users.noreply.github.com> --- clang/test/SemaCXX/fold_lambda_with_variadics.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp index f4ecfe9807e5d..8539674b57190 100644 --- a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp +++ b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp @@ -35,6 +35,7 @@ template <class = void> void f() { ...); }.template operator()<char, int, float>(); // expected-note {{requested here}} + []<class... Is>() { ([](Is) requires (!C<Is>) >From c2a0bf947718e63442f448cba5bb7fa5b71ebc86 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Fri, 26 Jul 2024 23:27:11 +0800 Subject: [PATCH 18/23] Fix ReleaseNotes --- clang/docs/ReleaseNotes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index caf998aa2d7af..c34c66268cc08 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -152,7 +152,7 @@ Bug Fixes to C++ Support - Fixed a crash when an expression with a dependent ``__typeof__`` type is used as the operand of a unary operator. (#GH97646) - Fixed a failed assertion when checking invalid delete operator declaration. (#GH96191) - Clang now correctly handles unexpanded packs in a lambda used as the pattern of a fold expression. (#GH56852), - (#GH85667), (#99877). + (#GH85667), (#GH99877). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ >From ea94d6d802da0123acffc051e54f9529d59c6da9 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Tue, 30 Jul 2024 16:34:27 +0800 Subject: [PATCH 19/23] Use CurContext --- clang/lib/Sema/SemaTemplateInstantiate.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 42f11ed345963..4f8b261353124 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1398,17 +1398,15 @@ namespace { std::optional<unsigned> &NumExpansions, bool ForConstraints = false) { if (ForConstraints) { - LambdaScopeInfo *LSI = getSema().getCurLambda(); - if (LSI) { - MultiLevelTemplateArgumentList MLTAL = - getSema().getTemplateInstantiationArgs( - LSI->CallOperator, /*DC=*/nullptr, /*Final=*/false, - /*Innermost=*/std::nullopt, /*RelativeToPrimary=*/true, - /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true); - return getSema().CheckParameterPacksForExpansion( - EllipsisLoc, PatternRange, Unexpanded, MLTAL, ShouldExpand, - RetainExpansion, NumExpansions); - } + MultiLevelTemplateArgumentList MLTAL = + getSema().getTemplateInstantiationArgs( + cast<NamedDecl>(getSema().CurContext), /*DC=*/nullptr, + /*Final=*/false, + /*Innermost=*/std::nullopt, /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true); + return getSema().CheckParameterPacksForExpansion( + EllipsisLoc, PatternRange, Unexpanded, MLTAL, ShouldExpand, + RetainExpansion, NumExpansions); } return getSema().CheckParameterPacksForExpansion(EllipsisLoc, >From 412bf5ec0026a5ff899481f050ec748344e25131 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Tue, 30 Jul 2024 20:22:36 +0800 Subject: [PATCH 20/23] Remove the fixes for constraints --- clang/include/clang/Sema/Sema.h | 9 ---- clang/lib/Sema/SemaTemplateInstantiate.cpp | 19 ++----- clang/lib/Sema/SemaTemplateVariadic.cpp | 50 ++----------------- clang/lib/Sema/TreeTransform.h | 20 ++------ .../SemaCXX/fold_lambda_with_variadics.cpp | 23 +-------- 5 files changed, 12 insertions(+), 109 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f92e2b3d0bd98..7bfdaaae45a93 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -14037,15 +14037,6 @@ class Sema final : public SemaBase { TemplateArgument Arg, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); - /// Collect the set of unexpanded parameter packs within the given - /// template argument. - /// - /// \param Arg The template argument that will be traversed to find - /// unexpanded parameter packs. - void collectUnexpandedParameterPacksForFoldExprs( - Expr *E, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded, - SmallVectorImpl<UnexpandedParameterPack> &UnexpandedFromConstraints); - /// Collect the set of unexpanded parameter packs within the given /// template argument. /// diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 4f8b261353124..077787b45a141 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1395,20 +1395,7 @@ namespace { SourceRange PatternRange, ArrayRef<UnexpandedParameterPack> Unexpanded, bool &ShouldExpand, bool &RetainExpansion, - std::optional<unsigned> &NumExpansions, - bool ForConstraints = false) { - if (ForConstraints) { - MultiLevelTemplateArgumentList MLTAL = - getSema().getTemplateInstantiationArgs( - cast<NamedDecl>(getSema().CurContext), /*DC=*/nullptr, - /*Final=*/false, - /*Innermost=*/std::nullopt, /*RelativeToPrimary=*/true, - /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true); - return getSema().CheckParameterPacksForExpansion( - EllipsisLoc, PatternRange, Unexpanded, MLTAL, ShouldExpand, - RetainExpansion, NumExpansions); - } - + std::optional<unsigned> &NumExpansions) { return getSema().CheckParameterPacksForExpansion(EllipsisLoc, PatternRange, Unexpanded, TemplateArgs, @@ -1688,8 +1675,8 @@ namespace { // RecoveryExpr that wraps the uninstantiated default argument so // that downstream diagnostics are omitted. ExprResult ErrorResult = SemaRef.CreateRecoveryExpr( - UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), {UninstExpr}, - UninstExpr->getType()); + UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), + { UninstExpr }, UninstExpr->getType()); if (ErrorResult.isUsable()) PVD->setDefaultArg(ErrorResult.get()); } diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 168fc10342594..2966af847145e 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -8,18 +8,16 @@ // 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 "llvm/Support/SaveAndRestore.h" #include <optional> using namespace clang; @@ -41,10 +39,6 @@ namespace { bool InLambda = false; unsigned DepthLimit = (unsigned)-1; - FunctionDecl *CurrentFunction = nullptr; - bool InConstraint = false; - SmallVectorImpl<UnexpandedParameterPack> *UnexpandedFromConstraints; - void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) { if (auto *VD = dyn_cast<VarDecl>(ND)) { // For now, the only problematic case is a generic lambda's templated @@ -57,31 +51,18 @@ namespace { } else if (getDepthAndIndex(ND).first >= DepthLimit) return; - if (InConstraint && UnexpandedFromConstraints) { - UnexpandedFromConstraints->push_back({ND, Loc}); - return; - } - Unexpanded.push_back({ND, Loc}); } void addUnexpanded(const TemplateTypeParmType *T, SourceLocation Loc = SourceLocation()) { - if (T->getDepth() < DepthLimit) { - if (InConstraint && UnexpandedFromConstraints) { - UnexpandedFromConstraints->push_back({T, Loc}); - return; - } + if (T->getDepth() < DepthLimit) Unexpanded.push_back({T, Loc}); - } } public: explicit CollectUnexpandedParameterPacksVisitor( - SmallVectorImpl<UnexpandedParameterPack> &Unexpanded, - SmallVectorImpl<UnexpandedParameterPack> *UnexpandedFromConstraints = - nullptr) - : Unexpanded(Unexpanded), - UnexpandedFromConstraints(UnexpandedFromConstraints) {} + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) + : Unexpanded(Unexpanded) {} bool shouldWalkTypesOfTypeLocs() const { return false; } @@ -156,10 +137,6 @@ namespace { bool TraverseStmt(Stmt *S) { Expr *E = dyn_cast_or_null<Expr>(S); - llvm::SaveAndRestore _(InConstraint); - if (CurrentFunction && CurrentFunction->getTrailingRequiresClause() == S) - InConstraint = true; - if ((E && E->containsUnexpandedParameterPack()) || InLambda) return inherited::TraverseStmt(S); @@ -194,17 +171,6 @@ namespace { if (D && D->isParameterPack()) return true; - if (D && D->isFunctionOrFunctionTemplate()) { - FunctionDecl *FD; - if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) - FD = FTD->getTemplatedDecl(); - else - FD = cast<FunctionDecl>(D); - - llvm::SaveAndRestore _(CurrentFunction, FD); - return inherited::TraverseDecl(D); - } - return inherited::TraverseDecl(D); } @@ -571,14 +537,6 @@ void Sema::collectUnexpandedParameterPacks(TemplateArgument Arg, .TraverseTemplateArgument(Arg); } -void Sema::collectUnexpandedParameterPacksForFoldExprs( - Expr *E, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded, - SmallVectorImpl<UnexpandedParameterPack> &UnexpandedFromConstraints) { - CollectUnexpandedParameterPacksVisitor Visitor(Unexpanded, - &UnexpandedFromConstraints); - Visitor.TraverseTemplateArgument(E); -} - void Sema::collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 3de7b69c5e6b3..ce7320121b4ef 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -288,8 +288,7 @@ class TreeTransform { SourceRange PatternRange, ArrayRef<UnexpandedParameterPack> Unexpanded, bool &ShouldExpand, bool &RetainExpansion, - std::optional<unsigned> &NumExpansions, - bool ForConstraints = false) { + std::optional<unsigned> &NumExpansions) { ShouldExpand = false; return false; } @@ -15306,11 +15305,9 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) { Expr *Pattern = E->getPattern(); - SmallVector<UnexpandedParameterPack, 2> Unexpanded, UnexpandedFromConstraints; - getSema().collectUnexpandedParameterPacksForFoldExprs( - Pattern, Unexpanded, UnexpandedFromConstraints); - assert((!Unexpanded.empty() || !UnexpandedFromConstraints.empty()) && - "Pack expansion without parameter packs?"); + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); // Determine whether the set of unexpanded parameter packs can and should // be expanded. @@ -15325,15 +15322,6 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) { NumExpansions)) return true; - // Only constraints contain unexpanded packs. - if (Unexpanded.empty() && !UnexpandedFromConstraints.empty()) { - if (getDerived().TryExpandParameterPacks( - E->getEllipsisLoc(), Pattern->getSourceRange(), - UnexpandedFromConstraints, Expand, RetainExpansion, NumExpansions, - /*ForConstraints=*/true)) - return true; - } - if (!Expand) { // Do not expand any packs here, just transform and rebuild a fold // expression. diff --git a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp index 8539674b57190..200a19d8bc354 100644 --- a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp +++ b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp @@ -7,9 +7,6 @@ struct identity { using type = T; }; -template <class... T> -concept C = false; // #concept-C - template <class = void> void f() { static_assert([]<class... Is>(Is... x) { @@ -25,27 +22,9 @@ template <class = void> void f() { // expected-note@#instantiate-f {{requested here}} }(1); - []<class... Is>() { - ([]() // expected-error {{no matching function}} - requires C<Is> // expected-note {{because 'float' does not satisfy 'C'}} \ - // expected-note@-1 {{constraints not satisfied}} \ - // expected-note@#concept-C {{evaluated to false}} \ - // expected-note@#instantiate-f {{requested here}} - {}(), - ...); - }.template operator()<char, int, float>(); // expected-note {{requested here}} - - - []<class... Is>() { - ([](Is) - requires (!C<Is>) - {}(Is()), - ...); - }.template operator()<char, int, float>(); - []<class... Is>() { ([]<class = Is>(Is) - noexcept(bool(Is())) requires (!C<Is>) + noexcept(bool(Is())) {}(Is()), ...); }.template operator()<char, int, float>(); >From de76522ea2ed1021576a321f683ec7c69ab406e1 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Tue, 30 Jul 2024 20:25:34 +0800 Subject: [PATCH 21/23] Remove extra blanks --- clang/lib/Sema/SemaTemplateVariadic.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 2966af847145e..3d4ccaf68c700 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -136,7 +136,6 @@ namespace { /// do not contain unexpanded parameter packs. bool TraverseStmt(Stmt *S) { Expr *E = dyn_cast_or_null<Expr>(S); - if ((E && E->containsUnexpandedParameterPack()) || InLambda) return inherited::TraverseStmt(S); >From 930e8f9eda87fd8dbac42bde6a5de66aed5b52f9 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Tue, 30 Jul 2024 20:28:12 +0800 Subject: [PATCH 22/23] Remove changes for constraints in TransformLambdaExpr --- clang/lib/Sema/TreeTransform.h | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index ce7320121b4ef..49e6f79eedccc 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -14655,20 +14655,11 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { Params = FPTL.getParams(); } - Expr *TrailingRequiresExpr = - E->getCallOperator()->getTrailingRequiresClause(); - if (TrailingRequiresExpr) { - // If we're in an expansion, do not propagate up this flag. Otherwise we - // would fail to unexpand the surrounding CXXFoldExpr. - if (getSema().ArgumentPackSubstitutionIndex == -1) - LSI->ContainsUnexpandedParameterPack |= - TrailingRequiresExpr->containsUnexpandedParameterPack(); - } - getSema().CompleteLambdaCallOperator( NewCallOperator, E->getCallOperator()->getLocation(), - E->getCallOperator()->getInnerLocStart(), TrailingRequiresExpr, - NewCallOpTSI, E->getCallOperator()->getConstexprKind(), + E->getCallOperator()->getInnerLocStart(), + E->getCallOperator()->getTrailingRequiresClause(), NewCallOpTSI, + E->getCallOperator()->getConstexprKind(), E->getCallOperator()->getStorageClass(), Params, E->hasExplicitResultType()); >From 9ce3250477317ff65a053f542271919149a86b23 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Thu, 1 Aug 2024 22:06:51 +0800 Subject: [PATCH 23/23] Simplify the RebuildLambdaExpr() --- clang/lib/Sema/SemaLambda.cpp | 4 ++++ clang/lib/Sema/SemaTemplateInstantiate.cpp | 5 +++-- clang/lib/Sema/TreeTransform.h | 20 ++------------------ 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 601077e9f3334..b697918120806 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -1021,6 +1021,8 @@ void Sema::CompleteLambdaCallOperator( getGenericLambdaTemplateParameterList(LSI, *this); DeclContext *DC = Method->getLexicalDeclContext(); + // DeclContext::addDecl() assumes that the DeclContext we're adding to is the + // lexical context of the Method. Do so. Method->setLexicalDeclContext(LSI->Lambda); if (TemplateParams) { FunctionTemplateDecl *TemplateMethod = @@ -1105,6 +1107,8 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro, CXXMethodDecl *Method = CreateLambdaCallOperator(Intro.Range, Class); LSI->CallOperator = Method; + // Temporarily set the lexical declaration context to the current + // context, so that the Scope stack matches the lexical nesting. Method->setLexicalDeclContext(CurContext); PushDeclContext(CurScope, Method); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 077787b45a141..6bd8cbbba23b2 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1660,8 +1660,8 @@ namespace { return inherited::TransformLambdaExpr(E); } - void RebuildLambdaExprImpl(SourceLocation StartLoc, SourceLocation EndLoc, - LambdaScopeInfo *LSI) { + ExprResult RebuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, + LambdaScopeInfo *LSI) { CXXMethodDecl *MD = LSI->CallOperator; for (ParmVarDecl *PVD : MD->parameters()) { assert(PVD && "null in a parameter list"); @@ -1681,6 +1681,7 @@ namespace { PVD->setDefaultArg(ErrorResult.get()); } } + return inherited::RebuildLambdaExpr(StartLoc, EndLoc, LSI); } StmtResult TransformLambdaBody(LambdaExpr *E, Stmt *Body) { diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 49e6f79eedccc..d79ffc61fb785 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -4006,24 +4006,8 @@ class TreeTransform { NumExpansions); } - void RebuildLambdaExprImpl(SourceLocation StartLoc, SourceLocation EndLoc, - LambdaScopeInfo *LSI) {} - ExprResult RebuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, LambdaScopeInfo *LSI) { - CXXRecordDecl *Class = LSI->Lambda; - CXXMethodDecl *CallOperator = LSI->CallOperator; - CallOperator->setLexicalDeclContext(Class); - Decl *TemplateOrNonTemplateCallOperatorDecl = - CallOperator->getDescribedFunctionTemplate() - ? CallOperator->getDescribedFunctionTemplate() - : cast<Decl>(CallOperator); - // FIXME: Is this really the best choice? Keeping the lexical decl context - // set as CurContext seems more faithful to the source. - TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class); - - getDerived().RebuildLambdaExprImpl(StartLoc, EndLoc, LSI); - // Default arguments might contain unexpanded packs that would expand later. for (ParmVarDecl *PVD : LSI->CallOperator->parameters()) { if (Expr *Init = PVD->getInit()) @@ -14442,7 +14426,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { CXXMethodDecl *NewCallOperator = getSema().CreateLambdaCallOperator(E->getIntroducerRange(), Class); - NewCallOperator->setLexicalDeclContext(getSema().CurContext); // Enter the scope of the lambda. getSema().buildLambdaScope(LSI, NewCallOperator, E->getIntroducerRange(), @@ -14757,7 +14740,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { Class->setTypeForDecl(nullptr); getSema().Context.getTypeDeclType(Class); - return RebuildLambdaExpr(E->getBeginLoc(), Body.get()->getEndLoc(), &LSICopy); + return getDerived().RebuildLambdaExpr(E->getBeginLoc(), + Body.get()->getEndLoc(), &LSICopy); } template<typename Derived> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits