diff options
Diffstat (limited to 'include/clang/AST/TemplateBase.h')
-rw-r--r-- | include/clang/AST/TemplateBase.h | 283 |
1 files changed, 173 insertions, 110 deletions
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h index 7d5123f..a4e074e 100644 --- a/include/clang/AST/TemplateBase.h +++ b/include/clang/AST/TemplateBase.h @@ -23,6 +23,7 @@ namespace llvm { class FoldingSetNodeID; + class raw_ostream; } namespace clang { @@ -30,26 +31,14 @@ namespace clang { class Decl; class DiagnosticBuilder; class Expr; +struct PrintingPolicy; class TypeSourceInfo; /// \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. + /// \brief The kind of template argument we're storing. enum ArgKind { /// \brief Represents an empty template argument, e.g., one that has not /// been deduced. @@ -66,16 +55,42 @@ public: /// The template argument is a template name that was provided for a /// template template parameter. Template, + /// The template argument is a pack expansion of a template name that was + /// provided for a template template parameter. + TemplateExpansion, /// 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; + }; + +private: + /// \brief The kind of template argument we're storing. + unsigned Kind; + union { + uintptr_t TypeOrValue; + struct { + char Value[sizeof(llvm::APSInt)]; + void *Type; + } Integer; + struct { + const TemplateArgument *Args; + unsigned NumArgs; + } Args; + struct { + void *Name; + unsigned NumExpansions; + } TemplateArg; + }; + + TemplateArgument(TemplateName, bool); // DO NOT USE + +public: /// \brief Construct an empty, invalid template argument. - TemplateArgument() : TypeOrValue(0), Kind(Null) { } + TemplateArgument() : Kind(Null), TypeOrValue(0) { } /// \brief Construct a template type argument. TemplateArgument(QualType T) : Kind(Type) { @@ -92,6 +107,8 @@ public: /// \brief Construct an integral constant template argument. TemplateArgument(const llvm::APSInt &Value, QualType Type) : Kind(Integral) { + // FIXME: Large integral values will get leaked. Do something + // similar to what we did with IntegerLiteral. new (Integer.Value) llvm::APSInt(Value); Integer.Type = Type.getAsOpaquePtr(); } @@ -102,10 +119,35 @@ public: /// 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<uintptr_t>(Name.getAsVoidPointer()); + /// + /// \param Name The template name. + TemplateArgument(TemplateName Name) : Kind(Template) + { + TemplateArg.Name = Name.getAsVoidPointer(); + TemplateArg.NumExpansions = 0; } - + + /// \brief Construct a template argument that is a template pack expansion. + /// + /// 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. + /// + /// \param Name The template name. + /// + /// \param NumExpansions The number of expansions that will be generated by + /// instantiating + TemplateArgument(TemplateName Name, llvm::Optional<unsigned> NumExpansions) + : Kind(TemplateExpansion) + { + TemplateArg.Name = Name.getAsVoidPointer(); + if (NumExpansions) + TemplateArg.NumExpansions = *NumExpansions + 1; + else + TemplateArg.NumExpansions = 0; + } + /// \brief Construct a template argument that is an expression. /// /// This form of template argument only occurs in template argument @@ -115,46 +157,59 @@ public: TypeOrValue = reinterpret_cast<uintptr_t>(E); } + /// \brief Construct a template argument that is a template argument pack. + /// + /// We assume that storage for the template arguments provided + /// outlives the TemplateArgument itself. + TemplateArgument(const TemplateArgument *Args, unsigned NumArgs) : Kind(Pack){ + this->Args.Args = Args; + this->Args.NumArgs = NumArgs; + } + /// \brief Copy constructor for a template argument. TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) { + // FIXME: Large integral values will get leaked. Do something + // similar to what we did with IntegerLiteral. 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 + Args.Args = Other.Args.Args; + } else if (Kind == Template || Kind == TemplateExpansion) { + TemplateArg.Name = Other.TemplateArg.Name; + TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions; + } 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(); + return *this; + } + + // Destroy the current integral value, if that's what we're holding. + if (Kind == Integral) + getAsIntegral()->~APSInt(); - Kind = Other.Kind; + Kind = Other.Kind; - if (Other.Kind == Integral) { - new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); - Integer.Type = Other.Integer.Type; - } else - TypeOrValue = Other.TypeOrValue; + if (Other.Kind == Integral) { + new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); + Integer.Type = Other.Integer.Type; + } else if (Other.Kind == Pack) { + Args.NumArgs = Other.Args.NumArgs; + Args.Args = Other.Args.Args; + } else if (Kind == Template || Kind == TemplateExpansion) { + TemplateArg.Name = Other.TemplateArg.Name; + TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions; + } else { + TypeOrValue = Other.TypeOrValue; } return *this; @@ -165,16 +220,31 @@ public: if (Kind == Integral) getAsIntegral()->~APSInt(); - else if (Kind == Pack && Args.CopyArgs) - delete[] Args.Args; } + /// \brief Create a new template argument pack by copying the given set of + /// template arguments. + static TemplateArgument CreatePackCopy(ASTContext &Context, + const TemplateArgument *Args, + unsigned NumArgs); + /// \brief Return the kind of stored template argument. - ArgKind getKind() const { return Kind; } + ArgKind getKind() const { return (ArgKind)Kind; } /// \brief Determine whether this template argument has no value. bool isNull() const { return Kind == Null; } + /// \brief Whether this template argument is dependent on a template + /// parameter. + bool isDependent() const; + + /// \brief Whether this template argument contains an unexpanded + /// parameter pack. + bool containsUnexpandedParameterPack() const; + + /// \brief Determine whether this template argument is a pack expansion. + bool isPackExpansion() const; + /// \brief Retrieve the template argument as a type. QualType getAsType() const { if (Kind != Type) @@ -195,9 +265,21 @@ public: if (Kind != Template) return TemplateName(); - return TemplateName::getFromVoidPointer( - reinterpret_cast<void *> (TypeOrValue)); + return TemplateName::getFromVoidPointer(TemplateArg.Name); + } + + /// \brief Retrieve the template argument as a template name; if the argument + /// is a pack expansion, return the pattern as a template name. + TemplateName getAsTemplateOrTemplatePattern() const { + if (Kind != Template && Kind != TemplateExpansion) + return TemplateName(); + + return TemplateName::getFromVoidPointer(TemplateArg.Name); } + + /// \brief Retrieve the number of expansions that a template template argument + /// expansion will produce, if known. + llvm::Optional<unsigned> getNumTemplateExpansions() const; /// \brief Retrieve the template argument as an integral value. llvm::APSInt *getAsIntegral() { @@ -260,11 +342,17 @@ public: /// same. bool structurallyEquals(const TemplateArgument &Other) const; - /// \brief Construct a template argument pack. - void setArgumentPack(TemplateArgument *Args, unsigned NumArgs, bool CopyArgs); + /// \brief When the template argument is a pack expansion, returns + /// the pattern of the pack expansion. + /// + /// \param Ellipsis Will be set to the location of the ellipsis. + TemplateArgument getPackExpansionPattern() const; + /// \brief Print this template argument to the given output stream. + void print(const PrintingPolicy &Policy, llvm::raw_ostream &Out) const; + /// \brief Used to insert TemplateArguments into FoldingSets. - void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context) const; + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const; }; /// Location information for a TemplateArgument. @@ -276,95 +364,48 @@ private: struct { unsigned QualifierRange[2]; unsigned TemplateNameLoc; + unsigned EllipsisLoc; } Template; }; -#ifndef NDEBUG - enum Kind { - K_None, - K_TypeSourceInfo, - K_Expression, - K_Template - } Kind; -#endif - public: - TemplateArgumentLocInfo() - : Expression(0) -#ifndef NDEBUG - , Kind(K_None) -#endif - {} + TemplateArgumentLocInfo(); - TemplateArgumentLocInfo(TypeSourceInfo *TInfo) - : Declarator(TInfo) -#ifndef NDEBUG - , Kind(K_TypeSourceInfo) -#endif - {} + TemplateArgumentLocInfo(TypeSourceInfo *TInfo) : Declarator(TInfo) {} - TemplateArgumentLocInfo(Expr *E) - : Expression(E) -#ifndef NDEBUG - , Kind(K_Expression) -#endif - {} + TemplateArgumentLocInfo(Expr *E) : Expression(E) {} TemplateArgumentLocInfo(SourceRange QualifierRange, - SourceLocation TemplateNameLoc) -#ifndef NDEBUG - : Kind(K_Template) -#endif + SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc) { Template.QualifierRange[0] = QualifierRange.getBegin().getRawEncoding(); Template.QualifierRange[1] = QualifierRange.getEnd().getRawEncoding(); Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding(); + Template.EllipsisLoc = EllipsisLoc.getRawEncoding(); } TypeSourceInfo *getAsTypeSourceInfo() const { - assert(Kind == K_TypeSourceInfo); 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_TypeSourceInfo); - 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_unreachable("source info for null template argument?"); - } + SourceLocation getTemplateEllipsisLoc() const { + return SourceLocation::getFromRawEncoding(Template.EllipsisLoc); } -#endif }; /// Location wrapper for a TemplateArgument. TemplateArgument is to @@ -393,14 +434,18 @@ public: TemplateArgumentLoc(const TemplateArgument &Argument, SourceRange QualifierRange, - SourceLocation TemplateNameLoc) - : Argument(Argument), LocInfo(QualifierRange, TemplateNameLoc) { - assert(Argument.getKind() == TemplateArgument::Template); + SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc = SourceLocation()) + : Argument(Argument), + LocInfo(QualifierRange, TemplateNameLoc, EllipsisLoc) { + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); } /// \brief - Fetches the primary location of the argument. SourceLocation getLocation() const { - if (Argument.getKind() == TemplateArgument::Template) + if (Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion) return getTemplateNameLoc(); return getSourceRange().getBegin(); @@ -433,14 +478,32 @@ public: } SourceRange getTemplateQualifierRange() const { - assert(Argument.getKind() == TemplateArgument::Template); + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); return LocInfo.getTemplateQualifierRange(); } SourceLocation getTemplateNameLoc() const { - assert(Argument.getKind() == TemplateArgument::Template); + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); return LocInfo.getTemplateNameLoc(); } + + SourceLocation getTemplateEllipsisLoc() const { + assert(Argument.getKind() == TemplateArgument::TemplateExpansion); + return LocInfo.getTemplateEllipsisLoc(); + } + + /// \brief When the template argument is a pack expansion, returns + /// the pattern of the pack expansion. + /// + /// \param Ellipsis Will be set to the location of the ellipsis. + /// + /// \param NumExpansions Will be set to the number of expansions that will + /// be generated from this pack expansion, if known a priori. + TemplateArgumentLoc getPackExpansionPattern(SourceLocation &Ellipsis, + llvm::Optional<unsigned> &NumExpansions, + ASTContext &Context) const; }; /// A convenient class for passing around template argument |