[cfe-commits] r64716 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/AST/DeclNodes.def include/clang/AST/DeclTemplate.h include/clang/AST/Type.h lib/AST/DeclCXX.cpp lib/AST/DeclTemplate.cpp lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp test/SemaTemplate/class-template-id.cpp

Douglas Gregor dgregor at apple.com
Mon Feb 16 17:05:44 PST 2009


Author: dgregor
Date: Mon Feb 16 19:05:43 2009
New Revision: 64716

URL: http://llvm.org/viewvc/llvm-project?rev=64716&view=rev
Log:
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.


Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/AST/DeclNodes.def
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/DeclTemplate.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/SemaTemplate/class-template-id.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=64716&r1=64715&r2=64716&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Mon Feb 16 19:05:43 2009
@@ -23,6 +23,7 @@
 class CXXDestructorDecl;
 class CXXConversionDecl;
 class CXXMethodDecl;
+class ClassTemplateSpecializationDecl;
 
 /// OverloadedFunctionDecl - An instance of this class represents a
 /// set of overloaded functions. All of the functions have the same
@@ -231,7 +232,8 @@
   /// CXXConversionDecl.
   OverloadedFunctionDecl Conversions;
 
-  CXXRecordDecl(TagKind TK, DeclContext *DC,
+protected:
+  CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
                 SourceLocation L, IdentifierInfo *Id);
 
   ~CXXRecordDecl();
@@ -355,8 +357,14 @@
   /// GraphViz.
   void viewInheritance(ASTContext& Context) const;
 
-  static bool classof(const Decl *D) { return D->getKind() == CXXRecord; }
+  static bool classof(const Decl *D) { 
+    return D->getKind() == CXXRecord || 
+           D->getKind() == ClassTemplateSpecialization; 
+  }
   static bool classof(const CXXRecordDecl *D) { return true; }
+  static bool classof(const ClassTemplateSpecializationDecl *D) { 
+    return true; 
+  }
 
 protected:
   /// EmitImpl - Serialize this CXXRecordDecl.  Called by Decl::Emit.

Modified: cfe/trunk/include/clang/AST/DeclNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclNodes.def?rev=64716&r1=64715&r2=64716&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclNodes.def (original)
+++ cfe/trunk/include/clang/AST/DeclNodes.def Mon Feb 16 19:05:43 2009
@@ -84,6 +84,7 @@
       DECL(Enum, TagDecl)
       DECL(Record, TagDecl)
         DECL(CXXRecord, RecordDecl)
+          DECL(ClassTemplateSpecialization, CXXRecordDecl)
     DECL(TemplateTypeParm, TypeDecl)
   ABSTRACT_DECL(Value, NamedDecl)
     DECL(EnumConstant, ValueDecl)
@@ -139,7 +140,7 @@
 DECL_RANGE(Field, Field, ObjCAtDefsField)
 DECL_RANGE(Type, Typedef, TemplateTypeParm)
 DECL_RANGE(Tag, Enum, CXXRecord)
-DECL_RANGE(Record, Record, CXXRecord)
+DECL_RANGE(Record, Record, ClassTemplateSpecialization)
 DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm)
 DECL_RANGE(Function, Function, CXXConversion)
 DECL_RANGE(Template, Template, TemplateTemplateParm)

Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=64716&r1=64715&r2=64716&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Mon Feb 16 19:05:43 2009
@@ -15,6 +15,8 @@
 #define LLVM_CLANG_AST_DECLTEMPLATE_H
 
 #include "clang/AST/DeclCXX.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/FoldingSet.h"
 
 namespace clang {
 
@@ -161,37 +163,10 @@
   { return true; }
 };
 
