Skip to content

Commit 3dd62b0

Browse files
committed
[Clang] Don't assume unexpanded PackExpansions' size when expanding packs
1 parent 1d07098 commit 3dd62b0

File tree

3 files changed

+91
-8
lines changed

3 files changed

+91
-8
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5863,10 +5863,10 @@ def err_pack_expansion_without_parameter_packs : Error<
58635863
"pack expansion does not contain any unexpanded parameter packs">;
58645864
def err_pack_expansion_length_conflict : Error<
58655865
"pack expansion contains parameter packs %0 and %1 that have different "
5866-
"lengths (%2 vs. %3)">;
5866+
"lengths (%2 vs. %select{|at least }3%4))">;
58675867
def err_pack_expansion_length_conflict_multilevel : Error<
58685868
"pack expansion contains parameter pack %0 that has a different "
5869-
"length (%1 vs. %2) from outer parameter packs">;
5869+
"length (%1 vs. %select{|at least }2%3) from outer parameter packs">;
58705870
def err_pack_expansion_length_conflict_partial : Error<
58715871
"pack expansion contains parameter pack %0 that has a different "
58725872
"length (at least %1 vs. %2) from outer parameter packs">;

clang/lib/Sema/SemaTemplateVariadic.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,7 @@ bool Sema::CheckParameterPacksForExpansion(
780780
}
781781

782782
// Determine the size of this argument pack.
783-
unsigned NewPackSize;
783+
unsigned NewPackSize, PendingPackExpansionSize = 0;
784784
if (IsVarDeclPack) {
785785
// Figure out whether we're instantiating to an argument pack or not.
786786
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
@@ -808,7 +808,25 @@ bool Sema::CheckParameterPacksForExpansion(
808808
}
809809

810810
// Determine the size of the argument pack.
811-
NewPackSize = TemplateArgs(Depth, Index).pack_size();
811+
ArrayRef<TemplateArgument> Pack =
812+
TemplateArgs(Depth, Index).getPackAsArray();
813+
NewPackSize = Pack.size();
814+
PendingPackExpansionSize =
815+
llvm::count_if(Pack, [](const TemplateArgument &TA) {
816+
if (!TA.isPackExpansion())
817+
return false;
818+
819+
if (TA.getKind() == TemplateArgument::Type)
820+
return !TA.getAsType()
821+
->getAs<PackExpansionType>()
822+
->getNumExpansions();
823+
824+
if (TA.getKind() == TemplateArgument::Expression)
825+
return !cast<PackExpansionExpr>(TA.getAsExpr())
826+
->getNumExpansions();
827+
828+
return !TA.getNumTemplateExpansions();
829+
});
812830
}
813831

814832
// C++0x [temp.arg.explicit]p9:
@@ -831,7 +849,7 @@ bool Sema::CheckParameterPacksForExpansion(
831849
}
832850

833851
if (!NumExpansions) {
834-
// The is the first pack we've seen for which we have an argument.
852+
// This is the first pack we've seen for which we have an argument.
835853
// Record it.
836854
NumExpansions = NewPackSize;
837855
FirstPack.first = Name;
@@ -841,17 +859,23 @@ bool Sema::CheckParameterPacksForExpansion(
841859
}
842860

843861
if (NewPackSize != *NumExpansions) {
862+
unsigned LeastNewPackSize = NewPackSize - PendingPackExpansionSize;
863+
if (PendingPackExpansionSize && LeastNewPackSize <= *NumExpansions) {
864+
ShouldExpand = false;
865+
continue;
866+
}
844867
// C++0x [temp.variadic]p5:
845868
// All of the parameter packs expanded by a pack expansion shall have
846869
// the same number of arguments specified.
847870
if (HaveFirstPack)
848871
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict)
849-
<< FirstPack.first << Name << *NumExpansions << NewPackSize
872+
<< FirstPack.first << Name << *NumExpansions
873+
<< (LeastNewPackSize != NewPackSize) << LeastNewPackSize
850874
<< SourceRange(FirstPack.second) << SourceRange(ParmPack.second);
851875
else
852876
Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel)
853-
<< Name << *NumExpansions << NewPackSize
854-
<< SourceRange(ParmPack.second);
877+
<< Name << *NumExpansions << (LeastNewPackSize != NewPackSize)
878+
<< LeastNewPackSize << SourceRange(ParmPack.second);
855879
return true;
856880
}
857881
}

clang/test/SemaTemplate/pack-deduction.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,3 +199,62 @@ constexpr auto baz(Int<foo<T>(T())>... x) -> int { return 1; }
199199

200200
static_assert(baz<Int<1>, Int<2>, Int<3>>(Int<10>(), Int<10>(), Int<10>()) == 1, "");
201201
}
202+
203+
namespace GH17042 {
204+
205+
template <class... Ts> struct X {
206+
template <class... Us> using Y = X<void(Ts, Us)...>; // #GH17042_Y
207+
};
208+
209+
template <class... T>
210+
using any_pairs_list = X<int, int>::Y<T...>; // #any_pairs_list
211+
212+
template <class... T>
213+
using any_pairs_list_2 = X<int, int>::Y<>;
214+
// expected-error@#GH17042_Y {{different length (2 vs. 0)}} \
215+
// expected-note@-1 {{requested here}}
216+
217+
template <class A, class B, class... P>
218+
using any_pairs_list_3 = X<int, int>::Y<A, B, P...>; // #any_pairs_list_3
219+
220+
template <class A, class B, class C, class... P>
221+
using any_pairs_list_4 = X<int, int>::Y<A, B, C, P...>;
222+
// expected-error@#GH17042_Y {{different length (2 vs. at least 3)}} \
223+
// expected-note@-1 {{requested here}}
224+
225+
static_assert(__is_same(any_pairs_list<char, char>, X<void(int, char), void(int, char)>), "");
226+
227+
static_assert(!__is_same(any_pairs_list<char, char, char>, X<void(int, char), void(int, char)>), "");
228+
// expected-error@#GH17042_Y {{different length (2 vs. 3)}} \
229+
// expected-note@#any_pairs_list {{requested here}} \
230+
// expected-note@-1 {{requested here}}
231+
232+
static_assert(__is_same(any_pairs_list_3<char, char>, X<void(int, char), void(int, char)>), "");
233+
234+
static_assert(!__is_same(any_pairs_list_3<char, char, float>, X<void(int, char), void(int, char)>), "");
235+
// expected-error@#GH17042_Y {{different length (2 vs. 3)}} \
236+
// expected-note@#any_pairs_list_3 {{requested here}} \
237+
// expected-note@-1 {{requested here}}
238+
239+
namespace TemplateTemplateParameters {
240+
template <class... T> struct C {};
241+
242+
template <class T, template <class> class... Args1> struct Ttp {
243+
template <template <class> class... Args2>
244+
using B = C<void(Args1<T>, Args2<T>)...>;
245+
};
246+
template <class> struct D {};
247+
248+
template <template <class> class... Args>
249+
using Alias = Ttp<int, D, D>::B<Args...>;
250+
}
251+
252+
namespace NTTP {
253+
template <int... Args1> struct Nttp {
254+
template <int... Args2> using B = Nttp<(Args1 + Args2)...>;
255+
};
256+
257+
template <int... Args> using Alias = Nttp<1, 2, 3>::B<Args...>;
258+
}
259+
260+
}

0 commit comments

Comments
 (0)