Skip to content

Commit 78ac2f4

Browse files
committed
[clang] fix matching of nested template template parameters
When checking the template template parameters of template template parameters, the PartialOrdering context was not correctly propagated. This also has a few drive-by fixes, such as checking the template parameter lists of template template parameters, which was previously missing and would have been it's own bug, but we need to fix it in order to prevent crashes in error recovery in a simple way. Fixes #130362
1 parent b01c71b commit 78ac2f4

File tree

10 files changed

+63
-46
lines changed

10 files changed

+63
-46
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ related warnings within the method body.
161161
``__attribute__((model("large")))`` on non-TLS globals in x86-64 compilations.
162162
This forces the global to be considered small or large in regards to the
163163
x86-64 code model, regardless of the code model specified for the compilation.
164-
- Clang now emits a warning ``-Wreserved-init-priority`` instead of a hard error
165-
when ``__attribute__((init_priority(n)))`` is used with values of n in the
164+
- Clang now emits a warning ``-Wreserved-init-priority`` instead of a hard error
165+
when ``__attribute__((init_priority(n)))`` is used with values of n in the
166166
reserved range [0, 100]. The warning will be treated as an error by default.
167167

168168
- There is a new ``format_matches`` attribute to complement the existing
@@ -294,6 +294,9 @@ Bug Fixes to C++ Support
294294
direct-list-initialized from an array is corrected to direct-initialization.
295295
- Clang no longer crashes when a coroutine is declared ``[[noreturn]]``. (#GH127327)
296296
- Clang now uses the parameter location for abbreviated function templates in ``extern "C"``. (#GH46386)
297+
- Fixes matching of nested template template parameters. (#GH130362)
298+
- Correctly diagnoses template template paramters which have a pack parameter
299+
not in the last position.
297300

298301
Improvements to C++ diagnostics
299302
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Sema/Sema.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11363,14 +11363,16 @@ class Sema final : public SemaBase {
1136311363

1136411364
/// The context in which we are checking a template parameter list.
1136511365
enum TemplateParamListContext {
11366-
TPC_ClassTemplate,
11367-
TPC_VarTemplate,
11366+
// For this context, Class, Variable, TypeAlias, and non-pack Template
11367+
// Template Parameters are the same.
11368+
TPC_Other,
11369+
1136811370
TPC_FunctionTemplate,
1136911371
TPC_ClassTemplateMember,
1137011372
TPC_FriendClassTemplate,
1137111373
TPC_FriendFunctionTemplate,
1137211374
TPC_FriendFunctionTemplateDefinition,
11373-
TPC_TypeAliasTemplate
11375+
TPC_TemplateTemplateParameterPack,
1137411376
};
1137511377

1137611378
/// Checks the validity of a template parameter list, possibly

clang/lib/Sema/SemaDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8165,7 +8165,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
81658165
(D.getCXXScopeSpec().isSet() && DC && DC->isRecord() &&
81668166
DC->isDependentContext())
81678167
? TPC_ClassTemplateMember
8168-
: TPC_VarTemplate))
8168+
: TPC_Other))
81698169
NewVD->setInvalidDecl();
81708170

81718171
// If we are providing an explicit specialization of a static variable

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13586,7 +13586,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
1358613586
// Merge any previous default template arguments into our parameters,
1358713587
// and check the parameter list.
1358813588
if (CheckTemplateParameterList(TemplateParams, OldTemplateParams,
13589-
TPC_TypeAliasTemplate))
13589+
TPC_Other))
1359013590
return nullptr;
1359113591

