https://github.com/zyn0217 updated https://github.com/llvm/llvm-project/pull/107995
>From c97f213bc412dd2a4d6ee5c8e58a82f04dbbd03b Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Tue, 10 Sep 2024 17:23:55 +0800 Subject: [PATCH 1/2] [Clang] Introduce FunctionParmPackDecl for expanded lambda captures --- clang/docs/ReleaseNotes.rst | 2 +- clang/include/clang/AST/DeclTemplate.h | 37 +++++++++++++++++++ clang/include/clang/AST/RecursiveASTVisitor.h | 2 + clang/include/clang/Basic/DeclNodes.td | 1 + clang/include/clang/Sema/Template.h | 3 ++ .../include/clang/Serialization/ASTBitCodes.h | 5 ++- clang/lib/AST/DeclBase.cpp | 1 + clang/lib/AST/DeclTemplate.cpp | 37 +++++++++++++++++++ clang/lib/CodeGen/CGDecl.cpp | 1 + clang/lib/Sema/SemaTemplateInstantiate.cpp | 25 ++++++++++++- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 +++ clang/lib/Sema/TreeTransform.h | 14 +++++-- clang/lib/Serialization/ASTCommon.cpp | 1 + clang/lib/Serialization/ASTReaderDecl.cpp | 11 ++++++ clang/lib/Serialization/ASTWriterDecl.cpp | 10 +++++ .../SemaCXX/fold_lambda_with_variadics.cpp | 31 ++++------------ clang/tools/libclang/CIndex.cpp | 1 + 17 files changed, 157 insertions(+), 30 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 250821a9f9c45c..f39c39f8646d08 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -344,7 +344,7 @@ Bug Fixes to C++ Support module imports in those situations. (#GH60336) - Fix init-capture packs having a size of one before being instantiated. (#GH63677) - Clang now preserves the unexpanded flag in a lambda transform used for pack expansion. (#GH56852), (#GH85667), - (#GH99877). + (#GH99877), (#GH18873). - Fixed a bug when diagnosing ambiguous explicit specializations of constrained member functions. - Fixed an assertion failure when selecting a function from an overload set that includes a specialization of a conversion function template. diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 687715a22e9fd3..3730f5bee09d2a 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -3220,6 +3220,43 @@ class ImplicitConceptSpecializationDecl final friend class ASTDeclReader; }; +class FunctionParmPackDecl final + : public Decl, + private llvm::TrailingObjects<FunctionParmPackDecl, VarDecl *> { + friend TrailingObjects; + friend class ASTDeclReader; + + /// The function parameter pack which was referenced. + NamedDecl *Pattern; + + unsigned NumExpansions; + + FunctionParmPackDecl(DeclContext *DC, SourceLocation StartLoc, + NamedDecl *Pattern, ArrayRef<VarDecl *> ExpandedParams); + + void setExpandedParams(ArrayRef<VarDecl *> ExpandedParams); + +public: + static FunctionParmPackDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + NamedDecl *Pattern, + ArrayRef<VarDecl *> ExpandedParams); + + static FunctionParmPackDecl * + CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumExpansions); + + ArrayRef<VarDecl *> getExpandedParams() const { + return ArrayRef<VarDecl *>(getTrailingObjects<VarDecl *>(), NumExpansions); + } + + unsigned getNumExpansions() const { return NumExpansions; } + + NamedDecl *getPattern() const { return Pattern; } + + static bool classofKind(Kind K) { return K == FunctionParmPack; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } +}; + /// A template parameter object. /// /// Template parameter objects represent values of class type used as template diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 3389670a2ab9d9..3297e9eb009678 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2353,6 +2353,8 @@ DEF_TRAVERSE_DECL(ImplicitConceptSpecializationDecl, { TRY_TO(TraverseTemplateArguments(D->getTemplateArguments())); }) +DEF_TRAVERSE_DECL(FunctionParmPackDecl, {}) + #undef DEF_TRAVERSE_DECL // ----------------- Stmt traversal ----------------- diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index 48396e85c5adac..694d3d8b79a183 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -91,6 +91,7 @@ def Named : DeclNode<Decl, "named declarations", 1>; def ObjCProperty : DeclNode<Named, "Objective-C properties">; def ObjCCompatibleAlias : DeclNode<Named>; def ImplicitConceptSpecialization : DeclNode<Decl>; +def FunctionParmPack : DeclNode<Decl>; def LinkageSpec : DeclNode<Decl>, DeclContext; def Export : DeclNode<Decl>, DeclContext; def ObjCPropertyImpl : DeclNode<Decl>; diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 0340c23fd170d6..5de4bf0148652c 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -515,6 +515,9 @@ enum class TemplateSubstitutionKind : char { llvm::PointerUnion<Decl *, DeclArgumentPack *> * findInstantiationOf(const Decl *D); + llvm::PointerUnion<Decl *, DeclArgumentPack *> * + findInstantiationUnsafe(const Decl *D); + void InstantiatedLocal(const Decl *D, Decl *Inst); void InstantiatedLocalPackArg(const Decl *D, VarDecl *Inst); void MakeInstantiatedLocalArgPack(const Decl *D); diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 4410df296d8efc..3f23cea4591b40 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1493,7 +1493,10 @@ enum DeclCode { /// An ImplicitConceptSpecializationDecl record. DECL_IMPLICIT_CONCEPT_SPECIALIZATION, - DECL_LAST = DECL_IMPLICIT_CONCEPT_SPECIALIZATION + /// A FunctionParmPackDecl record. + DECL_FUNCTION_PARM_PACK, + + DECL_LAST = DECL_FUNCTION_PARM_PACK }; /// Record codes for each kind of statement or expression. diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index f42857f20efc44..728b20b39d1635 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -986,6 +986,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case LifetimeExtendedTemporary: case RequiresExprBody: case ImplicitConceptSpecialization: + case FunctionParmPack: // Never looked up by name. return 0; } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 976b3a3e1ecedb..34d60298929c2c 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -1132,6 +1132,43 @@ void ImplicitConceptSpecializationDecl::setTemplateArguments( getTrailingObjects<TemplateArgument>()); } +//===----------------------------------------------------------------------===// +// FunctionParmPackDecl Implementation +//===----------------------------------------------------------------------===// +FunctionParmPackDecl::FunctionParmPackDecl(DeclContext *DC, + SourceLocation StartLoc, + NamedDecl *Pattern, + ArrayRef<VarDecl *> ExpandedParams) + : Decl(FunctionParmPack, DC, StartLoc), Pattern(Pattern), + NumExpansions(ExpandedParams.size()) { + std::uninitialized_copy(ExpandedParams.begin(), ExpandedParams.end(), + getTrailingObjects<VarDecl *>()); +} + +FunctionParmPackDecl * +FunctionParmPackDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, NamedDecl *Pattern, + ArrayRef<VarDecl *> ExpandedParams) { + return new (C, DC, additionalSizeToAlloc<VarDecl *>(ExpandedParams.size())) + FunctionParmPackDecl(DC, StartLoc, Pattern, ExpandedParams); +} + +FunctionParmPackDecl * +FunctionParmPackDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, + unsigned NumExpansions) { + return new (C, ID, additionalSizeToAlloc<VarDecl *>(NumExpansions)) + FunctionParmPackDecl(/*DC=*/nullptr, SourceLocation(), + /*Pattern=*/nullptr, + SmallVector<VarDecl *>(NumExpansions, nullptr)); +} + +void FunctionParmPackDecl::setExpandedParams( + ArrayRef<VarDecl *> ExpandedParams) { + assert(ExpandedParams.size() == NumExpansions); + std::uninitialized_copy(ExpandedParams.begin(), ExpandedParams.end(), + getTrailingObjects<VarDecl *>()); +} + //===----------------------------------------------------------------------===// // ClassTemplatePartialSpecializationDecl Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 563f728e29d781..8269a2f9e0fb6f 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -134,6 +134,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::ImplicitConceptSpecialization: case Decl::LifetimeExtendedTemporary: case Decl::RequiresExprBody: + case Decl::FunctionParmPack: // None of these decls require codegen support. return; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index c42cc250bb904a..b09e42356a1c9c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1855,6 +1855,21 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { // template parameter. } + if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(D); + PVD && SemaRef.ArgumentPackSubstitutionIndex == -1) { + if (auto *Found = + SemaRef.CurrentInstantiationScope->findInstantiationUnsafe(D)) { + using DeclArgumentPack = LocalInstantiationScope::DeclArgumentPack; + if (auto *Pack = Found->dyn_cast<DeclArgumentPack *>()) { + assert(SemaRef.getCurLambda() && + "Only lambdas can hold off an expanded pack expansion"); + return FunctionParmPackDecl::Create(SemaRef.getASTContext(), + PVD->getDeclContext(), + PVD->getLocation(), PVD, *Pack); + } + } + } + return SemaRef.FindInstantiatedDecl(Loc, cast<NamedDecl>(D), TemplateArgs); } @@ -4369,9 +4384,8 @@ static const Decl *getCanonicalParmVarDecl(const Decl *D) { return D; } - llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> * -LocalInstantiationScope::findInstantiationOf(const Decl *D) { +LocalInstantiationScope::findInstantiationUnsafe(const Decl *D) { D = getCanonicalParmVarDecl(D); for (LocalInstantiationScope *Current = this; Current; Current = Current->Outer) { @@ -4395,6 +4409,13 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) { if (!Current->CombineWithOuterScope) break; } + return nullptr; +} + +llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> * +LocalInstantiationScope::findInstantiationOf(const Decl *D) { + if (auto *Result = findInstantiationUnsafe(D)) + return Result; // If we're performing a partial substitution during template argument // deduction, we may not have values for template parameters yet. diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6df412cbb09c83..6f2a301847c317 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4119,6 +4119,11 @@ Decl *TemplateDeclInstantiator::VisitImplicitConceptSpecializationDecl( llvm_unreachable("Concept specializations cannot reside inside a template"); } +Decl * +TemplateDeclInstantiator::VisitFunctionParmPackDecl(FunctionParmPackDecl *D) { + llvm_unreachable("Function param packs cannot reside inside a template"); +} + Decl * TemplateDeclInstantiator::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { return RequiresExprBodyDecl::Create(SemaRef.Context, D->getDeclContext(), diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 0daf620b4123e4..f8b7cca66bc83f 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -14722,12 +14722,20 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { } // Transform the captured variable. - auto *CapturedVar = cast_or_null<ValueDecl>( - getDerived().TransformDecl(C->getLocation(), C->getCapturedVar())); - if (!CapturedVar || CapturedVar->isInvalidDecl()) { + Decl *NewCapturedDecl = + getDerived().TransformDecl(C->getLocation(), C->getCapturedVar()); + if (!NewCapturedDecl || NewCapturedDecl->isInvalidDecl()) { Invalid = true; continue; } + if (auto *FPPD = dyn_cast<FunctionParmPackDecl>(NewCapturedDecl)) { + LSI->ContainsUnexpandedParameterPack = true; + for (VarDecl *Expanded : FPPD->getExpandedParams()) + getSema().tryCaptureVariable(Expanded, C->getLocation(), Kind, + EllipsisLoc); + continue; + } + auto *CapturedVar = cast<ValueDecl>(NewCapturedDecl); // This is not an init-capture; however it contains an unexpanded pack e.g. // ([Pack] {}(), ...) diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index f30642f513ae4a..151bfbf145c515 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -453,6 +453,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::RequiresExprBody: case Decl::UnresolvedUsingIfExists: case Decl::HLSLBuffer: + case Decl::FunctionParmPack: return false; // These indirectly derive from Redeclarable<T> but are not actually diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 9272e23c7da3fc..c20532601ebbfc 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -389,6 +389,7 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> { void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); void VisitDeclaratorDecl(DeclaratorDecl *DD); void VisitFunctionDecl(FunctionDecl *FD); + void VisitFunctionParmPackDecl(FunctionParmPackDecl *D); void VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *GD); void VisitCXXMethodDecl(CXXMethodDecl *D); void VisitCXXConstructorDecl(CXXConstructorDecl *D); @@ -2406,6 +2407,13 @@ void ASTDeclReader::VisitImplicitConceptSpecializationDecl( D->setTemplateArguments(Args); } +void ASTDeclReader::VisitFunctionParmPackDecl(FunctionParmPackDecl *D) { + SmallVector<VarDecl *, 4> Expanded; + for (unsigned I = 0; I < D->getNumExpansions(); ++I) + Expanded.push_back(cast<VarDecl>(Record.readDeclRef())); + D->setExpandedParams(Expanded); +} + void ASTDeclReader::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { } @@ -4158,6 +4166,9 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) { D = ImplicitConceptSpecializationDecl::CreateDeserialized(Context, ID, Record.readInt()); break; + case DECL_FUNCTION_PARM_PACK: + D = FunctionParmPackDecl::CreateDeserialized(Context, ID, Record.readInt()); + break; } assert(D && "Unknown declaration reading AST file"); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 555f6325da646b..a803d8d8c9611e 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -90,6 +90,7 @@ namespace clang { void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); void VisitDeclaratorDecl(DeclaratorDecl *D); void VisitFunctionDecl(FunctionDecl *D); + void VisitFunctionParmPackDecl(FunctionParmPackDecl *D); void VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D); void VisitCXXMethodDecl(CXXMethodDecl *D); void VisitCXXConstructorDecl(CXXConstructorDecl *D); @@ -1700,6 +1701,15 @@ void ASTDeclWriter::VisitImplicitConceptSpecializationDecl( Code = serialization::DECL_IMPLICIT_CONCEPT_SPECIALIZATION; } +void ASTDeclWriter::VisitFunctionParmPackDecl(FunctionParmPackDecl *D) { + Record.push_back(D->getNumExpansions()); + VisitDecl(D); + Record.AddDeclRef(D->getPattern()); + for (VarDecl *VD : D->getExpandedParams()) + Record.AddDeclRef(VD); + Code = serialization::DECL_FUNCTION_PARM_PACK; +} + void ASTDeclWriter::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { Code = serialization::DECL_REQUIRES_EXPR_BODY; } diff --git a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp index 14e242f009dc51..d86cc72ae09249 100644 --- a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp +++ b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp @@ -57,28 +57,14 @@ template <class = void> void f() { })(1); }(2, 'b'); -#if 0 - // FIXME: 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! + // https://github.com/llvm/llvm-project/issues/18873 + static_assert([]<auto... z>(auto ...x) { + return [&](auto ...y) { + return ([x, y] { + return x + y + z; + }() + ...); + }(1, 'a'); + }.template operator()<2, 'b'>(3, 'c') == 1 + 'a' + 2 + 'b' + 3 + 'c'); [](auto ...x) { // #outer ([&](auto ...y) { // #inner @@ -89,7 +75,6 @@ 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 diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index e821c5e4c588b6..432c9924e37d1f 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -7068,6 +7068,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::LifetimeExtendedTemporary: case Decl::RequiresExprBody: case Decl::UnresolvedUsingIfExists: + case Decl::FunctionParmPack: return C; // Declaration kinds that don't make any sense here, but are >From 720d105706800c3b94cda292da5431f27b17483f Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Tue, 10 Sep 2024 20:04:55 +0800 Subject: [PATCH 2/2] Fix CI --- clang/lib/Sema/SemaTemplateInstantiate.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index b09e42356a1c9c..89900be295cd18 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1856,7 +1856,8 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { } if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(D); - PVD && SemaRef.ArgumentPackSubstitutionIndex == -1) { + PVD && SemaRef.CurrentInstantiationScope && + SemaRef.ArgumentPackSubstitutionIndex == -1) { if (auto *Found = SemaRef.CurrentInstantiationScope->findInstantiationUnsafe(D)) { using DeclArgumentPack = LocalInstantiationScope::DeclArgumentPack; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits