Added ClassTemplateSpecializationDecl, which is a subclass of
CXXRecordDecl that is used to represent class template
specializations. These are canonical declarations that can refer to
either an actual class template specialization in the code, e.g.,

  template<> class vector<bool> { };

or to a template instantiation. However, neither of these features is
actually implemented yet, so really we're just using (and uniqing) the
declarations to make sure that, e.g., A<int> is a different type from
A<float>. Note that we carefully distinguish between what the user
wrote in the source code (e.g., "A<FLOAT>") and the semantic entity it
represents (e.g., "A<float, int>"); the former is in the sugared Type,
the latter is an actual Decl.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64716 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 6de5754..294e94f 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -21,9 +21,9 @@
 // Decl Allocation/Deallocation Method Implementations
 //===----------------------------------------------------------------------===//
 
-CXXRecordDecl::CXXRecordDecl(TagKind TK, DeclContext *DC,
+CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
                              SourceLocation L, IdentifierInfo *Id) 
-  : RecordDecl(CXXRecord, TK, DC, L, Id),
+  : RecordDecl(K, TK, DC, L, Id),
     UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
     UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
     Aggregate(true), PlainOldData(true), Polymorphic(false), Bases(0),
@@ -32,7 +32,7 @@
 CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
                                      SourceLocation L, IdentifierInfo *Id,
                                      CXXRecordDecl* PrevDecl) {
-  CXXRecordDecl* R = new (C) CXXRecordDecl(TK, DC, L, Id);
+  CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id);
   C.getTypeDeclType(R, PrevDecl);  
   return R;
 }
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index dccb8df..81ef3ab 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -143,3 +143,39 @@
   return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
                         : SourceLocation(); 
 }
+
+//===----------------------------------------------------------------------===//
+// ClassTemplateSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+ClassTemplateSpecializationDecl::
+ClassTemplateSpecializationDecl(DeclContext *DC, SourceLocation L,
+                                ClassTemplateDecl *SpecializedTemplate,
+                                TemplateArgument *TemplateArgs, 
+                                unsigned NumTemplateArgs)
+  : CXXRecordDecl(ClassTemplateSpecialization, 
+                  SpecializedTemplate->getTemplatedDecl()->getTagKind(), 
+                  DC, L,
+                  // FIXME: Should we use DeclarationName for the name of
+                  // class template specializations?
+                  SpecializedTemplate->getIdentifier()),
+    SpecializedTemplate(SpecializedTemplate),
+    NumTemplateArgs(NumTemplateArgs) {
+  TemplateArgument *Arg = reinterpret_cast<TemplateArgument *>(this + 1);
+  for (unsigned ArgIdx = 0; ArgIdx < NumTemplateArgs; ++ArgIdx, ++Arg)
+    *Arg = TemplateArgs[ArgIdx];
+}
+                  
+ClassTemplateSpecializationDecl *
+ClassTemplateSpecializationDecl::Create(ASTContext &Context, 
+                                        DeclContext *DC, SourceLocation L,
+                                        ClassTemplateDecl *SpecializedTemplate,
+                                        TemplateArgument *TemplateArgs, 
+                                        unsigned NumTemplateArgs) {
+  unsigned Size = sizeof(ClassTemplateSpecializationDecl) + 
+                  sizeof(TemplateArgument) * NumTemplateArgs;
+  unsigned Align = llvm::AlignOf<ClassTemplateSpecializationDecl>::Alignment;
+  void *Mem = Context.Allocate(Size, Align);
+  return new (Mem) ClassTemplateSpecializationDecl(DC, L, SpecializedTemplate,
+                                                   TemplateArgs, 
+                                                   NumTemplateArgs);
+}
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 3475b2d..2e45715 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -61,6 +61,7 @@
   class ExtVectorType;
   class TypedefDecl;
   class TemplateDecl;
+  class TemplateArgument;
   class TemplateParameterList;
   class TemplateTemplateParmDecl;
   class ObjCInterfaceDecl;
