[cfe-commits] r64153 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/DeclTemplate.h include/clang/AST/Type.h include/clang/Parse/Action.h include/clang/Parse/Parser.h lib/AST/ASTContext.cpp lib/AST/DeclTemplate.cpp lib/AST/Type.cpp lib/AST/TypeSerialization.cpp lib/CodeGen/CodeGenTypes.cpp lib/Parse/MinimalAction.cpp lib/Parse/ParseDecl.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseTemplate.cpp lib/Parse/Parser.cpp lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp test/SemaTemplate/class-template-id.cpp

Douglas Gregor dgregor at apple.com
Mon Feb 9 10:46:08 PST 2009


Author: dgregor
Date: Mon Feb  9 12:46:07 2009
New Revision: 64153

URL: http://llvm.org/viewvc/llvm-project?rev=64153&view=rev
Log:
Start processing template-ids as types when the template-name refers
to a class template. For example, the template-id 'vector<int>' now
has a nice, sugary type in the type system. What we can do now:

  - Parse template-ids like 'vector<int>' (where 'vector' names a
    class template) and form proper types for them in the type system.
  - Parse icky template-ids like 'A<5>' and 'A<(5 > 0)>' properly,
    using (sadly) a bool in the parser to tell it whether '>' should
    be treated as an operator or not.

This is a baby-step, with major problems and limitations:
  - There are currently two ways that we handle template arguments
  (whether they are types or expressions). These will be merged, and,
  most likely, TemplateArg will disappear.
  - We don't have any notion of the declaration of class template
  specializations or of template instantiations, so all template-ids
  are fancy names for 'int' :)


Added:
    cfe/trunk/test/SemaTemplate/class-template-id.cpp
Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/DeclTemplate.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/AST/TypeSerialization.cpp
    cfe/trunk/lib/CodeGen/CodeGenTypes.cpp
    cfe/trunk/lib/Parse/MinimalAction.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaTemplate.cpp

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

==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Mon Feb  9 12:46:07 2009
@@ -69,6 +69,8 @@
   llvm::FoldingSet<FunctionTypeNoProto> FunctionTypeNoProtos;
   llvm::FoldingSet<FunctionTypeProto> FunctionTypeProtos;
   llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
+  llvm::FoldingSet<ClassTemplateSpecializationType> 
+    ClassTemplateSpecializationTypes;
   llvm::FoldingSet<ObjCQualifiedInterfaceType> ObjCQualifiedInterfaceTypes;
   llvm::FoldingSet<ObjCQualifiedIdType> ObjCQualifiedIdTypes;
   /// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts.
@@ -262,6 +264,11 @@
   QualType getTemplateTypeParmType(unsigned Depth, unsigned Index, 
                                    IdentifierInfo *Name = 0);
 
+  QualType getClassTemplateSpecializationType(TemplateDecl *Template,
+                                              unsigned NumArgs,
+                                              uintptr_t *Args, bool *ArgIsType,
+                                              QualType Canon);
+
   /// getObjCQualifiedInterfaceType - Return a 
   /// ObjCQualifiedInterfaceType type for the given interface decl and
   /// the conforming protocol list.

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

==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Mon Feb  9 12:46:07 2009
@@ -14,6 +14,8 @@
 #ifndef LLVM_CLANG_AST_DECLTEMPLATE_H
 #define LLVM_CLANG_AST_DECLTEMPLATE_H
 
+#include "clang/AST/DeclCXX.h"
+
 namespace clang {
 
 class TemplateParameterList;
@@ -158,7 +160,7 @@
 public:
   /// Get the underlying class declarations of the template.
   CXXRecordDecl *getTemplatedDecl() const {
-    return static_cast<CXXRecordDecl*>(TemplatedDecl);
+    return static_cast<CXXRecordDecl *>(TemplatedDecl);
   }
 
   /// Create a class teplate node.
@@ -334,6 +336,35 @@
   friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
 };
 
+class TemplateArg {
+  enum {
+    TypeArg,
+    ExprArg
+  } Kind;
+
+  uintptr_t Ptr;
+
+public:
+  explicit TemplateArg(QualType Type) 
+    : Kind(TypeArg), Ptr(reinterpret_cast<uintptr_t>(Type.getAsOpaquePtr())) { }
+  explicit TemplateArg(Expr *E)
+    : Kind(ExprArg), Ptr(reinterpret_cast<uintptr_t>(E)) { }
+
+  QualType getAsType() const {
+    if (Kind == TypeArg) 
+      return QualType::getFromOpaquePtr(reinterpret_cast<void*>(Ptr));
+    return QualType();
+  }
+
+  Expr *getAsExpr() const {
+    if (Kind == ExprArg) return reinterpret_cast<Expr *>(Ptr);
+    return 0;
+  }
+
+  void Destroy(ASTContext &C);
+};
+
+
 } /* 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=64153&r1=64152&r2=64153&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Mon Feb  9 12:46:07 2009
@@ -30,6 +30,7 @@
   class ASTContext;
   class Type;
   class TypedefDecl;
+  class TemplateDecl;
   class TemplateTypeParmDecl;
   class NonTypeTemplateParmDecl;
   class TemplateTemplateParamDecl;
@@ -69,6 +70,7 @@
   class ObjCQualifiedIdType;
   class ObjCQualifiedInterfaceType;
   class StmtIteratorBase;
+  class ClassTemplateSpecializationType;
 
 /// QualType - For efficiency, we don't store CVR-qualified types as nodes on
 /// their own: instead each reference to a type stores the qualifiers.  This
@@ -245,7 +247,7 @@
     Vector, ExtVector,
     FunctionNoProto, FunctionProto,
     TypeName, Tagged, ASQual,
-    TemplateTypeParm,
+    TemplateTypeParm, ClassTemplateSpecialization,
     ObjCInterface, ObjCQualifiedInterface,
     ObjCQualifiedId,
     TypeOfExp, TypeOfTyp, // GNU typeof extension.
@@ -391,6 +393,9 @@
   const ObjCQualifiedIdType *getAsObjCQualifiedIdType() const;
   const TemplateTypeParmType *getAsTemplateTypeParmType() const;
 
+  const ClassTemplateSpecializationType *
+    getClassTemplateSpecializationType() const;
+  
   /// getAsPointerToObjCInterfaceType - If this is a pointer to an ObjC
   /// interface, return the interface type, otherwise return null.
   const ObjCInterfaceType *getAsPointerToObjCInterfaceType() const;
@@ -400,8 +405,6 @@
   /// This method should never be used when type qualifiers are meaningful.
   const Type *getArrayElementTypeNoTypeQual() const;
   
-
-  
   /// getDesugaredType - Return the specified type with any "sugar" removed from
   /// the type.  This takes off typedefs, typeof's etc.  If the outer level of
   /// the type is already concrete, it returns it unmodified.  This is similar
@@ -1395,6 +1398,127 @@
   friend class Type;
 };
 
+/// \brief Represents the type of a class template specialization as
+/// written in the source code.
+///
+/// Class template specialization types represent the syntactic form
+/// of a template-id that refers to a type, e.g., @c vector<int>. All
+/// class template specialization types are syntactic sugar, whose
+/// canonical type will point to some other type node that represents
+/// the instantiation or class template specialization. For example, a
+/// class template specialization type of @c vector<int> will refer to
+/// a tag type for the instantiation
+/// @c std::vector<int, std::allocator<int>>.
+class ClassTemplateSpecializationType 
+  : public Type, public llvm::FoldingSetNode {
+
+  // FIXME: Do we want templates to have a representation in the type
+  // system? It will probably help with dependent templates and
+  // possibly with template-names preceded by a nested-name-specifier.
+  TemplateDecl *Template;
+
+  unsigned NumArgs;
+
+  ClassTemplateSpecializationType(TemplateDecl *T, unsigned NumArgs,
+                                  uintptr_t *Args, bool *ArgIsType,
+                                  QualType Canon);
+
+  /// \brief Retrieve the number of packed words that precede the
+  /// actual arguments.
+  ///
+  /// The flags that specify whether each argument is a type or an
+  /// expression are packed into the
+  /// ClassTemplateSpecializationType. This routine computes the
+  /// number of pointer-sized words we need to store this information,
+  /// based on the number of template arguments
+  static unsigned getNumPackedWords(unsigned NumArgs) {
+    const unsigned BitsPerWord = sizeof(uintptr_t) * CHAR_BIT;
+    return NumArgs / BitsPerWord + (NumArgs % BitsPerWord > 0);
+  }
+
+  /// \brief Pack the given boolean values into words.
+  static void 
+  packBooleanValues(unsigned NumArgs, bool *Values, uintptr_t *Words);
+  
+  friend class ASTContext;  // ASTContext creates these
+
+public:
+  /// \brief Retrieve the template that we are specializing.
+  TemplateDecl *getTemplate() const { return Template; }
+
+  /// \briefe Retrieve the number of template arguments.
+  unsigned getNumArgs() const { return NumArgs; }
+
+  /// \brief Retrieve a specific template argument as a type.
+  /// \precondition @c isArgType(Arg)
+  QualType getArgAsType(unsigned Arg) const {
+    assert(isArgType(Arg) && "Argument is not a type");
+    return QualType::getFromOpaquePtr(
+                          reinterpret_cast<void *>(getArgAsOpaqueValue(Arg)));
+  }
+
+  /// \brief Retrieve a specific template argument as an expression.
+  /// \precondition @c !isArgType(Arg)
+  Expr *getArgAsExpr(unsigned Arg) const {
+    assert(!isArgType(Arg) && "Argument is not an expression");
+    return reinterpret_cast<Expr *>(getArgAsOpaqueValue(Arg));
+  }
+
+  /// \brief Retrieve the specified template argument as an opaque value.
+  uintptr_t getArgAsOpaqueValue(unsigned Arg) const;
+
+  /// \brief Determine whether the given template argument is a type.
+  bool isArgType(unsigned Arg) const;
+
+  virtual void getAsStringInternal(std::string &InnerString) const;
+
+  void Profile(llvm::FoldingSetNodeID &ID) {
+    // Add the template
+    ID.AddPointer(Template);
+
+    // Add the packed words describing what kind of template arguments
+    // we have.
+    uintptr_t *Data = reinterpret_cast<uintptr_t *>(this + 1);
+    for (unsigned Packed = 0, NumPacked = getNumPackedWords(NumArgs); 
+         Packed != NumPacked; ++Packed)
+      ID.AddInteger(Data[Packed]);
+
+    // Add the template arguments themselves.
+    for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
+      ID.AddInteger(getArgAsOpaqueValue(Arg));
+  }
+
+  static void Profile(llvm::FoldingSetNodeID &ID, TemplateDecl *T,
+                      unsigned NumArgs, uintptr_t *Args, bool *ArgIsType) {
+    // Add the template
+    ID.AddPointer(T);
+
+    // Add the packed words describing what kind of template arguments
+    // we have.
+    unsigned NumPackedWords = getNumPackedWords(NumArgs);
+    unsigned NumPackedBytes = NumPackedWords * sizeof(uintptr_t);
+    uintptr_t *PackedWords 
+      = reinterpret_cast<uintptr_t *>(alloca(NumPackedBytes));
+    packBooleanValues(NumArgs, ArgIsType, PackedWords);
+    for (unsigned Packed = 0; Packed != NumPackedWords; ++Packed)
+      ID.AddInteger(PackedWords[Packed]);
+
+    // Add the template arguments themselves.
+    for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
+      ID.AddInteger(Args[Arg]);
+  }
+
+  static bool classof(const Type *T) { 
+    return T->getTypeClass() == ClassTemplateSpecialization; 
+  }
+  static bool classof(const ClassTemplateSpecializationType *T) { return true; }
+
+protected:
+  virtual void EmitImpl(llvm::Serializer& S) const;
+  static Type* CreateImpl(ASTContext& Context, llvm::Deserializer& D);
+  friend class Type;
+};
+
 /// ObjCInterfaceType - Interfaces are the core concept in Objective-C for
 /// object oriented design.  They basically correspond to C++ classes.  There
 /// are two kinds of interface types, normal interfaces like "NSString" and

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=64153&r1=64152&r2=64153&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Mon Feb  9 12:46:07 2009
@@ -108,7 +108,7 @@
   typedef ASTMultiPtr<&ActionBase::DeleteExpr> MultiExprArg;
   typedef ASTMultiPtr<&ActionBase::DeleteStmt> MultiStmtArg;
   typedef ASTMultiPtr<&ActionBase::DeleteTemplateParams> MultiTemplateParamsArg;
-  typedef ASTMultiPtr<&ActionBase::DeleteTemplateArg> MultiTemplateArgArg;
+  typedef ASTMultiPtr<&ActionBase::DeleteTemplateArg> MultiTemplateArgsArg;
 
   // Utilities for Action implementations to return smart results.
 
@@ -149,13 +149,28 @@
   virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
                                   const CXXScopeSpec *SS = 0) = 0;
 
-  /// isTemplateName - Determines whether the identifier II is a
-  /// template name in the current scope, and returns the template
-  /// declaration if II names a template. An optional CXXScope can be
-  /// passed to indicate the C++ scope in which the identifier will be
-  /// found. 
-  virtual DeclTy *isTemplateName(IdentifierInfo &II, Scope *S,
-                                 const CXXScopeSpec *SS = 0) = 0;
+  /// \brief Specifies the kind of template name. Returned from
+  /// isTemplateName.
+  enum TemplateNameKind {
+    /// The name does not refer to a template.
+    TNK_Non_template,
+    /// The name refers to a function template or a set of overloaded
+    /// functions that includes at least one function template.
+    TNK_Function_template,
+    /// The name refers to a class template.
+    TNK_Class_template,
+    /// The name referes to a template template parameter.
+    TNK_Template_template_parm
+  };
+
+  /// \brief Determines whether the identifier II is a template name
+  /// in the current scope. If so, the kind of template name is
+  /// returned, and \p TemplateDecl receives the declaration. An
+  /// optional CXXScope can be passed to indicate the C++ scope in
+  /// which the identifier will be found.
+  virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S,
+                                          DeclTy *&TemplateDecl,
+                                          const CXXScopeSpec *SS = 0) = 0;
 
   /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
   /// global scope ('::').
@@ -1111,8 +1126,16 @@
     return 0;
   }
 
-  // \brief Process the declaration or definition of a class template
-  // with the given template parameter lists.
+  virtual OwningTemplateArgResult ActOnTypeTemplateArgument(TypeTy *Type) {
+    return TemplateArgError();
+  }
+
+  virtual OwningTemplateArgResult ActOnExprTemplateArgument(ExprArg Value) {
+    return TemplateArgError();
+  }
+
+  /// \brief Process the declaration or definition of a class template
+  /// with the given template parameter lists.
   virtual DeclTy *
   ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
                      SourceLocation KWLoc, const CXXScopeSpec &SS,
@@ -1122,7 +1145,25 @@
     return 0;
   }
 
-  
+  /// \brief Form a class template specialization from a template and
+  /// a list of template arguments.
+  ///
+  /// \param Template  A template whose specialization results in a
+  /// type, e.g., a class template or template template parameter.
+  ///
+  /// \todo "Class template specialization" is the standard term for
+  /// the types that we're forming, but the name
+  /// ActOnClassTemplateSpecialization sounds like we're declaring a
+  /// new class template specialization.
+  virtual TypeTy * 
+  ActOnClassTemplateSpecialization(DeclTy *Template,
+                                   SourceLocation LAngleLoc,
+                                   MultiTemplateArgsArg TemplateArgs,
+                                   SourceLocation RAngleLoc,
+                                   const CXXScopeSpec *SS = 0) {
+    return 0;
+  };
+
   //===----------------------- Obj-C Declarations -------------------------===//
   
   // ActOnStartClassInterface - this action is called immediately after parsing
@@ -1372,13 +1413,9 @@
   virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S,
                                   const CXXScopeSpec *SS);
 
-  /// isTemplateName - Determines whether the identifier II is a
-  /// template name in the current scope, and returns the template
-  /// declaration if II names a template. An optional CXXScope can be
-  /// passed to indicate the C++ scope in which the identifier will be
-  /// found. 
-  virtual DeclTy *isTemplateName(IdentifierInfo &II, Scope *S,
-                                 const CXXScopeSpec *SS = 0);
+  virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S,
+                                          DeclTy *&TemplateDecl,
+                                          const CXXScopeSpec *SS = 0);
 
   /// ActOnDeclarator - If this is a typedef declarator, we modify the
   /// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=64153&r1=64152&r2=64153&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Feb  9 12:46:07 2009
@@ -58,6 +58,44 @@
 
   PragmaHandler *PackHandler;
 
+  /// Whether the '>' token acts as an operator or not. This will be
+  /// true except when we are parsing an expression within a C++
+  /// template argument list, where the '>' closes the template
+  /// argument list.
+  bool GreaterThanIsOperator;
+
+  /// \brief RAII object that makes '>' behave like the closing angle
+  /// bracket for a template argument list.
+  struct MakeGreaterThanTemplateArgumentListTerminator {
+    bool &GreaterThanIsOperator;
+    bool OldGreaterThanIsOperator;
+   
+    MakeGreaterThanTemplateArgumentListTerminator(bool &GTIO)
+      : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { 
+      GTIO = false;
+    }
+
+    ~MakeGreaterThanTemplateArgumentListTerminator() {
+      GreaterThanIsOperator = OldGreaterThanIsOperator;
+    }
+  };
+
+  /// \brief RAII object that makes '>' behave like an
+  /// operator. Occurs, for example, inside parentheses.
+  struct MakeGreaterThanAnOperator {
+    bool &GreaterThanIsOperator;
+    bool OldGreaterThanIsOperator;
+   
+    MakeGreaterThanAnOperator(bool &GTIO)
+      : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { 
+      GTIO = true;
+    }
+
+    ~MakeGreaterThanAnOperator() {
+      GreaterThanIsOperator = OldGreaterThanIsOperator;
+    }
+  };
+
 public:
   Parser(Preprocessor &PP, Action &Actions);
   ~Parser();
@@ -976,6 +1014,7 @@
   //===--------------------------------------------------------------------===//
   // C++ 14: Templates [temp]
   typedef llvm::SmallVector<DeclTy *, 4> TemplateParameterList;
+  typedef Action::TemplateNameKind TemplateNameKind;
 
   // C++ 14.1: Template Parameters [temp.param]
   DeclTy *ParseTemplateDeclaration(unsigned Context);
@@ -991,7 +1030,8 @@
   DeclTy *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position);
   // C++ 14.3: Template arguments [temp.arg]
   typedef llvm::SmallVector<TemplateArgTy*, 8> TemplateArgList;
-  void AnnotateTemplateIdToken(DeclTy *Template, const CXXScopeSpec *SS = 0);
+  void AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
+                               const CXXScopeSpec *SS = 0);
   bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs);
   OwningTemplateArgResult ParseTemplateArgument();
 

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

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon Feb  9 12:46:07 2009
@@ -1220,6 +1220,34 @@
   return QualType(TypeParm, 0);
 }
 
+QualType 
+ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template,
+                                               unsigned NumArgs,
+                                               uintptr_t *Args, bool *ArgIsType,
+                                               QualType Canon) {
+  llvm::FoldingSetNodeID ID;
+  ClassTemplateSpecializationType::Profile(ID, Template, NumArgs, Args, 
+                                           ArgIsType);
+  void *InsertPos = 0;
+  ClassTemplateSpecializationType *Spec
+    = ClassTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
+
+  if (Spec)
+    return QualType(Spec, 0);
+  
+  void *Mem = Allocate(sizeof(ClassTemplateSpecializationType) + 
+                       (sizeof(uintptr_t) * 
+                        (ClassTemplateSpecializationType::
+                           getNumPackedWords(NumArgs) + 
+                         NumArgs)), 8);
+  Spec = new (Mem) ClassTemplateSpecializationType(Template, NumArgs, Args,
+                                                   ArgIsType, Canon);
+  Types.push_back(Spec);
+  ClassTemplateSpecializationTypes.InsertNode(Spec, InsertPos);
+
+  return QualType(Spec, 0);  
+}
+
 /// CmpProtocolNames - Comparison predicate for sorting protocols
 /// alphabetically.
 static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,

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

==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Mon Feb  9 12:46:07 2009
@@ -13,6 +13,7 @@
 
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "llvm/ADT/STLExtras.h"
@@ -43,6 +44,11 @@
                                          NumParams, RAngleLoc);
 }
 
+void TemplateArg::Destroy(ASTContext &C) {
+  if (Kind == ExprArg)
+    getAsExpr()->Destroy(C);
+}
+
 //===----------------------------------------------------------------------===//
 // TemplateDecl Implementation
 //===----------------------------------------------------------------------===//

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

==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Mon Feb  9 12:46:07 2009
@@ -489,6 +489,14 @@
   return dyn_cast<TemplateTypeParmType>(CanonicalType);
 }
 
+const ClassTemplateSpecializationType *
+Type::getClassTemplateSpecializationType() const {
+  // There is no sugar for class template specialization types, so
+  // just return the canonical type pointer if it is the right class.
+  return dyn_cast<ClassTemplateSpecializationType>(CanonicalType);
+}
+
+
 bool Type::isIntegerType() const {
   if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
     return BT->getKind() >= BuiltinType::Bool &&
@@ -882,6 +890,54 @@
   return isa<EnumDecl>(TT->getDecl());
 }
 
+void 
+ClassTemplateSpecializationType::
+packBooleanValues(unsigned NumArgs, bool *Values, uintptr_t *Words) {
+  const unsigned BitsPerWord = sizeof(uintptr_t) * CHAR_BIT;
+
+  for (unsigned PW = 0, NumPackedWords = getNumPackedWords(NumArgs), Arg = 0;
+       PW != NumPackedWords; ++PW) {
+    uintptr_t Word = 0;
+    for (unsigned Bit = 0; Bit < BitsPerWord && Arg < NumArgs; ++Bit, ++Arg) {
+      Word <<= 1;
+      Word |= Values[Arg];
+    }
+    Words[PW] = Word;
+  }
+}
+
+ClassTemplateSpecializationType::
+ClassTemplateSpecializationType(TemplateDecl *T, unsigned NumArgs,
+                                uintptr_t *Args, bool *ArgIsType,
+                                QualType Canon)
+  : Type(ClassTemplateSpecialization, Canon, /*FIXME:Dependent=*/false),
+    Template(T), NumArgs(NumArgs) 
+{
+  uintptr_t *Data = reinterpret_cast<uintptr_t *>(this + 1);
+
+  // Pack the argument-is-type values into the words just after the
+  // class template specialization type.
+  packBooleanValues(NumArgs, ArgIsType, Data);
+
+  // Copy the template arguments after the packed words.
+  Data += getNumPackedWords(NumArgs);
+  for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
+    Data[Arg] = Args[Arg];
+}
+
+uintptr_t
+ClassTemplateSpecializationType::getArgAsOpaqueValue(unsigned Arg) const {
+  const uintptr_t *Data = reinterpret_cast<const uintptr_t *>(this + 1);
+  Data += getNumPackedWords(NumArgs);
+  return Data[Arg];
+}
+
+bool ClassTemplateSpecializationType::isArgType(unsigned Arg) const {
+  const unsigned BitsPerWord = sizeof(uintptr_t) * CHAR_BIT;
+  const uintptr_t *Data = reinterpret_cast<const uintptr_t *>(this + 1);
+  Data += Arg / BitsPerWord;
+  return (*Data >> (Arg % BitsPerWord)) & 0x01;
+}
 
 //===----------------------------------------------------------------------===//
 // Type Printing