-/// Declaration of a template class.
-class ClassTemplateDecl : public TemplateDecl {
-protected:
-  ClassTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
-                    TemplateParameterList *Params, NamedDecl *Decl)
-    : TemplateDecl(ClassTemplate, DC, L, Name, Params, Decl) { }
-public:
-  /// Get the underlying class declarations of the template.
-  CXXRecordDecl *getTemplatedDecl() const {
-    return static_cast<CXXRecordDecl *>(TemplatedDecl);
-  }
-
-  /// Create a class teplate node.
-  static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
-                                   SourceLocation L,
-                                   DeclarationName Name,
-                                   TemplateParameterList *Params,
-                                   NamedDecl *Decl);
-
-  // Implement isa/cast/dyncast support
-  static bool classof(const Decl *D)
-  { return D->getKind() == ClassTemplate; }
-  static bool classof(const ClassTemplateDecl *D)
-  { return true; }
-};
-
 //===----------------------------------------------------------------------===//
 // Kinds of Template Parameters
 //===----------------------------------------------------------------------===//
 
-
 /// The TemplateParmPosition class defines the position of a template parameter
 /// within a template parameter list. Because template parameter can be listed
 /// sequentially for out-of-line template members, each template parameter is
@@ -421,6 +396,236 @@
   friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
 };
 
