https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/112896
>From 6caf16d6ce8eb939c91ed87493c2ccab82d38411 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Fri, 18 Oct 2024 20:22:08 +0800 Subject: [PATCH 1/2] [Clang] Don't assert on substituted-but-yet-expanded packs for nested lambdas --- clang/docs/ReleaseNotes.rst | 2 +- clang/lib/Sema/SemaTemplateVariadic.cpp | 49 ++++++++++++++------ clang/test/SemaCXX/lambda-pack-expansion.cpp | 40 ++++++++++++++++ 3 files changed, 75 insertions(+), 16 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b430b2b0ee3187..d071c480f36dc7 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -486,7 +486,7 @@ Bug Fixes to C++ Support - Clang no longer tries to capture non-odr used default arguments of template parameters of generic lambdas (#GH107048) - Fixed a bug where defaulted comparison operators would remove ``const`` from base classes. (#GH102588) - Fix a crash when using ``source_location`` in the trailing return type of a lambda expression. (#GH67134) -- A follow-up fix was added for (#GH61460), as the previous fix was not entirely correct. (#GH86361) +- A follow-up fix was added for (#GH61460), as the previous fix was not entirely correct. (#GH86361), (#GH112352) - Fixed a crash in the typo correction of an invalid CTAD guide. (#GH107887) - Fixed a crash when clang tries to subtitute parameter pack while retaining the parameter pack. (#GH63819), (#GH107560) diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 19bd4547665835..151b328872bd75 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -41,7 +41,7 @@ namespace { unsigned DepthLimit = (unsigned)-1; #ifndef NDEBUG - bool ContainsFunctionParmPackExpr = false; + bool ContainsIntermediatePacks = false; #endif void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) { @@ -114,6 +114,11 @@ namespace { addUnexpanded(TTP); } +#ifndef NDEBUG + ContainsIntermediatePacks |= + (bool)Template.getAsSubstTemplateTemplateParmPack(); +#endif + return inherited::TraverseTemplateName(Template); } @@ -297,13 +302,28 @@ namespace { #ifndef NDEBUG bool TraverseFunctionParmPackExpr(FunctionParmPackExpr *) { - ContainsFunctionParmPackExpr = true; + ContainsIntermediatePacks = true; + return true; + } + + bool TraverseSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *) { + ContainsIntermediatePacks = true; + return true; + } + + bool VisitSubstTemplateTypeParmPackType(SubstTemplateTypeParmPackType *) { + ContainsIntermediatePacks = true; return true; } - bool containsFunctionParmPackExpr() const { - return ContainsFunctionParmPackExpr; + bool + VisitSubstTemplateTypeParmPackTypeLoc(SubstTemplateTypeParmPackTypeLoc) { + ContainsIntermediatePacks = true; + return true; } + + bool containsIntermediatePacks() const { return ContainsIntermediatePacks; } #endif }; } @@ -439,21 +459,20 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E, if (!E->containsUnexpandedParameterPack()) return false; - // FunctionParmPackExprs are special: - // - // 1) they're used to model DeclRefExprs to packs that have been expanded but - // had that expansion held off in the process of transformation. - // - // 2) they always have the unexpanded dependencies but don't introduce new - // unexpanded packs. - // - // We might encounter a FunctionParmPackExpr being a full expression, which a - // larger CXXFoldExpr would expand. SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor Visitor(Unexpanded); Visitor.TraverseStmt(E); - assert((!Unexpanded.empty() || Visitor.containsFunctionParmPackExpr()) && +#ifndef NDEBUG + // The expression might contain a type/subexpression that has been substituted + // but has the expansion held off, e.g. a FunctionParmPackExpr which a larger + // CXXFoldExpr would expand. It's only possible when expanding a lambda as a + // pattern of a fold expression, so don't fire on an empty result in that + // case. + bool LambdaReferencingOuterPacks = + getEnclosingLambdaOrBlock() && Visitor.containsIntermediatePacks(); + assert((!Unexpanded.empty() || LambdaReferencingOuterPacks) && "Unable to find unexpanded parameter packs"); +#endif return DiagnoseUnexpandedParameterPacks(E->getBeginLoc(), UPPC, Unexpanded); } diff --git a/clang/test/SemaCXX/lambda-pack-expansion.cpp b/clang/test/SemaCXX/lambda-pack-expansion.cpp index 0e60ecd8756600..7f7dd3bb095d57 100644 --- a/clang/test/SemaCXX/lambda-pack-expansion.cpp +++ b/clang/test/SemaCXX/lambda-pack-expansion.cpp @@ -94,3 +94,43 @@ template <typename... Ts> void g2(Ts... p1s) { void f1() { g(); } } // namespace GH61460 + +namespace GH112352 { + +template <class> +constexpr bool foo = false; + +template <int> +constexpr bool bar = false; + +template <template<class> class> +constexpr bool baz = false; + +struct S { + template <typename... Types, int... Values> void foldExpr1() { + (void)[]<int... Is> { + ([] { + Is; + foo<Types>; + bar<Values>; + } && + ...); + }; + } + + template <template<class> class... TTPs> void foldExpr2() { + (void)[]<int... Is> { + ([] { + Is; + baz<TTPs>; + } && ...); + }; + } +}; + +void use() { + S().foldExpr1(); + S().foldExpr2(); +} + +} // namespace GH112352 >From c2d5cc751b37c4aa6f5472e17906bd4eee3723c7 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Fri, 18 Oct 2024 21:14:56 +0800 Subject: [PATCH 2/2] Propagate up ContainsUnexpandedParameterPack for VarDecls --- clang/lib/Sema/TreeTransform.h | 21 ++++++++++++-------- clang/test/SemaCXX/lambda-pack-expansion.cpp | 2 ++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 45e8b3cf6bd8fc..ca04fb7f71be00 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -8385,14 +8385,19 @@ 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(); + if (LSI) { + if (auto *TD = dyn_cast<TypeDecl>(Transformed)) + LSI->ContainsUnexpandedParameterPack |= + getSema() + .getASTContext() + .getTypeDeclType(TD) + .getCanonicalType() + ->containsUnexpandedParameterPack(); + + if (auto *VD = dyn_cast<VarDecl>(Transformed)) + LSI->ContainsUnexpandedParameterPack |= + VD->getType()->containsUnexpandedParameterPack(); + } Decls.push_back(Transformed); } diff --git a/clang/test/SemaCXX/lambda-pack-expansion.cpp b/clang/test/SemaCXX/lambda-pack-expansion.cpp index 7f7dd3bb095d57..3d724c5e4d168b 100644 --- a/clang/test/SemaCXX/lambda-pack-expansion.cpp +++ b/clang/test/SemaCXX/lambda-pack-expansion.cpp @@ -111,6 +111,8 @@ struct S { (void)[]<int... Is> { ([] { Is; + // Propagate up the flag ContainsUnexpandedParameterPack from VarDecl. + S var(foo<Types>); foo<Types>; bar<Values>; } && _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits