diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-01-13 00:08:50 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-01-13 00:08:50 +0000 |
commit | a03478231363c67ea0e1f4bc1bc708e064040e56 (patch) | |
tree | 8a84ca83949cc6c9d9f63f0a8c33ac1c721305c2 /lib/Sema/SemaTemplate.cpp | |
parent | 2dea7c7c23b37508976b90b871390450b9c8bc3b (diff) |
Implement C++0x [temp.arg.template]p3, which allows slightly fuzzy
matching of variadic template template parameters to template
arguments. This paragraph was the subject of ISO C++ committee
document N2555: Extending Variadic Template Template Parameters.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123348 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 99 |
1 files changed, 76 insertions, 23 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 8d0462daad..08384ccef5 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3651,7 +3651,12 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, } // Check that both are parameter packs are neither are parameter packs. - if (Old->isTemplateParameterPack() != New->isTemplateParameterPack()) { + // However, if we are matching a template template argument to a + // template template parameter, the template template parameter can have + // a parameter pack where the template template argument does not. + if (Old->isTemplateParameterPack() != New->isTemplateParameterPack() && + !(Kind == Sema::TPL_TemplateTemplateArgumentMatch && + Old->isTemplateParameterPack())) { if (Complain) { unsigned NextDiag = diag::err_template_parameter_pack_non_pack; if (TemplateArgLoc.isValid()) { @@ -3726,6 +3731,28 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, return true; } +/// \brief Diagnose a known arity mismatch when comparing template argument +/// lists. +static +void DiagnoseTemplateParameterListArityMismatch(Sema &S, + TemplateParameterList *New, + TemplateParameterList *Old, + Sema::TemplateParameterListEqualKind Kind, + SourceLocation TemplateArgLoc) { + unsigned NextDiag = diag::err_template_param_list_different_arity; + if (TemplateArgLoc.isValid()) { + S.Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_param_list_different_arity; + } + S.Diag(New->getTemplateLoc(), NextDiag) + << (New->size() > Old->size()) + << (Kind != Sema::TPL_TemplateMatch) + << SourceRange(New->getTemplateLoc(), New->getRAngleLoc()); + S.Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration) + << (Kind != Sema::TPL_TemplateMatch) + << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc()); +} + /// \brief Determine whether the given template parameter lists are /// equivalent. /// @@ -3755,21 +3782,10 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, bool Complain, TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) { - if (Old->size() != New->size()) { - if (Complain) { - unsigned NextDiag = diag::err_template_param_list_different_arity; - if (TemplateArgLoc.isValid()) { - Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); - NextDiag = diag::note_template_param_list_different_arity; - } - Diag(New->getTemplateLoc(), NextDiag) - << (New->size() > Old->size()) - << (Kind != TPL_TemplateMatch) - << SourceRange(New->getTemplateLoc(), New->getRAngleLoc()); - Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration) - << (Kind != TPL_TemplateMatch) - << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc()); - } + if (Old->size() != New->size() && Kind != TPL_TemplateTemplateArgumentMatch) { + if (Complain) + DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind, + TemplateArgLoc); return false; } @@ -3779,15 +3795,52 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, // when each of the template parameters in the template-parameter-list of // the template-argument’s corresponding class template or template alias // (call it A) matches the corresponding template parameter in the - // template-parameter-list of P. + // template-parameter-list of P. [...] + TemplateParameterList::iterator NewParm = New->begin(); + TemplateParameterList::iterator NewParmEnd = New->end(); for (TemplateParameterList::iterator OldParm = Old->begin(), - OldParmEnd = Old->end(), NewParm = New->begin(); - OldParm != OldParmEnd; ++OldParm, ++NewParm) { - if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain, - Kind, TemplateArgLoc)) - return false; + OldParmEnd = Old->end(); + OldParm != OldParmEnd; ++OldParm) { + if (!(*OldParm)->isTemplateParameterPack()) { + if (NewParm == NewParmEnd) { + if (Complain) + DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind, + TemplateArgLoc); + + return false; + } + + if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain, + Kind, TemplateArgLoc)) + return false; + + ++NewParm; + continue; + } + + // C++0x [temp.arg.template]p3: + // [...] When P’s template- parameter-list contains a template parameter + // pack (14.5.3), the template parameter pack will match zero or more + // template parameters or template parameter packs in the + // template-parameter-list of A with the same type and form as the + // template parameter pack in P (ignoring whether those template + // parameters are template parameter packs). + for (; NewParm != NewParmEnd; ++NewParm) { + if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain, + Kind, TemplateArgLoc)) + return false; + } } - + + // Make sure we exhausted all of the arguments. + if (NewParm != NewParmEnd) { + if (Complain) + DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind, + TemplateArgLoc); + + return false; + } + return true; } |