@@ -1146,6 +1202,47 @@
     InnerString = Name->getName() + InnerString;
 }
 
+void 
+ClassTemplateSpecializationType::
+getAsStringInternal(std::string &InnerString) const {
+  std::string SpecString = Template->getNameAsString();
+  SpecString += '<';
+  for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+    if (Arg)
+      SpecString += ", ";
+    
+    // Print the argument into a string.
+    std::string ArgString;
+    if (isArgType(Arg))
+      getArgAsType(Arg).getAsStringInternal(ArgString);
+    else {
+      llvm::raw_string_ostream s(ArgString);
+      getArgAsExpr(Arg)->printPretty(s);
+    }
+
+    // If this is the first argument and its string representation
+    // begins with the global scope specifier ('::foo'), add a space
+    // to avoid printing the diagraph '<:'.
+    if (!Arg && !ArgString.empty() && ArgString[0] == ':')
+      SpecString += ' ';
+
+    SpecString += ArgString;
+  }
+
+  // If the last character of our string is '>', add another space to
+  // keep the two '>''s separate tokens. We don't *have* to do this in
+  // C++0x, but it's still good hygiene.
+  if (SpecString[SpecString.size() - 1] == '>')
+    SpecString += ' ';
+
+  SpecString += '>';
+
+  if (InnerString.empty())
+    InnerString.swap(SpecString);
+  else
+    InnerString = SpecString + ' ' + InnerString;
+}
+
 void ObjCInterfaceType::getAsStringInternal(std::string &InnerString) const {
   if (!InnerString.empty())    // Prefix the basic type, e.g. 'typedefname X'.
     InnerString = ' ' + InnerString;

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

==============================================================================
--- cfe/trunk/lib/AST/TypeSerialization.cpp (original)
+++ cfe/trunk/lib/AST/TypeSerialization.cpp Mon Feb  9 12:46:07 2009
@@ -13,6 +13,7 @@
 
 #include "clang/AST/Type.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ASTContext.h"
 #include "llvm/Bitcode/Serialize.h"
@@ -377,6 +378,48 @@
 }
 
 //===----------------------------------------------------------------------===//
