//===-- TemplateBase.h - Core classes for 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 provides definitions which are common for all kinds of // template representation. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_TEMPLATEBASE_H #define LLVM_CLANG_AST_TEMPLATEBASE_H #include "llvm/ADT/APSInt.h" #include "llvm/Support/ErrorHandling.h" #include "clang/AST/Type.h" #include "clang/AST/TemplateName.h" namespace llvm { class FoldingSetNodeID; } namespace clang { class Decl; class Expr; class DeclaratorInfo; /// \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; }; public: /// \brief The type of template argument we're storing. enum ArgKind { /// \brief Represents an empty template argument, e.g., one that has not /// been deduced. Null = 0, /// The template argument is a type. Its value is stored in the /// TypeOrValue field. Type, /// The template argument is a declaration that was provided for a pointer /// or reference non-type template parameter. Declaration, /// The template argument is an integral value stored in an llvm::APSInt /// that was provided for an integral non-type template parameter. Integral, /// The template argument is a template name that was provided for a /// template template parameter. Template, /// The template argument is a value- or type-dependent expression /// stored in an Expr*. Expression, /// The template argument is actually a parameter pack. Arguments are stored /// in the Args struct. Pack } Kind; /// \brief Construct an empty, invalid template argument. TemplateArgument() : TypeOrValue(0), Kind(Null) { } /// \brief Construct a template type argument. TemplateArgument(QualType T) : Kind(Type) { TypeOrValue = reinterpret_cast(T.getAsOpaquePtr()); } /// \brief Construct a template argument that refers to a /// declaration, which is either an external declaration or a /// template declaration. TemplateArgument(Decl *D) : Kind(Declaration) { // FIXME: Need to be sure we have the "canonical" declaration! TypeOrValue = reinterpret_cast(D); } /// \brief Construct an integral constant template argument. TemplateArgument(const llvm::APSInt &Value, QualType Type) : Kind(Integral) { new (Integer.Value) llvm::APSInt(Value); Integer.Type = Type.getAsOpaquePtr(); } /// \brief Construct a template argument that is a template. /// /// This form of template argument is generally used for template template /// parameters. However, the template name could be a dependent template /// name that ends up being instantiated to a function template whose address /// is taken. TemplateArgument(TemplateName Name) : Kind(Template) { TypeOrValue = reinterpret_cast(Name.getAsVoidPointer()); } /// \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) : Kind(Expression) { TypeOrValue = reinterpret_cast(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; } 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; } 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 a template name. TemplateName getAsTemplate() const { if (Kind != Template) return TemplateName(); return TemplateName::getFromVoidPointer( 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 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; }; /// Location information for a TemplateArgument. struct TemplateArgumentLocInfo { private: union { Expr *Expression; DeclaratorInfo *Declarator; struct { unsigned QualifierRange[2]; unsigned TemplateNameLoc; } Template; }; #ifndef NDEBUG enum Kind { K_None, K_DeclaratorInfo, K_Expression, K_Template } Kind; #endif public: TemplateArgumentLocInfo() : Expression(0) #ifndef NDEBUG , Kind(K_None) #endif {} TemplateArgumentLocInfo(DeclaratorInfo *DInfo) : Declarator(DInfo) #ifndef NDEBUG , Kind(K_DeclaratorInfo) #endif {} TemplateArgumentLocInfo(Expr *E) : Expression(E) #ifndef NDEBUG , Kind(K_Expression) #endif {} TemplateArgumentLocInfo(SourceRange QualifierRange, SourceLocation TemplateNameLoc) #ifndef NDEBUG : Kind(K_Template) #endif { Template.QualifierRange[0] = QualifierRange.getBegin().getRawEncoding(); Template.QualifierRange[1] = QualifierRange.getEnd().getRawEncoding(); Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding(); } DeclaratorInfo *getAsDeclaratorInfo() const { assert(Kind == K_DeclaratorInfo); return Declarator; } Expr *getAsExpr() const { assert(Kind == K_Expression); return Expression; } SourceRange getTemplateQualifierRange() const { assert(Kind == K_Template); return SourceRange( SourceLocation::getFromRawEncoding(Template.QualifierRange[0]), SourceLocation::getFromRawEncoding(Template.QualifierRange[1])); } SourceLocation getTemplateNameLoc() const { assert(Kind == K_Template); return SourceLocation::getFromRawEncoding(Template.TemplateNameLoc); } #ifndef NDEBUG void validateForArgument(const TemplateArgument &Arg) { switch (Arg.getKind()) { case TemplateArgument::Type: assert(Kind == K_DeclaratorInfo); break; case TemplateArgument::Expression: case TemplateArgument::Declaration: assert(Kind == K_Expression); break; case TemplateArgument::Template: assert(Kind == K_Template); break; case TemplateArgument::Integral: case TemplateArgument::Pack: assert(Kind == K_None); break; case TemplateArgument::Null: llvm::llvm_unreachable("source info for null template argument?"); } } #endif }; /// Location wrapper for a TemplateArgument. TemplateArgument is to /// TemplateArgumentLoc as Type is to TypeLoc. class TemplateArgumentLoc { TemplateArgument Argument; TemplateArgumentLocInfo LocInfo; public: TemplateArgumentLoc() {} TemplateArgumentLoc(const TemplateArgument &Argument, TemplateArgumentLocInfo Opaque) : Argument(Argument), LocInfo(Opaque) { } TemplateArgumentLoc(const TemplateArgument &Argument, DeclaratorInfo *DInfo) : Argument(Argument), LocInfo(DInfo) { assert(Argument.getKind() == TemplateArgument::Type); } TemplateArgumentLoc(const TemplateArgument &Argument, Expr *E) : Argument(Argument), LocInfo(E) { assert(Argument.getKind() == TemplateArgument::Expression); } TemplateArgumentLoc(const TemplateArgument &Argument, SourceRange QualifierRange, SourceLocation TemplateNameLoc) : Argument(Argument), LocInfo(QualifierRange, TemplateNameLoc) { assert(Argument.getKind() == TemplateArgument::Template); } /// \brief - Fetches the primary location of the argument. SourceLocation getLocation() const { if (Argument.getKind() == TemplateArgument::Template) return getTemplateNameLoc(); return getSourceRange().getBegin(); } /// \brief - Fetches the full source range of the argument. SourceRange getSourceRange() const; const TemplateArgument &getArgument() const { return Argument; } TemplateArgumentLocInfo getLocInfo() const { return LocInfo; } DeclaratorInfo *getSourceDeclaratorInfo() const { assert(Argument.getKind() == TemplateArgument::Type); return LocInfo.getAsDeclaratorInfo(); } Expr *getSourceExpression() const { assert(Argument.getKind() == TemplateArgument::Expression); return LocInfo.getAsExpr(); } Expr *getSourceDeclExpression() const { assert(Argument.getKind() == TemplateArgument::Declaration); return LocInfo.getAsExpr(); } SourceRange getTemplateQualifierRange() const { assert(Argument.getKind() == TemplateArgument::Template); return LocInfo.getTemplateQualifierRange(); } SourceLocation getTemplateNameLoc() const { assert(Argument.getKind() == TemplateArgument::Template); return LocInfo.getTemplateNameLoc(); } }; } #endif