[cfe-commits] r74454 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/DeclTemplate.h lib/AST/ASTContext.cpp lib/AST/Decl.cpp lib/AST/DeclTemplate.cpp lib/CodeGen/CodeGenModule.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CodeGenCXX/function-template-specialization.cpp

Douglas Gregor dgregor at apple.com
Mon Jun 29 13:59:41 PDT 2009


Author: dgregor
Date: Mon Jun 29 15:59:39 2009
New Revision: 74454

URL: http://llvm.org/viewvc/llvm-project?rev=74454&view=rev
Log:
Keep track of function template specializations, to eliminate
redundant, implicit instantiations of function templates and provide a
place where we can hang function template specializations.


Added:
    cfe/trunk/test/CodeGenCXX/function-template-specialization.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/AST/DeclTemplate.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp

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

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Mon Jun 29 15:59:39 2009
@@ -809,9 +809,7 @@
     return PreviousDeclaration;
   }
 
-  void setPreviousDeclaration(FunctionDecl * PrevDecl) {
-    PreviousDeclaration = PrevDecl;
-  }
+  void setPreviousDeclaration(FunctionDecl * PrevDecl);
 
   unsigned getBuiltinID(ASTContext &Context) const;
 
@@ -961,7 +959,8 @@
   /// function template specialization from the template.
   void setFunctionTemplateSpecialization(ASTContext &Context,
                                          FunctionTemplateDecl *Template,
-                                      const TemplateArgumentList *TemplateArgs);
+                                      const TemplateArgumentList *TemplateArgs,
+                                         void *InsertPos);
   
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) {

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

==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Mon Jun 29 15:59:39 2009
@@ -100,671 +100,723 @@
   }
 };
 
-//===----------------------------------------------------------------------===//
-// Kinds of Templates
-//===----------------------------------------------------------------------===//
-
-/// TemplateDecl - The base class of all kinds of template declarations (e.g.,
-/// class, function, etc.). The TemplateDecl class stores the list of template
-/// parameters and a reference to the templated scoped declaration: the
-/// underlying AST node.
-class TemplateDecl : public NamedDecl {
-protected:
-  // This is probably never used.
-  TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
-               DeclarationName Name)
-    : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(0)
-  { }
-
-  // Construct a template decl with the given name and parameters.
-  // Used when there is not templated element (tt-params, alias?).
-  TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
-               DeclarationName Name, TemplateParameterList *Params)
-    : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(Params)
-  { }
-
-  // Construct a template decl with name, parameters, and templated element.
-  TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
-               DeclarationName Name, TemplateParameterList *Params,
-               NamedDecl *Decl)
-    : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl),
-      TemplateParams(Params) { }
+/// \brief Represents a template argument within a class template
+/// specialization.
+class TemplateArgument {
+  union {
+    uintptr_t TypeOrValue;
+    struct {
+      char Value[sizeof(llvm::APSInt)];
+      void *Type;
+    } Integer;
+    struct {
+      TemplateArgument *Args;
+      unsigned NumArgs;
+      bool CopyArgs;
+    } Args;
+  };
+  
+  /// \brief Location of the beginning of this template argument.
+  SourceLocation StartLoc;
+  
 public:
-  ~TemplateDecl();
-
-  /// Get the list of template parameters
-  TemplateParameterList *getTemplateParameters() const {
-    return TemplateParams;
+  /// \brief The type of template argument we're storing.
+  enum ArgKind {
+    Null = 0,
+    /// The template argument is a type. Its value is stored in the
+    /// TypeOrValue field.
+    Type = 1,
+    /// The template argument is a declaration
+    Declaration = 2,
+    /// The template argument is an integral value stored in an llvm::APSInt.
+    Integral = 3,
+    /// The template argument is a value- or type-dependent expression
+    /// stored in an Expr*.
+    Expression = 4,
+    
+    /// The template argument is actually a parameter pack. Arguments are stored
+    /// in the Args struct.
+    Pack = 5
+  } Kind;
+  
+  /// \brief Construct an empty, invalid template argument.
+  TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Null) { }
+  
+  /// \brief Construct a template type argument.
+  TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) {
+    TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+    StartLoc = Loc;
   }
-
-  /// Get the underlying, templated declaration.
-  NamedDecl *getTemplatedDecl() const { return TemplatedDecl; }
-
-  // Implement isa/cast/dyncast/etc.
-  static bool classof(const Decl *D) {
-      return D->getKind() >= TemplateFirst && D->getKind() <= TemplateLast;
+  
+  /// \brief Construct a template argument that refers to a
+  /// declaration, which is either an external declaration or a
+  /// template declaration.
+  TemplateArgument(SourceLocation Loc, Decl *D) : Kind(Declaration) {
+    // FIXME: Need to be sure we have the "canonical" declaration!
+    TypeOrValue = reinterpret_cast<uintptr_t>(D);
+    StartLoc = Loc;
   }
-  static bool classof(const TemplateDecl *D) { return true; }
-  static bool classof(const FunctionTemplateDecl *D) { return true; }
-  static bool classof(const ClassTemplateDecl *D) { return true; }
-  static bool classof(const TemplateTemplateParmDecl *D) { return true; }
-
-protected:
-  NamedDecl *TemplatedDecl;
-  TemplateParameterList* TemplateParams;
-};
- 
-/// \brief Provides information about a function template specialization, 
-/// which is a FunctionDecl that has been explicitly specialization or
-/// instantiated from a function template.
-class FunctionTemplateSpecializationInfo {
-public:
-  FunctionTemplateDecl *Template;
-  const TemplateArgumentList *TemplateArguments;
-};
   
-/// Declaration of a template function.
-class FunctionTemplateDecl : public TemplateDecl {
-protected:
-  /// \brief Data that is common to all of the declarations of a given
-  /// class template.
-  struct Common {
-    /// \brief The class template specializations for this class
-    /// template, including explicit specializations and instantiations.
-    llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations;
+  /// \brief Construct an integral constant template argument.
+  TemplateArgument(SourceLocation Loc, const llvm::APSInt &Value,
+                   QualType Type)
+  : Kind(Integral) {
+    new (Integer.Value) llvm::APSInt(Value);
+    Integer.Type = Type.getAsOpaquePtr();
+    StartLoc = Loc;
+  }
+  
+  /// \brief Construct a template argument that is an expression. 
+  ///
+  /// This form of template argument only occurs in template argument
+  /// lists used for dependent types and for expression; it will not
+  /// occur in a non-dependent, canonical template argument list.
+  TemplateArgument(Expr *E);
+  
+  /// \brief Copy constructor for a template argument.
+  TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
+    if (Kind == Integral) {
+      new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
+      Integer.Type = Other.Integer.Type;
+    } else if (Kind == Pack) {
+      Args.NumArgs = Other.Args.NumArgs;
+      Args.Args = new TemplateArgument[Args.NumArgs];
+      for (unsigned I = 0; I != Args.NumArgs; ++I)
+        Args.Args[I] = Other.Args.Args[I];
+    }
+    else
+      TypeOrValue = Other.TypeOrValue;
+    StartLoc = Other.StartLoc;
+  }
+  
+  TemplateArgument& operator=(const TemplateArgument& Other) {
+    // FIXME: Does not provide the strong guarantee for exception
+    // safety.
+    using llvm::APSInt;
     
-    /// \brief The class template partial specializations for this class
-    /// template.
-    llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> 
-    PartialSpecializations;
+    // FIXME: Handle Packs
+    assert(Kind != Pack && "FIXME: Handle packs");
+    assert(Other.Kind != Pack && "FIXME: Handle packs");
     
-    /// \brief The injected-class-name type for this class template.
-    QualType InjectedClassNameType;
+    if (Kind == Other.Kind && Kind == Integral) {
+      // Copy integral values.
+      *this->getAsIntegral() = *Other.getAsIntegral();
+      Integer.Type = Other.Integer.Type; 
+    } else {
+      // Destroy the current integral value, if that's what we're holding.
+      if (Kind == Integral)
+        getAsIntegral()->~APSInt();
+      
+      Kind = Other.Kind;
+      
+      if (Other.Kind == Integral) {
+        new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
+        Integer.Type = Other.Integer.Type;
+      } else
+        TypeOrValue = Other.TypeOrValue;
+    }
+    StartLoc = Other.StartLoc;
+    
+    return *this;
+  }
+  
+  ~TemplateArgument() {
+    using llvm::APSInt;
+    
+    if (Kind == Integral)
+      getAsIntegral()->~APSInt();
+    else if (Kind == Pack && Args.CopyArgs)
+      delete[] Args.Args;
+  }
+  
+  /// \brief Return the kind of stored template argument.
+  ArgKind getKind() const { return Kind; }
+  
+  /// \brief Determine whether this template argument has no value.
+  bool isNull() const { return Kind == Null; }
+  
+  /// \brief Retrieve the template argument as a type.
+  QualType getAsType() const {
+    if (Kind != Type)
+      return QualType();
+    
+    return QualType::getFromOpaquePtr(
+                                      reinterpret_cast<void*>(TypeOrValue));
+  }
+  
+  /// \brief Retrieve the template argument as a declaration.
+  Decl *getAsDecl() const {
+    if (Kind != Declaration)
+      return 0;
+    return reinterpret_cast<Decl *>(TypeOrValue);
+  }
+  
+  /// \brief Retrieve the template argument as an integral value.
+  llvm::APSInt *getAsIntegral() {
+    if (Kind != Integral)
+      return 0;
+    return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]);
+  }
+  
+  const llvm::APSInt *getAsIntegral() const {
+    return const_cast<TemplateArgument*>(this)->getAsIntegral();
+  }
+  
+  /// \brief Retrieve the type of the integral value.
+  QualType getIntegralType() const {
+    if (Kind != Integral)
+      return QualType();
+    
+    return QualType::getFromOpaquePtr(Integer.Type);
+  }
+  
+  void setIntegralType(QualType T) {
+    assert(Kind == Integral && 
+           "Cannot set the integral type of a non-integral template argument");
+    Integer.Type = T.getAsOpaquePtr();
   };
   
-  FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
-                       TemplateParameterList *Params, NamedDecl *Decl)
-    : TemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl) { }
-public:
-  /// Get the underling function declaration of the template.
-  FunctionDecl *getTemplatedDecl() const {
-    return static_cast<FunctionDecl*>(TemplatedDecl);
+  /// \brief Retrieve the template argument as an expression.
+  Expr *getAsExpr() const {
+    if (Kind != Expression)
+      return 0;
+    
+    return reinterpret_cast<Expr *>(TypeOrValue);
   }
-
-  /// Create a template function node.
-  static FunctionTemplateDecl *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() == FunctionTemplate; }
-  static bool classof(const FunctionTemplateDecl *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
-/// given a Depth - the nesting of template parameter scopes - and a Position -
-/// the occurrence within the parameter list.
-/// This class is inheritedly privately by different kinds of template
-/// parameters and is not part of the Decl hierarchy. Just a facility.
-class TemplateParmPosition
-{
-protected:
-  // FIXME: This should probably never be called, but it's here as
-  TemplateParmPosition()
-    : Depth(0), Position(0)
-  { /* assert(0 && "Cannot create positionless template parameter"); */ }
-
-  TemplateParmPosition(unsigned D, unsigned P)
-    : Depth(D), Position(P)
-  { }
-
-  // FIXME: These probably don't need to be ints. int:5 for depth, int:8 for
-  // position? Maybe?
-  unsigned Depth;
-  unsigned Position;
-
-public:
-  /// Get the nesting depth of the template parameter.
-  unsigned getDepth() const { return Depth; }
-
-  /// Get the position of the template parameter within its parameter list.
-  unsigned getPosition() const { return Position; }
   
-  /// Get the index of the template parameter within its parameter list.
-  unsigned getIndex() const { return Position; }
-};
-
-/// TemplateTypeParmDecl - Declaration of a template type parameter,
-/// e.g., "T" in
-/// @code
-/// template<typename T> class vector;
-/// @endcode
-class TemplateTypeParmDecl : public TypeDecl {
-  /// \brief Whether this template type parameter was declaration with
-  /// the 'typename' keyword. If false, it was declared with the
-  /// 'class' keyword.
-  bool Typename : 1;
-
-  /// \brief Whether this template type parameter inherited its
-  /// default argument.
-  bool InheritedDefault : 1;
-
-  /// \brief Whether this is a parameter pack.
-  bool ParameterPack : 1;
-
-  /// \brief The location of the default argument, if any.
-  SourceLocation DefaultArgumentLoc;
-
-  /// \brief The default template argument, if any.
-  QualType DefaultArgument;
-
-  TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, 
-                       bool Typename, QualType Type, bool ParameterPack)
-    : TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename),
-      InheritedDefault(false), ParameterPack(ParameterPack), DefaultArgument() { 
-    TypeForDecl = Type.getTypePtr();
+  /// \brief Iterator that traverses the elements of a template argument pack.
+  typedef const TemplateArgument * pack_iterator;
+  
+  /// \brief Iterator referencing the first argument of a template argument 
+  /// pack.
+  pack_iterator pack_begin() const {
+    assert(Kind == Pack);
+    return Args.Args;
+  }
+  
+  /// \brief Iterator referencing one past the last argument of a template
+  /// argument pack.
+  pack_iterator pack_end() const {
+    assert(Kind == Pack);
+    return Args.Args + Args.NumArgs;
   }
-
-public:
-  static TemplateTypeParmDecl *Create(ASTContext &C, DeclContext *DC,
-                                      SourceLocation L, unsigned D, unsigned P,
-                                      IdentifierInfo *Id, bool Typename,
-                                      bool ParameterPack);
-
-  /// \brief Whether this template type parameter was declared with
-  /// the 'typename' keyword. If not, it was declared with the 'class'
-  /// keyword.
-  bool wasDeclaredWithTypename() const { return Typename; }
-
-  /// \brief Determine whether this template parameter has a default
-  /// argument.
-  bool hasDefaultArgument() const { return !DefaultArgument.isNull(); }
-
-  /// \brief Retrieve the default argument, if any.
-  QualType getDefaultArgument() const { return DefaultArgument; }
-
-  /// \brief Retrieve the location of the default argument, if any.
-  SourceLocation getDefaultArgumentLoc() const { return DefaultArgumentLoc; }
-
-  /// \brief Determines whether the default argument was inherited
-  /// from a previous declaration of this template.
-  bool defaultArgumentWasInherited() const { return InheritedDefault; }
-
-  /// \brief Set the default argument for this template parameter, and
-  /// whether that default argument was inherited from another
-  /// declaration.
-  void setDefaultArgument(QualType DefArg, SourceLocation DefArgLoc,
-                          bool Inherited) {
-    DefaultArgument = DefArg;
-    DefaultArgumentLoc = DefArgLoc;
-    InheritedDefault = Inherited;
+  
+  /// \brief The number of template arguments in the given template argument
+  /// pack.
+  unsigned pack_size() const {
+    assert(Kind == Pack);
+    return Args.NumArgs;
   }
-
-  /// \brief Returns whether this is a parameter pack.
-  bool isParameterPack() const { return ParameterPack; }
-
-  // Implement isa/cast/dyncast/etc.
-  static bool classof(const Decl *D) {
-    return D->getKind() == TemplateTypeParm;
+  
+  /// \brief Retrieve the location where the template argument starts.
+  SourceLocation getLocation() const { return StartLoc; }
+  
+  /// \brief Construct a template argument pack.
+  void setArgumentPack(TemplateArgument *Args, unsigned NumArgs, bool CopyArgs);
+  
+  /// \brief Used to insert TemplateArguments into FoldingSets.
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    ID.AddInteger(Kind);
+    switch (Kind) {
+      case Null:
+        break;
+        
+      case Type:
+        getAsType().Profile(ID);
+        break;
+        
+      case Declaration:
+        ID.AddPointer(getAsDecl()); // FIXME: Must be canonical!
+        break;
+        
+      case Integral:
+        getAsIntegral()->Profile(ID);
+        getIntegralType().Profile(ID);
+        break;
+        
+      case Expression:
+        // FIXME: We need a canonical representation of expressions.
+        ID.AddPointer(getAsExpr());
+        break;
+        
+      case Pack:
+        ID.AddInteger(Args.NumArgs);
+        for (unsigned I = 0; I != Args.NumArgs; ++I)
+          Args.Args[I].Profile(ID);
+    }
   }
-  static bool classof(const TemplateTypeParmDecl *D) { return true; }
 };
 
-/// NonTypeTemplateParmDecl - Declares a non-type template parameter,
-/// e.g., "Size" in
-/// @code
-/// template<int Size> class array { };
-/// @endcode
-class NonTypeTemplateParmDecl
-  : public VarDecl, protected TemplateParmPosition {
-  /// \brief The default template argument, if any.
-  Expr *DefaultArgument;
-
-  NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
-                          unsigned P, IdentifierInfo *Id, QualType T,
-                          SourceLocation TSSL = SourceLocation())
-    : VarDecl(NonTypeTemplateParm, DC, L, Id, T, VarDecl::None, TSSL),
-      TemplateParmPosition(D, P), DefaultArgument(0) 
-  { }
-
+/// \brief A helper class for making template argument lists.
+class TemplateArgumentListBuilder {
+  TemplateArgument *StructuredArgs;
+  unsigned MaxStructuredArgs;
+  unsigned NumStructuredArgs;
+  
+  TemplateArgument *FlatArgs;
+  unsigned MaxFlatArgs;
+  unsigned NumFlatArgs;
+  
+  bool AddingToPack;
+  unsigned PackBeginIndex;
+  
 public:
-  static NonTypeTemplateParmDecl *
-  Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
-         unsigned P, IdentifierInfo *Id, QualType T,
-         SourceLocation TypeSpecStartLoc = SourceLocation());
-
-  using TemplateParmPosition::getDepth;
-  using TemplateParmPosition::getPosition;
-  using TemplateParmPosition::getIndex;
+  TemplateArgumentListBuilder(const TemplateParameterList *Parameters,
+                              unsigned NumTemplateArgs)
+  : StructuredArgs(0), MaxStructuredArgs(Parameters->size()), 
+  NumStructuredArgs(0), FlatArgs(0), 
+  MaxFlatArgs(std::max(MaxStructuredArgs, NumTemplateArgs)), NumFlatArgs(0),
+  AddingToPack(false), PackBeginIndex(0) { }
+  
+  void Append(const TemplateArgument& Arg);
+  void BeginPack();
+  void EndPack();
+  
+  void ReleaseArgs();
+  
+  unsigned flatSize() const { 
+    return NumFlatArgs;
+  }
+  const TemplateArgument *getFlatArguments() const {
+    return FlatArgs;
+  }
+  
+  unsigned structuredSize() const {
+    // If we don't have any structured args, just reuse the flat size.
+    if (!StructuredArgs)
+      return flatSize();
     
-  /// \brief Determine whether this template parameter has a default
-  /// argument.
-  bool hasDefaultArgument() const { return DefaultArgument; }
-
-  /// \brief Retrieve the default argument, if any.
-  Expr *getDefaultArgument() const { return DefaultArgument; }
-
-  /// \brief Retrieve the location of the default argument, if any.
-  SourceLocation getDefaultArgumentLoc() const;
-
-  /// \brief Set the default argument for this template parameter.
-  void setDefaultArgument(Expr *DefArg) {
-    DefaultArgument = DefArg;
+    return NumStructuredArgs;
   }
-
-  // Implement isa/cast/dyncast/etc.
-  static bool classof(const Decl *D) {
-    return D->getKind() == NonTypeTemplateParm;
+  const TemplateArgument *getStructuredArguments() const {
+    // If we don't have any structured args, just reuse the flat args.
+    if (!StructuredArgs)
+      return getFlatArguments();
+    
+    return StructuredArgs;
   }
-  static bool classof(const NonTypeTemplateParmDecl *D) { return true; }
 };
 
-/// TemplateTemplateParmDecl - Declares a template template parameter,
-/// e.g., "T" in
-/// @code
-/// template <template <typename> class T> class container { };
-/// @endcode
-/// A template template parameter is a TemplateDecl because it defines the
-/// name of a template and the template parameters allowable for substitution.
-class TemplateTemplateParmDecl
-  : public TemplateDecl, protected TemplateParmPosition {
-
-  /// \brief The default template argument, if any.
-  Expr *DefaultArgument;
-
-  TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
-                           unsigned D, unsigned P,
-                           IdentifierInfo *Id, TemplateParameterList *Params)
-    : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
-      TemplateParmPosition(D, P), DefaultArgument(0)
-    { }
-
+/// \brief A template argument list.
+///
+/// FIXME: In the future, this class will be extended to support
+/// variadic templates and member templates, which will make some of
+/// the function names below make more sense.
+class TemplateArgumentList {
+  /// \brief The template argument list.
+  ///
+  /// The integer value will be non-zero to indicate that this
+  /// template argument list does not own the pointer.
+  llvm::PointerIntPair<const TemplateArgument *, 1> FlatArguments;
+  
+  /// \brief The number of template arguments in this template
+  /// argument list.
+  unsigned NumFlatArguments;
+  
+  llvm::PointerIntPair<const TemplateArgument *, 1> StructuredArguments;
+  unsigned NumStructuredArguments;
+  
 public:
-  static TemplateTemplateParmDecl *Create(ASTContext &C, DeclContext *DC,
-                                          SourceLocation L, unsigned D,
-                                          unsigned P, IdentifierInfo *Id,
-                                          TemplateParameterList *Params);
+  TemplateArgumentList(ASTContext &Context,
+                       TemplateArgumentListBuilder &Builder,
+                       bool TakeArgs);
+  
+  ~TemplateArgumentList();
+  
+  /// \brief Retrieve the template argument at a given index.
+  const TemplateArgument &get(unsigned Idx) const { 
+    assert(Idx < NumFlatArguments && "Invalid template argument index");
+    return getFlatArgumentList()[Idx];
+  }
+  
+  /// \brief Retrieve the template argument at a given index.
+  const TemplateArgument &operator[](unsigned Idx) const { return get(Idx); }
+  
+  /// \brief Retrieve the number of template arguments in this
+  /// template argument list.
+  unsigned size() const { return NumFlatArguments; }
+  
+  /// \brief Retrieve the number of template arguments in the
+  /// flattened template argument list.
+  unsigned flat_size() const { return NumFlatArguments; }
+  
+  /// \brief Retrieve the flattened template argument list.
+  const TemplateArgument *getFlatArgumentList() const { 
+    return FlatArguments.getPointer();
+  }
+};
+  
+//===----------------------------------------------------------------------===//
+// Kinds of Templates
+//===----------------------------------------------------------------------===//
 
-  using TemplateParmPosition::getDepth;
-  using TemplateParmPosition::getPosition;
-  using TemplateParmPosition::getIndex;
-    
-  /// \brief Determine whether this template parameter has a default
-  /// argument.
-  bool hasDefaultArgument() const { return DefaultArgument; }
+/// TemplateDecl - The base class of all kinds of template declarations (e.g.,
+/// class, function, etc.). The TemplateDecl class stores the list of template
+/// parameters and a reference to the templated scoped declaration: the
+/// underlying AST node.
+class TemplateDecl : public NamedDecl {
+protected:
+  // This is probably never used.
+  TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
+               DeclarationName Name)
+    : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(0)
+  { }
 
-  /// \brief Retrieve the default argument, if any.
-  Expr *getDefaultArgument() const { return DefaultArgument; }
+  // Construct a template decl with the given name and parameters.
+  // Used when there is not templated element (tt-params, alias?).
+  TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
+               DeclarationName Name, TemplateParameterList *Params)
+    : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(Params)
+  { }
 
-  /// \brief Retrieve the location of the default argument, if any.
-  SourceLocation getDefaultArgumentLoc() const;
+  // Construct a template decl with name, parameters, and templated element.
+  TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
+               DeclarationName Name, TemplateParameterList *Params,
+               NamedDecl *Decl)
+    : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl),
+      TemplateParams(Params) { }
+public:
+  ~TemplateDecl();
 