+// ClassTemplateSpecializationType
+//===----------------------------------------------------------------------===//
+
+void ClassTemplateSpecializationType::EmitImpl(Serializer& S) const {
+  S.Emit(getCanonicalTypeInternal());
+  S.EmitPtr(Template);
+  S.EmitInt(NumArgs);
+  for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+    S.EmitBool(isArgType(Arg));
+    if (isArgType(Arg))
+      S.Emit(getArgAsType(Arg));
+    else
+      S.EmitOwnedPtr(getArgAsExpr(Arg));
+  }
+}
+
+Type* 
+ClassTemplateSpecializationType::
+CreateImpl(ASTContext& Context, Deserializer& D) {
+  llvm::SmallVector<uintptr_t, 16> Args;
+  llvm::SmallVector<bool, 16> ArgIsType;
+
+  QualType Canon = QualType::ReadVal(D);
+  TemplateDecl *Template = cast<TemplateDecl>(D.ReadPtr<Decl>());
+  unsigned NumArgs = D.ReadInt();
+
+  for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+    bool IsType = D.ReadBool();
+    ArgIsType.push_back(IsType);
+    if (IsType)
+      Args.push_back(
+         reinterpret_cast<uintptr_t>(QualType::ReadVal(D).getAsOpaquePtr()));
+    else
+      Args.push_back(reinterpret_cast<uintptr_t>(D.ReadOwnedPtr<Expr>(Context)));
+  }
+
+  return Context.getClassTemplateSpecializationType(Template, NumArgs,
+                                                    &Args[0], &ArgIsType[0],
+                                                    Canon).getTypePtr();
+}
+
+//===----------------------------------------------------------------------===//
 // VariableArrayType
 //===----------------------------------------------------------------------===//
 

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

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenTypes.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenTypes.cpp Mon Feb  9 12:46:07 2009
@@ -176,6 +176,7 @@
   switch (Ty.getTypeClass()) {
   case Type::TypeName:        // typedef isn't canonical.
   case Type::TemplateTypeParm:// template type parameters never generated
+  case Type::ClassTemplateSpecialization: // these types are always sugar
   case Type::DependentSizedArray: // dependent types are never generated
   case Type::TypeOfExp:       // typeof isn't canonical.
   case Type::TypeOfTyp:       // typeof isn't canonical.

Modified: cfe/trunk/lib/Parse/MinimalAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/MinimalAction.cpp?rev=64153&r1=64152&r2=64153&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/MinimalAction.cpp (original)
+++ cfe/trunk/lib/Parse/MinimalAction.cpp Mon Feb  9 12:46:07 2009
@@ -95,14 +95,11 @@
   return false;
 }
 
