aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Sema
diff options
context:
space:
mode:
authorJason Rice <ricejasonf@gmail.com>2025-01-29 12:43:52 -0800
committerGitHub <noreply@github.com>2025-01-29 21:43:52 +0100
commitabc8812df02599fc413d9ed77b992f8236ed2af9 (patch)
treed5fc8a01c03d5700aed337d8b8516fa3d461a326 /clang/lib/Sema
parent608012ace43b42d97884204016c6a8f4883b4359 (diff)
downloadllvm-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.cpp117
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp3
-rw-r--r--clang/lib/Sema/SemaStmt.cpp6
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp29
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp47
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp60
-rw-r--r--clang/lib/Sema/TreeTransform.h32
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(