From 19ac2d6494621c6b574a72f1735011c72be1d961 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 12 Nov 2009 16:20:59 +0000 Subject: [PATCH] When comparing template parameter lists, distinguish between three cases: - Comparing template parameter lists to determine if we have a redeclaration - Comparing template parameter lists to determine if we have equivalent template template parameters - Comparing template parameter lists to determine whether a template template argument is valid for a given template template parameter. Previously, we did not distinguish between the last two cases, which got us into trouble when we were looking for exact type matches between the types of non-type template parameters that were dependent types. Now we do, so we properly delay checking of template template arguments until instantiation time. Also, fix an accidental fall-through in a case statement that was causing crashes. llvm-svn: 86992 --- clang/lib/AST/TypePrinter.cpp | 1 + clang/lib/Sema/Sema.h | 37 ++++++++++++++++++- clang/lib/Sema/SemaOverload.cpp | 2 +- clang/lib/Sema/SemaTemplate.cpp | 36 +++++++++++------- .../instantiate-template-template-parm.cpp | 15 +++++++- 5 files changed, 75 insertions(+), 16 deletions(-) diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index ed1200621187..234d38a59ffb 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -579,6 +579,7 @@ static void PrintTemplateArgument(std::string &Buffer, case TemplateArgument::Template: { llvm::raw_string_ostream s(Buffer); Arg.getAsTemplate().print(s, Policy); + break; } case TemplateArgument::Integral: diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 30c337dff8fa..2557dfeb8973 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2621,10 +2621,45 @@ public: TemplateArgument &Converted); bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, const TemplateArgumentLoc &Arg); + + /// \brief Enumeration describing how template parameter lists are compared + /// for equality. + enum TemplateParameterListEqualKind { + /// \brief We are matching the template parameter lists of two templates + /// that might be redeclarations. + /// + /// \code + /// template struct X; + /// template struct X; + /// \endcode + TPL_TemplateMatch, + + /// \brief We are matching the template parameter lists of two template + /// template parameters as part of matching the template parameter lists + /// of two templates that might be redeclarations. + /// + /// \code + /// template class TT> struct X; + /// template class Other> struct X; + /// \endcode + TPL_TemplateTemplateParmMatch, + + /// \brief We are matching the template parameter lists of a template + /// template argument against the template parameter lists of a template + /// template parameter. + /// + /// \code + /// template class Metafun> struct X; + /// template struct integer_c; + /// X xic; + /// \endcode + TPL_TemplateTemplateArgumentMatch + }; + bool TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, bool Complain, - bool IsTemplateTemplateParm = false, + TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc = SourceLocation()); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 69e5a5230706..3f3627d59002 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -350,7 +350,7 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD, if (NewTemplate && (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), OldTemplate->getTemplateParameters(), - false, false, SourceLocation()) || + false, TPL_TemplateMatch) || OldType->getResultType() != NewType->getResultType())) return true; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 419347adcf6a..af7634ae86aa 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -706,7 +706,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // Ensure that the template parameter lists are compatible. if (!TemplateParameterListsAreEqual(TemplateParams, PrevClassTemplate->getTemplateParameters(), - /*Complain=*/true)) + /*Complain=*/true, + TPL_TemplateMatch)) return true; // C++ [temp.class]p4: @@ -1124,7 +1125,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, if (ExpectedTemplateParams) TemplateParameterListsAreEqual(ParamLists[Idx], ExpectedTemplateParams, - true); + true, TPL_TemplateMatch); } } else if (ParamLists[Idx]->size() > 0) Diag(ParamLists[Idx]->getTemplateLoc(), @@ -2511,7 +2512,8 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), Param->getTemplateParameters(), - true, true, + true, + TPL_TemplateTemplateArgumentMatch, Arg.getLocation()); } @@ -2528,9 +2530,7 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, /// \param Complain If true, this routine will produce a diagnostic if /// the template parameter lists are not equivalent. /// -/// \param IsTemplateTemplateParm If true, this routine is being -/// called to compare the template parameter lists of a template -/// template parameter. +/// \param Kind describes how we are to match the template parameter lists. /// /// \param TemplateArgLoc If this source location is valid, then we /// are actually checking the template parameter list of a template @@ -2544,7 +2544,7 @@ bool Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, bool Complain, - bool IsTemplateTemplateParm, + TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) { if (Old->size() != New->size()) { if (Complain) { @@ -2555,10 +2555,10 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, } Diag(New->getTemplateLoc(), NextDiag) << (New->size() > Old->size()) - << IsTemplateTemplateParm + << (Kind != TPL_TemplateMatch) << SourceRange(New->getTemplateLoc(), New->getRAngleLoc()); Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration) - << IsTemplateTemplateParm + << (Kind != TPL_TemplateMatch) << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc()); } @@ -2576,9 +2576,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, NextDiag = diag::note_template_param_different_kind; } Diag((*NewParm)->getLocation(), NextDiag) - << IsTemplateTemplateParm; + << (Kind != TPL_TemplateMatch); Diag((*OldParm)->getLocation(), diag::note_template_prev_declaration) - << IsTemplateTemplateParm; + << (Kind != TPL_TemplateMatch); } return false; } @@ -2591,6 +2591,16 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, // The types of non-type template parameters must agree. NonTypeTemplateParmDecl *NewNTTP = cast(*NewParm); + + // 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) { @@ -2602,7 +2612,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, } Diag(NewNTTP->getLocation(), NextDiag) << NewNTTP->getType() - << IsTemplateTemplateParm; + << (Kind != TPL_TemplateMatch); Diag(OldNTTP->getLocation(), diag::note_template_nontype_parm_prev_declaration) << OldNTTP->getType(); @@ -2621,7 +2631,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, if (!TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), OldTTP->getTemplateParameters(), Complain, - /*IsTemplateTemplateParm=*/true, + (Kind == TPL_TemplateMatch? TPL_TemplateTemplateParmMatch : Kind), TemplateArgLoc)) return false; } diff --git a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp index 00b2c0ecc2f2..30ba113e20d4 100644 --- a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp +++ b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -fsyntax-only -verify %s - template class MetaFun, typename Value> struct apply { typedef typename MetaFun::type type; @@ -31,3 +30,17 @@ struct X0 { }; X0 x0b1; X0 x0b2; // expected-note{{while substituting}} X0 x0b3; // expected-error{{template template argument has different template parameters}} + +template class TT> // expected-note{{parameter with type 'int'}} +struct X1 { }; + +template class TT> +struct X2 { + X1 x1; // expected-error{{has different template parameters}} +}; + +template struct X3i { }; +template struct X3l { }; // expected-note{{different type 'long'}} + +X2 x2okay; +X2 x2bad; // expected-note{{instantiation}}