diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-03-30 22:58:21 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-03-30 22:58:21 +0000 |
commit | 7532dc66648cfe7432c9fe66dec5225f0ab301c6 (patch) | |
tree | daa4d64ecc29357f90c6a51341fecdf79eae2025 | |
parent | e31c0d206b872b056dc42c3af21b11d5de4edfd9 (diff) |
Improve the representation of template names in the AST. This
representation handles the various ways in which one can name a
template, including unqualified references ("vector"), qualified
references ("std::vector"), and dependent template names
("MetaFun::template apply").
One immediate effect of this change is that the representation of
nested-name-specifiers in type names for class template
specializations (e.g., std::vector<int>) is more accurate. Rather than
representing std::vector<int> as
std::(vector<int>)
we represent it as
(std::vector)<int>
which more closely follows the C++ grammar.
Additionally, templates are no longer represented as declarations
(DeclPtrTy) in Parse-Sema interactions. Instead, I've introduced a new
OpaquePtr type (TemplateTy) that holds the representation of a
TemplateName. This will simplify the handling of dependent
template-names, once we get there.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68074 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/ASTContext.h | 22 | ||||
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 2 | ||||
-rw-r--r-- | include/clang/AST/TemplateName.h | 246 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 52 | ||||
-rw-r--r-- | include/clang/AST/TypeNodes.def | 2 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 26 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 5 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 78 | ||||
-rw-r--r-- | lib/AST/TemplateName.cpp | 54 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 60 | ||||
-rw-r--r-- | lib/AST/TypeSerialization.cpp | 22 | ||||
-rw-r--r-- | lib/CodeGen/CGDebugInfo.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenTypes.cpp | 3 | ||||
-rw-r--r-- | lib/Parse/MinimalAction.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 25 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 27 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 120 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 22 |
21 files changed, 576 insertions, 200 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index bb2d80e7d1..b270ddca67 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -19,6 +19,7 @@ #include "clang/AST/Builtins.h" #include "clang/AST/Decl.h" #include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/DenseMap.h" @@ -71,13 +72,15 @@ class ASTContext { llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes; llvm::FoldingSet<FunctionProtoType> FunctionProtoTypes; llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes; - llvm::FoldingSet<ClassTemplateSpecializationType> - ClassTemplateSpecializationTypes; + llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes; llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes; llvm::FoldingSet<TypenameType> TypenameTypes; llvm::FoldingSet<ObjCQualifiedInterfaceType> ObjCQualifiedInterfaceTypes; llvm::FoldingSet<ObjCQualifiedIdType> ObjCQualifiedIdTypes; + llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames; + llvm::FoldingSet<DependentTemplateName> DependentTemplateNames; + /// \brief The set of nested name specifiers. /// /// This set is managed by the NestedNameSpecifier class. @@ -291,10 +294,10 @@ public: QualType getTemplateTypeParmType(unsigned Depth, unsigned Index, IdentifierInfo *Name = 0); - QualType getClassTemplateSpecializationType(TemplateDecl *Template, - const TemplateArgument *Args, - unsigned NumArgs, - QualType Canon = QualType()); + QualType getTemplateSpecializationType(TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs, + QualType Canon = QualType()); QualType getQualifiedNameType(NestedNameSpecifier *NNS, QualType NamedType); @@ -407,6 +410,13 @@ public: QualType getFixedWidthIntType(unsigned Width, bool Signed); + TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, + bool TemplateKeyword, + TemplateDecl *Template); + + TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, + const IdentifierInfo *Name); + private: QualType getFromTargetType(unsigned Type) const; diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 4638e6bef4..794ab2cf08 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -705,7 +705,7 @@ protected: llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations; }; - /// \brief Previous declaration of + /// \brief Previous declaration of this class template. ClassTemplateDecl *PreviousDeclaration; /// \brief Pointer to the data that is common to all of the diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h new file mode 100644 index 0000000000..3107a35841 --- /dev/null +++ b/include/clang/AST/TemplateName.h @@ -0,0 +1,246 @@ +//===--- TemplateName.h - C++ Template Name Representation-------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TemplateName interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TEMPLATENAME_H +#define LLVM_CLANG_AST_TEMPLATENAME_H + +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/Support/PointerLikeTypeTraits.h" + +namespace llvm { + class raw_ostream; +} + +namespace clang { + +class DependentTemplateName; +class IdentifierInfo; +class NestedNameSpecifier; +class QualifiedTemplateName; +class TemplateDecl; + +/// \brief Represents a C++ template name within the type system. +/// +/// A C++ template name refers to a template within the C++ type +/// system. In most cases, a template name is simply a reference to a +/// class template, e.g. +/// +/// \code +/// template<typename T> class X { }; +/// +/// X<int> xi; +/// \endcode +/// +/// Here, the 'X' in \c X<int> is a template name that refers to the +/// declaration of the class template X, above. Template names can +/// also refer to function templates, C++0x template aliases, etc. +/// +/// Some template names are dependent. For example, consider: +/// +/// \code +/// template<typename MetaFun, typename T1, typename T2> struct apply2 { +/// typedef typename MetaFun::template apply<T1, T2>::type type; +/// }; +/// \endcode +/// +/// Here, "apply" is treated as a template name within the typename +/// specifier in the typedef. "apply" is a nested template, and can +/// only be understood in the context of +class TemplateName { + typedef llvm::PointerUnion3<TemplateDecl *, QualifiedTemplateName *, + DependentTemplateName *> StorageType; + + StorageType Storage; + + explicit TemplateName(void *Ptr) { + Storage = StorageType::getFromOpaqueValue(Ptr); + } + +public: + TemplateName() : Storage() { } + explicit TemplateName(TemplateDecl *Template) : Storage(Template) { } + explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { } + explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { } + + /// \brief Retrieve the the underlying template declaration that + /// this template name refers to, if known. + /// + /// \returns The template declaration that this template name refers + /// to, if any. If the template name does not refer to a specific + /// declaration because it is a dependent name, returns NULL. + TemplateDecl *getAsTemplateDecl() const; + + /// \brief Retrieve the underlying qualified template name + /// structure, if any. + QualifiedTemplateName *getAsQualifiedTemplateName() const { + return Storage.dyn_cast<QualifiedTemplateName *>(); + } + + /// \brief Retrieve the underlying dependent template name + /// structure, if any. + DependentTemplateName *getAsDependentTemplateName() const { + return Storage.dyn_cast<DependentTemplateName *>(); + } + + /// \brief Determines whether this is a dependent template name. + bool isDependent() const; + + /// \brief Print the template name. + void Print(llvm::raw_ostream &OS) const; + + void Profile(llvm::FoldingSetNodeID &ID) { + ID.AddPointer(Storage.getOpaqueValue()); + } + + /// \brief Retrieve the template name as a void pointer. + void *getAsVoidPointer() const { return Storage.getOpaqueValue(); } + + /// \brief Build a template name from a void pointer. + static TemplateName getFromVoidPointer(void *Ptr) { + return TemplateName(Ptr); + } +}; + +/// \brief Represents a template name that was expressed as a +/// qualified name. +/// +/// This kind of template name refers to a template name that was +/// preceded by a nested name specifier, e.g., \c std::vector. Here, +/// the nested name specifier is "std::" and the template name is the +/// declaration for "vector". The QualifiedTemplateName class is only +/// used to provide "sugar" for template names that were expressed +/// with a qualified name, and has no semantic meaning. In this +/// manner, it is to TemplateName what QualifiedNameType is to Type, +/// providing extra syntactic sugar for downstream clients. +class QualifiedTemplateName : public llvm::FoldingSetNode { + /// \brief The nested name specifier that qualifies the template name. + /// + /// The bit is used to indicate whether the "template" keyword was + /// present before the template name itself. Note that the + /// "template" keyword is always redundant in this case (otherwise, + /// the template name would be a dependent name and we would express + /// this name with DependentTemplateName). + llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier; + + /// \brief The template declaration that this qualified name refers + /// to. + TemplateDecl *Template; + + friend class ASTContext; + + QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, + TemplateDecl *Template) + : Qualifier(NNS, TemplateKeyword? 1 : 0), Template(Template) { } + +public: + /// \brief Return the nested name specifier that qualifies this name. + NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); } + + /// \brief Whether the template name was prefixed by the "template" + /// keyword. + bool hasTemplateKeyword() const { return Qualifier.getInt(); } + + /// \brief The template declaration to which this qualified name + /// refers. + TemplateDecl *getTemplateDecl() const { return Template; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getQualifier(), hasTemplateKeyword(), getTemplateDecl()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + bool TemplateKeyword, TemplateDecl *Template) { + ID.AddPointer(NNS); + ID.AddBoolean(TemplateKeyword); + ID.AddPointer(Template); + } +}; + +/// \brief Represents a dependent template name that cannot be +/// resolved prior to template instantiation. +/// +/// This kind of template name refers to a dependent template name, +/// including its nested name specifier. For example, +/// DependentTemplateName can refer to "MetaFun::template apply", +/// where "MetaFun::" is the nested name specifier and "apply" is the +/// template name referenced. The "template" keyword is implied. +class DependentTemplateName : public llvm::FoldingSetNode { + /// \brief The nested name specifier that qualifies the template + /// name. + NestedNameSpecifier *Qualifier; + + /// \brief The dependent template name. + const IdentifierInfo *Name; + + /// \brief The canonical template name to which this dependent + /// template name refers. + /// + /// The canonical template name for a dependent template name is + /// another dependent template name whose nested name specifier is + /// canonical. + TemplateName CanonicalTemplateName; + + friend class ASTContext; + + DependentTemplateName(NestedNameSpecifier *Qualifier, + const IdentifierInfo *Name) + : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(this) { } + + DependentTemplateName(NestedNameSpecifier *Qualifier, + const IdentifierInfo *Name, + TemplateName Canon) + : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(Canon) { } + +public: + /// \brief Return the nested name specifier that qualifies this name. + NestedNameSpecifier *getQualifier() const { return Qualifier; } + + /// \brief Return the name to which this dependent template name + /// refers. + const IdentifierInfo *getName() const { return Name; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getQualifier(), getName()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + const IdentifierInfo *Name) { + ID.AddPointer(NNS); + ID.AddPointer(Name); + } +}; + +} + +namespace llvm { + +/// \brief The clang::TemplateName class is effectively a pointer. +template<> +class PointerLikeTypeTraits<clang::TemplateName> { +public: + static inline void *getAsVoidPointer(clang::TemplateName TN) { + return TN.getAsVoidPointer(); + } + + static inline clang::TemplateName getFromVoidPointer(void *Ptr) { + return clang::TemplateName::getFromVoidPointer(Ptr); + } + + // No bits are available! + enum { NumLowBitsAvailable = 0 }; +}; + +} + +#endif diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index ea1b496cd3..62cd2787ac 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -16,11 +16,13 @@ #include "clang/Basic/Diagnostic.h" #include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateName.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/Bitcode/SerializationFwd.h" + using llvm::isa; using llvm::cast; using llvm::cast_or_null; @@ -39,7 +41,7 @@ namespace clang { class TemplateDecl; class TemplateTypeParmDecl; class NonTypeTemplateParmDecl; - class TemplateTemplateParamDecl; + class TemplateTemplateParmDecl; class TagDecl; class RecordDecl; class CXXRecordDecl; @@ -437,8 +439,8 @@ public: const ObjCQualifiedIdType *getAsObjCQualifiedIdType() const; const TemplateTypeParmType *getAsTemplateTypeParmType() const; - const ClassTemplateSpecializationType * - getAsClassTemplateSpecializationType() const; + const TemplateSpecializationType * + getAsTemplateSpecializationType() const; /// getAsPointerToObjCInterfaceType - If this is a pointer to an ObjC /// interface, return the interface type, otherwise return null. @@ -1494,32 +1496,34 @@ protected: friend class Type; }; -/// \brief Represents the type of a class template specialization as -/// written in the source code. +/// \brief Represents the type of a 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 +/// Template specialization types represent the syntactic form of a +/// template-id that refers to a type, e.g., @c vector<int>. Some +/// 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 +/// a tag type for the instantiation /// @c std::vector<int, std::allocator<int>>. -class ClassTemplateSpecializationType +/// +/// Other template specialization types, for which the template name +/// is dependent, may be canonical types. These types are always +/// dependent. +class TemplateSpecializationType : 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; + /// \brief The name of the template being specialized. + TemplateName Template; /// \brief - The number of template arguments named in this class /// template specialization. unsigned NumArgs; - ClassTemplateSpecializationType(TemplateDecl *T, - const TemplateArgument *Args, - unsigned NumArgs, QualType Canon); + TemplateSpecializationType(TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs, QualType Canon); virtual void Destroy(ASTContext& C); @@ -1541,8 +1545,8 @@ public: iterator begin() const { return getArgs(); } iterator end() const; - /// \brief Retrieve the template that we are specializing. - TemplateDecl *getTemplate() const { return Template; } + /// \brief Retrieve the name of the template that we are specializing. + TemplateName getTemplateName() const { return Template; } /// \brief Retrieve the template arguments. const TemplateArgument *getArgs() const { @@ -1562,13 +1566,13 @@ public: Profile(ID, Template, getArgs(), NumArgs); } - static void Profile(llvm::FoldingSetNodeID &ID, TemplateDecl *T, + static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, const TemplateArgument *Args, unsigned NumArgs); static bool classof(const Type *T) { - return T->getTypeClass() == ClassTemplateSpecialization; + return T->getTypeClass() == TemplateSpecialization; } - static bool classof(const ClassTemplateSpecializationType *T) { return true; } + static bool classof(const TemplateSpecializationType *T) { return true; } protected: virtual void EmitImpl(llvm::Serializer& S) const; diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 42057139f8..e98ff4200f 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -72,7 +72,7 @@ ABSTRACT_TYPE(Tag, Type) TYPE(Record, TagType) TYPE(Enum, TagType) DEPENDENT_TYPE(TemplateTypeParm, Type) -NON_CANONICAL_TYPE(ClassTemplateSpecialization, Type) +TYPE(TemplateSpecialization, Type) NON_CANONICAL_TYPE(QualifiedName, Type) DEPENDENT_TYPE(Typename, Type) TYPE(ObjCInterface, Type) diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index a58fc81c83..f1837faac5 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -72,7 +72,8 @@ public: typedef ActionBase::StmtTy StmtTy; typedef OpaquePtr<0> DeclPtrTy; typedef OpaquePtr<1> DeclGroupPtrTy; - typedef void TypeTy; // FIXME: Change TypeTy to use OpaquePtr<1>. + typedef void TypeTy; // FIXME: Change TypeTy to use OpaquePtr<N>. + typedef OpaquePtr<2> TemplateTy; typedef void AttrTy; typedef void BaseTy; typedef void MemInitTy; @@ -157,7 +158,7 @@ public: /// optional CXXScope can be passed to indicate the C++ scope in /// which the identifier will be found. virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S, - DeclPtrTy &TemplateDecl, + TemplateTy &Template, const CXXScopeSpec *SS = 0) = 0; /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the @@ -1206,8 +1207,8 @@ public: return DeclResult(); } - /// \brief Form a class template specialization from a template and - /// a list of template arguments. + /// \brief Form a type from a template and a list of template + /// arguments. /// /// This action merely forms the type for the template-id, possibly /// checking well-formedness of the template arguments. It does not @@ -1219,13 +1220,12 @@ public: /// \param IsSpecialization true when we are naming the class /// template specialization as part of an explicit class /// specialization or class template partial specialization. - virtual TypeResult ActOnClassTemplateId(DeclPtrTy Template, - SourceLocation TemplateLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, - SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc, - const CXXScopeSpec *SS) { + virtual TypeResult ActOnTemplateIdType(TemplateTy Template, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc) { return TypeResult(); }; @@ -1279,7 +1279,7 @@ public: ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, SourceLocation KWLoc, const CXXScopeSpec &SS, - DeclPtrTy Template, + TemplateTy Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, @@ -1569,7 +1569,7 @@ public: const CXXScopeSpec *SS); virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S, - DeclPtrTy &TemplateDecl, + TemplateTy &Template, const CXXScopeSpec *SS = 0); /// ActOnDeclarator - If this is a typedef declarator, we modify the diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index ca2d706f23..86bda4551a 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -126,6 +126,7 @@ public: typedef Action::MemInitTy MemInitTy; typedef Action::CXXScopeTy CXXScopeTy; typedef Action::TemplateParamsTy TemplateParamsTy; + typedef Action::TemplateTy TemplateTy; typedef llvm::SmallVector<TemplateParamsTy *, 4> TemplateParameterLists; @@ -1050,7 +1051,7 @@ private: typedef llvm::SmallVector<bool, 16> TemplateArgIsTypeList; typedef llvm::SmallVector<SourceLocation, 16> TemplateArgLocationList; - bool ParseTemplateIdAfterTemplateName(DeclPtrTy Template, + bool ParseTemplateIdAfterTemplateName(TemplateTy Template, SourceLocation TemplateNameLoc, const CXXScopeSpec *SS, bool ConsumeLastToken, @@ -1060,7 +1061,7 @@ private: TemplateArgLocationList &TemplateArgLocations, SourceLocation &RAngleLoc); - void AnnotateTemplateIdToken(DeclPtrTy Template, TemplateNameKind TNK, + void AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, const CXXScopeSpec *SS, SourceLocation TemplateKWLoc = SourceLocation(), bool AllowTypeAnnotation = true); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index f3cf6b18eb..bb17954727 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -483,6 +483,10 @@ ASTContext::getTypeInfo(const Type *T) { Align = Layout.getAlignment(); break; } + + case Type::TemplateSpecialization: + assert(false && "Dependent types have no size"); + break; } assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2"); @@ -1358,30 +1362,31 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, } QualType -ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template, - const TemplateArgument *Args, - unsigned NumArgs, - QualType Canon) { +ASTContext::getTemplateSpecializationType(TemplateName Template, + const TemplateArgument *Args, + unsigned NumArgs, + QualType Canon) { + // FIXME: If Template is dependent, canonicalize it! + if (!Canon.isNull()) Canon = getCanonicalType(Canon); llvm::FoldingSetNodeID ID; - ClassTemplateSpecializationType::Profile(ID, Template, Args, NumArgs); + TemplateSpecializationType::Profile(ID, Template, Args, NumArgs); void *InsertPos = 0; - ClassTemplateSpecializationType *Spec - = ClassTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + TemplateSpecializationType *Spec + = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); if (Spec) return QualType(Spec, 0); - void *Mem = Allocate((sizeof(ClassTemplateSpecializationType) + + void *Mem = Allocate((sizeof(TemplateSpecializationType) + sizeof(TemplateArgument) * NumArgs), 8); - Spec = new (Mem) ClassTemplateSpecializationType(Template, Args, NumArgs, - Canon); + Spec = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, Canon); Types.push_back(Spec); - ClassTemplateSpecializationTypes.InsertNode(Spec, InsertPos); + TemplateSpecializationTypes.InsertNode(Spec, InsertPos); return QualType(Spec, 0); } @@ -2486,6 +2491,53 @@ void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { ObjCConstantStringType = getObjCInterfaceType(Decl); } +/// \brief Retrieve the template name that represents a qualified +/// template name such as \c std::vector. +TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, + bool TemplateKeyword, + TemplateDecl *Template) { + llvm::FoldingSetNodeID ID; + QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template); + + void *InsertPos = 0; + QualifiedTemplateName *QTN = + QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + if (!QTN) { + QTN = new (*this,4) QualifiedTemplateName(NNS, TemplateKeyword, Template); + QualifiedTemplateNames.InsertNode(QTN, InsertPos); + } + + return TemplateName(QTN); +} + +/// \brief Retrieve the template name that represents a dependent +/// template name such as \c MetaFun::template apply. +TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, + const IdentifierInfo *Name) { + assert(NNS->isDependent() && "Nested name specifier must be dependent"); + + llvm::FoldingSetNodeID ID; + DependentTemplateName::Profile(ID, NNS, Name); + + void *InsertPos = 0; + DependentTemplateName *QTN = + DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + + if (QTN) + return TemplateName(QTN); + + NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + if (CanonNNS == NNS) { + QTN = new (*this,4) DependentTemplateName(NNS, Name); + } else { + TemplateName Canon = getDependentTemplateName(CanonNNS, Name); + QTN = new (*this,4) DependentTemplateName(NNS, Name, Canon); + } + + DependentTemplateNames.InsertNode(QTN, InsertPos); + return TemplateName(QTN); +} + /// getFromTargetType - Given one of the integer types provided by /// TargetInfo, produce the corresponding type. The unsigned @p Type /// is actually a value of type @c TargetInfo::IntType. @@ -3033,6 +3085,10 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { ResultType.setCVRQualifiers(LHSCan.getCVRQualifiers()); return ResultType; #endif + + case Type::TemplateSpecialization: + assert(false && "Dependent types have no size"); + break; } return QualType(); diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp new file mode 100644 index 0000000000..4e54fe4955 --- /dev/null +++ b/lib/AST/TemplateName.cpp @@ -0,0 +1,54 @@ +//===--- TemplateName.h - C++ Template Name Representation-------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TemplateName interface and subclasses. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/TemplateName.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +TemplateDecl *TemplateName::getAsTemplateDecl() const { + if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) + return Template; + + if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) + return QTN->getTemplateDecl(); + + return 0; +} + +bool TemplateName::isDependent() const { + if (TemplateDecl *Template = getAsTemplateDecl()) { + // FIXME: We don't yet have a notion of dependent + // declarations. When we do, check that. This hack won't last + // long!. + return isa<TemplateTemplateParmDecl>(Template); + } + + return true; +} + +void TemplateName::Print(llvm::raw_ostream &OS) const { + if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) + OS << Template->getIdentifier()->getName(); + else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { + QTN->getQualifier()->Print(OS); + if (QTN->hasTemplateKeyword()) + OS << "template "; + OS << QTN->getTemplateDecl()->getIdentifier()->getName(); + } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { + DTN->getQualifier()->Print(OS); + OS << "template "; + OS << DTN->getName()->getName(); + } +} diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 0a3e8f91f0..6922dcc6c0 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -93,8 +93,8 @@ QualType Type::getDesugaredType() const { return TOE->getUnderlyingExpr()->getType().getDesugaredType(); if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this)) return TOT->getUnderlyingType().getDesugaredType(); - if (const ClassTemplateSpecializationType *Spec - = dyn_cast<ClassTemplateSpecializationType>(this)) + if (const TemplateSpecializationType *Spec + = dyn_cast<TemplateSpecializationType>(this)) return Spec->getCanonicalTypeInternal().getDesugaredType(); if (const QualifiedNameType *QualName = dyn_cast<QualifiedNameType>(this)) return QualName->getNamedType().getDesugaredType(); @@ -549,11 +549,11 @@ const TemplateTypeParmType *Type::getAsTemplateTypeParmType() const { return dyn_cast<TemplateTypeParmType>(CanonicalType); } -const ClassTemplateSpecializationType * -Type::getAsClassTemplateSpecializationType() const { +const TemplateSpecializationType * +Type::getAsTemplateSpecializationType() 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<ClassTemplateSpecializati |