aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-06-16 21:09:37 +0000
committerDouglas Gregor <dgregor@apple.com>2010-06-16 21:09:37 +0000
commit3e1274f2b99cb99c03cc8e2c6517c37d330b597a (patch)
tree8c2fb7dc9a64e7b1098c937c852f68a6e471f978
parent65d72857b30fc83fd4ac27e6d57ef8921bb1d1d9 (diff)
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
-rw-r--r--include/clang/AST/ASTContext.h22
-rw-r--r--lib/AST/ASTContext.cpp100
-rw-r--r--test/SemaTemplate/member-function-template.cpp16
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<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/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<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/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<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);
+ }
+}