+/// \brief Represents a template argument within a class template
+/// specialization.
+class TemplateArgument {
+  union {
+    uintptr_t TypeOrDeclaration;
+    char IntegralValue[sizeof(llvm::APInt)];
+  };
+
+public:
+  /// \brief The type of template argument we're storing.
+  enum ArgKind {
+    /// The template argument is a type. It's value is stored in the
+    /// TypeOrDeclaration field.
+    Type = 0,
+    /// The template argument is a declaration
+    Declaration = 1,
+    /// The template argument is an integral value stored in an llvm::APInt.
+    Integral = 2
+  } Kind;
+
+  /// \brief Construct a template type argument.
+  TemplateArgument(QualType T) : Kind(Type) {
+    assert(T->isCanonical() && 
+           "Template arguments always use the canonical type");
+    TypeOrDeclaration = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+  }
+
+  /// \brief Construct a template argument that refers to a
+  /// declaration, which is either an external declaration or a
+  /// template declaration.
+  TemplateArgument(Decl *D) : Kind(Declaration) {
+    // FIXME: Need to be sure we have the "canonical" declaration!
+    TypeOrDeclaration = reinterpret_cast<uintptr_t>(D);
+  }
+
+  /// \brief Construct an integral constant template argument.
+  TemplateArgument(const llvm::APInt &Value) : Kind(Integral) {
+    new (IntegralValue) llvm::APInt(Value);
+  }
+
+  /// \brief Copy constructor for a template argument.
+  TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
+    if (Kind == Integral)
+      new (IntegralValue) llvm::APInt(*Other.getAsIntegral());
+    else
+      TypeOrDeclaration = Other.TypeOrDeclaration;
+  }
+
+  TemplateArgument& operator=(const TemplateArgument& Other) {
+    using llvm::APInt;
+
+    if (Kind == Other.Kind && Kind == Integral) {
+      // Copy integral values.
+      *this->getAsIntegral() = *Other.getAsIntegral();
+    } else {
+      // Destroy the current integral value, if that's what we're holding.
+      if (Kind == Integral)
+        getAsIntegral()->~APInt();
+      
+      Kind = Other.Kind;
+      
+      if (Other.Kind == Integral)
+        new (IntegralValue) llvm::APInt(*Other.getAsIntegral());
+      else
+        TypeOrDeclaration = Other.TypeOrDeclaration;
+    }
+    return *this;
+  }
+
+  ~TemplateArgument() {
+    using llvm::APInt;
+
+    if (Kind == Integral)
+      getAsIntegral()->~APInt();
+  }
+
+  /// \brief Return the kind of stored template argument.
+  ArgKind getKind() const { return Kind; }
+
+  /// \brief Retrieve the template argument as a type.
+  QualType getAsType() const {
+    if (Kind != Type)
+      return QualType();
+
+    return QualType::getFromOpaquePtr(
+                                 reinterpret_cast<void*>(TypeOrDeclaration));
+  }
+
+  /// \brief Retrieve the template argument as a declaration.
+  Decl *getAsDecl() const {
+    if (Kind != Declaration)
+      return 0;
+    return reinterpret_cast<Decl *>(TypeOrDeclaration);
+  }
+
+  /// \brief Retrieve the template argument as an integral value.
+  llvm::APInt *getAsIntegral() {
+    if (Kind != Integral)
+      return 0;
+    return reinterpret_cast<llvm::APInt*>(&IntegralValue[0]);
+  }
+
+  const llvm::APInt *getAsIntegral() const {
+    return const_cast<TemplateArgument*>(this)->getAsIntegral();
+  }
+
+  /// \brief Used to insert TemplateArguments into FoldingSets.
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    ID.AddInteger(Kind);
+    switch (Kind) {
+    case Type:
+      getAsType().Profile(ID);
+      break;
+
+    case Declaration:
+      ID.AddPointer(getAsDecl()); // FIXME: Must be canonical!
+      break;
+
+    case Integral:
+      getAsIntegral()->Profile(ID);
+      break;
+    }
+  }
+};
+
+/// \brief Represents a class template specialization, which refers to
+/// a class template with a given set of template arguments.
+///
+/// Class template specializations represent both explicit
+/// specialization of class templates, as in the example below, and
+/// implicit instantiations of class templates.
+///
+/// \code
+/// template<typename T> class array;
+/// 
+/// template<> 
+/// class array<bool> { }; // class template specialization array<bool>
+/// \endcode
+class ClassTemplateSpecializationDecl 
+  : public CXXRecordDecl, public llvm::FoldingSetNode {
+  /// \brief The template that this specialization specializes
+  ClassTemplateDecl *SpecializedTemplate;
+
+  /// \brief The number of template arguments. The actual arguments
+  /// are allocated after the ClassTemplateSpecializationDecl object.
+  unsigned NumTemplateArgs;
+  
+  ClassTemplateSpecializationDecl(DeclContext *DC, SourceLocation L,
+                                  ClassTemplateDecl *SpecializedTemplate,
+                                  TemplateArgument *TemplateArgs, 
+                                  unsigned NumTemplateArgs);
+                                  
+public:
+  static ClassTemplateSpecializationDecl *
+  Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
+         ClassTemplateDecl *SpecializedTemplate,
+         TemplateArgument *TemplateArgs, unsigned NumTemplateArgs);
+
+  /// \brief Retrieve the template that this specialization specializes.
+  ClassTemplateDecl *getSpecializedTemplate() const { 
+    return SpecializedTemplate; 
+  }
+
+  typedef const TemplateArgument * template_arg_iterator;
+  template_arg_iterator template_arg_begin() const {
+    return reinterpret_cast<template_arg_iterator>(this + 1);
+  }
+
+  template_arg_iterator template_arg_end() const {
+    return template_arg_begin() + NumTemplateArgs;
+  }
+
+  unsigned getNumTemplateArgs() const { return NumTemplateArgs; }
+
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    Profile(ID, template_arg_begin(), getNumTemplateArgs());
+  }
+
+  static void 
+  Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs, 
+          unsigned NumTemplateArgs) {
+    for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
+      TemplateArgs[Arg].Profile(ID);
+  }
+
+  static bool classof(const Decl *D) { 
+    return D->getKind() == ClassTemplateSpecialization;
+  }
+
+  static bool classof(const ClassTemplateSpecializationDecl *) {
+    return true;
+  }
+};
+
+/// Declaration of a class template.
+class ClassTemplateDecl : public TemplateDecl {
+protected:
+  ClassTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
+                    TemplateParameterList *Params, NamedDecl *Decl)
+    : TemplateDecl(ClassTemplate, DC, L, Name, Params, Decl) { }
+
+  /// \brief The class template specializations for this class
+  /// template, including explicit specializations and instantiations.
+  llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations;
+
+public:
+  /// Get the underlying class declarations of the template.
+  CXXRecordDecl *getTemplatedDecl() const {
+    return static_cast<CXXRecordDecl *>(TemplatedDecl);
+  }
+
+  /// Create a class teplate node.
+  static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
+                                   SourceLocation L,
+                                   DeclarationName Name,
+                                   TemplateParameterList *Params,
+                                   NamedDecl *Decl);
+
+  /// \brief Retrieve the set of specializations of this class template.
+  llvm::FoldingSet<ClassTemplateSpecializationDecl> &getSpecializations() {
+    return Specializations;
+  }
+
+  // Implement isa/cast/dyncast support
+  static bool classof(const Decl *D)
+  { return D->getKind() == ClassTemplate; }
+  static bool classof(const ClassTemplateDecl *D)
+  { return true; }
+};
+
 } /* end of namespace clang */
 
 #endif

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=64716&r1=64715&r2=64716&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Mon Feb 16 19:05:43 2009
@@ -1502,6 +1502,8 @@
 
     // Add the packed words describing what kind of template arguments
     // we have.