-  /// isTemplateName - Determines whether the identifier II is a
-  /// template name in the current scope, and returns the template
-  /// declaration if II names a template. An optional CXXScope can be
-  /// passed to indicate the C++ scope in which the identifier will be
-  /// found. 
-Action::DeclTy *MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S,
-                                              const CXXScopeSpec *SS ) {
-  return 0;
+Action::TemplateNameKind 
+MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S,
+                              DeclTy *&TemplateDecl,
+                              const CXXScopeSpec *SS) {
+  return TNK_Non_template;
 }
 
 /// ActOnDeclarator - If this is a typedef declarator, we modify the

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=64153&r1=64152&r2=64153&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Feb  9 12:46:07 2009
@@ -499,6 +499,7 @@
       Token Next = NextToken();
       TypeTy *TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(),
                                             Next.getLocation(), CurScope, &SS);
+
       if (TypeRep == 0)
         goto DoneWithDeclSpec;
 
@@ -553,9 +554,23 @@
       // It has to be available as a typedef too!
       TypeTy *TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(), 
                                             Tok.getLocation(), CurScope);
+
+      if (TypeRep == 0 && getLang().CPlusPlus && NextToken().is(tok::less)) {
+        // If we have a template name, annotate the token and try again.
+        DeclTy *Template = 0;
+        if (TemplateNameKind TNK =
+              Actions.isTemplateName(*Tok.getIdentifierInfo(), CurScope,
+                                     Template)) {
+          AnnotateTemplateIdToken(Template, TNK, 0);
+          continue;
+        }
+      }
+
       if (TypeRep == 0)
         goto DoneWithDeclSpec;
       
