Skip to content

Commit 2ba33cb

Browse files
changpengmizvekov
andauthored
[clang] fix matching of nested template template parameters (llvm#130447) (llvm#2913)
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 llvm#130362 Cherry-pick to mainline to fix: SWDEV-540630 --------- Co-authored-by: Matheus Izvekov <[email protected]>
1 parent 3987e44 commit 2ba33cb

File tree

10 files changed

+59
-46
lines changed

10 files changed

+59
-46
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,9 @@ Bug Fixes to C++ Support
10781078
template parameter. Now, such expression can be used with ``static_assert`` and ``constexpr``. (#GH123498)
10791079
- Correctly determine the implicit constexprness of lambdas in dependent contexts. (#GH97958) (#GH114234)
10801080
- Fix that some dependent immediate expressions did not cause immediate escalation (#GH119046)
1081+
- Fixes matching of nested template template parameters. (#GH130362)
1082+
- Correctly diagnoses template template paramters which have a pack parameter
1083+
not in the last position.
10811084

10821085
Bug Fixes to AST Handling
10831086
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Sema/Sema.h

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

1128111281
/// The context in which we are checking a template parameter list.
1128211282
enum TemplateParamListContext {
11283-
TPC_ClassTemplate,
11284-
TPC_VarTemplate,
11283+
// For this context, Class, Variable, TypeAlias, and non-pack Template
11284+
// Template Parameters are treated uniformly.
11285+
TPC_Other,
11286+
1128511287
TPC_FunctionTemplate,
1128611288
TPC_ClassTemplateMember,
1128711289
TPC_FriendClassTemplate,
1128811290
TPC_FriendFunctionTemplate,
1128911291
TPC_FriendFunctionTemplateDefinition,
11290-
TPC_TypeAliasTemplate
11292+
TPC_TemplateTemplateParameterPack,
1129111293
};
1129211294

1129311295
/// 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
@@ -8141,7 +8141,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
81418141
(D.getCXXScopeSpec().isSet() && DC && DC->isRecord() &&
81428142
DC->isDependentContext())
81438143
? TPC_ClassTemplateMember
8144-
: TPC_VarTemplate))
8144+
: TPC_Other))
81458145
NewVD->setInvalidDecl();
81468146

81478147
// 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
@@ -13533,7 +13533,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
1353313533
// Merge any previous default template arguments into our parameters,
1353413534
// and check the parameter list.
1353513535
if (CheckTemplateParameterList(TemplateParams, OldTemplateParams,
13536-
TPC_TypeAliasTemplate))
13536+
TPC_Other))
1353713537
return nullptr;
1353813538

1353913539
TypeAliasTemplateDecl *NewDecl =

clang/lib/Sema/SemaTemplate.cpp

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

1594-
// Construct the parameter object.
15951594
bool IsParameterPack = EllipsisLoc.isValid();
1595+
1596+
bool Invalid = false;
1597+
if (CheckTemplateParameterList(
1598+
Params,
1599+
/*OldParams=*/nullptr,
1600+
IsParameterPack ? TPC_TemplateTemplateParameterPack : TPC_Other))
1601+
Invalid = true;
1602+
1603+
// Construct the parameter object.
15961604
TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(
15971605
Context, Context.getTranslationUnitDecl(),
15981606
NameLoc.isInvalid() ? TmpLoc : NameLoc, Depth, Position, IsParameterPack,
@@ -1615,9 +1623,12 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(
16151623
if (Params->size() == 0) {
16161624
Diag(Param->getLocation(), diag::err_template_template_parm_no_parms)
16171625
<< SourceRange(Params->getLAngleLoc(), Params->getRAngleLoc());
1618-
Param->setInvalidDecl();
1626+
Invalid = true;
16191627
}
16201628

1629+
if (Invalid)
1630+
Param->setInvalidDecl();
1631+
16211632
// C++0x [temp.param]p9:
16221633
// A default template-argument may be specified for any kind of
16231634
// template-parameter that is not a template parameter pack.
@@ -2066,7 +2077,7 @@ DeclResult Sema::CheckClassTemplate(
20662077
SemanticContext->isDependentContext())
20672078
? TPC_ClassTemplateMember
20682079
: TUK == TagUseKind::Friend ? TPC_FriendClassTemplate
2069-
: TPC_ClassTemplate,
2080+
: TPC_Other,
20702081
SkipBody))
20712082
Invalid = true;
20722083