-  /// \brief Set the default argument for this template parameter.
-  void setDefaultArgument(Expr *DefArg) {
-    DefaultArgument = DefArg;
+  /// Get the list of template parameters
+  TemplateParameterList *getTemplateParameters() const {
+    return TemplateParams;
   }
 
+  /// Get the underlying, templated declaration.
+  NamedDecl *getTemplatedDecl() const { return TemplatedDecl; }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) {
-    return D->getKind() == TemplateTemplateParm;
+      return D->getKind() >= TemplateFirst && D->getKind() <= TemplateLast;
   }
+  static bool classof(const TemplateDecl *D) { return true; }
+  static bool classof(const FunctionTemplateDecl *D) { return true; }
+  static bool classof(const ClassTemplateDecl *D) { return true; }
   static bool classof(const TemplateTemplateParmDecl *D) { return true; }
-};
 
-/// \brief Represents a template argument within a class template
-/// specialization.
-class TemplateArgument {
-  union {
-    uintptr_t TypeOrValue;
-    struct {
-      char Value[sizeof(llvm::APSInt)];
-      void *Type;
-    } Integer;
-    struct {
-      TemplateArgument *Args;
-      unsigned NumArgs;
-      bool CopyArgs;
-    } Args;
+protected:
+  NamedDecl *TemplatedDecl;
+  TemplateParameterList* TemplateParams;
+};
+ 
+/// \brief Provides information about a function template specialization, 
+/// which is a FunctionDecl that has been explicitly specialization or
+/// instantiated from a function template.
+class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode {
+public:
+  /// \brief The function template specialization that this structure 
+  /// describes.
+  FunctionDecl *Function;
+  
+  /// \brief The function template from which this function template 
+  /// specialization was generated.
+  FunctionTemplateDecl *Template;
+  
+  /// \brief The template arguments used to produce the function template
+  /// specialization from the function template.
+  const TemplateArgumentList *TemplateArguments;
+  
+  void Profile(llvm::FoldingSetNodeID &ID) {
+    Profile(ID, TemplateArguments->getFlatArgumentList(), 
+            TemplateArguments->flat_size());    
+  }
+  
+  static void 
+  Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs, 
+          unsigned NumTemplateArgs) {
+    ID.AddInteger(NumTemplateArgs);
+    for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
+      TemplateArgs[Arg].Profile(ID);
+  }  
+};
+  
+/// Declaration of a template function.
+class FunctionTemplateDecl : public TemplateDecl {  
+protected:
+  /// \brief Data that is common to all of the declarations of a given
+  /// function template.
+  struct Common {
+    /// \brief The function template specializations for this function
+    /// template, including explicit specializations and instantiations.
+    llvm::FoldingSet<FunctionTemplateSpecializationInfo> Specializations;
   };
-
-  /// \brief Location of the beginning of this template argument.
-  SourceLocation StartLoc;
-
+  
+  /// \brief A pointer to the previous declaration (if this is a redeclaration)
+  /// or to the data that is common to all declarations of this function
+  /// template.
+  llvm::PointerUnion<Common*, FunctionTemplateDecl*> CommonOrPrev;
+  
+  /// \brief Retrieves the "common" pointer shared by all 
+  /// (re-)declarations of the same function template. Calling this routine
+  /// may implicitly allocate memory for the common pointer.
+  Common *getCommonPtr();
+  
+  FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
+                       TemplateParameterList *Params, NamedDecl *Decl)
+    : TemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl),
+      CommonOrPrev((Common*)0) { }
+  
 public:
