diff options
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 239 |
1 files changed, 106 insertions, 133 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 0a319b17f6..8d0462daad 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3628,6 +3628,103 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, return Owned(E); } +/// \brief Match two template parameters within template parameter lists. +static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, + bool Complain, + Sema::TemplateParameterListEqualKind Kind, + SourceLocation TemplateArgLoc) { + // Check the actual kind (type, non-type, template). + if (Old->getKind() != New->getKind()) { + if (Complain) { + unsigned NextDiag = diag::err_template_param_different_kind; + if (TemplateArgLoc.isValid()) { + S.Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_param_different_kind; + } + S.Diag(New->getLocation(), NextDiag) + << (Kind != Sema::TPL_TemplateMatch); + S.Diag(Old->getLocation(), diag::note_template_prev_declaration) + << (Kind != Sema::TPL_TemplateMatch); + } + + return false; + } + + // Check that both are parameter packs are neither are parameter packs. + if (Old->isTemplateParameterPack() != New->isTemplateParameterPack()) { + if (Complain) { + unsigned NextDiag = diag::err_template_parameter_pack_non_pack; + if (TemplateArgLoc.isValid()) { + S.Diag(TemplateArgLoc, + diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_parameter_pack_non_pack; + } + + unsigned ParamKind = isa<TemplateTypeParmDecl>(New)? 0 + : isa<NonTypeTemplateParmDecl>(New)? 1 + : 2; + S.Diag(New->getLocation(), NextDiag) + << ParamKind << New->isParameterPack(); + S.Diag(Old->getLocation(), diag::note_template_parameter_pack_here) + << ParamKind << Old->isParameterPack(); + } + + return false; + } + + // For non-type template parameters, check the type of the parameter. + if (NonTypeTemplateParmDecl *OldNTTP + = dyn_cast<NonTypeTemplateParmDecl>(Old)) { + NonTypeTemplateParmDecl *NewNTTP = cast<NonTypeTemplateParmDecl>(New); + + // If we are matching a template template argument to a template + // template parameter and one of the non-type template parameter types + // is dependent, then we must wait until template instantiation time + // to actually compare the arguments. + if (Kind == Sema::TPL_TemplateTemplateArgumentMatch && + (OldNTTP->getType()->isDependentType() || + NewNTTP->getType()->isDependentType())) + return true; + + if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) { + if (Complain) { + unsigned NextDiag = diag::err_template_nontype_parm_different_type; + if (TemplateArgLoc.isValid()) { + S.Diag(TemplateArgLoc, + diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_nontype_parm_different_type; + } + S.Diag(NewNTTP->getLocation(), NextDiag) + << NewNTTP->getType() + << (Kind != Sema::TPL_TemplateMatch); + S.Diag(OldNTTP->getLocation(), + diag::note_template_nontype_parm_prev_declaration) + << OldNTTP->getType(); + } + + return false; + } + + return true; + } + + // For template template parameters, check the template parameter types. + // The template parameter lists of template template + // parameters must agree. + if (TemplateTemplateParmDecl *OldTTP + = dyn_cast<TemplateTemplateParmDecl>(Old)) { + TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New); + return S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), + OldTTP->getTemplateParameters(), + Complain, + (Kind == Sema::TPL_TemplateMatch + ? Sema::TPL_TemplateTemplateParmMatch + : Kind), + TemplateArgLoc); + } + + return true; +} /// \brief Determine whether the given template parameter lists are /// equivalent. @@ -3677,142 +3774,18 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, return false; } + // C++0x [temp.arg.template]p3: + // A template-argument matches a template template-parameter (call it P) + // 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. for (TemplateParameterList::iterator OldParm = Old->begin(), OldParmEnd = Old->end(), NewParm = New->begin(); OldParm != OldParmEnd; ++OldParm, ++NewParm) { - if ((*OldParm)->getKind() != (*NewParm)->getKind()) { - if (Complain) { - unsigned NextDiag = diag::err_template_param_different_kind; - if (TemplateArgLoc.isValid()) { - Diag(TemplateArgLoc, diag::err_template_arg_template_params_mismatch); - NextDiag = diag::note_template_param_different_kind; - } - Diag((*NewParm)->getLocation(), NextDiag) - << (Kind != TPL_TemplateMatch); - Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration) - << (Kind != TPL_TemplateMatch); - } - return false; - } - - if (TemplateTypeParmDecl *OldTTP - = dyn_cast<TemplateTypeParmDecl>(*OldParm)) { - // Template type parameters are equivalent if either both are template - // type parameter packs or neither are (since we know we're at the same - // index). - TemplateTypeParmDecl *NewTTP = cast<TemplateTypeParmDecl>(*NewParm); - if (OldTTP->isParameterPack() != NewTTP->isParameterPack()) { - // FIXME: Implement the rules in C++0x [temp.arg.template]p5 that - // allow one to match a template parameter pack in the template - // parameter list of a template template parameter to one or more - // template parameters in the template parameter list of the - // corresponding template template argument. - if (Complain) { - unsigned NextDiag = diag::err_template_parameter_pack_non_pack; - if (TemplateArgLoc.isValid()) { - Diag(TemplateArgLoc, - diag::err_template_arg_template_params_mismatch); - NextDiag = diag::note_template_parameter_pack_non_pack; - } - Diag(NewTTP->getLocation(), NextDiag) - << 0 << NewTTP->isParameterPack(); - Diag(OldTTP->getLocation(), diag::note_template_parameter_pack_here) - << 0 << OldTTP->isParameterPack(); - } - return false; - } - } else if (NonTypeTemplateParmDecl *OldNTTP - = dyn_cast<NonTypeTemplateParmDecl>(*OldParm)) { - // The types of non-type template parameters must agree. - NonTypeTemplateParmDecl *NewNTTP - = cast<NonTypeTemplateParmDecl>(*NewParm); - - if (OldNTTP->isParameterPack() != NewNTTP->isParameterPack()) { - // FIXME: Implement the rules in C++0x [temp.arg.template]p5 that - // allow one to match a template parameter pack in the template - // parameter list of a template template parameter to one or more - // template parameters in the template parameter list of the - // corresponding template template argument. - if (Complain) { - unsigned NextDiag = diag::err_template_parameter_pack_non_pack; - if (TemplateArgLoc.isValid()) { - Diag(TemplateArgLoc, - diag::err_template_arg_template_params_mismatch); - NextDiag = diag::note_template_parameter_pack_non_pack; - } - Diag(NewNTTP->getLocation(), NextDiag) - << 1 << NewNTTP->isParameterPack(); - Diag(OldNTTP->getLocation(), diag::note_template_parameter_pack_here) - << 1 << OldNTTP->isParameterPack(); - } - return false; - } - - // If we are matching a template template argument to a template - // template parameter and one of the non-type template parameter types - // is dependent, then we must wait until template instantiation time - // to actually compare the arguments. - if (Kind == TPL_TemplateTemplateArgumentMatch && - (OldNTTP->getType()->isDependentType() || - NewNTTP->getType()->isDependentType())) - continue; - - if (Context.getCanonicalType(OldNTTP->getType()) != - Context.getCanonicalType(NewNTTP->getType())) { - if (Complain) { - unsigned NextDiag = diag::err_template_nontype_parm_different_type; - if (TemplateArgLoc.isValid()) { - Diag(TemplateArgLoc, - diag::err_template_arg_template_params_mismatch); - NextDiag = diag::note_template_nontype_parm_different_type; - } - Diag(NewNTTP->getLocation(), NextDiag) - << NewNTTP->getType() - << (Kind != TPL_TemplateMatch); - Diag(OldNTTP->getLocation(), - diag::note_template_nontype_parm_prev_declaration) - << OldNTTP->getType(); - } - return false; - } - } else { - // The template parameter lists of template template - // parameters must agree. - assert(isa<TemplateTemplateParmDecl>(*OldParm) && - "Only template template parameters handled here"); - TemplateTemplateParmDecl *OldTTP - = cast<TemplateTemplateParmDecl>(*OldParm); - TemplateTemplateParmDecl *NewTTP - = cast<TemplateTemplateParmDecl>(*NewParm); - - if (OldTTP->isParameterPack() != NewTTP->isParameterPack()) { - // FIXME: Implement the rules in C++0x [temp.arg.template]p5 that - // allow one to match a template parameter pack in the template - // parameter list of a template template parameter to one or more - // template parameters in the template parameter list of the - // corresponding template template argument. - if (Complain) { - unsigned NextDiag = diag::err_template_parameter_pack_non_pack; - if (TemplateArgLoc.isValid()) { - Diag(TemplateArgLoc, - diag::err_template_arg_template_params_mismatch); - NextDiag = diag::note_template_parameter_pack_non_pack; - } - Diag(NewTTP->getLocation(), NextDiag) - << 2 << NewTTP->isParameterPack(); - Diag(OldTTP->getLocation(), diag::note_template_parameter_pack_here) - << 2 << OldTTP->isParameterPack(); - } - return false; - } - - if (!TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), - OldTTP->getTemplateParameters(), - Complain, - (Kind == TPL_TemplateMatch? TPL_TemplateTemplateParmMatch : Kind), - TemplateArgLoc)) - return false; - } + if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain, + Kind, TemplateArgLoc)) + return false; } return true; |