Skip to content

Commit 9abb97f

Browse files
authored
[clang] Handle template argument conversions for non-pack param to pack argument (#110963)
This fixes a regression introduced in #96023, reported in #110231 (comment)
1 parent 5114758 commit 9abb97f

File tree

7 files changed

+63
-45
lines changed

7 files changed

+63
-45
lines changed

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5579,9 +5579,6 @@ bool Sema::CheckTemplateArgumentList(
55795579
return true;
55805580
}
55815581

5582-
// We're now done with this argument.
5583-
++ArgIdx;
5584-
55855582
if ((*Param)->isTemplateParameterPack()) {
55865583
// The template parameter was a template parameter pack, so take the
55875584
// deduced argument and place it on the argument pack. Note that we
@@ -5592,8 +5589,19 @@ bool Sema::CheckTemplateArgumentList(
55925589
} else {
55935590
// Move to the next template parameter.
55945591
++Param;
5592+
if (PartialOrderingTTP && PackExpansionIntoNonPack) {
5593+
// Keep converting the pattern in the argument against
5594+
// subsequent parameters. The argument is converted
5595+
// in place and will be added back when we are done.
5596+
SugaredConverted.pop_back();
5597+
CanonicalConverted.pop_back();
5598+
continue;
5599+
}
55955600
}
55965601

5602+
// We're now done with this argument.
5603+
++ArgIdx;
5604+
55975605
// If we just saw a pack expansion into a non-pack, then directly convert
55985606
// the remaining arguments, because we don't know what parameters they'll
55995607
// match up with.
@@ -5727,15 +5735,10 @@ bool Sema::CheckTemplateArgumentList(
57275735
// pack expansions; they might be empty. This can happen even if
57285736
// PartialTemplateArgs is false (the list of arguments is complete but
57295737
// still dependent).
5730-
if (PartialOrderingTTP ||
5731-
(CurrentInstantiationScope &&
5732-
CurrentInstantiationScope->getPartiallySubstitutedPack())) {
5733-
while (ArgIdx < NumArgs &&
5734-
NewArgs[ArgIdx].getArgument().isPackExpansion()) {
5735-
const TemplateArgument &Arg = NewArgs[ArgIdx++].getArgument();
5736-
SugaredConverted.push_back(Arg);
5737-
CanonicalConverted.push_back(Context.getCanonicalTemplateArgument(Arg));
5738-
}
5738+
while (ArgIdx < NumArgs && NewArgs[ArgIdx].getArgument().isPackExpansion()) {
5739+
const TemplateArgument &Arg = NewArgs[ArgIdx++].getArgument();
5740+
SugaredConverted.push_back(Arg);
5741+
CanonicalConverted.push_back(Context.getCanonicalTemplateArgument(Arg));
57395742
}
57405743

57415744
// If we have any leftover arguments, then there were too many arguments.

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3377,35 +3377,40 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction(
33773377
return Result;
33783378

33793379
// Check that we produced the correct argument list.
3380-
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
3381-
auto isSame = [&](unsigned I, const TemplateArgument &P,
3382-
const TemplateArgument &A) {
3383-
if (isSameTemplateArg(S.Context, P, A, PartialOrdering,
3384-
/*PackExpansionMatchesPack=*/true))
3385-
return true;
3386-
Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
3380+
for (ArrayRef<TemplateArgument> Ps = TemplateArgs, As = CanonicalBuilder;
3381+
!Ps.empty() && !As.empty();
3382+
/**/) {
3383+
TemplateArgument P = Ps.front(), A = As.front();
3384+
if (P.getKind() == TemplateArgument::Pack) {
3385+
assert(Ps.size() == 1 && "Pack not last element?");
3386+
Ps = P.getPackAsArray();
3387+
continue;
3388+
}
3389+
if (A.getKind() == TemplateArgument::Pack) {
3390+
assert(As.size() == 1 && "Pack not last element?");
3391+
As = A.getPackAsArray();
3392+
continue;
3393+
}
3394+
3395+
if (P.isPackExpansion())
3396+
P = P.getPackExpansionPattern();
3397+
else
3398+
Ps = Ps.drop_front();
3399+
if (A.isPackExpansion())
3400+
A = A.getPackExpansionPattern();
3401+
else
3402+
As = As.drop_front();
3403+
3404+
if (isSameTemplateArg(S.Context, P, A, PartialOrdering))
3405+
continue;
3406+
unsigned I = As.end() == CanonicalBuilder.end()
3407+
? As.begin() - CanonicalBuilder.begin()
3408+
: CanonicalBuilder.size() - 1;
3409+
Info.Param =
3410+
makeTemplateParameter(Template->getTemplateParameters()->getParam(I));
33873411
Info.FirstArg = P;
33883412
Info.SecondArg = A;
3389-
return false;
3390-
};
3391-
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
3392-
const TemplateArgument &P = TemplateArgs[I];
3393-
if (P.isPackExpansion()) {
3394-
assert(I == TemplateArgs.size() - 1);
3395-
for (/**/; I != E; ++I) {
3396-
const TemplateArgument &A = CanonicalBuilder[I];
3397-
if (A.getKind() == TemplateArgument::Pack) {
3398-
for (const TemplateArgument &Ai : A.getPackAsArray())
3399-
if (!isSame(I, P, Ai))
3400-
return TemplateDeductionResult::NonDeducedMismatch;
3401-
} else if (!isSame(I, P, A)) {
3402-
return TemplateDeductionResult::NonDeducedMismatch;
3403-
}
3404-
}
3405-
break;
3406-
}
3407-
if (!isSame(I, P, CanonicalBuilder[I]))
3408-
return TemplateDeductionResult::NonDeducedMismatch;
3413+
return TemplateDeductionResult::NonDeducedMismatch;
34093414
}
34103415

34113416
if (!PartialOrdering) {

clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ eval<D<int, 17>> eD; // expected-error{{implicit instantiation of undefined temp
1818
eval<E<int, float>> eE; // expected-error{{implicit instantiation of undefined template 'eval<E<int, float>>}}
1919

2020
template<
21-
template <int ...N> // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('int' vs 'long')}}
21+
template <int ...N> // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('long' vs 'int')}}
2222
class TT // expected-note {{previous template template parameter is here}}
2323
> struct X0 { };
2424

@@ -31,7 +31,7 @@ X0<X0b> inst_x0b;
3131
X0<X0c> inst_x0c; // expected-note{{template template argument has different template parameters than its corresponding template template parameter}}
3232

3333
template<typename T,
34-
template <T ...N> // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('short' vs 'long')}}
34+
template <T ...N> // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('long' vs 'short')}}
3535
class TT // expected-note {{previous template template parameter is here}}
3636
> struct X1 { };
3737
template<int I, int J, int ...Rest> struct X1a;

clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,14 @@ namespace PackExpansionNotAtEnd {
2929
>::value? 1 : -1];
3030

3131
template<typename ... Types> struct UselessPartialSpec;
32+
// expected-note@-1 {{template is declared here}}
3233

34+
// FIXME: We should simply disallow a pack expansion which is not at
35+
// the end of the partial spec template argument list.
3336
template<typename ... Types, // expected-note{{non-deducible template parameter 'Types'}}
3437
typename Tail> // expected-note{{non-deducible template parameter 'Tail'}}
3538
struct UselessPartialSpec<Types..., Tail>; // expected-error{{class template partial specialization contains template parameters that cannot be deduced; this partial specialization will never be used}}
39+
// expected-error@-1 {{is not more specialized than the primary template}}
3640
}
3741

3842
// When a pack expansion occurs within a template argument list, the entire

clang/test/SemaTemplate/cwg2398.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,3 +541,9 @@ namespace regression2 {
541541
template <typename, int> struct Matrix;
542542
template struct D<Matrix<double, 3>>;
543543
} // namespace regression2
544+
545+
namespace regression3 {
546+
template <template <auto...> class TT> struct A {};
547+
template <auto, int> struct B;
548+
template struct A<B>;
549+
} // namespace regression3

clang/test/SemaTemplate/temp_arg_template_p0522.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ template<int, int> struct ii;
2121
template<int...> struct Pi;
2222
template<int, int, int...> struct iiPi;
2323

24-
template<int, typename = int> struct iDt; // #iDt
24+
template<int, typename = int> struct iDt;
2525
template<int, typename> struct it; // #it
2626

2727
template<typename T, T v> struct t0;
@@ -50,9 +50,9 @@ namespace IntPackParam {
5050
using ok_compat = Pt<TPi<i>, TPi<iDi>, TPi<ii>, TPi<iiPi>>;
5151
using err1 = TPi<t0>; // expected-error@#TPi {{template argument for template type parameter must be a type}}
5252
// expected-note@-1 {{different template parameters}}
53-
using err2 = TPi<iDt>; // expected-error@#iDt {{could not match 'type-parameter-0-1' against}}
53+
using err2 = TPi<iDt>; // expected-error@#TPi {{template argument for template type parameter must be a type}}
5454
// expected-note@-1 {{different template parameters}}
55-
using err3 = TPi<it>; // expected-error@#it {{could not match 'type-parameter-0-1' against}}
55+
using err3 = TPi<it>; // expected-error@#TPi {{template argument for template type parameter must be a type}}
5656
// expected-note@-1 {{different template parameters}}
5757
}
5858

libcxx/test/libcxx/type_traits/is_specialization.verify.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@
1717
#include <array>
1818
#include <utility>
1919

20-
// expected-error-re@*:* {{{{could not match _Size against 'type-parameter-0-0'|different template parameters}}}}
20+
// expected-error-re@*:* {{{{must be an expression|different template parameters}}}}
2121
static_assert(!std::__is_specialization_v<std::pair<int, std::size_t>, std::array>);

0 commit comments

Comments
 (0)