-  /// \brief The type of template argument we're storing.
-  enum ArgKind {
-    Null = 0,
-    /// The template argument is a type. Its value is stored in the
-    /// TypeOrValue field.
-    Type = 1,
-    /// The template argument is a declaration
-    Declaration = 2,
-    /// The template argument is an integral value stored in an llvm::APSInt.
-    Integral = 3,
-    /// The template argument is a value- or type-dependent expression
-    /// stored in an Expr*.
-    Expression = 4,
-
-    /// The template argument is actually a parameter pack. Arguments are stored
-    /// in the Args struct.
-    Pack = 5
-  } Kind;
-
-  /// \brief Construct an empty, invalid template argument.
-  TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Null) { }
-
-  /// \brief Construct a template type argument.
-  TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) {
-    TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
-    StartLoc = Loc;
+  void Destroy(ASTContext &C);
+  
+  /// Get the underlying function declaration of the template.
+  FunctionDecl *getTemplatedDecl() const {
+    return static_cast<FunctionDecl*>(TemplatedDecl);
   }
 
-  /// \brief Construct a template argument that refers to a
-  /// declaration, which is either an external declaration or a
-  /// template declaration.
-  TemplateArgument(SourceLocation Loc, Decl *D) : Kind(Declaration) {
-    // FIXME: Need to be sure we have the "canonical" declaration!
-    TypeOrValue = reinterpret_cast<uintptr_t>(D);
-    StartLoc = Loc;
+  /// \brief Retrieve the set of function template specializations of this
+  /// function template.
+  llvm::FoldingSet<FunctionTemplateSpecializationInfo> &getSpecializations() {
+    return getCommonPtr()->Specializations;
   }
-
-  /// \brief Construct an integral constant template argument.
-  TemplateArgument(SourceLocation Loc, const llvm::APSInt &Value,
-                   QualType Type)
-    : Kind(Integral) {
-    new (Integer.Value) llvm::APSInt(Value);
-    Integer.Type = Type.getAsOpaquePtr();
-    StartLoc = Loc;
+  
+  /// \brief Retrieve the previous declaration of this function template, or
+  /// NULL if no such declaration exists.
+  const FunctionTemplateDecl *getPreviousDeclaration() const {
+    return CommonOrPrev.dyn_cast<FunctionTemplateDecl*>();
   }
 
-  /// \brief Construct a template argument that is an expression. 
-  ///
-  /// This form of template argument only occurs in template argument
-  /// lists used for dependent types and for expression; it will not
-  /// occur in a non-dependent, canonical template argument list.
-  TemplateArgument(Expr *E);
-
-  /// \brief Copy constructor for a template argument.
-  TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
-    if (Kind == Integral) {
-      new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
-      Integer.Type = Other.Integer.Type;
-    } else if (Kind == Pack) {
-      Args.NumArgs = Other.Args.NumArgs;
-      Args.Args = new TemplateArgument[Args.NumArgs];
-      for (unsigned I = 0; I != Args.NumArgs; ++I)
-            Args.Args[I] = Other.Args.Args[I];
-    }
-    else
-      TypeOrValue = Other.TypeOrValue;
-    StartLoc = Other.StartLoc;
+  /// \brief Retrieve the previous declaration of this function template, or
+  /// NULL if no such declaration exists.
+  FunctionTemplateDecl *getPreviousDeclaration() {
+    return CommonOrPrev.dyn_cast<FunctionTemplateDecl*>();
   }
+  
+  /// \brief Set the previous declaration of this function template.
+  void setPreviousDeclaration(FunctionTemplateDecl *Prev) {
+    if (Prev)
+      CommonOrPrev = Prev;
+  }
+  
+  /// Create a template function node.
+  static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
+                                      SourceLocation L,
+                                      DeclarationName Name,
+                                      TemplateParameterList *Params,
+                                      NamedDecl *Decl);
 
-  TemplateArgument& operator=(const TemplateArgument& Other) {
-    // FIXME: Does not provide the strong guarantee for exception
-    // safety.
-    using llvm::APSInt;
-
-    // FIXME: Handle Packs
-    assert(Kind != Pack && "FIXME: Handle packs");
-    assert(Other.Kind != Pack && "FIXME: Handle packs");
+  // Implement isa/cast/dyncast support
+  static bool classof(const Decl *D)
+  { return D->getKind() == FunctionTemplate; }
+  static bool classof(const FunctionTemplateDecl *D)
+  { return true; }
+};
 
-    if (Kind == Other.Kind && Kind == Integral) {
-      // Copy integral values.
-      *this->getAsIntegral() = *Other.getAsIntegral();
-      Integer.Type = Other.Integer.Type; 
-    } else {
-      // Destroy the current integral value, if that's what we're holding.
-      if (Kind == Integral)
-        getAsIntegral()->~APSInt();
-      
-      Kind = Other.Kind;
-      
-      if (Other.Kind == Integral) {
-        new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
-        Integer.Type = Other.Integer.Type;
-      } else
-        TypeOrValue = Other.TypeOrValue;
-    }
-    StartLoc = Other.StartLoc;
+//===----------------------------------------------------------------------===//
+// Kinds of Template Parameters
+//===----------------------------------------------------------------------===//
 
-    return *this;
-  }
+/// 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
+/// given a Depth - the nesting of template parameter scopes - and a Position -
+/// the occurrence within the parameter list.
+/// This class is inheritedly privately by different kinds of template
+/// parameters and is not part of the Decl hierarchy. Just a facility.
+class TemplateParmPosition
+{
+protected:
+  // FIXME: This should probably never be called, but it's here as
+  TemplateParmPosition()
+    : Depth(0), Position(0)
+  { /* assert(0 && "Cannot create positionless template parameter"); */ }
 
-  ~TemplateArgument() {
-    using llvm::APSInt;
+  TemplateParmPosition(unsigned D, unsigned P)
+    : Depth(D), Position(P)
+  { }
 
-    if (Kind == Integral)
-      getAsIntegral()->~APSInt();
-    else if (Kind == Pack && Args.CopyArgs)
-      delete[] Args.Args;
-  }
+  // FIXME: These probably don't need to be ints. int:5 for depth, int:8 for
+  // position? Maybe?
+  unsigned Depth;
+  unsigned Position;
 
-  /// \brief Return the kind of stored template argument.
-  ArgKind getKind() const { return Kind; }
+public:
+  /// Get the nesting depth of the template parameter.
+  unsigned getDepth() const { return Depth; }
 
-  /// \brief Determine whether this template argument has no value.
-  bool isNull() const { return Kind == Null; }
+  /// Get the position of the template parameter within its parameter list.
+  unsigned getPosition() const { return Position; }
   
-  /// \brief Retrieve the template argument as a type.
-  QualType getAsType() const {
-    if (Kind != Type)
-      return QualType();
+  /// Get the index of the template parameter within its parameter list.
+  unsigned getIndex() const { return Position; }
+};
 
-    return QualType::getFromOpaquePtr(
-                                 reinterpret_cast<void*>(TypeOrValue));
-  }
+/// TemplateTypeParmDecl - Declaration of a template type parameter,
+/// e.g., "T" in
+/// @code
+/// template<typename T> class vector;
+/// @endcode
+class TemplateTypeParmDecl : public TypeDecl {
+  /// \brief Whether this template type parameter was declaration with
+  /// the 'typename' keyword. If false, it was declared with the
+  /// 'class' keyword.
+  bool Typename : 1;
 
-  /// \brief Retrieve the template argument as a declaration.
-  Decl *getAsDecl() const {
-    if (Kind != Declaration)
-      return 0;
-    return reinterpret_cast<Decl *>(TypeOrValue);
-  }
+  /// \brief Whether this template type parameter inherited its
+  /// default argument.
+  bool InheritedDefault : 1;
 
-  /// \brief Retrieve the template argument as an integral value.
-  llvm::APSInt *getAsIntegral() {
-    if (Kind != Integral)
-      return 0;
-    return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]);
-  }
+  /// \brief Whether this is a parameter pack.
+  bool ParameterPack : 1;
+
+  /// \brief The location of the default argument, if any.
+  SourceLocation DefaultArgumentLoc;
 