@@ -1554,13 +1555,16 @@
                                  SourceLocation LAngleLoc,
                                  ASTTemplateArgsPtr& TemplateArgs,
                                  SourceLocation *TemplateArgLocs,
-                                 SourceLocation RAngleLoc);
+                                 SourceLocation RAngleLoc,
+                       llvm::SmallVectorImpl<TemplateArgument> &Converted);
 
   bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg,
                              SourceLocation ArgLoc);
-  bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg);
-  bool CheckTemplateArgumentPointerToMember(Expr *Arg);
-  bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Expr *&Arg);
+  bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg, 
+                                                      NamedDecl *&Entity);
+  bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member);
+  bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Expr *&Arg,
+                       llvm::SmallVectorImpl<TemplateArgument> *Converted = 0);
   bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg);
   bool TemplateParameterListsAreEqual(TemplateParameterList *New,
                                       TemplateParameterList *Old,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index b339a7b..8c2a8bc 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -654,21 +654,51 @@
                                        SourceLocation RAngleLoc,
                                        const CXXScopeSpec *SS) {
   TemplateDecl *Template = cast<TemplateDecl>(static_cast<Decl *>(TemplateD));
+  ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(Template);
 
   // Check that the template argument list is well-formed for this
   // template.
+  llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
   if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc, 
-                                TemplateArgs, TemplateArgLocs, RAngleLoc))
+                                TemplateArgs, TemplateArgLocs, RAngleLoc,
+                                ConvertedTemplateArgs))
     return 0;
 
-  // Yes, all class template specializations are just silly sugar for
-  // 'int'. Gotta problem wit dat?
+  assert((ConvertedTemplateArgs.size() == 
+            Template->getTemplateParameters()->size()) &&
+         "Converted template argument list is too short!");
+
+  // Find the class template specialization declaration that
+  // corresponds to these arguments.
+  llvm::FoldingSetNodeID ID;
+  ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
+                                           ConvertedTemplateArgs.size());
+  void *InsertPos = 0;
+  ClassTemplateSpecializationDecl *Decl
+    = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
+  if (!Decl) {
+    // This is the first time we have referenced this class template
+    // specialization. Create an appropriate declaration node and add
+    // it to the list of specializations. This is the canonical
+    // declaration of the class template.
+    Decl = ClassTemplateSpecializationDecl::Create(Context, 
+                                           ClassTemplate->getDeclContext(),
+                                                   TemplateLoc,
+                                                   ClassTemplate,
+                                                   &ConvertedTemplateArgs[0],
+                                           ConvertedTemplateArgs.size());
+    ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
+  }
+
+  // Build the fully-sugared type for this class template
+  // specialization, which refers back to the class template
+  // specialization we created or found.
   QualType Result
     = Context.getClassTemplateSpecializationType(Template, 
                                                  TemplateArgs.size(),
                     reinterpret_cast<uintptr_t *>(TemplateArgs.getArgs()), 
                                                  TemplateArgs.getArgIsType(),
-                                                 Context.IntTy);
+                                               Context.getTypeDeclType(Decl));
   TemplateArgs.release();
   return Result.getAsOpaquePtr();
 }
@@ -680,7 +710,8 @@
                                      SourceLocation LAngleLoc,
                                      ASTTemplateArgsPtr& Args,
                                      SourceLocation *TemplateArgLocs,