+    // FIXME: Would like to be smarter about the profile of expressions, 
+    // so that we can combine expression nodes more effectively.
     uintptr_t *Data = reinterpret_cast<uintptr_t *>(this + 1);
     for (unsigned Packed = 0, NumPacked = getNumPackedWords(NumArgs); 
          Packed != NumPacked; ++Packed)

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=64716&r1=64715&r2=64716&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Mon Feb 16 19:05:43 2009
@@ -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;
 }

Modified: cfe/trunk/lib/AST/DeclTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=64716&r1=64715&r2=64716&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Mon Feb 16 19:05:43 2009
@@ -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);
+}

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=64716&r1=64715&r2=64716&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Feb 16 19:05:43 2009
@@ -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,

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=64716&r1=64715&r2=64716&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Feb 16 19:05:43 2009
@@ -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

Modified: cfe/trunk/test/SemaTemplate/class-template-id.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/class-template-id.cpp?rev=64716&r1=64715&r2=64716&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/class-template-id.cpp (original)
+++ cfe/trunk/test/SemaTemplate/class-template-id.cpp Mon Feb 16 19:05:43 2009
@@ -1,17 +1,29 @@
 // RUN: clang -fsyntax-only -verify %s
-template<typename T> struct A { };
+template<typename T, typename U = float> struct A { };
 
 typedef A<int> A_int;
 
-float *foo(A<int> *ptr, A<int> const *ptr2) {
+typedef float FLOAT;
+
+A<int, FLOAT> *foo(A<int> *ptr, A<int> const *ptr2, A<int, double> *ptr3) {
   if (ptr)
-    return ptr; // expected-error{{incompatible type returning 'A<int> *', expected 'float *'}}
+    return ptr; // okay
   else if (ptr2)
-    return ptr2; // expected-error{{incompatible type returning 'A<int> const *', expected 'float *'}}
+    return ptr2; // expected-error{{incompatible type returning 'A<int> const *', expected 'A<int, FLOAT> *'}}
   else {
-    // FIXME: This is completely bogus, but we're using it temporarily
-    // to test the syntactic sugar for class template specializations.
-    int *ip = ptr;
-    return 0;
+    return ptr3; // expected-error{{incompatible type returning 'A<int, double> *', expected 'A<int, FLOAT> *'}}
   }
 }
+
+template<int I> struct B;
+
+const int value = 12;
+B<17 + 2> *bar(B<(19)> *ptr1, B< (::value + 7) > *ptr2, B<19 - 3> *ptr3) {
+  if (ptr1)
+    return ptr1;
+  else if (ptr2)
+    return ptr2;
+  else
+    return ptr3; // expected-error{{incompatible type returning 'B<19 - 3> *', expected 'B<17 + 2> *'}}
+}
+





More information about the cfe-commits mailing list