-  const llvm::APSInt *getAsIntegral() const {
-    return const_cast<TemplateArgument*>(this)->getAsIntegral();
+  /// \brief The default template argument, if any.
+  QualType DefaultArgument;
+
+  TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, 
+                       bool Typename, QualType Type, bool ParameterPack)
+    : TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename),
+      InheritedDefault(false), ParameterPack(ParameterPack), DefaultArgument() { 
+    TypeForDecl = Type.getTypePtr();
   }
 
-  /// \brief Retrieve the type of the integral value.
-  QualType getIntegralType() const {
-    if (Kind != Integral)
-      return QualType();
+public:
+  static TemplateTypeParmDecl *Create(ASTContext &C, DeclContext *DC,
+                                      SourceLocation L, unsigned D, unsigned P,
+                                      IdentifierInfo *Id, bool Typename,
+                                      bool ParameterPack);
 
-    return QualType::getFromOpaquePtr(Integer.Type);
-  }
+  /// \brief Whether this template type parameter was declared with
+  /// the 'typename' keyword. If not, it was declared with the 'class'
+  /// keyword.
+  bool wasDeclaredWithTypename() const { return Typename; }
 
-  void setIntegralType(QualType T) {
-    assert(Kind == Integral && 
-           "Cannot set the integral type of a non-integral template argument");
-    Integer.Type = T.getAsOpaquePtr();
-  };
+  /// \brief Determine whether this template parameter has a default
+  /// argument.
+  bool hasDefaultArgument() const { return !DefaultArgument.isNull(); }
 
-  /// \brief Retrieve the template argument as an expression.
-  Expr *getAsExpr() const {
-    if (Kind != Expression)
-      return 0;
+  /// \brief Retrieve the default argument, if any.
+  QualType getDefaultArgument() const { return DefaultArgument; }
 
-    return reinterpret_cast<Expr *>(TypeOrValue);
-  }
+  /// \brief Retrieve the location of the default argument, if any.
+  SourceLocation getDefaultArgumentLoc() const { return DefaultArgumentLoc; }
 
-  /// \brief Iterator that traverses the elements of a template argument pack.
-  typedef const TemplateArgument * pack_iterator;
-  
-  /// \brief Iterator referencing the first argument of a template argument 
-  /// pack.
-  pack_iterator pack_begin() const {
-    assert(Kind == Pack);
-    return Args.Args;
-  }
+  /// \brief Determines whether the default argument was inherited
+  /// from a previous declaration of this template.
+  bool defaultArgumentWasInherited() const { return InheritedDefault; }
 
