llvm-project/clang/lib/AST/DeclTemplate.cpp
Douglas Gregor a8a089bfd5 Whenever we're creating an expression that is typically an rvalue
(e.g., a call, cast, etc.), immediately adjust the expression's type
to strip cv-qualifiers off of all non-class types (in C++) or all
types (in C). This effectively extends my previous fix for PR7463,
which was restricted to calls, to other kinds of expressions within
similar characteristics. I've audited every use of
getNonReferenceType() in the code base, switching to the newly-renamed
getNonLValueExprType() where necessary. 

Big thanks to Eli for pointing out just how incomplete my original fix
for PR7463 actually was. We've been handling cv-qualifiers on rvalues
wrong for a very, very long time. Fixes PR7463.

llvm-svn: 108253
2010-07-13 18:40:04 +00:00

587 lines
23 KiB
C++

//===--- DeclTemplate.cpp - Template Declaration AST Node 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 the C++ related Decl classes for templates.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// TemplateParameterList Implementation
//===----------------------------------------------------------------------===//
TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
NamedDecl **Params, unsigned NumParams,
SourceLocation RAngleLoc)
: TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
NumParams(NumParams) {
for (unsigned Idx = 0; Idx < NumParams; ++Idx)
begin()[Idx] = Params[Idx];
}
TemplateParameterList *
TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc,
SourceLocation LAngleLoc, NamedDecl **Params,
unsigned NumParams, SourceLocation RAngleLoc) {
unsigned Size = sizeof(TemplateParameterList)
+ sizeof(NamedDecl *) * NumParams;
unsigned Align = llvm::AlignOf<TemplateParameterList>::Alignment;
void *Mem = C.Allocate(Size, Align);
return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params,
NumParams, RAngleLoc);
}
unsigned TemplateParameterList::getMinRequiredArguments() const {
unsigned NumRequiredArgs = size();
iterator Param = const_cast<TemplateParameterList *>(this)->end(),
ParamBegin = const_cast<TemplateParameterList *>(this)->begin();
while (Param != ParamBegin) {
--Param;
if (!(*Param)->isTemplateParameterPack() &&
!(isa<TemplateTypeParmDecl>(*Param) &&
cast<TemplateTypeParmDecl>(*Param)->hasDefaultArgument()) &&
!(isa<NonTypeTemplateParmDecl>(*Param) &&
cast<NonTypeTemplateParmDecl>(*Param)->hasDefaultArgument()) &&
!(isa<TemplateTemplateParmDecl>(*Param) &&
cast<TemplateTemplateParmDecl>(*Param)->hasDefaultArgument()))
break;
--NumRequiredArgs;
}
return NumRequiredArgs;
}
unsigned TemplateParameterList::getDepth() const {
if (size() == 0)
return 0;
const NamedDecl *FirstParm = getParam(0);
if (const TemplateTypeParmDecl *TTP
= dyn_cast<TemplateTypeParmDecl>(FirstParm))
return TTP->getDepth();
else if (const NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(FirstParm))
return NTTP->getDepth();
else
return cast<TemplateTemplateParmDecl>(FirstParm)->getDepth();
}
//===----------------------------------------------------------------------===//
// TemplateDecl Implementation
//===----------------------------------------------------------------------===//
TemplateDecl::~TemplateDecl() {
}
//===----------------------------------------------------------------------===//
// FunctionTemplateDecl Implementation
//===----------------------------------------------------------------------===//
void FunctionTemplateDecl::DeallocateCommon(void *Ptr) {
static_cast<Common *>(Ptr)->~Common();
}
FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
NamedDecl *Decl) {
return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl);
}
void FunctionTemplateDecl::Destroy(ASTContext &C) {
if (Common *CommonPtr = CommonOrPrev.dyn_cast<Common*>()) {
for (llvm::FoldingSet<FunctionTemplateSpecializationInfo>::iterator
Spec = CommonPtr->Specializations.begin(),
SpecEnd = CommonPtr->Specializations.end();
Spec != SpecEnd; ++Spec)
C.Deallocate(&*Spec);
}
Decl::Destroy(C);
}
FunctionTemplateDecl *FunctionTemplateDecl::getCanonicalDecl() {
FunctionTemplateDecl *FunTmpl = this;
while (FunTmpl->getPreviousDeclaration())
FunTmpl = FunTmpl->getPreviousDeclaration();
return FunTmpl;
}
FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() {
// Find the first declaration of this function template.
FunctionTemplateDecl *First = this;
while (First->getPreviousDeclaration())
First = First->getPreviousDeclaration();
if (First->CommonOrPrev.isNull()) {
Common *CommonPtr = new (getASTContext()) Common;
getASTContext().AddDeallocation(DeallocateCommon, CommonPtr);
First->CommonOrPrev = CommonPtr;
}
return First->CommonOrPrev.get<Common*>();
}
//===----------------------------------------------------------------------===//
// ClassTemplateDecl Implementation
//===----------------------------------------------------------------------===//
void ClassTemplateDecl::DeallocateCommon(void *Ptr) {
static_cast<Common *>(Ptr)->~Common();
}
ClassTemplateDecl *ClassTemplateDecl::getCanonicalDecl() {
ClassTemplateDecl *Template = this;
while (Template->getPreviousDeclaration())
Template = Template->getPreviousDeclaration();
return Template;
}
ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
NamedDecl *Decl,
ClassTemplateDecl *PrevDecl) {
ClassTemplateDecl *New = new (C) ClassTemplateDecl(DC, L, Name, Params, Decl);
New->setPreviousDeclaration(PrevDecl);
return New;
}
void ClassTemplateDecl::Destroy(ASTContext& C) {
Decl::Destroy(C);
}
void ClassTemplateDecl::getPartialSpecializations(
llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS) {
llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &PartialSpecs
= getPartialSpecializations();
PS.clear();
PS.resize(PartialSpecs.size());
for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
P = PartialSpecs.begin(), PEnd = PartialSpecs.end();
P != PEnd; ++P) {
assert(!PS[P->getSequenceNumber()]);
PS[P->getSequenceNumber()] = &*P;
}
}
ClassTemplatePartialSpecializationDecl *
ClassTemplateDecl::findPartialSpecialization(QualType T) {
ASTContext &Context = getASTContext();
typedef llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
partial_spec_iterator;
for (partial_spec_iterator P = getPartialSpecializations().begin(),
PEnd = getPartialSpecializations().end();
P != PEnd; ++P) {
if (Context.hasSameType(P->getInjectedSpecializationType(), T))
return &*P;
}
return 0;
}
QualType
ClassTemplateDecl::getInjectedClassNameSpecialization() {
Common *CommonPtr = getCommonPtr();
if (!CommonPtr->InjectedClassNameType.isNull())
return CommonPtr->InjectedClassNameType;
// FIXME: n2800 14.6.1p1 should say how the template arguments
// corresponding to template parameter packs should be pack
// expansions. We already say that in 14.6.2.1p2, so it would be
// better to fix that redundancy.
ASTContext &Context = getASTContext();
TemplateParameterList *Params = getTemplateParameters();
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
TemplateArgs.reserve(Params->size());
for (TemplateParameterList::iterator Param = Params->begin(),
ParamEnd = Params->end();
Param != ParamEnd; ++Param) {
if (isa<TemplateTypeParmDecl>(*Param)) {
QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param));
TemplateArgs.push_back(TemplateArgument(ParamType));
} else if (NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
Expr *E = new (Context) DeclRefExpr(NTTP,
NTTP->getType().getNonLValueExprType(Context),
NTTP->getLocation());
TemplateArgs.push_back(TemplateArgument(E));
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
TemplateArgs.push_back(TemplateArgument(TemplateName(TTP)));
}
}
CommonPtr->InjectedClassNameType
= Context.getTemplateSpecializationType(TemplateName(this),
&TemplateArgs[0],
TemplateArgs.size());
return CommonPtr->InjectedClassNameType;
}
ClassTemplateDecl::Common *ClassTemplateDecl::getCommonPtr() {
// Find the first declaration of this function template.
ClassTemplateDecl *First = this;
while (First->getPreviousDeclaration())
First = First->getPreviousDeclaration();
if (First->CommonOrPrev.isNull()) {
Common *CommonPtr = new (getASTContext()) Common;
getASTContext().AddDeallocation(DeallocateCommon, CommonPtr);
First->CommonOrPrev = CommonPtr;
}
return First->CommonOrPrev.get<Common*>();
}
//===----------------------------------------------------------------------===//
// TemplateTypeParm Allocation/Deallocation Method Implementations
//===----------------------------------------------------------------------===//
TemplateTypeParmDecl *
TemplateTypeParmDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id, bool Typename,
bool ParameterPack) {
QualType Type = C.getTemplateTypeParmType(D, P, ParameterPack, Id);
return new (C) TemplateTypeParmDecl(DC, L, Id, Typename, Type, ParameterPack);
}
TemplateTypeParmDecl *
TemplateTypeParmDecl::Create(ASTContext &C, EmptyShell Empty) {
return new (C) TemplateTypeParmDecl(0, SourceLocation(), 0, false,
QualType(), false);
}
SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
return DefaultArgument->getTypeLoc().getSourceRange().getBegin();
}
unsigned TemplateTypeParmDecl::getDepth() const {
return TypeForDecl->getAs<TemplateTypeParmType>()->getDepth();
}
unsigned TemplateTypeParmDecl::getIndex() const {
return TypeForDecl->getAs<TemplateTypeParmType>()->getIndex();
}
//===----------------------------------------------------------------------===//
// NonTypeTemplateParmDecl Method Implementations
//===----------------------------------------------------------------------===//
NonTypeTemplateParmDecl *
NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo) {
return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, TInfo);
}
SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
return hasDefaultArgument()
? getDefaultArgument()->getSourceRange().getBegin()
: SourceLocation();
}
//===----------------------------------------------------------------------===//
// TemplateTemplateParmDecl Method Implementations
//===----------------------------------------------------------------------===//
TemplateTemplateParmDecl *
TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id,
TemplateParameterList *Params) {
return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params);
}
//===----------------------------------------------------------------------===//
// TemplateArgumentListBuilder Implementation
//===----------------------------------------------------------------------===//
void TemplateArgumentListBuilder::Append(const TemplateArgument &Arg) {
assert((Arg.getKind() != TemplateArgument::Type ||
Arg.getAsType().isCanonical()) && "Type must be canonical!");
assert(FlatArgs.size() < MaxFlatArgs && "Argument list builder is full!");
assert(!StructuredArgs &&
"Can't append arguments when an argument pack has been added!");
FlatArgs.push_back(Arg);
}
void TemplateArgumentListBuilder::BeginPack() {
assert(!AddingToPack && "Already adding to pack!");
assert(!StructuredArgs && "Argument list already contains a pack!");
AddingToPack = true;
PackBeginIndex = FlatArgs.size();
}
void TemplateArgumentListBuilder::EndPack() {
assert(AddingToPack && "Not adding to pack!");
assert(!StructuredArgs && "Argument list already contains a pack!");
AddingToPack = false;
// FIXME: This is a memory leak!
StructuredArgs = new TemplateArgument[MaxStructuredArgs];
// First copy the flat entries over to the list (if any)
for (unsigned I = 0; I != PackBeginIndex; ++I) {
NumStructuredArgs++;
StructuredArgs[I] = FlatArgs[I];
}
// Next, set the pack.
TemplateArgument *PackArgs = 0;
unsigned NumPackArgs = NumFlatArgs - PackBeginIndex;
// FIXME: NumPackArgs shouldn't be negative here???
if (NumPackArgs)
PackArgs = FlatArgs.data()+PackBeginIndex;
StructuredArgs[NumStructuredArgs++].setArgumentPack(PackArgs, NumPackArgs,
/*CopyArgs=*/false);
}
//===----------------------------------------------------------------------===//
// TemplateArgumentList Implementation
//===----------------------------------------------------------------------===//
TemplateArgumentList::TemplateArgumentList(ASTContext &Context,
TemplateArgumentListBuilder &Builder,
bool TakeArgs)
: FlatArguments(Builder.getFlatArguments(), TakeArgs),
NumFlatArguments(Builder.flatSize()),
StructuredArguments(Builder.getStructuredArguments(), TakeArgs),
NumStructuredArguments(Builder.structuredSize()) {
if (!TakeArgs)
return;
// If this does take ownership of the arguments, then we have to new them
// and copy over.
TemplateArgument *NewArgs =
new (Context) TemplateArgument[Builder.flatSize()];
std::copy(Builder.getFlatArguments(),
Builder.getFlatArguments()+Builder.flatSize(), NewArgs);
FlatArguments.setPointer(NewArgs);
// Just reuse the structured and flat arguments array if possible.
if (Builder.getStructuredArguments() == Builder.getFlatArguments()) {
StructuredArguments.setPointer(NewArgs);
StructuredArguments.setInt(0);
} else {
TemplateArgument *NewSArgs =
new (Context) TemplateArgument[Builder.flatSize()];
std::copy(Builder.getFlatArguments(),
Builder.getFlatArguments()+Builder.flatSize(), NewSArgs);
StructuredArguments.setPointer(NewSArgs);
}
}
TemplateArgumentList::TemplateArgumentList(ASTContext &Context,
const TemplateArgument *Args,
unsigned NumArgs)
: NumFlatArguments(0), NumStructuredArguments(0) {
init(Context, Args, NumArgs);
}
/// Produces a shallow copy of the given template argument list. This
/// assumes that the input argument list outlives it. This takes the list as
/// a pointer to avoid looking like a copy constructor, since this really
/// really isn't safe to use that way.
TemplateArgumentList::TemplateArgumentList(const TemplateArgumentList *Other)
: FlatArguments(Other->FlatArguments.getPointer(), false),
NumFlatArguments(Other->flat_size()),
StructuredArguments(Other->StructuredArguments.getPointer(), false),
NumStructuredArguments(Other->NumStructuredArguments) { }
void TemplateArgumentList::init(ASTContext &Context,
const TemplateArgument *Args,
unsigned NumArgs) {
assert(NumFlatArguments == 0 && NumStructuredArguments == 0 &&
"Already initialized!");
NumFlatArguments = NumStructuredArguments = NumArgs;
TemplateArgument *NewArgs = new (Context) TemplateArgument[NumArgs];
std::copy(Args, Args+NumArgs, NewArgs);
FlatArguments.setPointer(NewArgs);
FlatArguments.setInt(1); // Owns the pointer.
// Just reuse the flat arguments array.
StructuredArguments.setPointer(NewArgs);
StructuredArguments.setInt(0); // Doesn't own the pointer.
}
void TemplateArgumentList::Destroy(ASTContext &C) {
if (FlatArguments.getInt())
C.Deallocate((void*)FlatArguments.getPointer());
if (StructuredArguments.getInt())
C.Deallocate((void*)StructuredArguments.getPointer());
}
TemplateArgumentList::~TemplateArgumentList() {}
//===----------------------------------------------------------------------===//
// ClassTemplateSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
ClassTemplateSpecializationDecl::
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgumentListBuilder &Builder,
ClassTemplateSpecializationDecl *PrevDecl)
: CXXRecordDecl(DK, TK, DC, L,
SpecializedTemplate->getIdentifier(),
PrevDecl),
SpecializedTemplate(SpecializedTemplate),
ExplicitInfo(0),
TemplateArgs(Context, Builder, /*TakeArgs=*/true),
SpecializationKind(TSK_Undeclared) {
}
ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(Kind DK)
: CXXRecordDecl(DK, TTK_Struct, 0, SourceLocation(), 0, 0),
ExplicitInfo(0),
SpecializationKind(TSK_Undeclared) {
}
ClassTemplateSpecializationDecl *
ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgumentListBuilder &Builder,
ClassTemplateSpecializationDecl *PrevDecl) {
ClassTemplateSpecializationDecl *Result
= new (Context)ClassTemplateSpecializationDecl(Context,
ClassTemplateSpecialization,
TK, DC, L,
SpecializedTemplate,
Builder,
PrevDecl);
Context.getTypeDeclType(Result, PrevDecl);
return Result;
}
ClassTemplateSpecializationDecl *
ClassTemplateSpecializationDecl::Create(ASTContext &Context, EmptyShell Empty) {
return
new (Context)ClassTemplateSpecializationDecl(ClassTemplateSpecialization);
}
void ClassTemplateSpecializationDecl::Destroy(ASTContext &C) {
delete ExplicitInfo;
if (SpecializedPartialSpecialization *PartialSpec
= SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
C.Deallocate(PartialSpec);
CXXRecordDecl::Destroy(C);
}
void
ClassTemplateSpecializationDecl::getNameForDiagnostic(std::string &S,
const PrintingPolicy &Policy,
bool Qualified) const {
NamedDecl::getNameForDiagnostic(S, Policy, Qualified);
const TemplateArgumentList &TemplateArgs = getTemplateArgs();
S += TemplateSpecializationType::PrintTemplateArgumentList(
TemplateArgs.getFlatArgumentList(),
TemplateArgs.flat_size(),
Policy);
}
ClassTemplateDecl *
ClassTemplateSpecializationDecl::getSpecializedTemplate() const {
if (SpecializedPartialSpecialization *PartialSpec
= SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
return PartialSpec->PartialSpecialization->getSpecializedTemplate();
return SpecializedTemplate.get<ClassTemplateDecl*>();
}
//===----------------------------------------------------------------------===//
// ClassTemplatePartialSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
ClassTemplatePartialSpecializationDecl *
ClassTemplatePartialSpecializationDecl::
Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgumentListBuilder &Builder,
const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType,
ClassTemplatePartialSpecializationDecl *PrevDecl,
unsigned SequenceNumber) {
unsigned N = ArgInfos.size();
TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N];
for (unsigned I = 0; I != N; ++I)
ClonedArgs[I] = ArgInfos[I];
ClassTemplatePartialSpecializationDecl *Result
= new (Context)ClassTemplatePartialSpecializationDecl(Context, TK,
DC, L, Params,
SpecializedTemplate,
Builder,
ClonedArgs, N,
PrevDecl,
SequenceNumber);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
Context.getInjectedClassNameType(Result, CanonInjectedType);
return Result;
}
ClassTemplatePartialSpecializationDecl *
ClassTemplatePartialSpecializationDecl::Create(ASTContext &Context,
EmptyShell Empty) {
return new (Context)ClassTemplatePartialSpecializationDecl();
}
void ClassTemplatePartialSpecializationDecl::
initTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgInfos) {
assert(ArgsAsWritten == 0 && "ArgsAsWritten already set");
unsigned N = ArgInfos.size();
TemplateArgumentLoc *ClonedArgs
= new (getASTContext()) TemplateArgumentLoc[N];
for (unsigned I = 0; I != N; ++I)
ClonedArgs[I] = ArgInfos[I];
ArgsAsWritten = ClonedArgs;
NumArgsAsWritten = N;
}
//===----------------------------------------------------------------------===//
// FriendTemplateDecl Implementation
//===----------------------------------------------------------------------===//
FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context,
DeclContext *DC,
SourceLocation L,
unsigned NParams,
TemplateParameterList **Params,
FriendUnion Friend,
SourceLocation FLoc) {
FriendTemplateDecl *Result
= new (Context) FriendTemplateDecl(DC, L, NParams, Params, Friend, FLoc);
return Result;
}