llvm-project/clang/lib/AST/TemplateBase.cpp
Douglas Gregor a6e053e61a Variadic templates: extend the Expr class with a bit that specifies
whether the expression contains an unexpanded parameter pack, in the
same vein as the changes to the Type hierarchy. Compute this bit
within all of the Expr subclasses.

This change required a bunch of reshuffling of dependency
calculations, mainly to consolidate them inside the constructors and
to fuse multiple loops that iterate over arguments to determine type
dependence, value dependence, and (now) containment of unexpanded
parameter packs.

Again, testing is painfully sparse, because all of the diagnostics
will change and it is more important to test the to-be-written visitor
that collects unexpanded parameter packs.

llvm-svn: 121831
2010-12-15 01:34:56 +00:00

244 lines
6.5 KiB
C++

//===--- TemplateBase.cpp - Common template AST class implementation ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements common classes used throughout C++ template
// representations.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/FoldingSet.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Diagnostic.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// TemplateArgument Implementation
//===----------------------------------------------------------------------===//
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 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::containsUnexpandedParameterPack() const {
switch (getKind()) {
case Null:
case Declaration:
case Integral:
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;
case Pack:
for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P)
if (P->containsUnexpandedParameterPack())
return true;
break;
}
return false;
}
void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
ASTContext &Context) const {
ID.AddInteger(Kind);
switch (Kind) {
case Null:
break;
case Type:
getAsType().Profile(ID);
break;
case Declaration:
ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0);
break;
case Template:
if (TemplateTemplateParmDecl *TTP
= dyn_cast_or_null<TemplateTemplateParmDecl>(
getAsTemplate().getAsTemplateDecl())) {
ID.AddBoolean(true);
ID.AddInteger(TTP->getDepth());
ID.AddInteger(TTP->getPosition());
} else {
ID.AddBoolean(false);
ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate())
.getAsVoidPointer());
}
break;
case Integral:
getAsIntegral()->Profile(ID);
getIntegralType().Profile(ID);
break;
case Expression:
getAsExpr()->Profile(ID, Context, true);
break;
case Pack:
ID.AddInteger(Args.NumArgs);
for (unsigned I = 0; I != Args.NumArgs; ++I)
Args.Args[I].Profile(ID, Context);
}
}
bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
if (getKind() != Other.getKind()) return false;
switch (getKind()) {
case Null:
case Type:
case Declaration:
case Template:
case Expression:
return TypeOrValue == Other.TypeOrValue;
case Integral:
return getIntegralType() == Other.getIntegralType() &&
*getAsIntegral() == *Other.getAsIntegral();
case Pack:
if (Args.NumArgs != Other.Args.NumArgs) return false;
for (unsigned I = 0, E = Args.NumArgs; I != E; ++I)
if (!Args.Args[I].structurallyEquals(Other.Args.Args[I]))
return false;
return true;
}
// Suppress warnings.
return false;
}
//===----------------------------------------------------------------------===//
// TemplateArgumentLoc Implementation
//===----------------------------------------------------------------------===//
SourceRange TemplateArgumentLoc::getSourceRange() const {
switch (Argument.getKind()) {
case TemplateArgument::Expression:
return getSourceExpression()->getSourceRange();
case TemplateArgument::Declaration:
return getSourceDeclExpression()->getSourceRange();
case TemplateArgument::Type:
if (TypeSourceInfo *TSI = getTypeSourceInfo())
return TSI->getTypeLoc().getSourceRange();
else
return SourceRange();
case TemplateArgument::Template:
if (getTemplateQualifierRange().isValid())
return SourceRange(getTemplateQualifierRange().getBegin(),
getTemplateNameLoc());
return SourceRange(getTemplateNameLoc());
case TemplateArgument::Integral:
case TemplateArgument::Pack:
case TemplateArgument::Null:
return SourceRange();
}
// Silence bonus gcc warning.
return SourceRange();
}
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
const TemplateArgument &Arg) {
switch (Arg.getKind()) {
case TemplateArgument::Null:
// This is bad, but not as bad as crashing because of argument
// count mismatches.
return DB << "(null template argument)";
case TemplateArgument::Type:
return DB << Arg.getAsType();
case TemplateArgument::Declaration:
return DB << Arg.getAsDecl();
case TemplateArgument::Integral:
return DB << Arg.getAsIntegral()->toString(10);
case TemplateArgument::Template:
return DB << Arg.getAsTemplate();
case TemplateArgument::Expression: {
// This shouldn't actually ever happen, so it's okay that we're
// regurgitating an expression here.
// 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.getAsExpr()->printPretty(OS, 0, Policy);
return DB << OS.str();
}
case TemplateArgument::Pack:
// FIXME: Format arguments in a list!
return DB << "<parameter pack>";
}
return DB;
}