Author: Erich Keane Date: 2023-03-09T09:16:53-08:00 New Revision: acecf68c8b7c3c625cfa00f00f8ddc8f15baae44
URL: https://github.com/llvm/llvm-project/commit/acecf68c8b7c3c625cfa00f00f8ddc8f15baae44 DIFF: https://github.com/llvm/llvm-project/commit/acecf68c8b7c3c625cfa00f00f8ddc8f15baae44.diff LOG: Revert two patches to fix GH58452 regression GH58452 is a regression in the 16.0 release branch caused by both: b8a1b698afb2fc84819c7596090aabf4d826b436 and 3a0309c53674be56b5cfce038d78a0c2c6e2a98c This patch reverts both of those to make the 'valid' code stop diagnosing at the expense of crashes on invalid + unclear diagnostics. This patch also adds the tests from GH58452 to prevent any re-application from breaking this again. Revert "[clang] Improve diagnostics for expansion length mismatch" This reverts commit 3a0309c53674be56b5cfce038d78a0c2c6e2a98c. Revert "[clang] fix missing initialization of original number of expansions" This reverts commit b8a1b698afb2fc84819c7596090aabf4d826b436. Differential Revision: https://reviews.llvm.org/D145605 Added: Modified: clang/include/clang/Sema/Sema.h clang/include/clang/Sema/SemaInternal.h clang/lib/Sema/SemaTemplateDeduction.cpp clang/lib/Sema/SemaTemplateVariadic.cpp clang/lib/Sema/TreeTransform.h clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp clang/test/SemaTemplate/cxx1z-fold-expressions.cpp clang/test/SemaTemplate/pack-deduction.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index d1342876f85dc..a492721f77bfa 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -238,11 +238,9 @@ namespace threadSafety { // FIXME: No way to easily map from TemplateTypeParmTypes to // TemplateTypeParmDecls, so we have this horrible PointerUnion. -using UnexpandedParameterPack = std::pair< - llvm::PointerUnion< - const TemplateTypeParmType *, const SubstTemplateTypeParmPackType *, - const SubstNonTypeTemplateParmPackExpr *, const NamedDecl *>, - SourceLocation>; +typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType *, NamedDecl *>, + SourceLocation> + UnexpandedParameterPack; /// 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 4eca50919dc7e..842eec099540c 100644 --- a/clang/include/clang/Sema/SemaInternal.h +++ b/clang/include/clang/Sema/SemaInternal.h @@ -62,7 +62,7 @@ inline InheritableAttr *getDLLAttr(Decl *D) { } /// Retrieve the depth and index of a template parameter. -inline std::pair<unsigned, unsigned> getDepthAndIndex(const NamedDecl *ND) { +inline std::pair<unsigned, unsigned> getDepthAndIndex(NamedDecl *ND) { if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) return std::make_pair(TTP->getDepth(), TTP->getIndex()); @@ -79,7 +79,7 @@ getDepthAndIndex(UnexpandedParameterPack UPP) { if (const auto *TTP = UPP.first.dyn_cast<const TemplateTypeParmType *>()) return std::make_pair(TTP->getDepth(), TTP->getIndex()); - return getDepthAndIndex(UPP.first.get<const NamedDecl *>()); + return getDepthAndIndex(UPP.first.get<NamedDecl *>()); } class TypoCorrectionConsumer : public VisibleDeclConsumer { diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 9e48a2a35a344..1fe2d3fac6859 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -756,11 +756,8 @@ class PackDeductionScope { SmallVector<UnexpandedParameterPack, 2> Unexpanded; S.collectUnexpandedParameterPacks(Pattern, Unexpanded); for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { - UnexpandedParameterPack U = Unexpanded[I]; - if (U.first.is<const SubstTemplateTypeParmPackType *>() || - U.first.is<const SubstNonTypeTemplateParmPackExpr *>()) - continue; - auto [Depth, Index] = getDepthAndIndex(U); + unsigned Depth, Index; + std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); if (Depth == Info.getDeducedDepth()) AddPack(Index); } diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 01a435668d883..86268b504cbb3 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -89,23 +89,6 @@ namespace { return true; } - bool - VisitSubstTemplateTypeParmPackTypeLoc(SubstTemplateTypeParmPackTypeLoc TL) { - Unexpanded.push_back({TL.getTypePtr(), TL.getNameLoc()}); - 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) { @@ -324,8 +307,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, auto *TTPD = dyn_cast<TemplateTypeParmDecl>(LocalPack); return TTPD && TTPD->getTypeForDecl() == TTPT; } - return declaresSameEntity(Pack.first.get<const NamedDecl *>(), - LocalPack); + return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack); }; if (llvm::any_of(LSI->LocalPacks, DeclaresThisPack)) LambdaParamPackReferences.push_back(Pack); @@ -377,7 +359,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) Name = TTP->getIdentifier(); else - Name = Unexpanded[I].first.get<const NamedDecl *>()->getIdentifier(); + Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier(); if (Name && NamesKnown.insert(Name).second) Names.push_back(Name); @@ -440,7 +422,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<const NamedDecl *>())) + if (ParmSet.contains(Parm.first.dyn_cast<NamedDecl *>())) UnexpandedParms.push_back(Parm); if (UnexpandedParms.empty()) return false; @@ -692,95 +674,109 @@ bool Sema::CheckParameterPacksForExpansion( bool &RetainExpansion, std::optional<unsigned> &NumExpansions) { ShouldExpand = true; RetainExpansion = false; - std::pair<const IdentifierInfo *, SourceLocation> FirstPack; - std::optional<std::pair<unsigned, SourceLocation>> PartialExpansion; - std::optional<unsigned> CurNumExpansions; + std::pair<IdentifierInfo *, SourceLocation> FirstPack; + bool HaveFirstPack = false; + std::optional<unsigned> NumPartialExpansions; + SourceLocation PartiallySubstitutedPackLoc; - for (auto [P, Loc] : Unexpanded) { + for (UnexpandedParameterPack ParmPack : Unexpanded) { // Compute the depth and index for this parameter pack. - std::optional<std::pair<unsigned, unsigned>> Pos; + 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 = ParmPack.first.get<NamedDecl *>(); + if (isa<VarDecl>(ND)) + IsVarDeclPack = true; + else + std::tie(Depth, Index) = getDepthAndIndex(ND); + + Name = ND->getIdentifier(); + } + + // Determine the size of this argument pack. unsigned NewPackSize; - const auto *ND = P.dyn_cast<const NamedDecl *>(); - if (ND && isa<VarDecl>(ND)) { - const auto *DAP = - CurrentInstantiationScope->findInstantiationOf(ND) - ->dyn_cast<LocalInstantiationScope::DeclArgumentPack *>(); - if (!DAP) { + 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( + ParmPack.first.get<NamedDecl *>()); + if (Instantiation->is<DeclArgumentPack *>()) { + // We could expand this function parameter pack. + NewPackSize = Instantiation->get<DeclArgumentPack *>()->size(); + } else { // 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 = P.dyn_cast<const TemplateTypeParmType *>()) { - 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 = - P.dyn_cast<const SubstTemplateTypeParmPackType *>()) { - NewPackSize = STP->getNumArgs(); - ND = STP->getReplacedParameter(); } else { - const auto *SEP = P.get<const SubstNonTypeTemplateParmPackExpr *>(); - NewPackSize = SEP->getArgumentPack().pack_size(); - 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 (Pos->first >= TemplateArgs.getNumLevels() || - !TemplateArgs.hasTemplateArgument(Pos->first, Pos->second)) { + if (Depth >= TemplateArgs.getNumLevels() || + !TemplateArgs.hasTemplateArgument(Depth, Index)) { ShouldExpand = false; continue; } + // Determine the size of the argument pack. - NewPackSize = TemplateArgs(Pos->first, Pos->second).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 (CurrentInstantiationScope) - if (const NamedDecl *PartialPack = - CurrentInstantiationScope->getPartiallySubstitutedPack(); - PartialPack && getDepthAndIndex(PartialPack) == *Pos) { + 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. - PartialExpansion = {NewPackSize, Loc}; + NumPartialExpansions = NewPackSize; + PartiallySubstitutedPackLoc = ParmPack.second; continue; } + } } - // FIXME: Workaround for Canonical TTP. - const IdentifierInfo *Name = ND ? ND->getIdentifier() : nullptr; - if (!CurNumExpansions) { + if (!NumExpansions) { // The is the first pack we've seen for which we have an argument. // Record it. - CurNumExpansions = NewPackSize; - FirstPack = {Name, Loc}; - } else if (NewPackSize != *CurNumExpansions) { + NumExpansions = NewPackSize; + FirstPack.first = Name; + FirstPack.second = ParmPack.second; + HaveFirstPack = true; + continue; + } + + if (NewPackSize != *NumExpansions) { // C++0x [temp.variadic]p5: // All of the parameter packs expanded by a pack expansion shall have // the same number of arguments specified. - Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) - << FirstPack.first << Name << *CurNumExpansions << NewPackSize - << SourceRange(FirstPack.second) << SourceRange(Loc); + if (HaveFirstPack) + Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) + << FirstPack.first << Name << *NumExpansions << NewPackSize + << SourceRange(FirstPack.second) << SourceRange(ParmPack.second); + else + Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel) + << Name << *NumExpansions << NewPackSize + << SourceRange(ParmPack.second); return true; } } - if (NumExpansions && CurNumExpansions && - *NumExpansions != *CurNumExpansions) { - Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel) - << FirstPack.first << *CurNumExpansions << *NumExpansions - << SourceRange(FirstPack.second); - return true; - } - // If we're performing a partial expansion but we also have a full expansion, // expand to the number of common arguments. For example, given: // @@ -790,18 +786,17 @@ bool Sema::CheckParameterPacksForExpansion( // // ... a call to 'A<int, int>().f<int>' should expand the pack once and // retain an expansion. - if (PartialExpansion) { - if (CurNumExpansions && *CurNumExpansions < PartialExpansion->first) { + if (NumPartialExpansions) { + if (NumExpansions && *NumExpansions < *NumPartialExpansions) { NamedDecl *PartialPack = CurrentInstantiationScope->getPartiallySubstitutedPack(); Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial) - << PartialPack << PartialExpansion->first << *CurNumExpansions - << SourceRange(PartialExpansion->second); + << PartialPack << *NumPartialExpansions << *NumExpansions + << SourceRange(PartiallySubstitutedPackLoc); return true; } - NumExpansions = PartialExpansion->first; - } else { - NumExpansions = CurNumExpansions; + + NumExpansions = NumPartialExpansions; } return false; @@ -814,48 +809,47 @@ std::optional<unsigned> Sema::getNumArgumentsInExpansion( CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern); std::optional<unsigned> Result; - auto setResultSz = [&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. - setResultSz(TemplateArgs(Depth, Index).pack_size()); - return false; - }; + for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { + // Compute the depth and index for this parameter pack. + unsigned Depth; + unsigned Index; - 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 *>()) { - setResultSz(STP->getNumArgs()); - } else if (const auto *SEP = - I.dyn_cast<const SubstNonTypeTemplateParmPackExpr *>()) { - setResultSz(SEP->getArgumentPack().pack_size()); + if (const TemplateTypeParmType *TTP = + Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) { + Depth = TTP->getDepth(); + Index = TTP->getIndex(); } else { - const auto *ND = I.get<const NamedDecl *>(); - // Function parameter pack or init-capture pack. + NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>(); if (isa<VarDecl>(ND)) { - const auto *DAP = - CurrentInstantiationScope->findInstantiationOf(ND) - ->dyn_cast<LocalInstantiationScope::DeclArgumentPack *>(); - if (!DAP) + // Function parameter pack or init-capture pack. + typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; + + llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation = + CurrentInstantiationScope->findInstantiationOf( + Unexpanded[I].first.get<NamedDecl *>()); + if (Instantiation->is<Decl *>()) // The pattern refers to an unexpanded pack. We're not ready to expand // this pack yet. return std::nullopt; - setResultSz(DAP->size()); - } else if (setResultPos(getDepthAndIndex(ND))) { - return std::nullopt; + + unsigned Size = Instantiation->get<DeclArgumentPack *>()->size(); + assert((!Result || *Result == Size) && "inconsistent pack sizes"); + Result = Size; + continue; } + + 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 44e4a14b487be..c6a3af1b72b07 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -5897,7 +5897,6 @@ 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 2d82a4f26b147..7542186c22c71 100644 --- a/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp @@ -473,51 +473,45 @@ int fn() { } } -namespace pr56094 { -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 diff erent 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}} +namespace GH58452 { +template <typename... As> struct A { + template <typename... Bs> using B = void(As...(Bs)); }; -using t1 = D<float>::B<int>; -// expected-note@-1 {{in instantiation of template class 'pr56094::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 diff erent 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}} + +template <typename... Cs> struct C { + template <typename... Ds> using D = typename A<Cs...>::template B<Ds...>; }; -using t2 = E<true>::B<false>; -// expected-note@-1 {{in instantiation of template class 'pr56094::E<true>' requested here}} -} // namespace pr56094 - -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; +using t1 = C<int, int>::template D<float, float>; -template <int> struct B; -template <> struct B<1> { using b1 = void; }; +template <typename A, typename B> +using ConditionalRewrite = B; -template <class> using C = char; +template <typename T> +using SignatureType = int; -template <class... Ds> int D{ B<A<C<Ds>>>{}... }; +template <typename... Args> +struct Type1 { + template <typename... Params> + using Return = SignatureType<int(ConditionalRewrite<Args, Params>...)>; -struct E { - template <class E1, class = typename B<A<E1>>::b1> E(E1); }; -template <typename... Es> int F{ E(C<Es>{})... }; -#endif -} // namespace GH58679 +template <typename... Args> +struct Type2 { + using T1 = Type1<Args...>; + + template <typename... Params> + using Return = typename T1::template Return<Params...>; + +}; + +template <typename T> +typename T::template Return<int, int> InvokeMethod() { + return 3; +} + +int Function1() { + return InvokeMethod<Type2<int, int>>(); +} +} diff --git a/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp b/clang/test/SemaTemplate/cxx1z-fold-expressions.cpp index 98876baf1f3ec..518eaf0e05239 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 packs 'Is' and 'Js' that have diff erent lengths (1 vs. 2)}} + template <int... Js> using type = Constant<((Is + Js) + ... + 0)>; // expected-error {{pack expansion contains parameter pack 'Js' that has a diff erent length (1 vs. 2) from outer parameter packs}} }; 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 f07bafdf86bca..e42709820e9cf 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 packs 'T' and 'U' that have diff erent lengths (2 vs. 3)}} + // expected-note@-1 {{[with U = <char, double, long>]: pack expansion contains parameter pack 'U' that has a diff erent length (2 vs. 3) from outer parameter packs}} // expected-note@-2 {{[with U = <char, double, void>]: pack expansion contains parameter pack 'U' that has a diff erent 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 packs 'T' and 'U' that have diff erent lengths (2 vs. 3)}} + // expected-note@-1 {{[with U = <char, double, long>]: pack expansion contains parameter pack 'U' that has a diff erent length (2 vs. 3) from outer parameter packs}} 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 packs 'T' and 'U' that have diff erent lengths (2 vs. 1)}} + // expected-note@-1 {{[with U = <int[2]>]: pack expansion contains parameter pack 'U' that has a diff erent length (2 vs. 1) from outer parameter packs}} }; pair<tuple<int, float>, tuple<char, double>> k1 = A<int, float>().f<char>(pair<int, char>(), pair<float, double>()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits