diff options
| author | Douglas Gregor <dgregor@apple.com> | 2010-06-16 21:09:37 +0000 |
|---|---|---|
| committer | Douglas Gregor <dgregor@apple.com> | 2010-06-16 21:09:37 +0000 |
| commit | 7dbfb4616377442f6424f903b045b70c29467630 (patch) | |
| tree | 65c4dc982ba165c4fc2755e9b5714a9594dc91c4 | |
| parent | 2c8b829238d4000557ce989c665ab3f73f2e62a9 (diff) | |
| download | bcm5719-llvm-7dbfb4616377442f6424f903b045b70c29467630.tar.gz bcm5719-llvm-7dbfb4616377442f6424f903b045b70c29467630.zip | |
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.
llvm-svn: 106147
| -rw-r--r-- | clang/include/clang/AST/ASTContext.h | 22 | ||||
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 100 | ||||
| -rw-r--r-- | clang/test/SemaTemplate/member-function-template.cpp | 16 |
3 files changed, 135 insertions, 3 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 9d0469368f3..2778d46dd2d 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/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<ObjCContainerDecl*, ObjCImplDecl*> 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<CanonicalTemplateTemplateParm> 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/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index fbf26ccca5e..2db5c5e914a 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/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<TemplateTypeParmDecl>(*P)) { + ID.AddInteger(0); + ID.AddBoolean(TTP->isParameterPack()); + continue; + } + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + ID.AddInteger(1); + // FIXME: Parameter pack + ID.AddPointer(NTTP->getType().getAsOpaquePtr()); + continue; + } + + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*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<NamedDecl *, 4> CanonParams; + CanonParams.reserve(Params->size()); + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) + CanonParams.push_back( + TemplateTypeParmDecl::Create(*this, getTranslationUnitDecl(), + SourceLocation(), TTP->getDepth(), + TTP->getIndex(), 0, false, + TTP->isParameterPack())); + else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(*P)) + CanonParams.push_back( + NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(), + SourceLocation(), NTTP->getDepth(), + NTTP->getPosition(), 0, + getCanonicalType(NTTP->getType()), + 0)); + else + CanonParams.push_back(getCanonicalTemplateTemplateParmDecl( + cast<TemplateTemplateParmDecl>(*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<TemplateTemplateParmDecl>(Template)) + Template = getCanonicalTemplateTemplateParmDecl(TTP); + + // The canonical template name is the canonical template declaration. return TemplateName(cast<TemplateDecl>(Template->getCanonicalDecl())); + } assert(!Name.getAsOverloadedTemplate()); diff --git a/clang/test/SemaTemplate/member-function-template.cpp b/clang/test/SemaTemplate/member-function-template.cpp index aea62855c22..44954ed881a 100644 --- a/clang/test/SemaTemplate/member-function-template.cpp +++ b/clang/test/SemaTemplate/member-function-template.cpp @@ -85,3 +85,19 @@ namespace TTP { void test_f(X<3> x, Y<int> y) { x.f(y); } } + +namespace PR7387 { + template <typename T> struct X {}; + + template <typename T1> struct S { + template <template <typename> class TC> void foo(const TC<T1>& arg); + }; + + template <typename T1> template <template <typename> class TC> + void S<T1>::foo(const TC<T1>& arg) {} + + void test(const X<int>& x) { + S<int> s; + s.foo(x); + } +} |

