[clang] Reapply "[Clang] Improve diagnostics for expansion length mismatch" (PR #121044)
Matheus Izvekov via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 21 06:38:07 PDT 2025
================
@@ -749,132 +759,124 @@ ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
PackExpansionExpr(Context.DependentTy, Pattern, EllipsisLoc, NumExpansions);
}
+static bool IsUnexpandedPackExpansion(const TemplateArgument &TA) {
+ if (!TA.isPackExpansion())
+ return false;
+
+ if (TA.getKind() == TemplateArgument::Type)
+ return !TA.getAsType()->getAs<PackExpansionType>()->getNumExpansions();
+
+ if (TA.getKind() == TemplateArgument::Expression)
+ return !cast<PackExpansionExpr>(TA.getAsExpr())->getNumExpansions();
+
+ return !TA.getNumTemplateExpansions();
+}
+
bool Sema::CheckParameterPacksForExpansion(
SourceLocation EllipsisLoc, SourceRange PatternRange,
ArrayRef<UnexpandedParameterPack> Unexpanded,
const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand,
bool &RetainExpansion, std::optional<unsigned> &NumExpansions) {
ShouldExpand = true;
RetainExpansion = false;
- std::pair<IdentifierInfo *, SourceLocation> FirstPack;
- bool HaveFirstPack = false;
- std::optional<unsigned> NumPartialExpansions;
- SourceLocation PartiallySubstitutedPackLoc;
- typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
+ std::pair<const IdentifierInfo *, SourceLocation> FirstPack;
+ std::optional<std::pair<unsigned, SourceLocation>> PartialExpansion;
+ std::optional<unsigned> CurNumExpansions, CurMaximumOfLeastExpansions;
- for (UnexpandedParameterPack ParmPack : Unexpanded) {
+ for (auto [P, Loc] : Unexpanded) {
// Compute the depth and index for this parameter pack.
- unsigned Depth = 0, Index = 0;
- IdentifierInfo *Name;
- bool IsVarDeclPack = false;
- FunctionParmPackExpr *BindingPack = nullptr;
-
- if (const TemplateTypeParmType *TTP =
- ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) {
- Depth = TTP->getDepth();
- Index = TTP->getIndex();
- Name = TTP->getIdentifier();
- } else {
- NamedDecl *ND = cast<NamedDecl *>(ParmPack.first);
- if (isa<VarDecl>(ND))
- IsVarDeclPack = true;
- else if (isa<BindingDecl>(ND)) {
+ std::optional<std::pair<unsigned, unsigned>> Pos;
+ unsigned NewPackSize, PendingPackExpansionSize = 0;
+ const auto *ND = dyn_cast_if_present<const NamedDecl *>(P);
+ if (ND) {
+ if (isa<VarDecl>(ND)) {
+ auto *DAP = dyn_cast<LocalInstantiationScope::DeclArgumentPack *>(
+ *CurrentInstantiationScope->findInstantiationOf(ND));
+ if (!DAP) {
+ // We can't expand this function parameter pack, so we can't expand
+ // the pack expansion.
+ ShouldExpand = false;
+ continue;
+ }
+ NewPackSize = DAP->size();
+ } else if (isa<BindingDecl>(ND)) {
// Find the instantiated BindingDecl and check it for a resolved pack.
- llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation =
- CurrentInstantiationScope->findInstantiationOf(ND);
+ llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *>
+ *Instantiation = CurrentInstantiationScope->findInstantiationOf(ND);
Decl *B = cast<Decl *>(*Instantiation);
Expr *BindingExpr = cast<BindingDecl>(B)->getBinding();
- BindingPack = cast_if_present<FunctionParmPackExpr>(BindingExpr);
+ auto *BindingPack = cast_if_present<FunctionParmPackExpr>(BindingExpr);
if (!BindingPack) {
ShouldExpand = false;
continue;
}
+ NewPackSize = BindingPack->getNumExpansions();
} else
- std::tie(Depth, Index) = getDepthAndIndex(ND);
-
- Name = ND->getIdentifier();
+ Pos = getDepthAndIndex(ND);
+ } else if (const auto *TTP = dyn_cast<const TemplateTypeParmType *>(P)) {
+ Pos = {TTP->getDepth(), TTP->getIndex()};
+ ND = TTP->getDecl();
+ // FIXME: We either should have some fallback for canonical TTP, or
+ // never have canonical TTP here.
+ } else if (const auto *STP =
+ dyn_cast<const SubstTemplateTypeParmPackType *>(P)) {
+ NewPackSize = STP->getNumArgs();
+ PendingPackExpansionSize = llvm::count_if(
+ STP->getArgumentPack().getPackAsArray(), IsUnexpandedPackExpansion);
+ ND = STP->getReplacedParameter();
+ } else {
+ const auto *SEP = cast<const SubstNonTypeTemplateParmPackExpr *>(P);
+ NewPackSize = SEP->getArgumentPack().pack_size();
+ PendingPackExpansionSize = llvm::count_if(
+ SEP->getArgumentPack().getPackAsArray(), IsUnexpandedPackExpansion);
+ ND = SEP->getParameterPack();
}
- // Determine the size of this argument pack.
- unsigned NewPackSize, PendingPackExpansionSize = 0;
- if (IsVarDeclPack) {
- // Figure out whether we're instantiating to an argument pack or not.
- llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation =
- CurrentInstantiationScope->findInstantiationOf(
- cast<NamedDecl *>(ParmPack.first));
- if (isa<DeclArgumentPack *>(*Instantiation)) {
- // We could expand this function parameter pack.
- NewPackSize = cast<DeclArgumentPack *>(*Instantiation)->size();
- } else {
- // We can't expand this function parameter pack, so we can't expand
- // the pack expansion.
- ShouldExpand = false;
- continue;
- }
- } else if (BindingPack) {
- NewPackSize = BindingPack->getNumExpansions();
- } else {
+ if (Pos) {
// 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
// want to check any parameter packs we *do* have arguments for.
- if (Depth >= TemplateArgs.getNumLevels() ||
- !TemplateArgs.hasTemplateArgument(Depth, Index)) {
+ if (Pos->first >= TemplateArgs.getNumLevels() ||
+ !TemplateArgs.hasTemplateArgument(Pos->first, Pos->second)) {
ShouldExpand = false;
continue;
}
-
// Determine the size of the argument pack.
ArrayRef<TemplateArgument> Pack =
- TemplateArgs(Depth, Index).getPackAsArray();
+ TemplateArgs(Pos->first, Pos->second).getPackAsArray();
NewPackSize = Pack.size();
PendingPackExpansionSize =
- llvm::count_if(Pack, [](const TemplateArgument &TA) {
- if (!TA.isPackExpansion())
- return false;
-
- if (TA.getKind() == TemplateArgument::Type)
- return !TA.getAsType()
- ->castAs<PackExpansionType>()
- ->getNumExpansions();
-
- if (TA.getKind() == TemplateArgument::Expression)
- return !cast<PackExpansionExpr>(TA.getAsExpr())
- ->getNumExpansions();
-
- return !TA.getNumTemplateExpansions();
- });
- }
-
- // C++0x [temp.arg.explicit]p9:
- // 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 (NamedDecl *PartialPack =
- CurrentInstantiationScope->getPartiallySubstitutedPack()) {
- unsigned PartialDepth, PartialIndex;
- std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack);
- if (PartialDepth == Depth && PartialIndex == Index) {
+ llvm::count_if(Pack, IsUnexpandedPackExpansion);
+ // C++0x [temp.arg.explicit]p9:
+ // 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 (CurrentInstantiationScope)
+ if (const NamedDecl *PartialPack =
+ CurrentInstantiationScope->getPartiallySubstitutedPack();
+ PartialPack && getDepthAndIndex(PartialPack) == *Pos) {
RetainExpansion = true;
// We don't actually know the new pack size yet.
- NumPartialExpansions = NewPackSize;
- PartiallySubstitutedPackLoc = ParmPack.second;
+ PartialExpansion = {NewPackSize, Loc};
continue;
}
- }
}
- if (!NumExpansions) {
+ unsigned LeastNewPackSize = NewPackSize - PendingPackExpansionSize;
+ if (PendingPackExpansionSize)
+ CurMaximumOfLeastExpansions =
+ CurMaximumOfLeastExpansions
+ ? std::max(LeastNewPackSize, *CurMaximumOfLeastExpansions)
+ : LeastNewPackSize;
+
+ // FIXME: Workaround for Canonical TTP.
----------------
mizvekov wrote:
FWIW we also print anonymous TTP as `type-parameter-*-*`, even though they are not canonical and you do have source location for them.
That's why storing only the name is a bad idea, ideally we should point the diagnostic to the source location, and only print index+depth when it's truly canonical.
https://github.com/llvm/llvm-project/pull/121044
More information about the cfe-commits
mailing list