diff options
author | Jason Rice <ricejasonf@gmail.com> | 2025-01-29 12:43:52 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-29 21:43:52 +0100 |
commit | abc8812df02599fc413d9ed77b992f8236ed2af9 (patch) | |
tree | d5fc8a01c03d5700aed337d8b8516fa3d461a326 /clang/lib/Sema | |
parent | 608012ace43b42d97884204016c6a8f4883b4359 (diff) | |
download | llvm-abc8812df02599fc413d9ed77b992f8236ed2af9.zip llvm-abc8812df02599fc413d9ed77b992f8236ed2af9.tar.gz llvm-abc8812df02599fc413d9ed77b992f8236ed2af9.tar.bz2 |
[Clang][P1061] Add stuctured binding packs (#121417)
This is an implementation of P1061 Structure Bindings Introduce a Pack
without the ability to use packs outside of templates. There is a couple
of ways the AST could have been sliced so let me know what you think.
The only part of this change that I am unsure of is the
serialization/deserialization stuff. I followed the implementation of
other Exprs, but I do not really know how it is tested. Thank you for
your time considering this.
---------
Co-authored-by: Yanzuo Liu <zwuis@outlook.com>
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 117 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExceptionSpec.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 29 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 47 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateVariadic.cpp | 60 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 32 |
7 files changed, 241 insertions, 53 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index e4e3bba..0cf02fe 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -888,7 +888,15 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, Previous.clear(); } - auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, VarName); + QualType QT; + if (B.EllipsisLoc.isValid()) { + if (!cast<Decl>(DC)->isTemplated()) + Diag(B.EllipsisLoc, diag::err_pack_outside_template); + QT = Context.getPackExpansionType(Context.DependentTy, std::nullopt, + /*ExpectsPackInType=*/false); + } + + auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name, QT); ProcessDeclAttributeList(S, BD, *B.Attrs); @@ -951,20 +959,68 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, return New; } +// Check the arity of the structured bindings. +// Create the resolved pack expr if needed. +static bool CheckBindingsCount(Sema &S, DecompositionDecl *DD, + QualType DecompType, + ArrayRef<BindingDecl *> Bindings, + unsigned MemberCount) { + auto BindingWithPackItr = + std::find_if(Bindings.begin(), Bindings.end(), + [](BindingDecl *D) -> bool { return D->isParameterPack(); }); + bool HasPack = BindingWithPackItr != Bindings.end(); + bool IsValid; + if (!HasPack) { + IsValid = Bindings.size() == MemberCount; + } else { + // There may not be more members than non-pack bindings. + IsValid = MemberCount >= Bindings.size() - 1; + } + + if (IsValid && HasPack) { + // Create the pack expr and assign it to the binding. + unsigned PackSize = MemberCount - Bindings.size() + 1; + QualType PackType = S.Context.getPackExpansionType( + S.Context.DependentTy, std::nullopt, /*ExpectsPackInType=*/false); + BindingDecl *BD = (*BindingWithPackItr); + auto *RP = ResolvedUnexpandedPackExpr::Create(S.Context, DD->getBeginLoc(), + DecompType, PackSize); + BD->setDecomposedDecl(DD); + BD->setBinding(PackType, RP); + + BindingDecl *BPack = *BindingWithPackItr; + // Create the nested BindingDecls. + for (Expr *&E : RP->getExprs()) { + auto *NestedBD = BindingDecl::Create(S.Context, BPack->getDeclContext(), + BPack->getLocation(), + BPack->getIdentifier(), QualType()); + NestedBD->setDecomposedDecl(DD); + E = S.BuildDeclRefExpr(NestedBD, S.Context.DependentTy, VK_LValue, + BPack->getLocation()); + } + } + + if (IsValid) + return false; + + S.Diag(DD->getLocation(), diag::err_decomp_decl_wrong_number_bindings) + << DecompType << (unsigned)Bindings.size() << MemberCount << MemberCount + << (MemberCount < Bindings.size()); + return true; +} + static bool checkSimpleDecomposition( Sema &S, ArrayRef<BindingDecl *> Bindings, ValueDecl *Src, - QualType DecompType, const llvm::APSInt &NumElems, QualType ElemType, + QualType DecompType, const llvm::APSInt &NumElemsAPS, QualType ElemType, llvm::function_ref<ExprResult(SourceLocation, Expr *, unsigned)> GetInit) { - if ((int64_t)Bindings.size() != NumElems) { - S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) - << DecompType << (unsigned)Bindings.size() - << (unsigned)NumElems.getLimitedValue(UINT_MAX) - << toString(NumElems, 10) << (NumElems < Bindings.size()); + unsigned NumElems = (unsigned)NumElemsAPS.getLimitedValue(UINT_MAX); + auto *DD = cast<DecompositionDecl>(Src); + + if (CheckBindingsCount(S, DD, DecompType, Bindings, NumElems)) return true; - } unsigned I = 0; - for (auto *B : Bindings) { + for (auto *B : DD->flat_bindings()) { SourceLocation Loc = B->getLocation(); ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc); if (E.isInvalid()) @@ -1210,13 +1266,10 @@ static bool checkTupleLikeDecomposition(Sema &S, ArrayRef<BindingDecl *> Bindings, VarDecl *Src, QualType DecompType, const llvm::APSInt &TupleSize) { - if ((int64_t)Bindings.size() != TupleSize) { - S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) - << DecompType << (unsigned)Bindings.size() - << (unsigned)TupleSize.getLimitedValue(UINT_MAX) - << toString(TupleSize, 10) << (TupleSize < Bindings.size()); + auto *DD = cast<DecompositionDecl>(Src); + unsigned NumElems = (unsigned)TupleSize.getLimitedValue(UINT_MAX); + if (CheckBindingsCount(S, DD, DecompType, Bindings, NumElems)) return true; - } if (Bindings.empty()) return false; @@ -1250,7 +1303,7 @@ static bool checkTupleLikeDecomposition(Sema &S, } unsigned I = 0; - for (auto *B : Bindings) { + for (auto *B : DD->flat_bindings()) { InitializingBinding InitContext(S, B); SourceLocation Loc = B->getLocation(); @@ -1433,20 +1486,18 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings, QualType BaseType = S.Context.getQualifiedType(S.Context.getRecordType(RD), DecompType.getQualifiers()); - auto DiagnoseBadNumberOfBindings = [&]() -> bool { - unsigned NumFields = llvm::count_if( - RD->fields(), [](FieldDecl *FD) { return !FD->isUnnamedBitField(); }); - assert(Bindings.size() != NumFields); - S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) - << DecompType << (unsigned)Bindings.size() << NumFields << NumFields - << (NumFields < Bindings.size()); + auto *DD = cast<DecompositionDecl>(Src); + unsigned NumFields = llvm::count_if( + RD->fields(), [](FieldDecl *FD) { return !FD->isUnnamedBitField(); }); + if (CheckBindingsCount(S, DD, DecompType, Bindings, NumFields)) return true; - }; // all of E's non-static data members shall be [...] well-formed // when named as e.name in the context of the structured binding, // E shall not have an anonymous union member, ... - unsigned I = 0; + auto FlatBindings = DD->flat_bindings(); + assert(llvm::range_size(FlatBindings) == NumFields); + auto FlatBindingsItr = FlatBindings.begin(); for (auto *FD : RD->fields()) { if (FD->isUnnamedBitField()) continue; @@ -1471,9 +1522,8 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings, } // We have a real field to bind. - if (I >= Bindings.size()) - return DiagnoseBadNumberOfBindings(); - auto *B = Bindings[I++]; + assert(FlatBindingsItr != FlatBindings.end()); + BindingDecl *B = *(FlatBindingsItr++); SourceLocation Loc = B->getLocation(); // The field must be accessible in the context of the structured binding. @@ -1511,9 +1561,6 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings, B->setBinding(S.BuildQualifiedType(FD->getType(), Loc, Q), E.get()); } - if (I != Bindings.size()) - return DiagnoseBadNumberOfBindings(); - return false; } @@ -1523,8 +1570,12 @@ void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD) { // If the type of the decomposition is dependent, then so is the type of // each binding. if (DecompType->isDependentType()) { - for (auto *B : DD->bindings()) - B->setType(Context.DependentTy); + // Note that all of the types are still Null or PackExpansionType. + for (auto *B : DD->bindings()) { + // Do not overwrite any pack type. + if (B->getType().isNull()) + B->setType(Context.DependentTy); + } return; } diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 470d0d7..7b08a06 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1068,7 +1068,7 @@ static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) { // If this is a decomposition declaration, bindings might throw. if (auto *DD = dyn_cast<DecompositionDecl>(VD)) - for (auto *B : DD->bindings()) + for (auto *B : DD->flat_bindings()) if (auto *HD = B->getHoldingVar()) CT = mergeCanThrow(CT, canVarDeclThrow(Self, HD)); @@ -1286,6 +1286,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::ConvertVectorExprClass: case Expr::VAArgExprClass: case Expr::CXXParenListInitExprClass: + case Expr::ResolvedUnexpandedPackExprClass: return canSubStmtsThrow(*this, S); case Expr::CompoundLiteralExprClass: diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 947651d..ec38674 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2716,8 +2716,10 @@ StmtResult Sema::BuildCXXForRangeStmt( // them in properly when we instantiate the loop. if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) { if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar)) - for (auto *Binding : DD->bindings()) - Binding->setType(Context.DependentTy); + for (auto *Binding : DD->bindings()) { + if (!Binding->isParameterPack()) + Binding->setType(Context.DependentTy); + } LoopVar->setType(SubstAutoTypeDependent(LoopVar->getType())); } } else if (!BeginDeclStmt.get()) { diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index b4fa23d..12e98a3 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1583,6 +1583,10 @@ namespace { /// pack. ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E); + // Transform a ResolvedUnexpandedPackExpr + ExprResult + TransformResolvedUnexpandedPackExpr(ResolvedUnexpandedPackExpr *E); + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL) { // Call the base version; it will forward to our overridden version below. @@ -1848,7 +1852,8 @@ bool TemplateInstantiator::AlreadyTransformed(QualType T) { if (T.isNull()) return true; - if (T->isInstantiationDependentType() || T->isVariablyModifiedType()) + if (T->isInstantiationDependentType() || T->isVariablyModifiedType() || + T->containsUnexpandedParameterPack()) return false; getSema().MarkDeclarationsReferencedInType(Loc, T); @@ -2473,6 +2478,15 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { if (PD->isParameterPack()) return TransformFunctionParmPackRefExpr(E, PD); + if (BindingDecl *BD = dyn_cast<BindingDecl>(D); BD && BD->isParameterPack()) { + BD = cast_or_null<BindingDecl>(TransformDecl(BD->getLocation(), BD)); + if (!BD) + return ExprError(); + if (auto *RP = + dyn_cast_if_present<ResolvedUnexpandedPackExpr>(BD->getBinding())) + return TransformResolvedUnexpandedPackExpr(RP); + } + return inherited::TransformDeclRefExpr(E); } @@ -2637,6 +2651,19 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, return Result; } +ExprResult TemplateInstantiator::TransformResolvedUnexpandedPackExpr( + ResolvedUnexpandedPackExpr *E) { + if (getSema().ArgumentPackSubstitutionIndex != -1) { + assert(static_cast<unsigned>(getSema().ArgumentPackSubstitutionIndex) < + E->getNumExprs() && + "ArgumentPackSubstitutionIndex is out of range"); + return TransformExpr( + E->getExpansion(getSema().ArgumentPackSubstitutionIndex)); + } + + return inherited::TransformResolvedUnexpandedPackExpr(E); +} + QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType( TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL, bool SuppressObjCLifetime) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index f540431..d530ed0 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1168,26 +1168,57 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { Decl *TemplateDeclInstantiator::VisitBindingDecl(BindingDecl *D) { auto *NewBD = BindingDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getIdentifier()); + D->getIdentifier(), D->getType()); NewBD->setReferenced(D->isReferenced()); SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewBD); + return NewBD; } Decl *TemplateDeclInstantiator::VisitDecompositionDecl(DecompositionDecl *D) { // Transform the bindings first. + // The transformed DD will have all of the concrete BindingDecls. SmallVector<BindingDecl*, 16> NewBindings; - for (auto *OldBD : D->bindings()) + ResolvedUnexpandedPackExpr *OldResolvedPack = nullptr; + for (auto *OldBD : D->bindings()) { + Expr *BindingExpr = OldBD->getBinding(); + if (auto *RP = + dyn_cast_if_present<ResolvedUnexpandedPackExpr>(BindingExpr)) { + assert(!OldResolvedPack && "no more than one pack is allowed"); + OldResolvedPack = RP; + } NewBindings.push_back(cast<BindingDecl>(VisitBindingDecl(OldBD))); + } ArrayRef<BindingDecl*> NewBindingArray = NewBindings; - auto *NewDD = cast_or_null<DecompositionDecl>( + auto *NewDD = cast_if_present<DecompositionDecl>( VisitVarDecl(D, /*InstantiatingVarTemplate=*/false, &NewBindingArray)); if (!NewDD || NewDD->isInvalidDecl()) for (auto *NewBD : NewBindings) NewBD->setInvalidDecl(); + if (OldResolvedPack) { + // Mark the holding vars (if any) in the pack as instantiated since + // they are created implicitly. + auto Bindings = NewDD->bindings(); + auto BPack = llvm::find_if( + Bindings, [](BindingDecl *D) -> bool { return D->isParameterPack(); }); + auto *NewResolvedPack = + cast<ResolvedUnexpandedPackExpr>((*BPack)->getBinding()); + auto OldExprs = OldResolvedPack->getExprs(); + auto NewExprs = NewResolvedPack->getExprs(); + assert(OldExprs.size() == NewExprs.size()); + for (unsigned I = 0; I < OldResolvedPack->getNumExprs(); I++) { + DeclRefExpr *OldDRE = cast<DeclRefExpr>(OldExprs[I]); + BindingDecl *OldNestedBD = cast<BindingDecl>(OldDRE->getDecl()); + DeclRefExpr *NewDRE = cast<DeclRefExpr>(NewExprs[I]); + BindingDecl *NewNestedBD = cast<BindingDecl>(NewDRE->getDecl()); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldNestedBD, + NewNestedBD); + } + } + return NewDD; } @@ -6240,8 +6271,16 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // declarations to their instantiations. if (CurrentInstantiationScope) { if (auto Found = CurrentInstantiationScope->findInstantiationOf(D)) { - if (Decl *FD = Found->dyn_cast<Decl *>()) + if (Decl *FD = Found->dyn_cast<Decl *>()) { + if (auto *BD = dyn_cast<BindingDecl>(FD); + BD && BD->isParameterPack() && + ArgumentPackSubstitutionIndex != -1) { + auto *DRE = cast<DeclRefExpr>( + BD->getBindingPackExprs()[ArgumentPackSubstitutionIndex]); + return cast<NamedDecl>(DRE->getDecl()); + } return cast<NamedDecl>(FD); + } int PackIdx = ArgumentPackSubstitutionIndex; assert(PackIdx != -1 && diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index c8452db..3c56794 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -50,17 +50,29 @@ class CollectUnexpandedParameterPacksVisitor auto *FTD = FD ? FD->getDescribedFunctionTemplate() : nullptr; if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit) return; - } else if (getDepthAndIndex(ND).first >= DepthLimit) + } else if (auto *BD = dyn_cast<BindingDecl>(ND)) { + Expr *E = BD->getBinding(); + if (auto *RP = cast_if_present<ResolvedUnexpandedPackExpr>(E)) { + addUnexpanded(RP); + return; + } + } else if (getDepthAndIndex(ND).first >= DepthLimit) { return; + } Unexpanded.push_back({ND, Loc}); } + void addUnexpanded(const TemplateTypeParmType *T, SourceLocation Loc = SourceLocation()) { if (T->getDepth() < DepthLimit) Unexpanded.push_back({T, Loc}); } + void addUnexpanded(ResolvedUnexpandedPackExpr *E) { + Unexpanded.push_back({E, E->getBeginLoc()}); + } + public: explicit CollectUnexpandedParameterPacksVisitor( SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) @@ -103,6 +115,12 @@ class CollectUnexpandedParameterPacksVisitor return true; } + bool + VisitResolvedUnexpandedPackExpr(ResolvedUnexpandedPackExpr *E) override { + addUnexpanded(E); + return true; + } + /// Record occurrences of template template parameter packs. bool TraverseTemplateName(TemplateName Template) override { if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>( @@ -422,8 +440,8 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, if (const TemplateTypeParmType *TTP = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) Name = TTP->getIdentifier(); - else - Name = cast<NamedDecl *>(Unexpanded[I].first)->getIdentifier(); + else if (NamedDecl *ND = Unexpanded[I].first.dyn_cast<NamedDecl *>()) + Name = ND->getIdentifier(); if (Name && NamesKnown.insert(Name).second) Names.push_back(Name); @@ -757,23 +775,39 @@ bool Sema::CheckParameterPacksForExpansion( bool HaveFirstPack = false; std::optional<unsigned> NumPartialExpansions; SourceLocation PartiallySubstitutedPackLoc; + typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; for (UnexpandedParameterPack ParmPack : Unexpanded) { // Compute the depth and index for this parameter pack. unsigned Depth = 0, Index = 0; IdentifierInfo *Name; bool IsVarDeclPack = false; + ResolvedUnexpandedPackExpr *ResolvedPack = nullptr; if (const TemplateTypeParmType *TTP = ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) { Depth = TTP->getDepth(); Index = TTP->getIndex(); Name = TTP->getIdentifier(); + } else if (auto *RP = + ParmPack.first.dyn_cast<ResolvedUnexpandedPackExpr *>()) { + ResolvedPack = RP; } else { NamedDecl *ND = cast<NamedDecl *>(ParmPack.first); if (isa<VarDecl>(ND)) IsVarDeclPack = true; - else + else if (isa<BindingDecl>(ND)) { + // Find the instantiated BindingDecl and check it for a resolved pack. + llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation = + CurrentInstantiationScope->findInstantiationOf(ND); + Decl *B = cast<Decl *>(*Instantiation); + Expr *BindingExpr = cast<BindingDecl>(B)->getBinding(); + ResolvedPack = cast_if_present<ResolvedUnexpandedPackExpr>(BindingExpr); + if (!ResolvedPack) { + ShouldExpand = false; + continue; + } + } else std::tie(Depth, Index) = getDepthAndIndex(ND); Name = ND->getIdentifier(); @@ -783,8 +817,6 @@ bool Sema::CheckParameterPacksForExpansion( unsigned NewPackSize, PendingPackExpansionSize = 0; if (IsVarDeclPack) { // Figure out whether we're instantiating to an argument pack or not. - typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; - llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation = CurrentInstantiationScope->findInstantiationOf( cast<NamedDecl *>(ParmPack.first)); @@ -797,6 +829,8 @@ bool Sema::CheckParameterPacksForExpansion( ShouldExpand = false; continue; } + } else if (ResolvedPack) { + NewPackSize = ResolvedPack->getNumExprs(); } else { // If we don't have a template argument at this depth/index, then we // cannot expand the pack expansion. Make a note of this, but we still @@ -833,7 +867,7 @@ bool Sema::CheckParameterPacksForExpansion( // Template argument deduction can extend the sequence of template // arguments corresponding to a template parameter pack, even when the // sequence contains explicitly specified template arguments. - if (!IsVarDeclPack && CurrentInstantiationScope) { + if (!IsVarDeclPack && !ResolvedPack && CurrentInstantiationScope) { if (NamedDecl *PartialPack = CurrentInstantiationScope->getPartiallySubstitutedPack()) { unsigned PartialDepth, PartialIndex; @@ -939,6 +973,12 @@ std::optional<unsigned> Sema::getNumArgumentsInExpansionFromUnexpanded( Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) { Depth = TTP->getDepth(); Index = TTP->getIndex(); + } else if (auto *PE = Unexpanded[I] + .first.dyn_cast<ResolvedUnexpandedPackExpr *>()) { + unsigned Size = PE->getNumExprs(); + assert((!Result || *Result == Size) && "inconsistent pack sizes"); + Result = Size; + continue; } else { NamedDecl *ND = cast<NamedDecl *>(Unexpanded[I].first); if (isa<VarDecl>(ND)) { @@ -1167,8 +1207,12 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S, MarkAnyDeclReferenced(OpLoc, ParameterPack, true); + std::optional<unsigned> Length; + if (auto *RP = ResolvedUnexpandedPackExpr::getFromDecl(ParameterPack)) + Length = RP->getNumExprs(); + return SizeOfPackExpr::Create(Context, OpLoc, ParameterPack, NameLoc, - RParenLoc); + RParenLoc, Length); } static bool isParameterPack(Expr *PackExpression) { diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 2a5e354..808b564 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3680,6 +3680,13 @@ public: FullySubstituted); } + ExprResult RebuildResolvedUnexpandedPackExpr(SourceLocation BeginLoc, + QualType T, + ArrayRef<Expr *> Exprs) { + return ResolvedUnexpandedPackExpr::Create(SemaRef.Context, BeginLoc, T, + Exprs); + } + /// Build a new expression representing a call to a source location /// builtin. /// @@ -15427,12 +15434,11 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { // The transform has determined that we should perform an expansion; // transform and capture each of the arguments. // expansion of the pattern. Do so. - auto *Pack = cast<VarDecl>(C->getCapturedVar()); + auto *Pack = cast<ValueDecl>(C->getCapturedVar()); for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); - VarDecl *CapturedVar - = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(), - Pack)); + ValueDecl *CapturedVar = cast_if_present<ValueDecl>( + getDerived().TransformDecl(C->getLocation(), Pack)); if (!CapturedVar) { Invalid = true; continue; @@ -16127,6 +16133,24 @@ TreeTransform<Derived>::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) { return E; } +template <typename Derived> +ExprResult TreeTransform<Derived>::TransformResolvedUnexpandedPackExpr( + ResolvedUnexpandedPackExpr *E) { + bool ArgumentChanged = false; + SmallVector<Expr *, 12> NewExprs; + if (TransformExprs(E->getExprs().begin(), E->getNumExprs(), + /*IsCall=*/false, NewExprs, &ArgumentChanged)) + return ExprError(); + + if (!AlwaysRebuild() && !ArgumentChanged) + return E; + + // NOTE: The type is just a superficial PackExpansionType + // that needs no substitution. + return RebuildResolvedUnexpandedPackExpr(E->getBeginLoc(), E->getType(), + NewExprs); +} + template<typename Derived> ExprResult TreeTransform<Derived>::TransformMaterializeTemporaryExpr( |