Refactor the code that produces a TemplateSpecializationType, so that
canonicalization for dependent TemplateSpecializationTypes occurs
within ASTContext::getTemplateSpecializationType. Also, move template
argument canonicalization into ASTContext::getCanonicalTemplateArgument.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77388 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 06835cb..d607ca7 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1669,26 +1669,53 @@
                                           const TemplateArgument *Args,
                                           unsigned NumArgs,
                                           QualType Canon) {
-  if (!Canon.isNull())
+  if (Canon.isNull()) {
+    // Build the canonical template specialization type, since no type
+    // was provided.
+    TemplateName CanonTemplate = getCanonicalTemplateName(Template);
+    llvm::SmallVector<TemplateArgument, 4> CanonArgs;
+    CanonArgs.reserve(NumArgs);
+    for (unsigned I = 0; I != NumArgs; ++I)
+      CanonArgs.push_back(getCanonicalTemplateArgument(Args[I]));
+
+    // Determine whether this canonical template specialization type already
+    // exists.
+    llvm::FoldingSetNodeID ID;
+    TemplateSpecializationType::Profile(ID, CanonTemplate, 
+                                        CanonArgs.data(), NumArgs);
+
+    void *InsertPos = 0;
+    TemplateSpecializationType *Spec
+      = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
+    
+    if (!Spec) {
+      // Allocate a new canonical template specialization type.
+      void *Mem = Allocate((sizeof(TemplateSpecializationType) + 
+                            sizeof(TemplateArgument) * NumArgs),
+                           8);
+      Spec = new (Mem) TemplateSpecializationType(CanonTemplate, 
+                                                  CanonArgs.data(), NumArgs,
+                                                  QualType());
+      Types.push_back(Spec);
+      TemplateSpecializationTypes.InsertNode(Spec, InsertPos);      
+    }
+    
+    Canon = QualType(Spec, 0);
+    assert(Canon->isDependentType() && 
+           "Non-dependent template-id type must have a canonical type");
+  } else
     Canon = getCanonicalType(Canon);
 
-  llvm::FoldingSetNodeID ID;
-  TemplateSpecializationType::Profile(ID, Template, Args, NumArgs);
-
-  void *InsertPos = 0;
-  TemplateSpecializationType *Spec
-    = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
-
-  if (Spec)
-    return QualType(Spec, 0);
-  
+  // Allocate the (non-canonical) template specialization type, but don't
+  // try to unique it: these types typically have location information that
+  // we don't unique and don't want to lose.
   void *Mem = Allocate((sizeof(TemplateSpecializationType) + 
                         sizeof(TemplateArgument) * NumArgs),
                        8);
-  Spec = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, Canon);
+  TemplateSpecializationType *Spec 
+    = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, Canon);
+  
   Types.push_back(Spec);
-  TemplateSpecializationTypes.InsertNode(Spec, InsertPos);
-
   return QualType(Spec, 0);  
 }
 
@@ -2013,6 +2040,49 @@
   return DTN->CanonicalTemplateName;
 }
 
+TemplateArgument 
+ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) {
+  switch (Arg.getKind()) {
+    case TemplateArgument::Null:
+      return Arg;
+      
+    case TemplateArgument::Expression:
+      // FIXME: Build canonical expression?
+      return Arg;
+      
+    case TemplateArgument::Declaration:
+      return TemplateArgument(SourceLocation(),
+                              Arg.getAsDecl()->getCanonicalDecl());
+      
+    case TemplateArgument::Integral:
+      return TemplateArgument(SourceLocation(),
+                              *Arg.getAsIntegral(),
+                              getCanonicalType(Arg.getIntegralType()));
+      
+    case TemplateArgument::Type:
+      return TemplateArgument(SourceLocation(),
+                              getCanonicalType(Arg.getAsType()));
+      
+    case TemplateArgument::Pack: {
+      // FIXME: Allocate in ASTContext
+      TemplateArgument *CanonArgs = new TemplateArgument[Arg.pack_size()];
+      unsigned Idx = 0;
+      for (TemplateArgument::pack_iterator A = Arg.pack_begin(), 
+                                        AEnd = Arg.pack_end();
+           A != AEnd; (void)++A, ++Idx)
+        CanonArgs[Idx] = getCanonicalTemplateArgument(*A);
+      
+      TemplateArgument Result;
+      Result.setArgumentPack(CanonArgs, Arg.pack_size(), false);
+      return Result;
+    }
+  }
+
+  // Silence GCC warning
+  assert(false && "Unhandled template argument kind");
+  return TemplateArgument();
+}
+
 NestedNameSpecifier *
 ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) {
   if (!NNS) 
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index ce382db..686b78d 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -171,52 +171,32 @@
   // better to fix that redundancy.
 
   TemplateParameterList *Params = getTemplateParameters();
-
   llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
-  llvm::SmallVector<TemplateArgument, 16> CanonTemplateArgs;
   TemplateArgs.reserve(Params->size());
-  CanonTemplateArgs.reserve(Params->size());
-
-  for (TemplateParameterList::iterator 
-         Param = Params->begin(), ParamEnd = Params->end(); 
+  for (TemplateParameterList::iterator Param = Params->begin(), 
+                                    ParamEnd = Params->end(); 
        Param != ParamEnd; ++Param) {
     if (isa<TemplateTypeParmDecl>(*Param)) {
       QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param));
       TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(), 
                                               ParamType));
-      CanonTemplateArgs.push_back(
-                         TemplateArgument((*Param)->getLocation(),
-                                          Context.getCanonicalType(ParamType)));
     } else if (NonTypeTemplateParmDecl *NTTP = 
                  dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
-      // FIXME: Build canonical expression, too!
       Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(),
                                           NTTP->getLocation(),
                                           NTTP->getType()->isDependentType(),
                                           /*Value-dependent=*/true);
       TemplateArgs.push_back(TemplateArgument(E));
-      CanonTemplateArgs.push_back(TemplateArgument(E));
     } else { 
       TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
       TemplateArgs.push_back(TemplateArgument(TTP->getLocation(), TTP));
-      CanonTemplateArgs.push_back(TemplateArgument(TTP->getLocation(), 
-                                                   TTP->getCanonicalDecl()));
     }
   }
 
-  // FIXME: I should really move the "build-the-canonical-type" logic
-  // into ASTContext::getTemplateSpecializationType.
-  TemplateName Name = TemplateName(this);
-  QualType CanonType = Context.getTemplateSpecializationType(
-                                       Context.getCanonicalTemplateName(Name),
-                                             &CanonTemplateArgs[0],
-                                             CanonTemplateArgs.size());
-
   CommonPtr->InjectedClassNameType
-    = Context.getTemplateSpecializationType(Name,
+    = Context.getTemplateSpecializationType(TemplateName(this),
                                             &TemplateArgs[0],
-                                            TemplateArgs.size(),
-                                            CanonType);
+                                            TemplateArgs.size());
   return CommonPtr->InjectedClassNameType;
 }
 
@@ -290,6 +270,7 @@
     return;
   }
   
+  // FIXME: Allocate in ASTContext
   Args.Args = new TemplateArgument[NumArgs];
   for (unsigned I = 0; I != Args.NumArgs; ++I)
     Args.Args[I] = args[I];