diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -238,8 +238,11 @@ // FIXME: No way to easily map from TemplateTypeParmTypes to // TemplateTypeParmDecls, so we have this horrible PointerUnion. -typedef std::pair, - 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 --- a/clang/include/clang/Sema/SemaInternal.h +++ b/clang/include/clang/Sema/SemaInternal.h @@ -62,7 +62,7 @@ } /// Retrieve the depth and index of a template parameter. -inline std::pair getDepthAndIndex(NamedDecl *ND) { +inline std::pair getDepthAndIndex(const NamedDecl *ND) { if (const auto *TTP = dyn_cast(ND)) return std::make_pair(TTP->getDepth(), TTP->getIndex()); @@ -79,7 +79,7 @@ if (const auto *TTP = UPP.first.dyn_cast()) return std::make_pair(TTP->getDepth(), TTP->getIndex()); - return getDepthAndIndex(UPP.first.get()); + return getDepthAndIndex(UPP.first.get()); } class TypoCorrectionConsumer : public VisibleDeclConsumer { diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -744,8 +744,12 @@ SmallVector Unexpanded; S.collectUnexpandedParameterPacks(Pattern, Unexpanded); for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { + UnexpandedParameterPack U = Unexpanded[I]; + if (U.first.is() || + U.first.is()) + continue; unsigned Depth, Index; - std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); + std::tie(Depth, Index) = getDepthAndIndex(U); if (Depth == Info.getDeducedDepth()) AddPack(Index); } diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -88,6 +88,17 @@ return true; } + bool VisitSubstTemplateTypeParmPackType(SubstTemplateTypeParmPackType *T) { + Unexpanded.push_back({T, SourceLocation()}); + return true; + } + + bool + VisitSubstNonTypeTemplateParmPackExpr(SubstNonTypeTemplateParmPackExpr *E) { + Unexpanded.push_back({E, E->getParameterPackLocation()}); + return true; + } + /// Record occurrences of function and non-type template /// parameter packs in an expression. bool VisitDeclRefExpr(DeclRefExpr *E) { @@ -306,7 +317,8 @@ auto *TTPD = dyn_cast(LocalPack); return TTPD && TTPD->getTypeForDecl() == TTPT; } - return declaresSameEntity(Pack.first.get(), LocalPack); + return declaresSameEntity(Pack.first.get(), + LocalPack); }; if (llvm::any_of(LSI->LocalPacks, DeclaresThisPack)) LambdaParamPackReferences.push_back(Pack); @@ -358,7 +370,7 @@ = Unexpanded[I].first.dyn_cast()) Name = TTP->getIdentifier(); else - Name = Unexpanded[I].first.get()->getIdentifier(); + Name = Unexpanded[I].first.get()->getIdentifier(); if (Name && NamesKnown.insert(Name).second) Names.push_back(Name); @@ -421,7 +433,7 @@ llvm::SmallPtrSet ParmSet(Parms.begin(), Parms.end()); SmallVector UnexpandedParms; for (auto Parm : Unexpanded) - if (ParmSet.contains(Parm.first.dyn_cast())) + if (ParmSet.contains(Parm.first.dyn_cast())) UnexpandedParms.push_back(Parm); if (UnexpandedParms.empty()) return false; @@ -681,42 +693,51 @@ // Compute the depth and index for this parameter pack. unsigned Depth = 0, Index = 0; IdentifierInfo *Name; - bool IsVarDeclPack = false; + unsigned NewPackSize; + bool NotPack = true; - if (const TemplateTypeParmType *TTP = + if (const auto *TTP = ParmPack.first.dyn_cast()) { Depth = TTP->getDepth(); Index = TTP->getIndex(); Name = TTP->getIdentifier(); + } else if (const auto *STP = + ParmPack.first + .dyn_cast()) { + NewPackSize = STP->getNumArgs(); + Name = STP->getIdentifier(); + NotPack = false; + } else if (const auto *SEP = + ParmPack.first + .dyn_cast()) { + NewPackSize = SEP->getArgumentPack().pack_size(); + Name = SEP->getParameterPack()->getIdentifier(); + NotPack = false; } else { - NamedDecl *ND = ParmPack.first.get(); - if (isa(ND)) - IsVarDeclPack = true; - else + const auto *ND = ParmPack.first.get(); + if (isa(ND)) { + // Figure out whether we're instantiating to an argument pack or not. + using DeclArgumentPack = LocalInstantiationScope::DeclArgumentPack; + llvm::PointerUnion *Instantiation = + CurrentInstantiationScope->findInstantiationOf( + ParmPack.first.get()); + if (Instantiation->is()) { + // We could expand this function parameter pack. + NewPackSize = Instantiation->get()->size(); + } else { + // We can't expand this function parameter pack, so we can't expand + // the pack expansion. + ShouldExpand = false; + continue; + } + NotPack = false; + } else { std::tie(Depth, Index) = getDepthAndIndex(ND); - + } Name = ND->getIdentifier(); } - // Determine the size of this argument pack. - unsigned NewPackSize; - if (IsVarDeclPack) { - // Figure out whether we're instantiating to an argument pack or not. - typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; - - llvm::PointerUnion *Instantiation = - CurrentInstantiationScope->findInstantiationOf( - ParmPack.first.get()); - if (Instantiation->is()) { - // We could expand this function parameter pack. - NewPackSize = Instantiation->get()->size(); - } else { - // We can't expand this function parameter pack, so we can't expand - // the pack expansion. - ShouldExpand = false; - continue; - } - } else { + if (NotPack) { // 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. @@ -725,28 +746,25 @@ ShouldExpand = false; continue; } - // Determine the size of the argument pack. NewPackSize = TemplateArgs(Depth, Index).pack_size(); - } - - // 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) { - RetainExpansion = true; - // We don't actually know the new pack size yet. - NumPartialExpansions = NewPackSize; - PartiallySubstitutedPackLoc = ParmPack.second; - continue; + // 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 (NamedDecl *PartialPack = + CurrentInstantiationScope->getPartiallySubstitutedPack()) { + unsigned PartialDepth, PartialIndex; + std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack); + if (PartialDepth == Depth && PartialIndex == Index) { + RetainExpansion = true; + // We don't actually know the new pack size yet. + NumPartialExpansions = NewPackSize; + PartiallySubstitutedPackLoc = ParmPack.second; + continue; + } } - } } if (!NumExpansions) { @@ -807,32 +825,47 @@ CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern); Optional Result; + auto setResult = [&Result](unsigned Size) { + assert((!Result || *Result == Size) && "inconsistent pack sizes"); + Result = Size; + }; + for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { // Compute the depth and index for this parameter pack. unsigned Depth; unsigned Index; - if (const TemplateTypeParmType *TTP - = Unexpanded[I].first.dyn_cast()) { + if (const auto *TTP = + Unexpanded[I].first.dyn_cast()) { Depth = TTP->getDepth(); Index = TTP->getIndex(); + } else if (const auto *STP = + Unexpanded[I] + .first + .dyn_cast()) { + setResult(STP->getNumArgs()); + continue; + } else if (const auto *SEP = + Unexpanded[I] + .first + .dyn_cast()) { + setResult(SEP->getArgumentPack().pack_size()); + continue; } else { - NamedDecl *ND = Unexpanded[I].first.get(); + const auto *ND = Unexpanded[I].first.get(); if (isa(ND)) { // Function parameter pack or init-capture pack. typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; - llvm::PointerUnion *Instantiation - = CurrentInstantiationScope->findInstantiationOf( - Unexpanded[I].first.get()); + llvm::PointerUnion *Instantiation = + CurrentInstantiationScope->findInstantiationOf( + Unexpanded[I].first.get()); if (Instantiation->is()) // The pattern refers to an unexpanded pack. We're not ready to expand // this pack yet. return None; - unsigned Size = Instantiation->get()->size(); - assert((!Result || *Result == Size) && "inconsistent pack sizes"); - Result = Size; + setResult(Instantiation->get()->size()); continue; } @@ -845,9 +878,7 @@ return None; // Determine the size of the argument pack. - unsigned Size = TemplateArgs(Depth, Index).pack_size(); - assert((!Result || *Result == Size) && "inconsistent pack sizes"); - Result = Size; + setResult(TemplateArgs(Depth, Index).pack_size()); } return Result; diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp --- a/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp @@ -469,3 +469,25 @@ bar(b); } } + +namespace pr56094 { +template struct D { + template 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 D(B *); + // expected-note@-1 {{in instantiation of template type alias 'B' requested here}} +}; +using t1 = D::B; +// expected-note@-1 {{in instantiation of template class 'pr56094::D' requested here}} + +template struct F {}; +template struct G {}; +template struct E { + template using B = G...>; + // expected-error@-1 {{pack expansion contains parameter pack 'U' that has a different length (1 vs. 2) from outer parameter packs}} + template E(B *); + // expected-note@-1 {{in instantiation of template type alias 'B' requested here}} +}; +using t2 = E::B; +// expected-note@-1 {{in instantiation of template class 'pr56094::E' requested here}} +} // namespace pr56094