From: Douglas Gregor Date: Mon, 29 Jun 2009 20:59:39 +0000 (+0000) Subject: Keep track of function template specializations, to eliminate X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=127102b5196ffe04bdb70fd553fe62c265ab10a9;p=clang Keep track of function template specializations, to eliminate redundant, implicit instantiations of function templates and provide a place where we can hang function template specializations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74454 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index c201409f51..2b42239b01 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -809,9 +809,7 @@ public: return PreviousDeclaration; } - void setPreviousDeclaration(FunctionDecl * PrevDecl) { - PreviousDeclaration = PrevDecl; - } + void setPreviousDeclaration(FunctionDecl * PrevDecl); unsigned getBuiltinID(ASTContext &Context) const; @@ -961,7 +959,8 @@ public: /// function template specialization from the template. void setFunctionTemplateSpecialization(ASTContext &Context, FunctionTemplateDecl *Template, - const TemplateArgumentList *TemplateArgs); + const TemplateArgumentList *TemplateArgs, + void *InsertPos); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 9a633ef73e..531525d5d4 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -100,671 +100,723 @@ public: } }; -//===----------------------------------------------------------------------===// -// 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) { } +/// \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: - ~TemplateDecl(); - - /// Get the list of template parameters - TemplateParameterList *getTemplateParameters() const { - return TemplateParams; + /// \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; } - - /// 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; + + /// \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; } - 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: - FunctionTemplateDecl *Template; - const TemplateArgumentList *TemplateArguments; -}; -/// Declaration of a template function. -class FunctionTemplateDecl : public TemplateDecl { -protected: - /// \brief Data that is common to all of the declarations of a given - /// class template. - struct Common { - /// \brief The class template specializations for this class - /// template, including explicit specializations and instantiations. - llvm::FoldingSet Specializations; + /// \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; - /// \brief The class template partial specializations for this class - /// template. - llvm::FoldingSet - PartialSpecializations; + // FIXME: Handle Packs + assert(Kind != Pack && "FIXME: Handle packs"); + assert(Other.Kind != Pack && "FIXME: Handle packs"); - /// \brief The injected-class-name type for this class template. - QualType InjectedClassNameType; + 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(); }; - FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, - TemplateParameterList *Params, NamedDecl *Decl) - : TemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl) { } -public: - /// Get the underling function declaration of the template. - FunctionDecl *getTemplatedDecl() const { - return static_cast(TemplatedDecl); + /// \brief Retrieve the template argument as an expression. + Expr *getAsExpr() const { + if (Kind != Expression) + return 0; + + return reinterpret_cast(TypeOrValue); } - - /// 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(); + /// \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; } - -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 The number of template arguments in the given template argument + /// pack. + unsigned pack_size() const { + assert(Kind == Pack); + return Args.NumArgs; } - - /// \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; + + /// \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) const { + ID.AddInteger(Kind); + switch (Kind) { + case Null: + break; + + case Type: + getAsType().Profile(ID); + break; + + case Declaration: + ID.AddPointer(getAsDecl()); // FIXME: Must be canonical! + break; + + case Integral: + getAsIntegral()->Profile(ID); + getIntegralType().Profile(ID); + break; + + case Expression: + // FIXME: We need a canonical representation of expressions. + ID.AddPointer(getAsExpr()); + break; + + case Pack: + ID.AddInteger(Args.NumArgs); + for (unsigned I = 0; I != Args.NumArgs; ++I) + Args.Args[I].Profile(ID); + } } - 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) - { } - +/// \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: - 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; + 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(); - /// \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; + return NumStructuredArgs; } - - // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { - return D->getKind() == NonTypeTemplateParm; + const TemplateArgument *getStructuredArguments() const { + // If we don't have any structured args, just reuse the flat args. + if (!StructuredArgs) + return getFlatArguments(); + + return StructuredArgs; } - static bool classof(const NonTypeTemplateParmDecl *D) { return true; } }; -/// TemplateTemplateParmDecl - Declares a template template parameter, -/// e.g., "T" in -/// @code -/// template