1359213592
TypeAliasTemplateDecl *NewDecl =

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,8 +1593,16 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(
15931593
assert(S->isTemplateParamScope() &&
15941594
"Template template parameter not in template parameter scope!");
15951595

1596-
// Construct the parameter object.
15971596
bool IsParameterPack = EllipsisLoc.isValid();
1597+
1598+
bool Invalid = false;
1599+
if (CheckTemplateParameterList(
1600+
Params,
1601+
/*OldParams=*/nullptr,
1602+
IsParameterPack ? TPC_TemplateTemplateParameterPack : TPC_Other))
1603+
Invalid = true;
1604+
1605+
// Construct the parameter object.
15981606
TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(
15991607
Context, Context.getTranslationUnitDecl(),
16001608
NameLoc.isInvalid() ? TmpLoc : NameLoc, Depth, Position, IsParameterPack,
@@ -1617,9 +1625,12 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(
16171625
if (Params->size() == 0) {
16181626
Diag(Param->getLocation(), diag::err_template_template_parm_no_parms)
16191627
<< SourceRange(Params->getLAngleLoc(), Params->getRAngleLoc());
1620-
Param->setInvalidDecl();
1628+
Invalid = true;
16211629
}
16221630

1631+
if (Invalid)
1632+
Param->setInvalidDecl();
1633+
16231634
// C++0x [temp.param]p9:
16241635
// A default template-argument may be specified for any kind of
16251636
// template-parameter that is not a template parameter pack.
@@ -2068,7 +2079,7 @@ DeclResult Sema::CheckClassTemplate(
20682079
SemanticContext->isDependentContext())
20692080
? TPC_ClassTemplateMember
20702081
: TUK == TagUseKind::Friend ? TPC_FriendClassTemplate
2071-
: TPC_ClassTemplate,
2082+
: TPC_Other,
20722083
SkipBody))
20732084
Invalid = true;
20742085

@@ -2210,9 +2221,8 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
22102221
SourceLocation ParamLoc,
22112222
SourceRange DefArgRange) {
22122223
switch (TPC) {
2213-
case Sema::TPC_ClassTemplate:
2214-
case Sema::TPC_VarTemplate:
2215-
case Sema::TPC_TypeAliasTemplate:
2224+
case Sema::TPC_Other:
2225+
case Sema::TPC_TemplateTemplateParameterPack:
22162226
return false;
22172227

22182228
case Sema::TPC_FunctionTemplate:
@@ -2385,8 +2395,11 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
23852395
MissingDefaultArg = true;
23862396
} else if (NonTypeTemplateParmDecl *NewNonTypeParm
23872397
= dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
2388-
// Check for unexpanded parameter packs.
2389-
if (!NewNonTypeParm->isParameterPack() &&
2398+
// Check for unexpanded parameter packs, except in a template template
2399+
// parameter pack, as in those any unexpanded packs should be expanded
2400+
// along with the parameter itself.
2401+
if (TPC != TPC_TemplateTemplateParameterPack &&
2402+
!NewNonTypeParm->isParameterPack() &&
23902403
DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(),
23912404
NewNonTypeParm->getTypeSourceInfo(),
23922405
UPPC_NonTypeTemplateParameterType)) {
@@ -2494,8 +2507,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
24942507
// If a template parameter of a primary class template or alias template
24952508
// is a template parameter pack, it shall be the last template parameter.
24962509
if (SawParameterPack && (NewParam + 1) != NewParamEnd &&
2497-
(TPC == TPC_ClassTemplate || TPC == TPC_VarTemplate ||
2498-
TPC == TPC_TypeAliasTemplate)) {
2510+
(TPC == TPC_Other || TPC == TPC_TemplateTemplateParameterPack)) {
24992511
Diag((*NewParam)->getLocation(),
25002512
diag::err_template_param_pack_must_be_last_template_parameter);
25012513
Invalid = true;
@@ -2528,8 +2540,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
25282540
<< PrevModuleName;
25292541
Invalid = true;
25302542
} else if (MissingDefaultArg &&
2531-
(TPC == TPC_ClassTemplate || TPC == TPC_FriendClassTemplate ||
2532-
TPC == TPC_VarTemplate || TPC == TPC_TypeAliasTemplate)) {
2543+
(TPC == TPC_Other || TPC == TPC_TemplateTemplateParameterPack ||
2544+
TPC == TPC_FriendClassTemplate)) {
25332545
// C++ 23[temp.param]p14:
25342546
// If a template-parameter of a class template, variable template, or
25352547
// alias template has a default template argument, each subsequent

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3427,9 +3427,9 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction(
34273427
if (!P.isPackExpansion() && !A.isPackExpansion()) {
34283428
Info.Param =
34293429
makeTemplateParameter(Template->getTemplateParameters()->getParam(
3430-
(PsStack.empty() ? TemplateArgs.end()
3431-
: PsStack.front().begin()) -
3432-
TemplateArgs.begin()));
3430+
(AsStack.empty() ? CTAI.CanonicalConverted.end()
3431+
: AsStack.front().begin()) -
3432+
1 - CTAI.CanonicalConverted.begin()));
34333433
Info.FirstArg = P;
34343434
Info.SecondArg = A;
34353435
return TemplateDeductionResult::NonDeducedMismatch;
@@ -6642,17 +6642,19 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
66426642

66436643
TemplateDeductionResult TDK;
66446644
runWithSufficientStackSpace(Info.getLocation(), [&] {
6645-
TDK = ::FinishTemplateArgumentDeduction(
6646-
*this, AArg, /*IsPartialOrdering=*/true, PArgs, Deduced, Info);
6645+
TDK = ::FinishTemplateArgumentDeduction(*this, AArg, PartialOrdering, PArgs,
6646+
Deduced, Info);
66476647
});
66486648
switch (TDK) {
66496649
case TemplateDeductionResult::Success:
66506650
return true;
66516651

66526652
// It doesn't seem possible to get a non-deduced mismatch when partial
6653-
// ordering TTPs.
6653+
// ordering TTPs, except with an invalid template parameter list which has
6654+
// a parameter after a pack.
66546655
case TemplateDeductionResult::NonDeducedMismatch:
6655-
llvm_unreachable("Unexpected NonDeducedMismatch");
6656+
assert(PArg->isInvalidDecl() && "Unexpected NonDeducedMismatch");
6657+
return false;
66566658

66576659
// Substitution failures should have already been diagnosed.
66586660
case TemplateDeductionResult::AlreadyDiagnosed:

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2176,7 +2176,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
21762176
// Do some additional validation, then merge default arguments
21772177
// from the existing declarations.
21782178
if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams,
2179-
Sema::TPC_ClassTemplate))
2179+
Sema::TPC_Other))
21802180
return nullptr;
21812181

21822182
Inst->setAccess(PrevClassTemplate->getAccess());

clang/test/SemaTemplate/cwg2398.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,11 @@ namespace regression3 {
602602
template <class...> class B {};
603603
template struct A<B, Node<None>>;
604604
} // namespace regression3
605+
namespace regression4 {
606+
template <template <template <class... T1> class TT1> class TT2> struct A {};
607+
template <template <class U1> class UU1> struct B {};
608+
template struct A<B>;
609+
} // namespace regression4
605610

606611
namespace nttp_auto {
607612
namespace t1 {
@@ -610,24 +615,16 @@ namespace nttp_auto {
610615
template struct A<B>;
611616
} // namespace t1
612617
namespace t2 {
613-
// FIXME: Shouldn't accept parameters after a parameter pack.
614618
template<template<auto... Va1, auto Va2> class> struct A {};
615-
// expected-error@-1 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('auto' vs 'int')}}
616-
// expected-note@-2 {{template parameter is declared here}}
619+
// expected-error@-1 {{template parameter pack must be the last template parameter}}
617620
template<int... Vi> struct B;
618-
// expected-note@-1 {{template parameter is declared here}}
619621
template struct A<B>;
620-
// expected-note@-1 {{template template argument is incompatible}}
621622
} // namespace t2
622623
namespace t3 {
623-
// FIXME: Shouldn't accept parameters after a parameter pack.
624624
template<template<auto... Va1, auto... Va2> class> struct A {};
625-
// expected-error@-1 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('auto' vs 'int')}}
626-
// expected-note@-2 {{template parameter is declared here}}
625+
// expected-error@-1 {{template parameter pack must be the last template parameter}}
627626
template<int... Vi> struct B;
628-
// expected-note@-1 {{template parameter is declared here}}
629627
template struct A<B>;
630-
// expected-note@-1 {{template template argument is incompatible}}
631628
} // namespace t3
632629
} // namespace nttp_auto
633630

clang/test/SemaTemplate/temp_arg_template_p0522.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
template<template<int> typename> struct Ti; // #Ti
66
template<template<int...> typename> struct TPi; // #TPi
77
template<template<int, int...> typename> struct TiPi;
8-
template<template<int..., int...> typename> struct TPiPi; // FIXME: Why is this not ill-formed?
8+
template<template<int..., int...> typename> struct TPiPi;
9+
// expected-error@-1 {{template parameter pack must be the last template parameter}}
910

1011
template<typename T, template<T> typename> struct tT0; // #tT0
1112
template<template<typename T, T> typename> struct Tt0; // #Tt0

clang/unittests/AST/DeclPrinterTest.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,21 +1196,21 @@ TEST(DeclPrinter, TestUnnamedTemplateParameters) {
11961196
}
11971197

11981198
TEST(DeclPrinter, TestUnnamedTemplateParametersPacks) {
1199-
ASSERT_TRUE(PrintedDeclCXX17Matches(
1200-
"template <typename ..., int ...,"
1201-
" template <typename ..., bool ...> class ...> void A();",
1202-
functionTemplateDecl(hasName("A")).bind("id"),
1203-
"template <typename ..., int ...,"
1204-
" template <typename ..., bool ...> class ...> void A()"));
1199+
ASSERT_TRUE(
1200+
PrintedDeclCXX17Matches("template <typename ..., int ...,"
1201+
" template <typename ...> class ...> void A();",
1202+
functionTemplateDecl(hasName("A")).bind("id"),
1203+
"template <typename ..., int ...,"
1204+
" template <typename ...> class ...> void A()"));
12051205
}
12061206

12071207
TEST(DeclPrinter, TestNamedTemplateParametersPacks) {
12081208
ASSERT_TRUE(PrintedDeclCXX17Matches(
12091209
"template <typename ...T, int ...I,"
1210-
" template <typename ...X, bool ...B> class ...Z> void A();",
1210+
" template <typename ...X> class ...Z> void A();",
12111211
functionTemplateDecl(hasName("A")).bind("id"),
12121212
"template <typename ...T, int ...I,"
1213-
" template <typename ...X, bool ...B> class ...Z> void A()"));
1213+
" template <typename ...X> class ...Z> void A()"));
12141214
}
12151215

12161216
TEST(DeclPrinter, TestTemplateTemplateParameterWrittenWithTypename) {

0 commit comments

Comments
 (0)