+
+
       // C++: If the identifier is actually the name of the class type
       // being defined and the next token is a '(', then this is a
       // constructor declaration. We're done with the decl-specifiers
@@ -1752,11 +1767,12 @@
 
         // If this identifier is followed by a '<', we may have a template-id.
         DeclTy *Template;
+        Action::TemplateNameKind TNK;
         if (getLang().CPlusPlus && NextToken().is(tok::less) &&
-            (Template = Actions.isTemplateName(*Tok.getIdentifierInfo(), 
-                                               CurScope))) {
+            (TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(), 
+                                          CurScope, Template))) {
           IdentifierInfo *II = Tok.getIdentifierInfo();
-          AnnotateTemplateIdToken(Template, 0);
+          AnnotateTemplateIdToken(Template, TNK, 0);
           // FIXME: Set the declarator to a template-id. How? I don't
           // know... for now, just use the identifier.
           D.SetIdentifier(II, Tok.getLocation());

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=64153&r1=64152&r2=64153&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Mon Feb  9 12:46:07 2009
@@ -55,8 +55,17 @@
 /// getBinOpPrecedence - Return the precedence of the specified binary operator
 /// token.  This returns:
 ///
-static prec::Level getBinOpPrecedence(tok::TokenKind Kind) {
+static prec::Level getBinOpPrecedence(tok::TokenKind Kind, 
+                                      bool GreaterThanIsOperator) {
   switch (Kind) {
+  case tok::greater:
+    // The '>' token can act as either an operator or as the ending
+    // token for a template argument list.  
+    // FIXME: '>>' is similar, for error recovery and C++0x.
+    if (GreaterThanIsOperator)
+      return prec::Relational;
+    return prec::Unknown;
+      
   default:                        return prec::Unknown;
   case tok::comma:                return prec::Comma;
   case tok::equal:
@@ -80,8 +89,7 @@
   case tok::equalequal:           return prec::Equality;
   case tok::lessequal:
   case tok::less:
-  case tok::greaterequal:
-  case tok::greater:              return prec::Relational;
+  case tok::greaterequal:         return prec::Relational;
   case tok::lessless:
   case tok::greatergreater:       return prec::Shift;
   case tok::plus:
@@ -266,7 +274,7 @@
 /// LHS and has a precedence of at least MinPrec.
 Parser::OwningExprResult
 Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
-  unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind());
+  unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator);
   SourceLocation ColonLoc;
 
   while (1) {
@@ -316,7 +324,7 @@
     // Remember the precedence of this operator and get the precedence of the
     // operator immediately to the right of the RHS.
     unsigned ThisPrec = NextTokPrec;
-    NextTokPrec = getBinOpPrecedence(Tok.getKind());
+    NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator);
 
     // Assignment and conditional expressions are right-associative.
     bool isRightAssoc = ThisPrec == prec::Conditional ||
@@ -335,7 +343,7 @@
       if (RHS.isInvalid())
         return move(RHS);
 
-      NextTokPrec = getBinOpPrecedence(Tok.getKind());
+      NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator);
     }
     assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
 
@@ -1104,6 +1112,7 @@
 Parser::ParseParenExpression(ParenParseOption &ExprType,
                              TypeTy *&CastTy, SourceLocation &RParenLoc) {
   assert(Tok.is(tok::l_paren) && "Not a paren expr!");
+  MakeGreaterThanAnOperator G(GreaterThanIsOperator);
   SourceLocation OpenLoc = ConsumeParen();
   OwningExprResult Result(Actions, true);
   CastTy = 0;

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=64153&r1=64152&r2=64153&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Mon Feb  9 12:46:07 2009
@@ -15,6 +15,7 @@
 #include "clang/Parse/ParseDiagnostic.h"
 #include "clang/Parse/DeclSpec.h"
 #include "clang/Parse/Scope.h"
+#include "AstGuard.h"
 
 using namespace clang;
 
@@ -354,7 +355,8 @@
 /// AnnotateTemplateIdToken - The current token is an identifier that
 /// refers to the template declaration Template, and is followed by a
 /// '<'. Turn this template-id into a template-id annotation token.
-void Parser::AnnotateTemplateIdToken(DeclTy *Template, const CXXScopeSpec *SS) {
+void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
+                                     const CXXScopeSpec *SS) {
   assert(getLang().CPlusPlus && "Can only annotate template-ids in C++");
   assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) &&
          "Parser isn't at the beginning of a template-id");
@@ -366,13 +368,16 @@
   SourceLocation LAngleLoc = ConsumeToken();
 
   // Parse the optional template-argument-list.
-  TemplateArgList TemplateArgs;
-  if (Tok.isNot(tok::greater) && ParseTemplateArgumentList(TemplateArgs)) {
-    // Try to find the closing '>'.
-    SkipUntil(tok::greater, true, true);
-
-    // FIXME: What's our recovery strategy for failed template-argument-lists?
-    return;
+  ASTVector<&ActionBase::DeleteTemplateArg, 8> TemplateArgs(Actions);
+  {
+    MakeGreaterThanTemplateArgumentListTerminator G(GreaterThanIsOperator);
+    if (Tok.isNot(tok::greater) && ParseTemplateArgumentList(TemplateArgs)) {
+      // Try to find the closing '>'.
+      SkipUntil(tok::greater, true, true);
+      
+      // FIXME: What's our recovery strategy for failed template-argument-lists?
+      return;
+    }
   }
 
   if (Tok.isNot(tok::greater))
@@ -382,24 +387,41 @@
   // token, because we'll be replacing it with the template-id.
   SourceLocation RAngleLoc = Tok.getLocation();
   
-  Tok.setKind(tok::annot_template_id);
+  // Build the annotation token.
+  if (TNK == Action::TNK_Function_template) {
+    // This is a function template. We'll be building a template-id
+    // annotation token.
+    TemplateArgs.take(); // Annotation token takes ownership
+    Tok.setKind(tok::annot_template_id);    
+    TemplateIdAnnotation *TemplateId 
+      = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) + 
+                                  sizeof(TemplateArgTy*) * TemplateArgs.size());
+    TemplateId->TemplateNameLoc = TemplateNameLoc;
+    TemplateId->Template = Template;
+    TemplateId->LAngleLoc = LAngleLoc;
+    TemplateId->NumArgs = TemplateArgs.size();
+    TemplateArgTy **Args = (TemplateArgTy**)(TemplateId + 1);
+    for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
+      Args[Arg] = TemplateArgs[Arg];
+    Tok.setAnnotationValue(TemplateId);
+  } else {
+    // This is a type template, e.g., a class template, template
+    // template parameter, or template alias. We'll be building a
+    // "typename" annotation token.
+    TypeTy *Ty 
+      = Actions.ActOnClassTemplateSpecialization(Template,LAngleLoc,
+                                                 move_arg(TemplateArgs),
+                                                 RAngleLoc, SS);
+    Tok.setKind(tok::annot_typename);
+    Tok.setAnnotationValue(Ty);
+  }
+
+  // Common fields for the annotation token
   Tok.setAnnotationEndLoc(RAngleLoc);
   Tok.setLocation(TemplateNameLoc);
   if (SS && SS->isNotEmpty())
     Tok.setLocation(SS->getBeginLoc());
 
