diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp | 356 |
1 files changed, 331 insertions, 25 deletions
diff --git a/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp b/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp index a3bf145..5ab5f46 100644 --- a/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp +++ b/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp @@ -12,41 +12,172 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/FoldingSet.h" #include "clang/AST/TemplateBase.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/FoldingSet.h" +#include <algorithm> +#include <cctype> +#include <iomanip> +#include <sstream> using namespace clang; +/// \brief Print a template integral argument value. +/// +/// \param TemplArg the TemplateArgument instance to print. +/// +/// \param Out the raw_ostream instance to use for printing. +static void printIntegral(const TemplateArgument &TemplArg, + llvm::raw_ostream &Out) { + const ::clang::Type *T = TemplArg.getIntegralType().getTypePtr(); + const llvm::APSInt *Val = TemplArg.getAsIntegral(); + + if (T->isBooleanType()) { + Out << (Val->getBoolValue() ? "true" : "false"); + } else if (T->isCharType()) { + char Ch = Val->getSExtValue(); + if (std::isprint(Ch)) { + Out << "'"; + if (Ch == '\'' || Ch == '\\') + Out << '\\'; + Out << Ch << "'"; + } else { + std::ostringstream Str; + Str << std::setw(2) << std::setfill('0') << std::hex << (int)Ch; + Out << "'\\x" << Str.str() << "'"; + } + } else { + Out << Val->toString(10); + } +} + //===----------------------------------------------------------------------===// // TemplateArgument Implementation //===----------------------------------------------------------------------===// -/// \brief Construct a template argument pack. -void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs, - bool CopyArgs) { - assert(isNull() && "Must call setArgumentPack on a null argument"); +TemplateArgument TemplateArgument::CreatePackCopy(ASTContext &Context, + const TemplateArgument *Args, + unsigned NumArgs) { + if (NumArgs == 0) + return TemplateArgument(0, 0); + + TemplateArgument *Storage = new (Context) TemplateArgument [NumArgs]; + std::copy(Args, Args + NumArgs, Storage); + return TemplateArgument(Storage, NumArgs); +} + +bool TemplateArgument::isDependent() const { + switch (getKind()) { + case Null: + assert(false && "Should not have a NULL template argument"); + return false; + + case Type: + return getAsType()->isDependentType(); + + case Template: + return getAsTemplate().isDependent(); + + case TemplateExpansion: + return true; + + case Declaration: + if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl())) + return DC->isDependentContext(); + return getAsDecl()->getDeclContext()->isDependentContext(); + + case Integral: + // Never dependent + return false; + + case Expression: + return (getAsExpr()->isTypeDependent() || getAsExpr()->isValueDependent()); + + case Pack: + for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P) { + if (P->isDependent()) + return true; + } + + return false; + } + + return false; +} + +bool TemplateArgument::isPackExpansion() const { + switch (getKind()) { + case Null: + case Declaration: + case Integral: + case Pack: + case Template: + return false; + + case TemplateExpansion: + return true; + + case Type: + return isa<PackExpansionType>(getAsType()); + + case Expression: + return isa<PackExpansionExpr>(getAsExpr()); + } + + return false; +} + +bool TemplateArgument::containsUnexpandedParameterPack() const { + switch (getKind()) { + case Null: + case Declaration: + case Integral: + case TemplateExpansion: + break; + + case Type: + if (getAsType()->containsUnexpandedParameterPack()) + return true; + break; + + case Template: + if (getAsTemplate().containsUnexpandedParameterPack()) + return true; + break; + + case Expression: + if (getAsExpr()->containsUnexpandedParameterPack()) + return true; + break; - Kind = Pack; - Args.NumArgs = NumArgs; - Args.CopyArgs = CopyArgs; - if (!Args.CopyArgs) { - Args.Args = args; - return; + case Pack: + for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P) + if (P->containsUnexpandedParameterPack()) + return true; + + break; } - // FIXME: Allocate in ASTContext - Args.Args = new TemplateArgument[NumArgs]; - for (unsigned I = 0; I != Args.NumArgs; ++I) - Args.Args[I] = args[I]; + return false; +} + +llvm::Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const { + assert(Kind == TemplateExpansion); + if (TemplateArg.NumExpansions) + return TemplateArg.NumExpansions - 1; + + return llvm::Optional<unsigned>(); } void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, - ASTContext &Context) const { + const ASTContext &Context) const { ID.AddInteger(Kind); switch (Kind) { case Null: @@ -61,18 +192,22 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, break; case Template: + case TemplateExpansion: { + TemplateName Template = getAsTemplateOrTemplatePattern(); if (TemplateTemplateParmDecl *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>( - getAsTemplate().getAsTemplateDecl())) { + Template.getAsTemplateDecl())) { ID.AddBoolean(true); ID.AddInteger(TTP->getDepth()); ID.AddInteger(TTP->getPosition()); + ID.AddBoolean(TTP->isParameterPack()); } else { ID.AddBoolean(false); - ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate()) - .getAsVoidPointer()); + ID.AddPointer(Context.getCanonicalTemplateName(Template) + .getAsVoidPointer()); } break; + } case Integral: getAsIntegral()->Profile(ID); @@ -97,8 +232,9 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const { case Null: case Type: case Declaration: + case Expression: case Template: - case Expression: + case TemplateExpansion: return TypeOrValue == Other.TypeOrValue; case Integral: @@ -117,10 +253,102 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const { return false; } +TemplateArgument TemplateArgument::getPackExpansionPattern() const { + assert(isPackExpansion()); + + switch (getKind()) { + case Type: + return getAsType()->getAs<PackExpansionType>()->getPattern(); + + case Expression: + return cast<PackExpansionExpr>(getAsExpr())->getPattern(); + + case TemplateExpansion: + return TemplateArgument(getAsTemplateOrTemplatePattern()); + + case Declaration: + case Integral: + case Pack: + case Null: + case Template: + return TemplateArgument(); + } + + return TemplateArgument(); +} + +void TemplateArgument::print(const PrintingPolicy &Policy, + llvm::raw_ostream &Out) const { + switch (getKind()) { + case Null: + Out << "<no value>"; + break; + + case Type: { + std::string TypeStr; + getAsType().getAsStringInternal(TypeStr, Policy); + Out << TypeStr; + break; + } + + case Declaration: { + bool Unnamed = true; + if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getAsDecl())) { + if (ND->getDeclName()) { + Unnamed = false; + Out << ND->getNameAsString(); + } + } + + if (Unnamed) { + Out << "<anonymous>"; + } + break; + } + + case Template: + getAsTemplate().print(Out, Policy); + break; + + case TemplateExpansion: + getAsTemplateOrTemplatePattern().print(Out, Policy); + Out << "..."; + break; + + case Integral: { + printIntegral(*this, Out); + break; + } + + case Expression: + getAsExpr()->printPretty(Out, 0, Policy); + break; + + case Pack: + Out << "<"; + bool First = true; + for (TemplateArgument::pack_iterator P = pack_begin(), PEnd = pack_end(); + P != PEnd; ++P) { + if (First) + First = false; + else + Out << ", "; + + P->print(Policy, Out); + } + Out << ">"; + break; + } +} + //===----------------------------------------------------------------------===// // TemplateArgumentLoc Implementation //===----------------------------------------------------------------------===// +TemplateArgumentLocInfo::TemplateArgumentLocInfo() { + memset(this, 0, sizeof(TemplateArgumentLocInfo)); +} + SourceRange TemplateArgumentLoc::getSourceRange() const { switch (Argument.getKind()) { case TemplateArgument::Expression: @@ -137,10 +365,16 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { case TemplateArgument::Template: if (getTemplateQualifierRange().isValid()) - return SourceRange(getTemplateQualifierRange().getBegin(), + return SourceRange(getTemplateQualifierRange().getBegin(), getTemplateNameLoc()); return SourceRange(getTemplateNameLoc()); + case TemplateArgument::TemplateExpansion: + if (getTemplateQualifierRange().isValid()) + return SourceRange(getTemplateQualifierRange().getBegin(), + getTemplateEllipsisLoc()); + return SourceRange(getTemplateNameLoc(), getTemplateEllipsisLoc()); + case TemplateArgument::Integral: case TemplateArgument::Pack: case TemplateArgument::Null: @@ -151,6 +385,68 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { return SourceRange(); } +TemplateArgumentLoc +TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis, + llvm::Optional<unsigned> &NumExpansions, + ASTContext &Context) const { + assert(Argument.isPackExpansion()); + + switch (Argument.getKind()) { + case TemplateArgument::Type: { + // FIXME: We shouldn't ever have to worry about missing + // type-source info! + TypeSourceInfo *ExpansionTSInfo = getTypeSourceInfo(); + if (!ExpansionTSInfo) + ExpansionTSInfo = Context.getTrivialTypeSourceInfo( + getArgument().getAsType(), + Ellipsis); + PackExpansionTypeLoc Expansion + = cast<PackExpansionTypeLoc>(ExpansionTSInfo->getTypeLoc()); + Ellipsis = Expansion.getEllipsisLoc(); + + TypeLoc Pattern = Expansion.getPatternLoc(); + NumExpansions = Expansion.getTypePtr()->getNumExpansions(); + + // FIXME: This is horrible. We know where the source location data is for + // the pattern, and we have the pattern's type, but we are forced to copy + // them into an ASTContext because TypeSourceInfo bundles them together + // and TemplateArgumentLoc traffics in TypeSourceInfo pointers. + TypeSourceInfo *PatternTSInfo + = Context.CreateTypeSourceInfo(Pattern.getType(), + Pattern.getFullDataSize()); + memcpy(PatternTSInfo->getTypeLoc().getOpaqueData(), + Pattern.getOpaqueData(), Pattern.getFullDataSize()); + return TemplateArgumentLoc(TemplateArgument(Pattern.getType()), + PatternTSInfo); + } + + case TemplateArgument::Expression: { + PackExpansionExpr *Expansion + = cast<PackExpansionExpr>(Argument.getAsExpr()); + Expr *Pattern = Expansion->getPattern(); + Ellipsis = Expansion->getEllipsisLoc(); + NumExpansions = Expansion->getNumExpansions(); + return TemplateArgumentLoc(Pattern, Pattern); + } + + case TemplateArgument::TemplateExpansion: + Ellipsis = getTemplateEllipsisLoc(); + NumExpansions = Argument.getNumTemplateExpansions(); + return TemplateArgumentLoc(Argument.getPackExpansionPattern(), + getTemplateQualifierRange(), + getTemplateNameLoc()); + + case TemplateArgument::Declaration: + case TemplateArgument::Template: + case TemplateArgument::Integral: + case TemplateArgument::Pack: + case TemplateArgument::Null: + return TemplateArgumentLoc(); + } + + return TemplateArgumentLoc(); +} + const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, const TemplateArgument &Arg) { switch (Arg.getKind()) { @@ -170,7 +466,10 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, case TemplateArgument::Template: return DB << Arg.getAsTemplate(); - + + case TemplateArgument::TemplateExpansion: + return DB << Arg.getAsTemplateOrTemplatePattern() << "..."; + case TemplateArgument::Expression: { // This shouldn't actually ever happen, so it's okay that we're // regurgitating an expression here. @@ -184,9 +483,16 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, return DB << OS.str(); } - case TemplateArgument::Pack: - // FIXME: Format arguments in a list! - return DB << "<parameter pack>"; + case TemplateArgument::Pack: { + // FIXME: We're guessing at LangOptions! + llvm::SmallString<32> Str; + llvm::raw_svector_ostream OS(Str); + LangOptions LangOpts; + LangOpts.CPlusPlus = true; + PrintingPolicy Policy(LangOpts); + Arg.print(Policy, OS); + return DB << OS.str(); + } } return DB; |