]> granicus.if.org Git - clang/commitdiff
Canonicalize template template parameters when canonicalizing a
authorDouglas Gregor <dgregor@apple.com>
Wed, 16 Jun 2010 21:09:37 +0000 (21:09 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 16 Jun 2010 21:09:37 +0000 (21:09 +0000)
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
lib/AST/ASTContext.cpp
test/SemaTemplate/member-function-template.cpp

index 9d0469368f39e0f3fad65c5068faf1d6e9620766..2778d46dd2d9a1ee5cd130b354d187ddd0d37f80 100644 (file)
@@ -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.
index fbf26ccca5ee402bb9eb3a0f0541b2be1d5285cc..2db5c5e914a419d333e3962a822e3e5d608c5922 100644 (file)
@@ -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());
 
index aea62855c2255fd756020e1e8b6d478bdc8c7af8..44954ed881abda822e6854e346b16f2c78fbeb42 100644 (file)
@@ -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);
+  }
+}