зеркало из https://github.com/microsoft/clang-1.git
479 строки
14 KiB
C++
479 строки
14 KiB
C++
//===-- 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/ADT/SmallVector.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 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.
|
|
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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(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<void*>(TypeOrValue));
|
|
}
|
|
|
|
/// \brief Retrieve the template argument as a declaration.
|
|
Decl *getAsDecl() const {
|
|
if (Kind != Declaration)
|
|
return 0;
|
|
return reinterpret_cast<Decl *>(TypeOrValue);
|
|
}
|
|
|
|
/// \brief Retrieve the template argument as a template name.
|
|
TemplateName getAsTemplate() const {
|
|
if (Kind != Template)
|
|
return TemplateName();
|
|
|
|
return TemplateName::getFromVoidPointer(
|
|
reinterpret_cast<void *> (TypeOrValue));
|
|
}
|
|
|
|
/// \brief Retrieve the template argument as an integral value.
|
|
llvm::APSInt *getAsIntegral() {
|
|
if (Kind != Integral)
|
|
return 0;
|
|
return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]);
|
|
}
|
|
|
|
const llvm::APSInt *getAsIntegral() const {
|
|
return const_cast<TemplateArgument*>(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<Expr *>(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;
|
|
TypeSourceInfo *Declarator;
|
|
struct {
|
|
unsigned QualifierRange[2];
|
|
unsigned TemplateNameLoc;
|
|
} 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(TypeSourceInfo *TInfo)
|
|
: Declarator(TInfo)
|
|
#ifndef NDEBUG
|
|
, Kind(K_TypeSourceInfo)
|
|
#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();
|
|
}
|
|
|
|
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?");
|
|
}
|
|
}
|
|
#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, TypeSourceInfo *TInfo)
|
|
: Argument(Argument), LocInfo(TInfo) {
|
|
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;
|
|
}
|
|
|
|
TypeSourceInfo *getTypeSourceInfo() const {
|
|
assert(Argument.getKind() == TemplateArgument::Type);
|
|
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();
|
|
}
|
|
|
|
SourceRange getTemplateQualifierRange() const {
|
|
assert(Argument.getKind() == TemplateArgument::Template);
|
|
return LocInfo.getTemplateQualifierRange();
|
|
}
|
|
|
|
SourceLocation getTemplateNameLoc() const {
|
|
assert(Argument.getKind() == TemplateArgument::Template);
|
|
return LocInfo.getTemplateNameLoc();
|
|
}
|
|
};
|
|
|
|
/// A convenient class for passing around template argument
|
|
/// information. Designed to be passed by reference.
|
|
class TemplateArgumentListInfo {
|
|
llvm::SmallVector<TemplateArgumentLoc, 8> Arguments;
|
|
SourceLocation LAngleLoc;
|
|
SourceLocation RAngleLoc;
|
|
|
|
public:
|
|
TemplateArgumentListInfo() {}
|
|
|
|
TemplateArgumentListInfo(SourceLocation LAngleLoc,
|
|
SourceLocation RAngleLoc)
|
|
: LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {}
|
|
|
|
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();
|
|
}
|
|
|
|
const TemplateArgumentLoc &operator[](unsigned I) const {
|
|
return Arguments[I];
|
|
}
|
|
|
|
void addArgument(const TemplateArgumentLoc &Loc) {
|
|
Arguments.push_back(Loc);
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|