Viewing file: TemplateBase.h (25.61 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
//===- TemplateBase.h - Core classes for C++ templates ----------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // 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 "clang/AST/DependenceFlags.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/TrailingObjects.h" #include <cassert> #include <cstddef> #include <cstdint> #include <optional>
namespace llvm {
class FoldingSetNodeID;
// Provide PointerLikeTypeTraits for clang::Expr*, this default one requires a // full definition of Expr, but this file only sees a forward del because of // the dependency. template <> struct PointerLikeTypeTraits<clang::Expr *> { static inline void *getAsVoidPointer(clang::Expr *P) { return P; } static inline clang::Expr *getFromVoidPointer(void *P) { return static_cast<clang::Expr *>(P); } static constexpr int NumLowBitsAvailable = 2; };
} // namespace llvm
namespace clang {
class APValue; class ASTContext; class Expr; struct PrintingPolicy; class TypeSourceInfo; class ValueDecl;
/// Represents a template argument. class TemplateArgument { public: /// The kind of template argument we're storing. enum ArgKind { /// Represents an empty template argument, e.g., one that has not /// been deduced. Null = 0,
/// The template argument is a type. Type,
/// The template argument is a declaration that was provided for a pointer, /// reference, or pointer to member non-type template parameter. Declaration,
/// The template argument is a null pointer or null pointer to member that /// was provided for a non-type template parameter. NullPtr,
/// 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 non-type template argument that can't be /// represented by the special-case Declaration, NullPtr, or Integral /// forms. These values are only ever produced by constant evaluation, /// so cannot be dependent. /// TODO: merge Declaration, NullPtr and Integral into this? StructuralValue,
/// 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 an expression, and we've not resolved it to one /// of the other forms yet, either because it's dependent or because we're /// representing a non-canonical template argument (for instance, in a /// TemplateSpecializationType). Expression,
/// The template argument is actually a parameter pack. Arguments are stored /// in the Args struct. Pack };
private: /// The kind of template argument we're storing.
struct DA { LLVM_PREFERRED_TYPE(ArgKind) unsigned Kind : 31; LLVM_PREFERRED_TYPE(bool) unsigned IsDefaulted : 1; void *QT; ValueDecl *D; }; struct I { LLVM_PREFERRED_TYPE(ArgKind) unsigned Kind : 31; LLVM_PREFERRED_TYPE(bool) unsigned IsDefaulted : 1; // We store a decomposed APSInt with the data allocated by ASTContext if // BitWidth > 64. The memory may be shared between multiple // TemplateArgument instances. unsigned BitWidth : 31; LLVM_PREFERRED_TYPE(bool) unsigned IsUnsigned : 1; union { /// Used to store the <= 64 bits integer value. uint64_t VAL;
/// Used to store the >64 bits integer value. const uint64_t *pVal; }; void *Type; }; struct V { LLVM_PREFERRED_TYPE(ArgKind) unsigned Kind : 31; LLVM_PREFERRED_TYPE(bool) unsigned IsDefaulted : 1; APValue *Value; void *Type; }; struct A { LLVM_PREFERRED_TYPE(ArgKind) unsigned Kind : 31; LLVM_PREFERRED_TYPE(bool) unsigned IsDefaulted : 1; unsigned NumArgs; const TemplateArgument *Args; }; struct TA { LLVM_PREFERRED_TYPE(ArgKind) unsigned Kind : 31; LLVM_PREFERRED_TYPE(bool) unsigned IsDefaulted : 1; unsigned NumExpansions; void *Name; }; struct TV { LLVM_PREFERRED_TYPE(ArgKind) unsigned Kind : 31; LLVM_PREFERRED_TYPE(bool) unsigned IsDefaulted : 1; uintptr_t V; }; union { struct DA DeclArg; struct I Integer; struct V Value; struct A Args; struct TA TemplateArg; struct TV TypeOrValue; };
void initFromType(QualType T, bool IsNullPtr, bool IsDefaulted); void initFromDeclaration(ValueDecl *D, QualType QT, bool IsDefaulted); void initFromIntegral(const ASTContext &Ctx, const llvm::APSInt &Value, QualType Type, bool IsDefaulted); void initFromStructural(const ASTContext &Ctx, QualType Type, const APValue &V, bool IsDefaulted);
public: /// Construct an empty, invalid template argument. constexpr TemplateArgument() : TypeOrValue({Null, 0, /* IsDefaulted */ 0}) {}
/// Construct a template type argument. TemplateArgument(QualType T, bool isNullPtr = false, bool IsDefaulted = false) { initFromType(T, isNullPtr, IsDefaulted); }
/// Construct a template argument that refers to a (non-dependent) /// declaration. TemplateArgument(ValueDecl *D, QualType QT, bool IsDefaulted = false) { initFromDeclaration(D, QT, IsDefaulted); }
/// Construct an integral constant template argument. The memory to /// store the value is allocated with Ctx. TemplateArgument(const ASTContext &Ctx, const llvm::APSInt &Value, QualType Type, bool IsDefaulted = false);
/// Construct a template argument from an arbitrary constant value. TemplateArgument(const ASTContext &Ctx, QualType Type, const APValue &Value, bool IsDefaulted = false);
/// Construct an integral constant template argument with the same /// value as Other but a different type. TemplateArgument(const TemplateArgument &Other, QualType Type) { Integer = Other.Integer; Integer.Type = Type.getAsOpaquePtr(); }
/// 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. /// /// \param Name The template name. /// /// \param IsDefaulted If 'true', implies that this TemplateArgument /// corresponds to a default template parameter TemplateArgument(TemplateName Name, bool IsDefaulted = false) { TemplateArg.Kind = Template; TemplateArg.IsDefaulted = IsDefaulted; TemplateArg.Name = Name.getAsVoidPointer(); TemplateArg.NumExpansions = 0; }
/// 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 /// /// \param IsDefaulted If 'true', implies that this TemplateArgument /// corresponds to a default template parameter TemplateArgument(TemplateName Name, std::optional<unsigned> NumExpansions, bool IsDefaulted = false) { TemplateArg.Kind = TemplateExpansion; TemplateArg.IsDefaulted = IsDefaulted; TemplateArg.Name = Name.getAsVoidPointer(); if (NumExpansions) TemplateArg.NumExpansions = *NumExpansions + 1; else TemplateArg.NumExpansions = 0; }
/// 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, bool IsDefaulted = false) { TypeOrValue.Kind = Expression; TypeOrValue.IsDefaulted = IsDefaulted; TypeOrValue.V = reinterpret_cast<uintptr_t>(E); }
/// Construct a template argument that is a template argument pack. /// /// We assume that storage for the template arguments provided /// outlives the TemplateArgument itself. explicit TemplateArgument(ArrayRef<TemplateArgument> Args) { this->Args.Kind = Pack; this->Args.IsDefaulted = false; this->Args.Args = Args.data(); this->Args.NumArgs = Args.size(); }
static TemplateArgument getEmptyPack() { return TemplateArgument(std::nullopt); }
/// Create a new template argument pack by copying the given set of /// template arguments. static TemplateArgument CreatePackCopy(ASTContext &Context, ArrayRef<TemplateArgument> Args);
/// Return the kind of stored template argument. ArgKind getKind() const { return (ArgKind)TypeOrValue.Kind; }
/// Determine whether this template argument has no value. bool isNull() const { return getKind() == Null; }
TemplateArgumentDependence getDependence() const;
/// Whether this template argument is dependent on a template /// parameter such that its result can change from one instantiation to /// another. bool isDependent() const;
/// Whether this template argument is dependent on a template /// parameter. bool isInstantiationDependent() const;
/// Whether this template argument contains an unexpanded /// parameter pack. bool containsUnexpandedParameterPack() const;
/// Determine whether this template argument is a pack expansion. bool isPackExpansion() const;
/// Retrieve the type for a type template argument. QualType getAsType() const { assert(getKind() == Type && "Unexpected kind"); return QualType::getFromOpaquePtr(reinterpret_cast<void *>(TypeOrValue.V)); }
/// Retrieve the declaration for a declaration non-type /// template argument. ValueDecl *getAsDecl() const { assert(getKind() == Declaration && "Unexpected kind"); return DeclArg.D; }
QualType getParamTypeForDecl() const { assert(getKind() == Declaration && "Unexpected kind"); return QualType::getFromOpaquePtr(DeclArg.QT); }
/// Retrieve the type for null non-type template argument. QualType getNullPtrType() const { assert(getKind() == NullPtr && "Unexpected kind"); return QualType::getFromOpaquePtr(reinterpret_cast<void *>(TypeOrValue.V)); }
/// Retrieve the template name for a template name argument. TemplateName getAsTemplate() const { assert(getKind() == Template && "Unexpected kind"); return TemplateName::getFromVoidPointer(TemplateArg.Name); }
/// 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 { assert((getKind() == Template || getKind() == TemplateExpansion) && "Unexpected kind");
return TemplateName::getFromVoidPointer(TemplateArg.Name); }
/// Retrieve the number of expansions that a template template argument /// expansion will produce, if known. std::optional<unsigned> getNumTemplateExpansions() const;
/// Retrieve the template argument as an integral value. // FIXME: Provide a way to read the integral data without copying the value. llvm::APSInt getAsIntegral() const { assert(getKind() == Integral && "Unexpected kind");
using namespace llvm;
if (Integer.BitWidth <= 64) return APSInt(APInt(Integer.BitWidth, Integer.VAL), Integer.IsUnsigned);
unsigned NumWords = APInt::getNumWords(Integer.BitWidth); return APSInt(APInt(Integer.BitWidth, ArrayRef(Integer.pVal, NumWords)), Integer.IsUnsigned); }
/// Retrieve the type of the integral value. QualType getIntegralType() const { assert(getKind() == Integral && "Unexpected kind"); return QualType::getFromOpaquePtr(Integer.Type); }
void setIntegralType(QualType T) { assert(getKind() == Integral && "Unexpected kind"); Integer.Type = T.getAsOpaquePtr(); }
/// Set to 'true' if this TemplateArgument corresponds to a /// default template parameter. void setIsDefaulted(bool v) { TypeOrValue.IsDefaulted = v; }
/// If returns 'true', this TemplateArgument corresponds to a /// default template parameter. bool getIsDefaulted() const { return (bool)TypeOrValue.IsDefaulted; }
/// Get the value of a StructuralValue. const APValue &getAsStructuralValue() const { return *Value.Value; }
/// Get the type of a StructuralValue. QualType getStructuralValueType() const { return QualType::getFromOpaquePtr(Value.Type); }
/// If this is a non-type template argument, get its type. Otherwise, /// returns a null QualType. QualType getNonTypeTemplateArgumentType() const;
/// Retrieve the template argument as an expression. Expr *getAsExpr() const { assert(getKind() == Expression && "Unexpected kind"); return reinterpret_cast<Expr *>(TypeOrValue.V); }
/// Iterator that traverses the elements of a template argument pack. using pack_iterator = const TemplateArgument *;
/// Iterator referencing the first argument of a template argument /// pack. pack_iterator pack_begin() const { assert(getKind() == Pack); return Args.Args; }
/// Iterator referencing one past the last argument of a template /// argument pack. pack_iterator pack_end() const { assert(getKind() == Pack); return Args.Args + Args.NumArgs; }
/// Iterator range referencing all of the elements of a template /// argument pack. ArrayRef<TemplateArgument> pack_elements() const { return llvm::ArrayRef(pack_begin(), pack_end()); }
/// The number of template arguments in the given template argument /// pack. unsigned pack_size() const { assert(getKind() == Pack); return Args.NumArgs; }
/// Return the array of arguments in this template argument pack. ArrayRef<TemplateArgument> getPackAsArray() const { assert(getKind() == Pack); return llvm::ArrayRef(Args.Args, Args.NumArgs); }
/// Determines whether two template arguments are superficially the /// same. bool structurallyEquals(const TemplateArgument &Other) const;
/// When the template argument is a pack expansion, returns /// the pattern of the pack expansion. TemplateArgument getPackExpansionPattern() const;
/// Print this template argument to the given output stream. void print(const PrintingPolicy &Policy, raw_ostream &Out, bool IncludeType) const;
/// Debugging aid that dumps the template argument. void dump(raw_ostream &Out, const ASTContext &Context) const;
/// Debugging aid that dumps the template argument to standard error. void dump() const;
/// Used to insert TemplateArguments into FoldingSets. void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const; };
/// Location information for a TemplateArgument. struct TemplateArgumentLocInfo { private: struct TemplateTemplateArgLocInfo { // FIXME: We'd like to just use the qualifier in the TemplateName, // but template arguments get canonicalized too quickly. NestedNameSpecifier *Qualifier; void *QualifierLocData; SourceLocation TemplateNameLoc; SourceLocation EllipsisLoc; };
llvm::PointerUnion<TemplateTemplateArgLocInfo *, Expr *, TypeSourceInfo *> Pointer;
TemplateTemplateArgLocInfo *getTemplate() const { return Pointer.get<TemplateTemplateArgLocInfo *>(); }
public: TemplateArgumentLocInfo() {} TemplateArgumentLocInfo(TypeSourceInfo *Declarator) { Pointer = Declarator; }
TemplateArgumentLocInfo(Expr *E) { Pointer = E; } // Ctx is used for allocation -- this case is unusually large and also rare, // so we store the payload out-of-line. TemplateArgumentLocInfo(ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc, SourceLocation EllipsisLoc);
TypeSourceInfo *getAsTypeSourceInfo() const { return Pointer.get<TypeSourceInfo *>(); }
Expr *getAsExpr() const { return Pointer.get<Expr *>(); }
NestedNameSpecifierLoc getTemplateQualifierLoc() const { const auto *Template = getTemplate(); return NestedNameSpecifierLoc(Template->Qualifier, Template->QualifierLocData); }
SourceLocation getTemplateNameLoc() const { return getTemplate()->TemplateNameLoc; }
SourceLocation getTemplateEllipsisLoc() const { return getTemplate()->EllipsisLoc; } };
/// 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, TypeSourceInfo *TInfo) : Argument(Argument), LocInfo(TInfo) { assert(Argument.getKind() == TemplateArgument::Type); }
TemplateArgumentLoc(const TemplateArgument &Argument, Expr *E) : Argument(Argument), LocInfo(E) {
// Permit any kind of template argument that can be represented with an // expression. assert(Argument.getKind() == TemplateArgument::NullPtr || Argument.getKind() == TemplateArgument::Integral || Argument.getKind() == TemplateArgument::Declaration || Argument.getKind() == TemplateArgument::StructuralValue || Argument.getKind() == TemplateArgument::Expression); }
TemplateArgumentLoc(ASTContext &Ctx, const TemplateArgument &Argument, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc, SourceLocation EllipsisLoc = SourceLocation()) : Argument(Argument), LocInfo(Ctx, QualifierLoc, TemplateNameLoc, EllipsisLoc) { assert(Argument.getKind() == TemplateArgument::Template || Argument.getKind() == TemplateArgument::TemplateExpansion); }
/// - Fetches the primary location of the argument. SourceLocation getLocation() const { if (Argument.getKind() == TemplateArgument::Template || Argument.getKind() == TemplateArgument::TemplateExpansion) return getTemplateNameLoc();
return getSourceRange().getBegin(); }
/// - Fetches the full source range of the argument. SourceRange getSourceRange() const LLVM_READONLY;
const TemplateArgument &getArgument() const { return Argument; }
TemplateArgumentLocInfo getLocInfo() const { return LocInfo; }
TypeSourceInfo *getTypeSourceInfo() const { if (Argument.getKind() != TemplateArgument::Type) return nullptr; return LocInfo.getAsTypeSourceInfo(); }
Expr *getSourceExpression() const { assert(Argument.getKind() == TemplateArgument::Expression); return LocInfo.getAsExpr(); }
Expr *getSourceDeclExpression() const { assert(Argument.getKind() == TemplateArgument::Declaration); return LocInfo.getAsExpr(); }
Expr *getSourceNullPtrExpression() const { assert(Argument.getKind() == TemplateArgument::NullPtr); return LocInfo.getAsExpr(); }
Expr *getSourceIntegralExpression() const { assert(Argument.getKind() == TemplateArgument::Integral); return LocInfo.getAsExpr(); }
Expr *getSourceStructuralValueExpression() const { assert(Argument.getKind() == TemplateArgument::StructuralValue); return LocInfo.getAsExpr(); }
NestedNameSpecifierLoc getTemplateQualifierLoc() const { if (Argument.getKind() != TemplateArgument::Template && Argument.getKind() != TemplateArgument::TemplateExpansion) return NestedNameSpecifierLoc(); return LocInfo.getTemplateQualifierLoc(); }
SourceLocation getTemplateNameLoc() const { if (Argument.getKind() != TemplateArgument::Template && Argument.getKind() != TemplateArgument::TemplateExpansion) return SourceLocation(); return LocInfo.getTemplateNameLoc(); }
SourceLocation getTemplateEllipsisLoc() const { if (Argument.getKind() != TemplateArgument::TemplateExpansion) return SourceLocation(); return LocInfo.getTemplateEllipsisLoc(); } };
/// A convenient class for passing around template argument /// information. Designed to be passed by reference. class TemplateArgumentListInfo { SmallVector<TemplateArgumentLoc, 8> Arguments; SourceLocation LAngleLoc; SourceLocation RAngleLoc;
public: TemplateArgumentListInfo() = default;
TemplateArgumentListInfo(SourceLocation LAngleLoc, SourceLocation RAngleLoc) : LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {}
// This can leak if used in an AST node, use ASTTemplateArgumentListInfo // instead. void *operator new(size_t bytes, ASTContext &C) = delete;
SourceLocation getLAngleLoc() const { return LAngleLoc; } SourceLocation getRAngleLoc() const { return RAngleLoc; }
void setLAngleLoc(SourceLocation Loc) { LAngleLoc = Loc; } void setRAngleLoc(SourceLocation Loc) { RAngleLoc = Loc; }
unsigned size() const { return Arguments.size(); }
const TemplateArgumentLoc *getArgumentArray() const { return Arguments.data(); }
llvm::ArrayRef<TemplateArgumentLoc> arguments() const { return Arguments; }
const TemplateArgumentLoc &operator[](unsigned I) const { return Arguments[I]; }
TemplateArgumentLoc &operator[](unsigned I) { return Arguments[I]; }
void addArgument(const TemplateArgumentLoc &Loc) { Arguments.push_back(Loc); } };
/// Represents an explicit template argument list in C++, e.g., /// the "<int>" in "sort<int>". /// This is safe to be used inside an AST node, in contrast with /// TemplateArgumentListInfo. struct ASTTemplateArgumentListInfo final : private llvm::TrailingObjects<ASTTemplateArgumentListInfo, TemplateArgumentLoc> { private: friend class ASTNodeImporter; friend TrailingObjects;
ASTTemplateArgumentListInfo(const TemplateArgumentListInfo &List);
// FIXME: Is it ever necessary to copy to another context? ASTTemplateArgumentListInfo(const ASTTemplateArgumentListInfo *List);
public: /// The source location of the left angle bracket ('<'). SourceLocation LAngleLoc;
/// The source location of the right angle bracket ('>'). SourceLocation RAngleLoc;
/// The number of template arguments in TemplateArgs. unsigned NumTemplateArgs;
SourceLocation getLAngleLoc() const { return LAngleLoc; } SourceLocation getRAngleLoc() const { return RAngleLoc; }
/// Retrieve the template arguments const TemplateArgumentLoc *getTemplateArgs() const { return getTrailingObjects<TemplateArgumentLoc>(); } unsigned getNumTemplateArgs() const { return NumTemplateArgs; }
llvm::ArrayRef<TemplateArgumentLoc> arguments() const { return llvm::ArrayRef(getTemplateArgs(), getNumTemplateArgs()); }
const TemplateArgumentLoc &operator[](unsigned I) const { return getTemplateArgs()[I]; }
static const ASTTemplateArgumentListInfo * Create(const ASTContext &C, const TemplateArgumentListInfo &List);
// FIXME: Is it ever necessary to copy to another context? static const ASTTemplateArgumentListInfo * Create(const ASTContext &C, const ASTTemplateArgumentListInfo *List); };
/// Represents an explicit template argument list in C++, e.g., /// the "<int>" in "sort<int>". /// /// It is intended to be used as a trailing object on AST nodes, and /// as such, doesn't contain the array of TemplateArgumentLoc itself, /// but expects the containing object to also provide storage for /// that. struct alignas(void *) ASTTemplateKWAndArgsInfo { /// The source location of the left angle bracket ('<'). SourceLocation LAngleLoc;
/// The source location of the right angle bracket ('>'). SourceLocation RAngleLoc;
/// The source location of the template keyword; this is used /// as part of the representation of qualified identifiers, such as /// S<T>::template apply<T>. Will be empty if this expression does /// not have a template keyword. SourceLocation TemplateKWLoc;
/// The number of template arguments in TemplateArgs. unsigned NumTemplateArgs;
void initializeFrom(SourceLocation TemplateKWLoc, const TemplateArgumentListInfo &List, TemplateArgumentLoc *OutArgArray); // FIXME: The parameter Deps is the result populated by this method, the // caller doesn't need it since it is populated by computeDependence. remove // it. void initializeFrom(SourceLocation TemplateKWLoc, const TemplateArgumentListInfo &List, TemplateArgumentLoc *OutArgArray, TemplateArgumentDependence &Deps); void initializeFrom(SourceLocation TemplateKWLoc);
void copyInto(const TemplateArgumentLoc *ArgArray, TemplateArgumentListInfo &List) const; };
const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, const TemplateArgument &Arg);
} // namespace clang
#endif // LLVM_CLANG_AST_TEMPLATEBASE_H
|