-                                     SourceLocation RAngleLoc) {
+                                     SourceLocation RAngleLoc,
+                          llvm::SmallVectorImpl<TemplateArgument> &Converted) {
   TemplateParameterList *Params = Template->getTemplateParameters();
   unsigned NumParams = Params->size();
   unsigned NumArgs = Args.size();
@@ -719,22 +750,51 @@
     Expr *ArgExpr = 0;
     SourceLocation ArgLoc;
     if (ArgIdx >= NumArgs) {
-      // FIXME: Get the default argument here, which might
-      // (eventually) require instantiation.
-      break;
-    } else
+      // Retrieve the default template argument from the template
+      // parameter.
+      if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+        if (!TTP->hasDefaultArgument())
+          break;
+
+        ArgType = TTP->getDefaultArgument();
+        ArgLoc = TTP->getDefaultArgumentLoc();
+      } else if (NonTypeTemplateParmDecl *NTTP 
+                   = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+        if (!NTTP->hasDefaultArgument())
+          break;
+
+        ArgExpr = NTTP->getDefaultArgument();
+        ArgLoc = NTTP->getDefaultArgumentLoc();
+      } else {
+        TemplateTemplateParmDecl *TempParm 
+          = cast<TemplateTemplateParmDecl>(*Param);      
+
+        if (!TempParm->hasDefaultArgument())
+          break;
+
+        ArgExpr = TempParm->getDefaultArgument();
+        ArgLoc = TempParm->getDefaultArgumentLoc();
+      }
+    } else {
+      // Retrieve the template argument produced by the user.
       ArgLoc = TemplateArgLocs[ArgIdx];
 
-    if (Args.getArgIsType()[ArgIdx])
-      ArgType = QualType::getFromOpaquePtr(Args.getArgs()[ArgIdx]);
-    else
-      ArgExpr = reinterpret_cast<Expr *>(Args.getArgs()[ArgIdx]);
+      if (Args.getArgIsType()[ArgIdx])
+        ArgType = QualType::getFromOpaquePtr(Args.getArgs()[ArgIdx]);
+      else
+        ArgExpr = reinterpret_cast<Expr *>(Args.getArgs()[ArgIdx]);
+    }
+
 
     if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
       // Check template type parameters.
       if (!ArgType.isNull()) {
         if (CheckTemplateArgument(TTP, ArgType, ArgLoc))
           Invalid = true;
+
+        // Add the converted template type argument.
+        Converted.push_back(
+                      TemplateArgument(Context.getCanonicalType(ArgType)));
         continue;
       }
 
@@ -752,7 +812,7 @@
                  = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
       // Check non-type template parameters.
       if (ArgExpr) {
-        if (CheckTemplateArgument(NTTP, ArgExpr))
+        if (CheckTemplateArgument(NTTP, ArgExpr, &Converted))
           Invalid = true;
         continue;
       }
@@ -783,6 +843,11 @@
           isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) {
         if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr)))
           Invalid = true;
+
+        // Add the converted template argument.
+        // FIXME: Need the "canonical" template declaration!
+        Converted.push_back(
+                   TemplateArgument(cast<DeclRefExpr>(ArgExpr)->getDecl()));
         continue;
       }
 
@@ -828,7 +893,8 @@
 
 /// \brief Checks whether the given template argument is the address
 /// of an object or function according to C++ [temp.arg.nontype]p1.
-bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg) {
+bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
+                                                          NamedDecl *&Entity) {
   bool Invalid = false;
 
   // See through any implicit casts we added to fix the type.
@@ -895,6 +961,7 @@
     }
 
     // Okay: we've named a function with external linkage.
+    Entity = Func;
     return Invalid;
   }
 
@@ -909,6 +976,7 @@
     }
 
     // Okay: we've named an object with external linkage
+    Entity = Var;
     return Invalid;
   }
   
@@ -923,7 +991,8 @@
 
 /// \brief Checks whether the given template argument is a pointer to
 /// member constant according to C++ [temp.arg.nontype]p1.
-bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg) {
+bool 
+Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
   bool Invalid = false;
 
   // See through any implicit casts we added to fix the type.
@@ -966,6 +1035,7 @@
 
     // Okay: this is the address of a non-static member, and therefore
     // a member pointer constant.
+    Member = DRE->getDecl();
     return Invalid;
   }
 
@@ -983,10 +1053,15 @@
 ///
 /// This routine implements the semantics of C++ [temp.arg.nontype]. 
 /// It returns true if an error occurred, and false otherwise.
+///
+/// If Converted is non-NULL and no errors occur, the value
+/// of this argument will be added to the end of the Converted vector.
 bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
