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