aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-02-09 18:46:07 +0000
committerDouglas Gregor <dgregor@apple.com>2009-02-09 18:46:07 +0000
commit55f6b14230c94272efbbcdd89a92224c8db9f225 (patch)
tree988ae940f14f93aac610fbc36d89766e539eab6c
parent00e68e2cc5ce37cb95beb801cae73c0d1e9dda37 (diff)
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' :) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64153 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTContext.h7
-rw-r--r--include/clang/AST/DeclTemplate.h33
-rw-r--r--include/clang/AST/Type.h130
-rw-r--r--include/clang/Parse/Action.h73
-rw-r--r--include/clang/Parse/Parser.h42
-rw-r--r--lib/AST/ASTContext.cpp28
-rw-r--r--lib/AST/DeclTemplate.cpp6
-rw-r--r--lib/AST/Type.cpp97
-rw-r--r--lib/AST/TypeSerialization.cpp43
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp1
-rw-r--r--lib/Parse/MinimalAction.cpp13
-rw-r--r--lib/Parse/ParseDecl.cpp22
-rw-r--r--lib/Parse/ParseExpr.cpp21
-rw-r--r--lib/Parse/ParseTemplate.cpp82
-rw-r--r--lib/Parse/Parser.cpp16
-rw-r--r--lib/Sema/Sema.h20
-rw-r--r--lib/Sema/SemaTemplate.cpp88
-rw-r--r--test/SemaTemplate/class-template-id.cpp17
18 files changed, 650 insertions, 89 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 7198332b29..2329ff5fe8 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -69,6 +69,8 @@ class ASTContext {
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 @@ public:
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.
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 2183298f9d..daf4210c44 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -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 @@ protected:
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 @@ protected:
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
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 666d952645..8b9826e347 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -30,6 +30,7 @@ namespace clang {
class ASTContext;
class Type;
class TypedefDecl;
+ class TemplateDecl;
class TemplateTypeParmDecl;
class NonTypeTemplateParmDecl;
class TemplateTemplateParamDecl;
@@ -69,6 +70,7 @@ namespace clang {
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 @@ public:
Vector, ExtVector,
FunctionNoProto, FunctionProto,
TypeName, Tagged, ASQual,
- TemplateTypeParm,
+ TemplateTypeParm, ClassTemplateSpecialization,
ObjCInterface, ObjCQualifiedInterface,
ObjCQualifiedId,
TypeOfExp, TypeOfTyp, // GNU typeof extension.
@@ -391,6 +393,9 @@ public:
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 @@ public:
/// 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 @@ protected:
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
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index f735f3e792..b13b8ef228 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -108,7 +108,7 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index da29208ccb..7a73fcba53 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -58,6 +58,44 @@ class Parser {
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 @@ private:
//===--------------------------------------------------------------------===//
// 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 @@ private:
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();
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index a87a902d06..72aef4269b 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1220,6 +1220,34 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
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,
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index d005ca3b06..ab5a3bc0b2 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -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 @@ TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc,
NumParams, RAngleLoc);
}
+void TemplateArg::Destroy(ASTContext &C) {
+ if (Kind == ExprArg)
+ getAsExpr()->Destroy(C);
+}
+
//===----------------------------------------------------------------------===//
// TemplateDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 106d0eb453..6ec5062f93 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -489,6 +489,14 @@ const TemplateTypeParmType *Type::getAsTemplateTypeParmType() const {
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 @@ bool EnumType::classof(const TagType *TT) {
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 @@ void TemplateTypeParmType::getAsStringInternal(std::string &InnerString) const {
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;
diff --git a/lib/AST/TypeSerialization.cpp b/lib/AST/TypeSerialization.cpp
index 57598d3afc..90bc67ad4d 100644
--- a/lib/AST/TypeSerialization.cpp
+++ b/lib/AST/TypeSerialization.cpp
@@ -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 @@ Type* TemplateTypeParmType::CreateImpl(ASTContext& Context, Deserializer& D) {
}
//===----------------------------------------------------------------------===//
+// 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
//===----------------------------------------------------------------------===//
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 0b74e1e636..37b7c5f68c 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -176,6 +176,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
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.
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index 2d6c9a6ba5..ce15cf9dda 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -95,14 +95,11 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
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
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 73a09ee39c..5d601bc4f1 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -499,6 +499,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
Token Next = NextToken();
TypeTy *TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(),
Next.getLocation(), CurScope, &SS);
+
if (TypeRep == 0)
goto DoneWithDeclSpec;
@@ -553,9 +554,23 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// 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 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// 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());
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 332ad7789e..0f04d13f6e 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/