-  TemplateIdAnnotation *TemplateId 
-    = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) + 
-                                  sizeof(TemplateArgTy*) * TemplateArgs.size());
-  TemplateId->TemplateNameLoc = TemplateNameLoc;
-  TemplateId->Template = Template;
-  TemplateId->LAngleLoc = LAngleLoc;
-  TemplateId->NumArgs = TemplateArgs.size();
-  TemplateArgTy **Args = (TemplateArgTy**)(TemplateId + 1);
-  for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
-    Args[Arg] = TemplateArgs[Arg];
-  Tok.setAnnotationValue(TemplateId);
-
   // In case the tokens were cached, have Preprocessor replace them with the
   // annotation token.
   PP.AnnotateCachedTokens(Tok);
@@ -412,8 +434,22 @@
 ///         type-id
 ///         id-expression
 Parser::OwningTemplateArgResult Parser::ParseTemplateArgument() {
-  // FIXME: Implement this!
-  return TemplateArgError();
+  // C++ [temp.arg]p2:
+  //   In a template-argument, an ambiguity between a type-id and an
+  //   expression is resolved to a type-id, regardless of the form of
+  //   the corresponding template-parameter.
+  //
+  // Therefore, we initially try to parse a type-id.
+  if (isTypeIdInParens()) {
+    TypeTy *TypeArg = ParseTypeName();
+    return Actions.ActOnTypeTemplateArgument(TypeArg);
+  }
+
+  OwningExprResult ExprArg = ParseExpression();
+  if (ExprArg.isInvalid())
+    return TemplateArgError();
+
+  return Actions.ActOnExprTemplateArgument(move(ExprArg));
 }
 
 /// ParseTemplateArgumentList - Parse a C++ template-argument-list

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=64153&r1=64152&r2=64153&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Mon Feb  9 12:46:07 2009
@@ -20,7 +20,8 @@
 using namespace clang;
 
 Parser::Parser(Preprocessor &pp, Action &actions)
-  : PP(pp), Actions(actions), Diags(PP.getDiagnostics()) {
+  : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), 
+    GreaterThanIsOperator(true) {
   Tok.setKind(tok::eof);
   CurScope = 0;
   NumCachedScopes = 0;
@@ -785,10 +786,15 @@
     }
     
     // If this is a template-id, annotate the template-id token.
-    if (NextToken().is(tok::less))
-      if (DeclTy *Template =
-          Actions.isTemplateName(*Tok.getIdentifierInfo(), CurScope, &SS))
-        AnnotateTemplateIdToken(Template, &SS);
+    if (NextToken().is(tok::less)) {
+      DeclTy *Template;
+      if (TemplateNameKind TNK 
+            = Actions.isTemplateName(*Tok.getIdentifierInfo(),
+                                     CurScope, Template, &SS)) {
+        AnnotateTemplateIdToken(Template, TNK, &SS);
+        return true;
+      }
+    }
 
     // We either have an identifier that is not a type name or we have
     // just created a template-id that might be a type name. Both

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Feb  9 12:46:07 2009
@@ -62,6 +62,7 @@
   class TypedefDecl;
   class TemplateDecl;
   class TemplateParameterList;
+  class TemplateArg;
   class ObjCInterfaceDecl;
   class ObjCCompatibleAliasDecl;
   class ObjCProtocolDecl;
@@ -258,6 +259,9 @@
     return OwningExprResult(*this, R.get());
   }
   OwningStmtResult Owned(Stmt* S) { return OwningStmtResult(*this, S); }
+  OwningTemplateArgResult Owned(TemplateArg *Arg) { 
+    return OwningTemplateArgResult(*this, Arg);
+  }
 
   virtual void ActOnEndOfTranslationUnit();
 
@@ -1478,8 +1482,9 @@
   //===--------------------------------------------------------------------===//
   // C++ Templates [C++ 14]
   //
-  virtual DeclTy *isTemplateName(IdentifierInfo &II, Scope *S,
-                                 const CXXScopeSpec *SS = 0);
+  virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S,
+                                          DeclTy *&TemplateDecl,
+                                          const CXXScopeSpec *SS = 0);
   bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
   TemplateDecl *AdjustDeclIfTemplate(DeclTy *&Decl);
 
@@ -1506,6 +1511,10 @@
                              DeclTy **Params, unsigned NumParams,
                              SourceLocation RAngleLoc);
   
+  virtual OwningTemplateArgResult ActOnTypeTemplateArgument(TypeTy *Type);
+
+  virtual OwningTemplateArgResult ActOnExprTemplateArgument(ExprArg Value);
+
   virtual DeclTy *
   ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
                      SourceLocation KWLoc, const CXXScopeSpec &SS,
@@ -1513,6 +1522,13 @@
                      AttributeList *Attr,
                      MultiTemplateParamsArg TemplateParameterLists);
 