-                                 Expr *&Arg) {
+                                 Expr *&Arg, 
+                         llvm::SmallVectorImpl<TemplateArgument> *Converted) {
   // If either the parameter has a dependent type or the argument is
   // type-dependent, there's nothing we can check now.
+  // FIXME: Add template argument to Converted!
   if (Param->getType()->isDependentType() || Arg->isTypeDependent())
     return false;
 
@@ -1011,6 +1086,7 @@
     //        type; or
     //     -- the name of a non-type template-parameter; or
     SourceLocation NonConstantLoc;
+    llvm::APSInt Value;
     if (!ArgType->isIntegralType() && !ArgType->isEnumeralType()) {
       Diag(Arg->getSourceRange().getBegin(), 
            diag::err_template_arg_not_integral_or_enumeral)
@@ -1018,7 +1094,7 @@
       Diag(Param->getLocation(), diag::note_template_param_here);
       return true;
     } else if (!Arg->isValueDependent() &&
-               !Arg->isIntegerConstantExpr(Context, &NonConstantLoc)) {
+               !Arg->isIntegerConstantExpr(Value, Context, &NonConstantLoc)) {
       Diag(NonConstantLoc, diag::err_template_arg_not_ice)
         << ArgType << Arg->getSourceRange();
       return true;
@@ -1048,6 +1124,23 @@
       return true;
     }
 
+    // FIXME: Check overflow of template arguments?
+
+    if (Converted) {
+      // Add the value of this argument to the list of converted
+      // arguments. We use the bitwidth and signedness of the template
+      // parameter.
+      QualType IntegerType = Context.getCanonicalType(ParamType);
+      if (const EnumType *Enum = IntegerType->getAsEnumType())
+        IntegerType = Enum->getDecl()->getIntegerType();
+      
+      llvm::APInt CanonicalArg(Context.getTypeSize(IntegerType), 0, 
+                               IntegerType->isSignedIntegerType());
+      CanonicalArg = Value;
+
+      Converted->push_back(TemplateArgument(CanonicalArg));
+    }
+
     return false;
   }
 
@@ -1100,10 +1193,24 @@
       return true;
     }
     
-    if (ParamType->isMemberPointerType())
-      return CheckTemplateArgumentPointerToMember(Arg);
+    if (ParamType->isMemberPointerType()) {
+      NamedDecl *Member = 0;
+      if (CheckTemplateArgumentPointerToMember(Arg, Member))
+        return true;
+
+      if (Converted)
+        Converted->push_back(TemplateArgument(Member));
+
+      return false;
+    }
     
-    return CheckTemplateArgumentAddressOfObjectOrFunction(Arg);
+    NamedDecl *Entity = 0;
+    if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
+      return true;
+
+    if (Converted)
+      Converted->push_back(TemplateArgument(Entity));
+    return false;
   }
 
   if (const PointerType *ParamPtrType = ParamType->getAsPointerType()) {
@@ -1132,7 +1239,14 @@
       return true;
     }
     
-    return CheckTemplateArgumentAddressOfObjectOrFunction(Arg);
+    NamedDecl *Entity = 0;
+    if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
+      return true;
+
+    if (Converted)
+      Converted->push_back(TemplateArgument(Entity));
+
+    return false;
   }
     
   if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) {
@@ -1167,7 +1281,14 @@
       return true;
     }
     
-    return CheckTemplateArgumentAddressOfObjectOrFunction(Arg);
+    NamedDecl *Entity = 0;
+    if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
+      return true;
+
+    if (Converted)
+      Converted->push_back(TemplateArgument(Entity));
+
+    return false;
   }
 
   //     -- For a non-type template-parameter of type pointer to data
@@ -1187,7 +1308,14 @@
     return true;    
   }
 
-  return CheckTemplateArgumentPointerToMember(Arg);
+  NamedDecl *Member = 0;
+  if (CheckTemplateArgumentPointerToMember(Arg, Member))
+    return true;
+  
+  if (Converted)
+    Converted->push_back(TemplateArgument(Member));
+  
+  return false;
 }
 
 /// \brief Check a template argument against its corresponding