-  /// \brief Iterator referencing one past the last argument of a template
-  /// argument pack.
-  pack_iterator pack_end() const {
-    assert(Kind == Pack);
-    return Args.Args + Args.NumArgs;
-  }
-  
-  /// \brief The number of template arguments in the given template argument
-  /// pack.
-  unsigned pack_size() const {
-    assert(Kind == Pack);
-    return Args.NumArgs;
+  /// \brief Set the default argument for this template parameter, and
+  /// whether that default argument was inherited from another
+  /// declaration.
+  void setDefaultArgument(QualType DefArg, SourceLocation DefArgLoc,
+                          bool Inherited) {
+    DefaultArgument = DefArg;
+    DefaultArgumentLoc = DefArgLoc;
+    InheritedDefault = Inherited;
   }
-  
-  /// \brief Retrieve the location where the template argument starts.
-  SourceLocation getLocation() const { return StartLoc; }
 
-  /// \brief Construct a template argument pack.
-  void setArgumentPack(TemplateArgument *Args, unsigned NumArgs, bool CopyArgs);
+  /// \brief Returns whether this is a parameter pack.
+  bool isParameterPack() const { return ParameterPack; }
 
-  /// \brief Used to insert TemplateArguments into FoldingSets.
-  void Profile(llvm::FoldingSetNodeID &ID) const {
-    ID.AddInteger(Kind);
-    switch (Kind) {
-    case Null:
-      break;
-        
-    case Type:
-      getAsType().Profile(ID);
-      break;
-
-    case Declaration:
-      ID.AddPointer(getAsDecl()); // FIXME: Must be canonical!
-      break;
-
-    case Integral:
-      getAsIntegral()->Profile(ID);
-      getIntegralType().Profile(ID);
-      break;
-
-    case Expression:
-      // FIXME: We need a canonical representation of expressions.
-      ID.AddPointer(getAsExpr());
-      break;
-    
-    case Pack:
-      ID.AddInteger(Args.NumArgs);
-      for (unsigned I = 0; I != Args.NumArgs; ++I)
-        Args.Args[I].Profile(ID);
-    }
+  // Implement isa/cast/dyncast/etc.
+  static bool classof(const Decl *D) {
+    return D->getKind() == TemplateTypeParm;
   }
+  static bool classof(const TemplateTypeParmDecl *D) { return true; }
 };
 
-/// \brief A helper class for making template argument lists.
-class TemplateArgumentListBuilder {
-  TemplateArgument *StructuredArgs;
-  unsigned MaxStructuredArgs;
-  unsigned NumStructuredArgs;
-    
-  TemplateArgument *FlatArgs;
-  unsigned MaxFlatArgs;
-  unsigned NumFlatArgs;
-  
-  bool AddingToPack;
-  unsigned PackBeginIndex;
-  
+/// NonTypeTemplateParmDecl - Declares a non-type template parameter,
+/// e.g., "Size" in
+/// @code
+/// template<int Size> class array { };
+/// @endcode
+class NonTypeTemplateParmDecl
+  : public VarDecl, protected TemplateParmPosition {
+  /// \brief The default template argument, if any.
+  Expr *DefaultArgument;
+
+  NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
+                          unsigned P, IdentifierInfo *Id, QualType T,
+                          SourceLocation TSSL = SourceLocation())
+    : VarDecl(NonTypeTemplateParm, DC, L, Id, T, VarDecl::None, TSSL),
+      TemplateParmPosition(D, P), DefaultArgument(0) 
+  { }
+
 public:
-  TemplateArgumentListBuilder(const TemplateParameterList *Parameters,
-                              unsigned NumTemplateArgs)
-    : StructuredArgs(0), MaxStructuredArgs(Parameters->size()), 
-    NumStructuredArgs(0), FlatArgs(0), 
-    MaxFlatArgs(std::max(MaxStructuredArgs, NumTemplateArgs)), NumFlatArgs(0),
-    AddingToPack(false), PackBeginIndex(0) { }
-  
-  void Append(const TemplateArgument& Arg);
-  void BeginPack();
-  void EndPack();
+  static NonTypeTemplateParmDecl *
+  Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
+         unsigned P, IdentifierInfo *Id, QualType T,
+         SourceLocation TypeSpecStartLoc = SourceLocation());
 
-  void ReleaseArgs();
-  
-  unsigned flatSize() const { 
-    return NumFlatArgs;
-  }
-  const TemplateArgument *getFlatArguments() const {
-    return FlatArgs;
-  }
-  
-  unsigned structuredSize() const {
-    // If we don't have any structured args, just reuse the flat size.
-    if (!StructuredArgs)
-      return flatSize();
+  using TemplateParmPosition::getDepth;
+  using TemplateParmPosition::getPosition;
+  using TemplateParmPosition::getIndex;
+    
+  /// \brief Determine whether this template parameter has a default
+  /// argument.
+  bool hasDefaultArgument() const { return DefaultArgument; }
 
-    return NumStructuredArgs;
+  /// \brief Retrieve the default argument, if any.
+  Expr *getDefaultArgument() const { return DefaultArgument; }
+
+  /// \brief Retrieve the location of the default argument, if any.
+  SourceLocation getDefaultArgumentLoc() const;
+
+  /// \brief Set the default argument for this template parameter.
+  void setDefaultArgument(Expr *DefArg) {
+    DefaultArgument = DefArg;
   }
-  const TemplateArgument *getStructuredArguments() const {
-    // If we don't have any structured args, just reuse the flat args.
-    if (!StructuredArgs)
-      return getFlatArguments();
-    
-    return StructuredArgs;
+
+  // Implement isa/cast/dyncast/etc.
+  static bool classof(const Decl *D) {
+    return D->getKind() == NonTypeTemplateParm;
   }
+  static bool classof(const NonTypeTemplateParmDecl *D) { return true; }
 };
 
-/// \brief A template argument list.
-///
-/// FIXME: In the future, this class will be extended to support
-/// variadic templates and member templates, which will make some of
-/// the function names below make more sense.
-class TemplateArgumentList {
-  /// \brief The template argument list.
-  ///
-  /// The integer value will be non-zero to indicate that this
-  /// template argument list does not own the pointer.
-  llvm::PointerIntPair<const TemplateArgument *, 1> FlatArguments;
+/// TemplateTemplateParmDecl - Declares a template template parameter,
+/// e.g., "T" in
+/// @code
+/// template <template <typename> class T> class container { };
+/// @endcode
+/// A template template parameter is a TemplateDecl because it defines the
+/// name of a template and the template parameters allowable for substitution.
+class TemplateTemplateParmDecl
+  : public TemplateDecl, protected TemplateParmPosition {
 
-  /// \brief The number of template arguments in this template
-  /// argument list.
-  unsigned NumFlatArguments;
+  /// \brief The default template argument, if any.
+  Expr *DefaultArgument;
 
-  llvm::PointerIntPair<const TemplateArgument *, 1> StructuredArguments;
-  unsigned NumStructuredArguments;
-  
-public:
-  TemplateArgumentList(ASTContext &Context,
-                       TemplateArgumentListBuilder &Builder,
-                       bool TakeArgs);
+  TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
+                           unsigned D, unsigned P,
+                           IdentifierInfo *Id, TemplateParameterList *Params)
+    : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
+      TemplateParmPosition(D, P), DefaultArgument(0)
+    { }
 
-  ~TemplateArgumentList();
+public:
+  static TemplateTemplateParmDecl *Create(ASTContext &C, DeclContext *DC,
+                                          SourceLocation L, unsigned D,
+                                          unsigned P, IdentifierInfo *Id,
+                                          TemplateParameterList *Params);
 
-  /// \brief Retrieve the template argument at a given index.
-  const TemplateArgument &get(unsigned Idx) const { 
-    assert(Idx < NumFlatArguments && "Invalid template argument index");
-    return getFlatArgumentList()[Idx];
-  }
+  using TemplateParmPosition::getDepth;
+  using TemplateParmPosition::getPosition;
+  using TemplateParmPosition::getIndex;
+    
+  /// \brief Determine whether this template parameter has a default
+  /// argument.
+  bool hasDefaultArgument() const { return DefaultArgument; }
 
-  /// \brief Retrieve the template argument at a given index.
-  const TemplateArgument &operator[](unsigned Idx) const { return get(Idx); }
+  /// \brief Retrieve the default argument, if any.
+  Expr *getDefaultArgument() const { return DefaultArgument; }
 
-  /// \brief Retrieve the number of template arguments in this
-  /// template argument list.
-  unsigned size() const { return NumFlatArguments; }
+  /// \brief Retrieve the location of the default argument, if any.
+  SourceLocation getDefaultArgumentLoc() const;
 
-  /// \brief Retrieve the number of template arguments in the
-  /// flattened template argument list.
-  unsigned flat_size() const { return NumFlatArguments; }
+  /// \brief Set the default argument for this template parameter.
+  void setDefaultArgument(Expr *DefArg) {
+    DefaultArgument = DefArg;
+  }
 
-  /// \brief Retrieve the flattened template argument list.
-  const TemplateArgument *getFlatArgumentList() const { 
-    return FlatArguments.getPointer();
+  // Implement isa/cast/dyncast/etc.
+  static bool classof(const Decl *D) {
+    return D->getKind() == TemplateTemplateParm;
   }
+  static bool classof(const TemplateTemplateParmDecl *D) { return true; }
 };
 
 // \brief Describes the kind of template specialization that a

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

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon Jun 29 15:59:39 2009
@@ -1806,6 +1806,12 @@
     return const_cast<FunctionDecl *>(Function);
   }
 
+  if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) {
+    while (FunTmpl->getPreviousDeclaration())
+      FunTmpl = FunTmpl->getPreviousDeclaration();
+    return FunTmpl;
+  }
+  
   if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
     while (Var->getPreviousDeclaration())
       Var = Var->getPreviousDeclaration();

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

==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Mon Jun 29 15:59:39 2009
@@ -372,11 +372,6 @@
 
   C.Deallocate(ParamInfo);
 
-  if (FunctionTemplateSpecializationInfo *Info 
-        = TemplateOrSpecialization
-            .dyn_cast<FunctionTemplateSpecializationInfo*>())
-    C.Deallocate(Info);
-  
   Decl::Destroy(C);
 }
 
