diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-02-09 18:46:07 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-02-09 18:46:07 +0000 |
commit | 55f6b14230c94272efbbcdd89a92224c8db9f225 (patch) | |
tree | 988ae940f14f93aac610fbc36d89766e539eab6c | |
parent | 00e68e2cc5ce37cb95beb801cae73c0d1e9dda37 (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.h | 7 | ||||
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 33 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 130 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 73 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 42 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 28 | ||||
-rw-r--r-- | lib/AST/DeclTemplate.cpp | 6 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 97 | ||||
-rw-r--r-- | lib/AST/TypeSerialization.cpp | 43 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenTypes.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/MinimalAction.cpp | 13 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 22 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 21 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 82 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 20 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 88 | ||||
-rw-r--r-- | test/SemaTemplate/class-template-id.cpp | 17 |
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 >IO) + : 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 >IO) + : 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/ |