+  virtual TypeTy * 
+  ActOnClassTemplateSpecialization(DeclTy *Template,
+                                   SourceLocation LAngleLoc,
+                                   MultiTemplateArgsArg TemplateArgs,
+                                   SourceLocation RAngleLoc,
+                                   const CXXScopeSpec *SS = 0);
+
   bool TemplateParameterListsAreEqual(TemplateParameterList *New,
                                       TemplateParameterList *Old,
                                       bool Complain,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Feb  9 12:46:07 2009
@@ -25,38 +25,43 @@
 /// declaration if II names a template. An optional CXXScope can be
 /// passed to indicate the C++ scope in which the identifier will be
 /// found. 
-Sema::DeclTy *Sema::isTemplateName(IdentifierInfo &II, Scope *S,
-                                   const CXXScopeSpec *SS) {
-  DeclContext *DC = 0;
-  
-  if (SS) {
-    if (SS->isInvalid())
-      return 0;
-    DC = static_cast<DeclContext*>(SS->getScopeRep());
-  }
+Sema::TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S,
+                                            DeclTy *&Template,
+                                            const CXXScopeSpec *SS) {
   NamedDecl *IIDecl = LookupParsedName(S, SS, &II, LookupOrdinaryName);
 
   if (IIDecl) {
-    // FIXME: We need to represent templates via some kind of
-    // TemplateDecl, because what follows is a hack that only works in
-    // one specific case.
-    if (isa<TemplateDecl>(IIDecl))
-      return IIDecl;
+    if (isa<TemplateDecl>(IIDecl)) {
+      Template = IIDecl;
+      if (isa<FunctionTemplateDecl>(IIDecl))
+        return TNK_Function_template;
+      else if (isa<ClassTemplateDecl>(IIDecl))
+        return TNK_Class_template;
+      else if (isa<TemplateTemplateParmDecl>(IIDecl))
+        return TNK_Template_template_parm;
+      else
+        assert(false && "Unknown TemplateDecl");
+    }
 
+    // FIXME: What follows is a gross hack.
     if (FunctionDecl *FD = dyn_cast<FunctionDecl>(IIDecl)) {
-      if (FD->getType()->isDependentType())
-        return FD;
+      if (FD->getType()->isDependentType()) {
+        Template = FD;
+        return TNK_Function_template;
+      }
     } else if (OverloadedFunctionDecl *Ovl 
                  = dyn_cast<OverloadedFunctionDecl>(IIDecl)) {
       for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
                                                   FEnd = Ovl->function_end();
            F != FEnd; ++F) {
-        if ((*F)->getType()->isDependentType())
-          return Ovl;
+        if ((*F)->getType()->isDependentType()) {
+          Template = Ovl;
+          return TNK_Function_template;
+        }
       }
     }
   }
-  return 0;
+  return TNK_Non_template;
 }
 
 /// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
@@ -226,6 +231,15 @@
                                        (Decl**)Params, NumParams, RAngleLoc);
 }
 
+Sema::OwningTemplateArgResult Sema::ActOnTypeTemplateArgument(TypeTy *Type) {
+  return Owned(new (Context) TemplateArg(QualType::getFromOpaquePtr(Type)));
+}
+
+Sema::OwningTemplateArgResult 
+Sema::ActOnExprTemplateArgument(ExprArg Value) {
+  return Owned(new (Context) TemplateArg(static_cast<Expr *>(Value.release())));
+}
+
 Sema::DeclTy *
 Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
                          SourceLocation KWLoc, const CXXScopeSpec &SS,
@@ -351,6 +365,42 @@
   return NewTemplate;
 }
 
+Action::TypeTy * 
+Sema::ActOnClassTemplateSpecialization(DeclTy *TemplateD,
+                                       SourceLocation LAngleLoc,
+                                       MultiTemplateArgsArg TemplateArgsIn,
+                                       SourceLocation RAngleLoc,
+                                       const CXXScopeSpec *SS) {
+  TemplateDecl *Template = cast<TemplateDecl>(static_cast<Decl *>(TemplateD));
+
+  // FIXME: Not happy about this. We should teach the parser to pass
+  // us opaque pointers + bools for template argument lists.
+  // FIXME: Also not happy about the fact that we leak these
+  // TemplateArg structures. Fixing the above will fix this, too.
+  llvm::SmallVector<uintptr_t, 16> Args;
+  llvm::SmallVector<bool, 16> ArgIsType;
+  unsigned NumArgs = TemplateArgsIn.size();
+  TemplateArg **TemplateArgs 
+    = reinterpret_cast<TemplateArg **>(TemplateArgsIn.release());
+  for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+    if (Expr *ExprArg = TemplateArgs[Arg]->getAsExpr()) {
+      Args.push_back(reinterpret_cast<uintptr_t>(ExprArg));
+      ArgIsType.push_back(false);
+    } else {
+      QualType T = TemplateArgs[Arg]->getAsType();
+      Args.push_back(reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()));
+      ArgIsType.push_back(true);
+    }
+  }
+
+  // Yes, all class template specializations are just silly sugar for
+  // 'int'. Gotta problem wit dat?
+  return Context.getClassTemplateSpecializationType(Template, NumArgs,
+                                                    &Args[0], &ArgIsType[0],
+                                                    Context.IntTy)
+    .getAsOpaquePtr();
+}
+
 /// \brief Determine whether the given template parameter lists are
 /// equivalent.
 ///

Added: cfe/trunk/test/SemaTemplate/class-template-id.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/class-template-id.cpp?rev=64153&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/class-template-id.cpp (added)
+++ cfe/trunk/test/SemaTemplate/class-template-id.cpp Mon Feb  9 12:46:07 2009
@@ -0,0 +1,17 @@
+// RUN: clang -fsyntax-only -verify %s
+template<typename T> struct A { };
+
+typedef A<int> A_int;
+
+float *foo(A<int> *ptr, A<int> const *ptr2) {
+  if (ptr)
+    return ptr; // expected-error{{incompatible type returning 'A<int> *', expected 'float *'}}
+  else if (ptr2)
+    return ptr2; // expected-error{{incompatible type returning 'A<int> const *', expected '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;
+  }
+}





More information about the cfe-commits mailing list