From 3e1274f2b99cb99c03cc8e2c6517c37d330b597a Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 16 Jun 2010 21:09:37 +0000 Subject: [PATCH] Canonicalize template template parameters when canonicalizing a template name that refers to such a parameter. It's amazing that this problem didn't surface earlier. Fixes PR7387. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106147 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 22 ++++ lib/AST/ASTContext.cpp | 100 +++++++++++++++++- .../SemaTemplate/member-function-template.cpp | 16 +++ 3 files changed, 135 insertions(+), 3 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 9d0469368f..2778d46dd2 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -62,6 +62,7 @@ namespace clang { class RecordDecl; class StoredDeclsMap; class TagDecl; + class TemplateTemplateParmDecl; class TemplateTypeParmDecl; class TranslationUnitDecl; class TypeDecl; @@ -127,6 +128,27 @@ class ASTContext { /// \brief Mapping from ObjCContainers to their ObjCImplementations. llvm::DenseMap ObjCImpls; + /// \brief Representation of a "canonical" template template parameter that + /// is used in canonical template names. + class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode { + TemplateTemplateParmDecl *Parm; + + public: + CanonicalTemplateTemplateParm(TemplateTemplateParmDecl *Parm) + : Parm(Parm) { } + + TemplateTemplateParmDecl *getParam() const { return Parm; } + + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Parm); } + + static void Profile(llvm::FoldingSetNodeID &ID, + TemplateTemplateParmDecl *Parm); + }; + llvm::FoldingSet CanonTemplateTemplateParms; + + TemplateTemplateParmDecl *getCanonicalTemplateTemplateParmDecl( + TemplateTemplateParmDecl *TTP); + /// BuiltinVaListType - built-in va list type. /// This is initially null and set by Sema::LazilyCreateBuiltin when /// a builtin that takes a valist is encountered. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index fbf26ccca5..2db5c5e914 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -35,6 +35,96 @@ enum FloatingRank { FloatRank, DoubleRank, LongDoubleRank }; +void +ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, + TemplateTemplateParmDecl *Parm) { + ID.AddInteger(Parm->getDepth()); + ID.AddInteger(Parm->getPosition()); + // FIXME: Parameter pack + + TemplateParameterList *Params = Parm->getTemplateParameters(); + ID.AddInteger(Params->size()); + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + if (TemplateTypeParmDecl *TTP = dyn_cast(*P)) { + ID.AddInteger(0); + ID.AddBoolean(TTP->isParameterPack()); + continue; + } + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*P)) { + ID.AddInteger(1); + // FIXME: Parameter pack + ID.AddPointer(NTTP->getType().getAsOpaquePtr()); + continue; + } + + TemplateTemplateParmDecl *TTP = cast(*P); + ID.AddInteger(2); + Profile(ID, TTP); + } +} + +TemplateTemplateParmDecl * +ASTContext::getCanonicalTemplateTemplateParmDecl( + TemplateTemplateParmDecl *TTP) { + // Check if we already have a canonical template template parameter. + llvm::FoldingSetNodeID ID; + CanonicalTemplateTemplateParm::Profile(ID, TTP); + void *InsertPos = 0; + CanonicalTemplateTemplateParm *Canonical + = CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos); + if (Canonical) + return Canonical->getParam(); + + // Build a canonical template parameter list. + TemplateParameterList *Params = TTP->getTemplateParameters(); + llvm::SmallVector CanonParams; + CanonParams.reserve(Params->size()); + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + if (TemplateTypeParmDecl *TTP = dyn_cast(*P)) + CanonParams.push_back( + TemplateTypeParmDecl::Create(*this, getTranslationUnitDecl(), + SourceLocation(), TTP->getDepth(), + TTP->getIndex(), 0, false, + TTP->isParameterPack())); + else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast(*P)) + CanonParams.push_back( + NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(), + SourceLocation(), NTTP->getDepth(), + NTTP->getPosition(), 0, + getCanonicalType(NTTP->getType()), + 0)); + else + CanonParams.push_back(getCanonicalTemplateTemplateParmDecl( + cast(*P))); + } + + TemplateTemplateParmDecl *CanonTTP + = TemplateTemplateParmDecl::Create(*this, getTranslationUnitDecl(), + SourceLocation(), TTP->getDepth(), + TTP->getPosition(), 0, + TemplateParameterList::Create(*this, SourceLocation(), + SourceLocation(), + CanonParams.data(), + CanonParams.size(), + SourceLocation())); + + // Get the new insert position for the node we care about. + Canonical = CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos); + assert(Canonical == 0 && "Shouldn't be in the map!"); + (void)Canonical; + + // Create the canonical template template parameter entry. + Canonical = new (*this) CanonicalTemplateTemplateParm(CanonTTP); + CanonTemplateTemplateParms.InsertNode(Canonical, InsertPos); + return CanonTTP; +} + ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, const TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, @@ -2419,10 +2509,14 @@ DeclarationName ASTContext::getNameForTemplate(TemplateName Name) { } TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { - // If this template name refers to a template, the canonical - // template name merely stores the template itself. - if (TemplateDecl *Template = Name.getAsTemplateDecl()) + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast(Template)) + Template = getCanonicalTemplateTemplateParmDecl(TTP); + + // The canonical template name is the canonical template declaration. return TemplateName(cast(Template->getCanonicalDecl())); + } assert(!Name.getAsOverloadedTemplate()); diff --git a/test/SemaTemplate/member-function-template.cpp b/test/SemaTemplate/member-function-template.cpp index aea62855c2..44954ed881 100644 --- a/test/SemaTemplate/member-function-template.cpp +++ b/test/SemaTemplate/member-function-template.cpp @@ -85,3 +85,19 @@ namespace TTP { void test_f(X<3> x, Y y) { x.f(y); } } + +namespace PR7387 { + template struct X {}; + + template struct S { + template