@@ -564,6 +559,18 @@
   return false;
 }
 
+void 
+FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
+  PreviousDeclaration = PrevDecl;
+  
+  if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
+    FunctionTemplateDecl *PrevFunTmpl 
+      = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
+    assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
+    FunTmpl->setPreviousDeclaration(PrevFunTmpl);
+  }
+}
+
 /// getOverloadedOperator - Which C++ overloaded operator this
 /// function represents, if any.
 OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
@@ -595,15 +602,21 @@
 void 
 FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
                                                 FunctionTemplateDecl *Template,
-                                     const TemplateArgumentList *TemplateArgs) {
+                                     const TemplateArgumentList *TemplateArgs,
+                                                void *InsertPos) {
   FunctionTemplateSpecializationInfo *Info 
     = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
   if (!Info)
     Info = new (Context) FunctionTemplateSpecializationInfo;
   
+  Info->Function = this;
   Info->Template = Template;
   Info->TemplateArguments = TemplateArgs;
   TemplateOrSpecialization = Info;
+  
+  // Insert this function template specialization into the set of known
+  // function template specialiations.
+  Template->getSpecializations().InsertNode(Info, InsertPos);
 }
 
 //===----------------------------------------------------------------------===//

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

==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Mon Jun 29 15:59:39 2009
@@ -81,11 +81,36 @@
                                                    DeclContext *DC,
                                                    SourceLocation L,
                                                    DeclarationName Name,
-                                                   TemplateParameterList *Params,
+                                               TemplateParameterList *Params,
                                                    NamedDecl *Decl) {
   return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl);
 }
 
+void FunctionTemplateDecl::Destroy(ASTContext &C) {
+  if (Common *CommonPtr = CommonOrPrev.dyn_cast<Common*>()) {
+    for (llvm::FoldingSet<FunctionTemplateSpecializationInfo>::iterator
+              Spec = CommonPtr->Specializations.begin(),
+           SpecEnd = CommonPtr->Specializations.end();
+         Spec != SpecEnd; ++Spec)
+      C.Deallocate(&*Spec);
+  }
+  
+  Decl::Destroy(C);
+}
+
+FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() {
+  // Find the first declaration of this function template.
+  FunctionTemplateDecl *First = this;
+  while (First->getPreviousDeclaration())
+    First = First->getPreviousDeclaration();
+  
+  if (First->CommonOrPrev.isNull()) {
+    // FIXME: Allocate with the ASTContext
+    First->CommonOrPrev = new Common;
+  }
+  return First->CommonOrPrev.get<Common*>();
+}
+
 //===----------------------------------------------------------------------===//
 // ClassTemplateDecl Implementation
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=74454&r1=74453&r2=74454&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Mon Jun 29 15:59:39 2009
@@ -1500,6 +1500,8 @@
     break;
     // No code generation needed.
   case Decl::Using:
+  case Decl::ClassTemplate:
+  case Decl::FunctionTemplate:
     break;
   case Decl::CXXConstructor:
     EmitCXXConstructors(cast<CXXConstructorDecl>(D));

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Mon Jun 29 15:59:39 2009
@@ -1036,14 +1036,22 @@
                          InstantiateDecl(FunctionTemplate->getTemplatedDecl(),
                                          FunctionTemplate->getDeclContext(),
                                          *DeducedArgumentList));
+  if (!Specialization)
+    return TDK_SubstitutionFailure;
   
-  if (!Specialization || Trap.hasErrorOccurred())
+  // If the template argument list is owned by the function template 
+  // specialization, release it.
+  if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList)
+    Info.take();
+
+  // There may have been an error that did not prevent us from constructing a
+  // declaration. Mark the declaration invalid and return with a substitution
+  // failure.
+  if (Trap.hasErrorOccurred()) {
+    Specialization->setInvalidDecl(true);
     return TDK_SubstitutionFailure;
-
-  // Turn the specialization into an actual function template specialization.
-  Specialization->setFunctionTemplateSpecialization(Context,
-                                                    FunctionTemplate,
-                                                    Info.take());
+  }
+  
   return TDK_Success;
 }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Jun 29 15:59:39 2009
@@ -294,7 +294,24 @@
 }
 
 Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
-  // FIXME: Look for existing specializations (explicit or otherwise).
+  // Check whether there is already a function template specialization for
+  // this declaration.
+  FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
+  void *InsertPos = 0;
+  if (FunctionTemplate) {
+    llvm::FoldingSetNodeID ID;
+    FunctionTemplateSpecializationInfo::Profile(ID, 
+                                          TemplateArgs.getFlatArgumentList(),
+                                                TemplateArgs.flat_size());
+    
+    FunctionTemplateSpecializationInfo *Info 
+      = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID, 
+                                                                   InsertPos);
+    
+    // If we already have a function template specialization, return it.
+    if (Info)
+      return Info->Function;
+  }
   
   Sema::LocalInstantiationScope Scope(SemaRef);
   
@@ -325,10 +342,15 @@
   NamedDecl *PrevDecl = 0;
   SemaRef.CheckFunctionDeclaration(Function, PrevDecl, Redeclaration,
                                    /*FIXME:*/OverloadableAttrRequired);
-  
 
-  // FIXME: link this to the function template from which it was instantiated.
-  
+  if (FunctionTemplate) {
+    // Record this function template specialization.
+    Function->setFunctionTemplateSpecialization(SemaRef.Context,
+                                                FunctionTemplate,
+                                                &TemplateArgs,
+                                                InsertPos);
+   }
+
   return Function;
 }
 

Added: cfe/trunk/test/CodeGenCXX/function-template-specialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/function-template-specialization.cpp?rev=74454&view=auto

==============================================================================
--- cfe/trunk/test/CodeGenCXX/function-template-specialization.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/function-template-specialization.cpp Mon Jun 29 15:59:39 2009
@@ -0,0 +1,21 @@
+// RUN: clang-cc -emit-llvm %s -o -
+template<typename T, typename U>
+T* next(T* ptr, const U& diff);
+
+template<typename T, typename U>
+T* next(T* ptr, const U& diff) { 
+  return ptr + diff; 
+}
+
+void test(int *iptr, float *fptr, int diff) {
+  iptr = next(iptr, diff);
+  fptr = next(fptr, diff);
+}
+
+template<typename T, typename U>
+T* next(T* ptr, const U& diff);
+
+void test2(int *iptr, double *dptr, int diff) {
+  iptr = next(iptr, diff);
+  dptr = next(dptr, diff);
+}
\ No newline at end of file





More information about the cfe-commits mailing list