@@ -2208,9 +2219,8 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
22082219
SourceLocation ParamLoc,
22092220
SourceRange DefArgRange) {
22102221
switch (TPC) {
2211-
case Sema::TPC_ClassTemplate:
2212-
case Sema::TPC_VarTemplate:
2213-
case Sema::TPC_TypeAliasTemplate:
2222+
case Sema::TPC_Other:
2223+
case Sema::TPC_TemplateTemplateParameterPack:
22142224
return false;
22152225

22162226
case Sema::TPC_FunctionTemplate:
@@ -2383,8 +2393,11 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
23832393
MissingDefaultArg = true;
23842394
} else if (NonTypeTemplateParmDecl *NewNonTypeParm
23852395
= dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
2386-
// Check for unexpanded parameter packs.
2387-
if (!NewNonTypeParm->isParameterPack() &&
2396+
// Check for unexpanded parameter packs, except in a template template
2397+
// parameter pack, as in those any unexpanded packs should be expanded
2398+
// along with the parameter itself.
2399+
if (TPC != TPC_TemplateTemplateParameterPack &&
2400+
!NewNonTypeParm->isParameterPack() &&
23882401
DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(),
23892402
NewNonTypeParm->getTypeSourceInfo(),
23902403
UPPC_NonTypeTemplateParameterType)) {
@@ -2492,8 +2505,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
24922505
// If a template parameter of a primary class template or alias template
24932506
// is a template parameter pack, it shall be the last template parameter.
24942507
if (SawParameterPack && (NewParam + 1) != NewParamEnd &&
2495-
(TPC == TPC_ClassTemplate || TPC == TPC_VarTemplate ||
2496-
TPC == TPC_TypeAliasTemplate)) {
2508+
(TPC == TPC_Other || TPC == TPC_TemplateTemplateParameterPack)) {
24972509
Diag((*NewParam)->getLocation(),
24982510
diag::err_template_param_pack_must_be_last_template_parameter);
24992511
Invalid = true;
@@ -2526,8 +2538,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
25262538
<< PrevModuleName;
25272539
Invalid = true;
25282540
} else if (MissingDefaultArg &&
2529-
(TPC == TPC_ClassTemplate || TPC == TPC_FriendClassTemplate ||
2530-
TPC == TPC_VarTemplate || TPC == TPC_TypeAliasTemplate)) {
2541+
(TPC == TPC_Other || TPC == TPC_TemplateTemplateParameterPack ||
2542+
TPC == TPC_FriendClassTemplate)) {
25312543
// C++ 23[temp.param]p14:
25322544
// If a template-parameter of a class template, variable template, or
25332545
// 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
@@ -3429,9 +3429,9 @@ static TemplateDeductionResult FinishTemplateArgumentDeduction(
34293429
if (!P.isPackExpansion() && !A.isPackExpansion()) {
34303430
Info.Param =
34313431
makeTemplateParameter(Template->getTemplateParameters()->getParam(
3432-
(PsStack.empty() ? TemplateArgs.end()
3433-
: PsStack.front().begin()) -
3434-
TemplateArgs.begin()));
3432+
(AsStack.empty() ? CTAI.CanonicalConverted.end()
3433+
: AsStack.front().begin()) -
3434+
1 - CTAI.CanonicalConverted.begin()));
34353435
Info.FirstArg = P;
34363436
Info.SecondArg = A;
34373437
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
@@ -1826,7 +1826,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
18261826
// Do some additional validation, then merge default arguments
18271827
// from the existing declarations.
18281828
if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams,
1829-
Sema::TPC_ClassTemplate))
1829+
Sema::TPC_Other))
18301830
return nullptr;
18311831

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

clang/test/SemaTemplate/cwg2398.cpp

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -638,26 +638,19 @@ namespace nttp_auto {
638638
template struct A<B>;
639639
} // namespace t1
640640
namespace t2 {
641-
// FIXME: Shouldn't accept parameters after a parameter pack.
642641
template<template<auto... Va1, auto Va2> class> struct A {};
643-
// new-error@-1 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('auto' vs 'int')}}
644-
// expected-note@-2 {{previous template template parameter is here}}
642+
// expected-error@-1 {{template parameter pack must be the last template parameter}}
643+
// old-note@-2 {{previous template template parameter is here}}
645644
template<int... Vi> struct B;
646-
// new-note@-1 {{template parameter is declared here}}
647-
// old-note@-2 {{too few template parameters}}
645+
// old-note@-1 {{too few template parameters}}
648646
template struct A<B>;
649-
// new-note@-1 {{different template parameters}}
650-
// old-error@-2 {{different template parameters}}
647+
// old-error@-1 {{different template parameters}}
651648
} // namespace t2
652649
namespace t3 {
653-
// FIXME: Shouldn't accept parameters after a parameter pack.
654650
template<template<auto... Va1, auto... Va2> class> struct A {};
655-
// new-error@-1 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('auto' vs 'int')}}
656-
// new-note@-2 {{previous template template parameter is here}}
651+
// expected-error@-1 {{template parameter pack must be the last template parameter}}
657652
template<int... Vi> struct B;
658-
// new-note@-1 {{template parameter is declared here}}
659653
template struct A<B>;
660-
// new-note@-1 {{different template parameters}}
661654
} // namespace t3
662655
} // namespace nttp_auto
663656

clang/test/SemaTemplate/temp_arg_template_p0522.cpp

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

1213
template<typename T, template<T> typename> struct tT0; // #tT0
1314
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)