https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/121044
... and "[Clang] fix missing initialization of original number of expansions" This reverts commit acecf68c8b7c3c625cfa00f00f8ddc8f15baae44. >From aa008450981a80a2d26e687df33f10038aa50a9c Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Tue, 24 Dec 2024 13:06:44 +0800 Subject: [PATCH] Reapply "[Clang] Improve diagnostics for expansion length mismatch" ... and "[Clang] fix missing initialization of original number of expansions" This reverts commit acecf68c8b7c3c625cfa00f00f8ddc8f15baae44. Co-authored-by: Matheus Izvekov <mizve...@gmail.com> --- clang/include/clang/Sema/Sema.h | 8 +- clang/include/clang/Sema/SemaInternal.h | 4 +- clang/lib/AST/ExprCXX.cpp | 2 +- clang/lib/Sema/SemaDeclCXX.cpp | 2 +- clang/lib/Sema/SemaTemplateDeduction.cpp | 7 +- clang/lib/Sema/SemaTemplateVariadic.cpp | 318 +++++++++--------- clang/lib/Sema/TreeTransform.h | 1 + .../CXX/temp/temp.decls/temp.variadic/p5.cpp | 50 +++ .../SemaTemplate/cxx1z-fold-expressions.cpp | 2 +- clang/test/SemaTemplate/pack-deduction.cpp | 51 ++- 10 files changed, 275 insertions(+), 170 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5ee7ea48cc983c..4a726ef809551e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -230,9 +230,11 @@ void threadSafetyCleanup(BeforeSet *Cache); // FIXME: No way to easily map from TemplateTypeParmTypes to // TemplateTypeParmDecls, so we have this horrible PointerUnion. -typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *>, - SourceLocation> - UnexpandedParameterPack; +using UnexpandedParameterPack = std::pair< + llvm::PointerUnion< + const TemplateTypeParmType *, const SubstTemplateTypeParmPackType *, + const SubstNonTypeTemplateParmPackExpr *, const NamedDecl *>, + SourceLocation>; /// Describes whether we've seen any nullability information for the given /// file. diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h index 27cda71989726d..acf6c8146d70d4 100644 --- a/clang/include/clang/Sema/SemaInternal.h +++ b/clang/include/clang/Sema/SemaInternal.h @@ -72,10 +72,10 @@ inline std::pair<unsigned, unsigned> getDepthAndIndex(const NamedDecl *ND) { /// Retrieve the depth and index of an unexpanded parameter pack. inline std::pair<unsigned, unsigned> getDepthAndIndex(UnexpandedParameterPack UPP) { - if (const auto *TTP = UPP.first.dyn_cast<const TemplateTypeParmType *>()) + if (const auto *TTP = dyn_cast<const TemplateTypeParmType *>(UPP.first)) return std::make_pair(TTP->getDepth(), TTP->getIndex()); - return getDepthAndIndex(cast<NamedDecl *>(UPP.first)); + return getDepthAndIndex(cast<const NamedDecl *>(UPP.first)); } class TypoCorrectionConsumer : public VisibleDeclConsumer { diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index fc09d24fc30cb4..715b819bfb96bb 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1734,7 +1734,7 @@ PackIndexingExpr *PackIndexingExpr::Create( NamedDecl *PackIndexingExpr::getPackDecl() const { if (auto *D = dyn_cast<DeclRefExpr>(getPackIdExpression()); D) { NamedDecl *ND = dyn_cast<NamedDecl>(D->getDecl()); - assert(ND && "exected a named decl"); + assert(ND && "expected a named decl"); return ND; } assert(false && "invalid declaration kind in pack indexing expression"); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index c5a72cf812ebc9..bf5f31c3a5ca4c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -17496,7 +17496,7 @@ DeclResult Sema::ActOnTemplatedFriendTag( unsigned FriendDeclDepth = TempParamLists.front()->getDepth(); for (UnexpandedParameterPack &U : Unexpanded) { if (getDepthAndIndex(U).first >= FriendDeclDepth) { - auto *ND = U.first.dyn_cast<NamedDecl *>(); + auto *ND = dyn_cast<const NamedDecl *>(U.first); if (!ND) ND = cast<const TemplateTypeParmType *>(U.first)->getDecl(); Diag(U.second, diag::friend_template_decl_malformed_pack_expansion) diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index fad20b37a7d9a2..1b541aa665a71a 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -868,8 +868,11 @@ class PackDeductionScope { SmallVector<UnexpandedParameterPack, 2> Unexpanded; S.collectUnexpandedParameterPacks(Pattern, Unexpanded); for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { - unsigned Depth, Index; - std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); + UnexpandedParameterPack U = Unexpanded[I]; + if (isa<const SubstTemplateTypeParmPackType *, + const SubstNonTypeTemplateParmPackExpr *>(U.first)) + continue; + auto [Depth, Index] = getDepthAndIndex(U); if (Depth == Info.getDeducedDepth()) AddPack(Index); } diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index c8452db6bc9014..b9e52080d62a96 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -38,7 +38,7 @@ class CollectUnexpandedParameterPacksVisitor unsigned DepthLimit = (unsigned)-1; #ifndef NDEBUG - bool ContainsIntermediatePacks = false; + bool ContainsIntermediatePacks = false; #endif void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) { @@ -94,6 +94,33 @@ class CollectUnexpandedParameterPacksVisitor return true; } + bool VisitSubstTemplateTypeParmPackTypeLoc( + SubstTemplateTypeParmPackTypeLoc TL) override { + Unexpanded.push_back({TL.getTypePtr(), TL.getNameLoc()}); +#ifdef NDEBUG + ContainsIntermediatePacks = true; +#endif + return true; + } + + bool VisitSubstTemplateTypeParmPackType( + SubstTemplateTypeParmPackType *T) override { + Unexpanded.push_back({T, SourceLocation()}); +#ifdef NDEBUG + ContainsIntermediatePacks = true; +#endif + return true; + } + + bool VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *E) override { + Unexpanded.push_back({E, E->getParameterPackLocation()}); +#ifdef NDEBUG + ContainsIntermediatePacks = true; +#endif + return true; + } + /// Record occurrences of function and non-type template /// parameter packs in an expression. bool VisitDeclRefExpr(DeclRefExpr *E) override { @@ -312,24 +339,6 @@ class CollectUnexpandedParameterPacksVisitor return true; } - bool TraverseSubstNonTypeTemplateParmPackExpr( - SubstNonTypeTemplateParmPackExpr *) override { - ContainsIntermediatePacks = true; - return true; - } - - bool VisitSubstTemplateTypeParmPackType( - SubstTemplateTypeParmPackType *) override { - ContainsIntermediatePacks = true; - return true; - } - - bool VisitSubstTemplateTypeParmPackTypeLoc( - SubstTemplateTypeParmPackTypeLoc) override { - ContainsIntermediatePacks = true; - return true; - } - bool containsIntermediatePacks() const { return ContainsIntermediatePacks; } #endif }; @@ -371,7 +380,8 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, auto *TTPD = dyn_cast<TemplateTypeParmDecl>(LocalPack); return TTPD && TTPD->getTypeForDecl() == TTPT; } - return declaresSameEntity(cast<NamedDecl *>(Pack.first), LocalPack); + return declaresSameEntity(cast<const NamedDecl *>(Pack.first), + LocalPack); }; if (llvm::any_of(CSI->LocalPacks, DeclaresThisPack)) ParamPackReferences.push_back(Pack); @@ -423,7 +433,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) Name = TTP->getIdentifier(); else - Name = cast<NamedDecl *>(Unexpanded[I].first)->getIdentifier(); + Name = cast<const NamedDecl *>(Unexpanded[I].first)->getIdentifier(); if (Name && NamesKnown.insert(Name).second) Names.push_back(Name); @@ -497,7 +507,7 @@ bool Sema::DiagnoseUnexpandedParameterPackInRequiresExpr(RequiresExpr *RE) { llvm::SmallPtrSet<NamedDecl*, 8> ParmSet(Parms.begin(), Parms.end()); SmallVector<UnexpandedParameterPack, 2> UnexpandedParms; for (auto Parm : Unexpanded) - if (ParmSet.contains(Parm.first.dyn_cast<NamedDecl *>())) + if (ParmSet.contains(dyn_cast<const NamedDecl *>(Parm.first))) UnexpandedParms.push_back(Parm); if (UnexpandedParms.empty()) return false; @@ -746,6 +756,19 @@ 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, @@ -753,112 +776,91 @@ bool Sema::CheckParameterPacksForExpansion( bool &RetainExpansion, std::optional<unsigned> &NumExpansions) { ShouldExpand = true; RetainExpansion = false; - std::pair<IdentifierInfo *, SourceLocation> FirstPack; - bool HaveFirstPack = false; - std::optional<unsigned> NumPartialExpansions; - SourceLocation PartiallySubstitutedPackLoc; + 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; - - 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 - std::tie(Depth, Index) = getDepthAndIndex(ND); - - Name = ND->getIdentifier(); - } - - // Determine the size of this argument pack. + std::optional<std::pair<unsigned, unsigned>> Pos; 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)); - if (isa<DeclArgumentPack *>(*Instantiation)) { - // We could expand this function parameter pack. - NewPackSize = cast<DeclArgumentPack *>(*Instantiation)->size(); - } else { + const auto *ND = dyn_cast_if_present<const NamedDecl *>(P); + if (isa_and_present<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 (ND) { + 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(); + } + + 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() - ->getAs<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. + const IdentifierInfo *Name = ND ? ND->getIdentifier() : nullptr; + if (!CurNumExpansions) { // This is the first pack we've seen for which we have an argument. // Record it. - NumExpansions = NewPackSize; - FirstPack.first = Name; - FirstPack.second = ParmPack.second; - HaveFirstPack = true; - continue; - } - - if (NewPackSize != *NumExpansions) { + CurNumExpansions = NewPackSize; + FirstPack = {Name, Loc}; + } else if (NewPackSize != *CurNumExpansions) { // In some cases, we might be handling packs with unexpanded template // arguments. For example, this can occur when substituting into a type // alias declaration that uses its injected template parameters as @@ -872,31 +874,40 @@ bool Sema::CheckParameterPacksForExpansion( // Pack comes from another template parameter. 'S<int>' is first // instantiated, expanding the outer pack 'Outer' to <int>. The alias // declaration is accordingly substituted, leaving the template arguments - // as unexpanded - // '<Pack...>'. + // as unexpanded '<Pack...>'. // // Since we have no idea of the size of '<Pack...>' until its expansion, // we shouldn't assume its pack size for validation. However if we are // certain that there are extra arguments beyond unexpanded packs, in // which case the pack size is already larger than the previous expansion, // we can complain that before instantiation. - unsigned LeastNewPackSize = NewPackSize - PendingPackExpansionSize; - if (PendingPackExpansionSize && LeastNewPackSize <= *NumExpansions) { + if (PendingPackExpansionSize && LeastNewPackSize <= *CurNumExpansions) { ShouldExpand = false; continue; } // C++0x [temp.variadic]p5: // All of the parameter packs expanded by a pack expansion shall have // the same number of arguments specified. - if (HaveFirstPack) - Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) - << FirstPack.first << Name << *NumExpansions - << (LeastNewPackSize != NewPackSize) << LeastNewPackSize - << SourceRange(FirstPack.second) << SourceRange(ParmPack.second); - else - Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel) - << Name << *NumExpansions << (LeastNewPackSize != NewPackSize) - << LeastNewPackSize << SourceRange(ParmPack.second); + Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) + << FirstPack.first << Name << *CurNumExpansions + << (LeastNewPackSize != NewPackSize) << LeastNewPackSize + << SourceRange(FirstPack.second) << SourceRange(Loc); + return true; + } + } + + if (NumExpansions && CurNumExpansions && + *NumExpansions != *CurNumExpansions) { + if (CurMaximumOfLeastExpansions && + *CurMaximumOfLeastExpansions <= *NumExpansions) { + ShouldExpand = false; + } else { + Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel) + << FirstPack.first << *NumExpansions + << bool(CurMaximumOfLeastExpansions) + << (CurMaximumOfLeastExpansions ? *CurMaximumOfLeastExpansions + : *CurNumExpansions) + << SourceRange(FirstPack.second); return true; } } @@ -910,17 +921,18 @@ bool Sema::CheckParameterPacksForExpansion( // // ... a call to 'A<int, int>().f<int>' should expand the pack once and // retain an expansion. - if (NumPartialExpansions) { - if (NumExpansions && *NumExpansions < *NumPartialExpansions) { + if (PartialExpansion) { + if (CurNumExpansions && *CurNumExpansions < PartialExpansion->first) { NamedDecl *PartialPack = CurrentInstantiationScope->getPartiallySubstitutedPack(); Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial) - << PartialPack << *NumPartialExpansions << *NumExpansions - << SourceRange(PartiallySubstitutedPackLoc); + << PartialPack << PartialExpansion->first << *CurNumExpansions + << SourceRange(PartialExpansion->second); return true; } - - NumExpansions = NumPartialExpansions; + NumExpansions = PartialExpansion->first; + } else { + NumExpansions = CurNumExpansions; } return false; @@ -930,47 +942,47 @@ std::optional<unsigned> Sema::getNumArgumentsInExpansionFromUnexpanded( llvm::ArrayRef<UnexpandedParameterPack> Unexpanded, const MultiLevelTemplateArgumentList &TemplateArgs) { std::optional<unsigned> Result; - for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { - // Compute the depth and index for this parameter pack. - unsigned Depth; - unsigned Index; + auto SetResultSize = [&Result](unsigned Size) { + assert((!Result || *Result == Size) && "inconsistent pack sizes"); + Result = Size; + }; + auto SetResultPos = [&](const std::pair<unsigned, unsigned> &Pos) -> bool { + unsigned Depth = Pos.first, Index = Pos.second; + if (Depth >= TemplateArgs.getNumLevels() || + !TemplateArgs.hasTemplateArgument(Depth, Index)) + // The pattern refers to an unknown template argument. We're not ready to + // expand this pack yet. + return true; + // Determine the size of the argument pack. + SetResultSize(TemplateArgs(Depth, Index).pack_size()); + return false; + }; - if (const TemplateTypeParmType *TTP = - Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) { - Depth = TTP->getDepth(); - Index = TTP->getIndex(); + for (auto [I, _] : Unexpanded) { + if (const auto *TTP = I.dyn_cast<const TemplateTypeParmType *>()) { + if (SetResultPos({TTP->getDepth(), TTP->getIndex()})) + return std::nullopt; + } else if (const auto *STP = + I.dyn_cast<const SubstTemplateTypeParmPackType *>()) { + SetResultSize(STP->getNumArgs()); + } else if (const auto *SEP = + I.dyn_cast<const SubstNonTypeTemplateParmPackExpr *>()) { + SetResultSize(SEP->getArgumentPack().pack_size()); } else { - NamedDecl *ND = cast<NamedDecl *>(Unexpanded[I].first); + const auto *ND = cast<const NamedDecl *>(I); + // Function parameter pack or init-capture pack. if (isa<VarDecl>(ND)) { - // Function parameter pack or init-capture pack. - typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; - - llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation = - CurrentInstantiationScope->findInstantiationOf( - cast<NamedDecl *>(Unexpanded[I].first)); - if (isa<Decl *>(*Instantiation)) + const auto *DAP = dyn_cast<LocalInstantiationScope::DeclArgumentPack *>( + *CurrentInstantiationScope->findInstantiationOf(ND)); + if (!DAP) // The pattern refers to an unexpanded pack. We're not ready to expand // this pack yet. return std::nullopt; - - unsigned Size = cast<DeclArgumentPack *>(*Instantiation)->size(); - assert((!Result || *Result == Size) && "inconsistent pack sizes"); - Result = Size; - continue; + SetResultSize(DAP->size()); + } else if (SetResultPos(getDepthAndIndex(ND))) { + return std::nullopt; } - - std::tie(Depth, Index) = getDepthAndIndex(ND); } - if (Depth >= TemplateArgs.getNumLevels() || - !TemplateArgs.hasTemplateArgument(Depth, Index)) - // The pattern refers to an unknown template argument. We're not ready to - // expand this pack yet. - return std::nullopt; - - // Determine the size of the argument pack. - unsigned Size = TemplateArgs(Depth, Index).pack_size(); - assert((!Result || *Result == Size) && "inconsistent pack sizes"); - Result = Size; } return Result; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 5d43d98ce49e46..e5786526e55fb1 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -6224,6 +6224,7 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams( = dyn_cast<PackExpansionType>(OldType)) { // We have a function parameter pack that may need to be expanded. QualType Pattern = Expansion->getPattern(); + NumExpansions = Expansion->getNumExpansions(); SmallVector<UnexpandedParameterPack, 2> Unexpanded; getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp index 16e668e971a214..dc254e0e3e11a1 100644 --- a/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp @@ -517,6 +517,56 @@ int fn() { } } +namespace GH56094 { +template <typename... T> struct D { + template <typename... U> using B = int(int (*...p)(T, U)); + // expected-error@-1 {{pack expansion contains parameter packs 'T' and 'U' that have different lengths (1 vs. 2)}} + template <typename U1, typename U2> D(B<U1, U2> *); + // expected-note@-1 {{in instantiation of template type alias 'B' requested here}} +}; +using t1 = D<float>::B<int>; +// expected-note@-1 {{in instantiation of template class 'GH56094::D<float>' requested here}} + +template <bool...> struct F {}; +template <class...> struct G {}; +template <bool... I> struct E { + template <bool... U> using B = G<F<I, U>...>; + // expected-error@-1 {{pack expansion contains parameter packs 'I' and 'U' that have different lengths (1 vs. 2)}} + template <bool U1, bool U2> E(B<U1, U2> *); + // expected-note@-1 {{in instantiation of template type alias 'B' requested here}} +}; +using t2 = E<true>::B<false>; +// expected-note@-1 {{in instantiation of template class 'GH56094::E<true>' requested here}} +} // namespace GH56094 + +namespace GH56094 { +#if __cplusplus >= 201402L +template <class> struct A; // expected-note {{template is declared here}} +template <class> using B = char; +template <class ...Cs> int C{ A<B<Cs>>{}... }; // expected-error {{implicit instantiation of undefined template}} +#endif +} // namespace GH56094 + +namespace GH58679 { +#if __cplusplus >= 201402L +template <class> constexpr int A = 1; + +template <int> struct B; +template <> struct B<1> { using b1 = void; }; + +template <class> using C = char; + +template <class... Ds> int D{ B<A<C<Ds>>>{}... }; + +struct E { + template <class E1, class = typename B<A<E1>>::b1> E(E1); +}; + +template <typename... Es> int F{ E(C<Es>{})... }; +#endif +} // namespace GH58679 + + namespace GH58452 { template <typename... As> struct A { template <typename... Bs> using B = void(As...(Bs)); diff --git a/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp b/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp index 47a252eb335f6e..e357a73e855fa1 100644 --- a/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp +++ b/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp @@ -97,7 +97,7 @@ namespace PR41845 { template <int I> struct Constant {}; template <int... Is> struct Sum { - template <int... Js> using type = Constant<((Is + Js) + ... + 0)>; // expected-error {{pack expansion contains parameter pack 'Js' that has a different length (1 vs. 2) from outer parameter packs}} + template <int... Js> using type = Constant<((Is + Js) + ... + 0)>; // expected-error {{pack expansion contains parameter packs 'Is' and 'Js' that have different lengths (1 vs. 2)}} }; Sum<1>::type<1, 2> x; // expected-note {{instantiation of}} diff --git a/clang/test/SemaTemplate/pack-deduction.cpp b/clang/test/SemaTemplate/pack-deduction.cpp index b3104609994a4e..c96ea74c9aebc8 100644 --- a/clang/test/SemaTemplate/pack-deduction.cpp +++ b/clang/test/SemaTemplate/pack-deduction.cpp @@ -134,14 +134,14 @@ namespace partial_full_mix { template<typename ...T> struct tuple {}; template<typename ...T> struct A { template<typename ...U> static pair<tuple<T...>, tuple<U...>> f(pair<T, U> ...p); - // expected-note@-1 {{[with U = <char, double, long>]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 3) from outer parameter packs}} + // expected-note@-1 {{[with U = <char, double, long>]: pack expansion contains parameter packs 'T' and 'U' that have different lengths (2 vs. 3)}} // expected-note@-2 {{[with U = <char, double, void>]: pack expansion contains parameter pack 'U' that has a different length (at least 3 vs. 2) from outer parameter packs}} template<typename ...U> static pair<tuple<T...>, tuple<U...>> g(pair<T, U> ...p, ...); - // expected-note@-1 {{[with U = <char, double, long>]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 3) from outer parameter packs}} + // expected-note@-1 {{[with U = <char, double, long>]: pack expansion contains parameter packs 'T' and 'U' that have different lengths (2 vs. 3)}} template<typename ...U> static tuple<U...> h(tuple<pair<T, U>..., pair<int, int>>); - // expected-note@-1 {{[with U = <int[2]>]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 1) from outer parameter packs}} + // expected-note@-1 {{[with U = <int[2]>]: pack expansion contains parameter packs 'T' and 'U' that have different lengths (2 vs. 1)}} }; pair<tuple<int, float>, tuple<char, double>> k1 = A<int, float>().f<char>(pair<int, char>(), pair<float, double>()); @@ -211,7 +211,7 @@ using any_pairs_list = X<int, int>::Y<T...>; // #any_pairs_list template <class... T> using any_pairs_list_2 = X<int, int>::Y<>; -// expected-error@#GH17042_Y {{different length (2 vs. 0)}} \ +// expected-error@#GH17042_Y {{different lengths (2 vs. 0)}} \ // expected-note@-1 {{requested here}} template <class A, class B, class... P> @@ -219,20 +219,20 @@ using any_pairs_list_3 = X<int, int>::Y<A, B, P...>; // #any_pairs_list_3 template <class A, class B, class C, class... P> using any_pairs_list_4 = X<int, int>::Y<A, B, C, P...>; -// expected-error@#GH17042_Y {{different length (2 vs. at least 3)}} \ +// expected-error@#GH17042_Y {{different lengths (2 vs. at least 3)}} \ // expected-note@-1 {{requested here}} static_assert(__is_same(any_pairs_list<char, char>, X<void(int, char), void(int, char)>), ""); static_assert(!__is_same(any_pairs_list<char, char, char>, X<void(int, char), void(int, char)>), ""); -// expected-error@#GH17042_Y {{different length (2 vs. 3)}} \ +// expected-error@#GH17042_Y {{different lengths (2 vs. 3)}} \ // expected-note@#any_pairs_list {{requested here}} \ // expected-note@-1 {{requested here}} static_assert(__is_same(any_pairs_list_3<char, char>, X<void(int, char), void(int, char)>), ""); static_assert(!__is_same(any_pairs_list_3<char, char, float>, X<void(int, char), void(int, char)>), ""); -// expected-error@#GH17042_Y {{different length (2 vs. 3)}} \ +// expected-error@#GH17042_Y {{different lengths (2 vs. 3)}} \ // expected-note@#any_pairs_list_3 {{requested here}} \ // expected-note@-1 {{requested here}} @@ -257,4 +257,41 @@ template <int... Args1> struct Nttp { template <int... Args> using Alias = Nttp<1, 2, 3>::B<Args...>; } +// This test case comes from https://bugs.llvm.org/show_bug.cgi?id=16668 +namespace PR16668 { + template<int, typename> struct P {}; + + template<int ...A> struct S { + template<int ...B> using sum = S<A + B ...>; // expected-error {{different lengths (3 vs. 4)}} + + template<typename ...Ts> void f(P<A, Ts> ...); + +#if 0 + // FIXME: Substituting into Fn resulted in rejects-valid. + template<typename ...Ts> using Fn = void(S::*)(P<A, Ts>...); + template<typename ...Ts> void g(Fn<Ts...>); +#endif + }; + + template<int ...C> using X = S<1, 2, 3>::sum<4, C ...>; // expected-note {{here}} + + using Y = X<5, 6>; + using Y = S<5, 7, 9>; + + using Z = X<5, 6, 7>; // expected-note {{here}} + + void g() { + P<0, int> p0; + P<1, char> p1; + P<2, double> p2; + using S = S<0, 1, 2>; + S s; + s.f(p0, p1, p2); +#if 0 + s.g(&S::f<int, char, double>); + s.g<int, char, double>(&S::f); +#endif + } +} + } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits