llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Douglas Gregor cd3a097925 Simplify, and improve the performance of, template instantiation for
declaration references. The key realization is that dependent Decls,
which actually require instantiation, can only refer to the current
instantiation or members thereof. And, since the current context
during instantiation contains all of those members of the current
instantiation, we can simply find the real instantiate that matches up
with the "current instantiation" template.

llvm-svn: 72486
2009-05-27 17:54:46 +00:00

767 lines
28 KiB
C++

//===--- SemaTemplateInstantiateDecl.cpp - C++ Template Decl Instantiation ===/
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//===----------------------------------------------------------------------===/
//
// This file implements C++ template instantiation for declarations.
//
//===----------------------------------------------------------------------===/
#include "Sema.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
#include "llvm/Support/Compiler.h"
using namespace clang;
namespace {
class VISIBILITY_HIDDEN TemplateDeclInstantiator
: public DeclVisitor<TemplateDeclInstantiator, Decl *> {
Sema &SemaRef;
DeclContext *Owner;
const TemplateArgumentList &TemplateArgs;
public:
typedef Sema::OwningExprResult OwningExprResult;
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
const TemplateArgumentList &TemplateArgs)
: SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs) { }
// FIXME: Once we get closer to completion, replace these manually-written
// declarations with automatically-generated ones from
// clang/AST/DeclNodes.def.
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
Decl *VisitTypedefDecl(TypedefDecl *D);
Decl *VisitVarDecl(VarDecl *D);
Decl *VisitFieldDecl(FieldDecl *D);
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
Decl *VisitCXXMethodDecl(CXXMethodDecl *D);
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
// Base case. FIXME: Remove once we can instantiate everything.
Decl *VisitDecl(Decl *) {
assert(false && "Template instantiation of unknown declaration kind!");
return 0;
}
// Helper functions for instantiating methods.
QualType InstantiateFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params);
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
};
}
Decl *
TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
assert(false && "Translation units cannot be instantiated");
return D;
}
Decl *
TemplateDeclInstantiator::VisitNamespaceDecl(NamespaceDecl *D) {
assert(false && "Namespaces cannot be instantiated");
return D;
}
Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
bool Invalid = false;
QualType T = D->getUnderlyingType();
if (T->isDependentType()) {
T = SemaRef.InstantiateType(T, TemplateArgs,
D->getLocation(), D->getDeclName());
if (T.isNull()) {
Invalid = true;
T = SemaRef.Context.IntTy;
}
}
// Create the new typedef
TypedefDecl *Typedef
= TypedefDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getIdentifier(), T);
if (Invalid)
Typedef->setInvalidDecl();
Owner->addDecl(SemaRef.Context, Typedef);
return Typedef;
}
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
// Instantiate the type of the declaration
QualType T = SemaRef.InstantiateType(D->getType(), TemplateArgs,
D->getTypeSpecStartLoc(),
D->getDeclName());
if (T.isNull())
return 0;
// Build the instantiated declaration
VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner,
D->getLocation(), D->getIdentifier(),
T, D->getStorageClass(),
D->getTypeSpecStartLoc());
Var->setThreadSpecified(D->isThreadSpecified());
Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
Var->setDeclaredInCondition(D->isDeclaredInCondition());
// FIXME: In theory, we could have a previous declaration for variables that
// are not static data members.
bool Redeclaration = false;
SemaRef.CheckVariableDeclaration(Var, 0, Redeclaration);
Owner->addDecl(SemaRef.Context, Var);
if (D->getInit()) {
OwningExprResult Init
= SemaRef.InstantiateExpr(D->getInit(), TemplateArgs);
if (Init.isInvalid())
Var->setInvalidDecl();
else
SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init),
D->hasCXXDirectInitializer());
} else {
// FIXME: Call ActOnUninitializedDecl? (Not always)
}
return Var;
}
Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
bool Invalid = false;
QualType T = D->getType();
if (T->isDependentType()) {
T = SemaRef.InstantiateType(T, TemplateArgs,
D->getLocation(), D->getDeclName());
if (!T.isNull() && T->isFunctionType()) {
// C++ [temp.arg.type]p3:
// If a declaration acquires a function type through a type
// dependent on a template-parameter and this causes a
// declaration that does not use the syntactic form of a
// function declarator to have function type, the program is
// ill-formed.
SemaRef.Diag(D->getLocation(), diag::err_field_instantiates_to_function)
<< T;
T = QualType();
Invalid = true;
}
}
Expr *BitWidth = D->getBitWidth();
if (Invalid)
BitWidth = 0;
else if (BitWidth) {
OwningExprResult InstantiatedBitWidth
= SemaRef.InstantiateExpr(BitWidth, TemplateArgs);
if (InstantiatedBitWidth.isInvalid()) {
Invalid = true;
BitWidth = 0;
} else
BitWidth = InstantiatedBitWidth.takeAs<Expr>();
}
FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(), T,
cast<RecordDecl>(Owner),
D->getLocation(),
D->isMutable(),
BitWidth,
D->getAccess(),
0);
if (Field) {
if (Invalid)
Field->setInvalidDecl();
Owner->addDecl(SemaRef.Context, Field);
}
return Field;
}
Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
Expr *AssertExpr = D->getAssertExpr();
OwningExprResult InstantiatedAssertExpr
= SemaRef.InstantiateExpr(AssertExpr, TemplateArgs);
if (InstantiatedAssertExpr.isInvalid())
return 0;
OwningExprResult Message = SemaRef.Clone(D->getMessage());
Decl *StaticAssert
= SemaRef.ActOnStaticAssertDeclaration(D->getLocation(),
move(InstantiatedAssertExpr),
move(Message)).getAs<Decl>();
return StaticAssert;
}
Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner,
D->getLocation(), D->getIdentifier(),
/*PrevDecl=*/0);
Enum->setInstantiationOfMemberEnum(D);
Enum->setAccess(D->getAccess());
Owner->addDecl(SemaRef.Context, Enum);
Enum->startDefinition();
llvm::SmallVector<Sema::DeclPtrTy, 16> Enumerators;
EnumConstantDecl *LastEnumConst = 0;
for (EnumDecl::enumerator_iterator EC = D->enumerator_begin(SemaRef.Context),
ECEnd = D->enumerator_end(SemaRef.Context);
EC != ECEnd; ++EC) {
// The specified value for the enumerator.
OwningExprResult Value = SemaRef.Owned((Expr *)0);
if (Expr *UninstValue = EC->getInitExpr())
Value = SemaRef.InstantiateExpr(UninstValue, TemplateArgs);
// Drop the initial value and continue.
bool isInvalid = false;
if (Value.isInvalid()) {
Value = SemaRef.Owned((Expr *)0);
isInvalid = true;
}
EnumConstantDecl *EnumConst
= SemaRef.CheckEnumConstant(Enum, LastEnumConst,
EC->getLocation(), EC->getIdentifier(),
move(Value));
if (isInvalid) {
if (EnumConst)
EnumConst->setInvalidDecl();
Enum->setInvalidDecl();
}
if (EnumConst) {
Enum->addDecl(SemaRef.Context, EnumConst);
Enumerators.push_back(Sema::DeclPtrTy::make(EnumConst));
LastEnumConst = EnumConst;
}
}
// FIXME: Fixup LBraceLoc and RBraceLoc
SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), SourceLocation(),
Sema::DeclPtrTy::make(Enum),
&Enumerators[0], Enumerators.size());
return Enum;
}
Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
assert(false && "EnumConstantDecls can only occur within EnumDecls.");
return 0;
}
Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
CXXRecordDecl *PrevDecl = 0;
if (D->isInjectedClassName())
PrevDecl = cast<CXXRecordDecl>(Owner);
CXXRecordDecl *Record
= CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
D->getLocation(), D->getIdentifier(), PrevDecl);
Record->setImplicit(D->isImplicit());
Record->setAccess(D->getAccess());
if (!D->isInjectedClassName())
Record->setInstantiationOfMemberClass(D);
Owner->addDecl(SemaRef.Context, Record);
return Record;
}
Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
// Only handle actual methods; we'll deal with constructors,
// destructors, etc. separately.
if (D->getKind() != Decl::CXXMethod)
return 0;
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 16> Params;
QualType T = InstantiateFunctionType(D, Params);
if (T.isNull())
return 0;
// Build the instantiated method declaration.
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
CXXMethodDecl *Method
= CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
D->getDeclName(), T, D->isStatic(),
D->isInline());
Method->setInstantiationOfMemberFunction(D);
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Method);
Method->setParams(SemaRef.Context, Params.data(), Params.size());
if (InitMethodInstantiation(Method, D))
Method->setInvalidDecl();
NamedDecl *PrevDecl
= SemaRef.LookupQualifiedName(Owner, Method->getDeclName(),
Sema::LookupOrdinaryName, true);
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
// tag type. Note that this does does not apply if we're declaring a
// typedef (C++ [dcl.typedef]p4).
if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
PrevDecl = 0;
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
if (!Method->isInvalidDecl() || !PrevDecl)
Owner->addDecl(SemaRef.Context, Method);
return Method;
}
Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 16> Params;
QualType T = InstantiateFunctionType(D, Params);
if (T.isNull())
return 0;
// Build the instantiated method declaration.
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
DeclarationName Name
= SemaRef.Context.DeclarationNames.getCXXConstructorName(
SemaRef.Context.getCanonicalType(ClassTy));
CXXConstructorDecl *Constructor
= CXXConstructorDecl::Create(SemaRef.Context, Record, D->getLocation(),
Name, T, D->isExplicit(), D->isInline(),
false);
Constructor->setInstantiationOfMemberFunction(D);
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Constructor);
Constructor->setParams(SemaRef.Context, Params.data(), Params.size());
if (InitMethodInstantiation(Constructor, D))
Constructor->setInvalidDecl();
NamedDecl *PrevDecl
= SemaRef.LookupQualifiedName(Owner, Name, Sema::LookupOrdinaryName, true);
// In C++, the previous declaration we find might be a tag type
// (class or enum). In this case, the new declaration will hide the
// tag type. Note that this does does not apply if we're declaring a
// typedef (C++ [dcl.typedef]p4).
if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
PrevDecl = 0;
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
SemaRef.CheckFunctionDeclaration(Constructor, PrevDecl, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
Record->addedConstructor(SemaRef.Context, Constructor);
Owner->addDecl(SemaRef.Context, Constructor);
return Constructor;
}
Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 16> Params;
QualType T = InstantiateFunctionType(D, Params);
if (T.isNull())
return 0;
assert(Params.size() == 0 && "Destructor with parameters?");
// Build the instantiated destructor declaration.
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
QualType ClassTy =
SemaRef.Context.getCanonicalType(SemaRef.Context.getTypeDeclType(Record));
CXXDestructorDecl *Destructor
= CXXDestructorDecl::Create(SemaRef.Context, Record,
D->getLocation(),
SemaRef.Context.DeclarationNames.getCXXDestructorName(ClassTy),
T, D->isInline(), false);
Destructor->setInstantiationOfMemberFunction(D);
if (InitMethodInstantiation(Destructor, D))
Destructor->setInvalidDecl();
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
NamedDecl *PrevDecl = 0;
SemaRef.CheckFunctionDeclaration(Destructor, PrevDecl, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
Owner->addDecl(SemaRef.Context, Destructor);
return Destructor;
}
Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 16> Params;
QualType T = InstantiateFunctionType(D, Params);
if (T.isNull())
return 0;
assert(Params.size() == 0 && "Destructor with parameters?");
// Build the instantiated conversion declaration.
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
QualType ConvTy
= SemaRef.Context.getCanonicalType(T->getAsFunctionType()->getResultType());
CXXConversionDecl *Conversion
= CXXConversionDecl::Create(SemaRef.Context, Record,
D->getLocation(),
SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(ConvTy),
T, D->isInline(), D->isExplicit());
Conversion->setInstantiationOfMemberFunction(D);
if (InitMethodInstantiation(Conversion, D))
Conversion->setInvalidDecl();
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
NamedDecl *PrevDecl = 0;
SemaRef.CheckFunctionDeclaration(Conversion, PrevDecl, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
Owner->addDecl(SemaRef.Context, Conversion);
return Conversion;
}
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
QualType OrigT = SemaRef.InstantiateType(D->getOriginalType(), TemplateArgs,
D->getLocation(), D->getDeclName());
if (OrigT.isNull())
return 0;
QualType T = SemaRef.adjustParameterType(OrigT);
if (D->getDefaultArg()) {
// FIXME: Leave a marker for "uninstantiated" default
// arguments. They only get instantiated on demand at the call
// site.
unsigned DiagID = SemaRef.Diags.getCustomDiagID(Diagnostic::Warning,
"sorry, dropping default argument during template instantiation");
SemaRef.Diag(D->getDefaultArg()->getSourceRange().getBegin(), DiagID)
<< D->getDefaultArg()->getSourceRange();
}
// Allocate the parameter
ParmVarDecl *Param = 0;
if (T == OrigT)
Param = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getIdentifier(), T, D->getStorageClass(),
0);
else
Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner,
D->getLocation(), D->getIdentifier(),
T, OrigT, D->getStorageClass(), 0);
// Note: we don't try to instantiate function parameters until after
// we've instantiated the function's type. Therefore, we don't have
// to check for 'void' parameter types here.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param);
return Param;
}
Decl *
TemplateDeclInstantiator::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) {
// Since parameter types can decay either before or after
// instantiation, we simply treat OriginalParmVarDecls as
// ParmVarDecls the same way, and create one or the other depending
// on what happens after template instantiation.
return VisitParmVarDecl(D);
}
Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner,
const TemplateArgumentList &TemplateArgs) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
return Instantiator.Visit(D);
}
/// \brief Instantiates the type of the given function, including
/// instantiating all of the function parameters.
///
/// \param D The function that we will be instantiated
///
/// \param Params the instantiated parameter declarations
/// \returns the instantiated function's type if successfull, a NULL
/// type if there was an error.
QualType
TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params) {
bool InvalidDecl = false;
// Instantiate the function parameters
TemplateDeclInstantiator ParamInstantiator(SemaRef, 0, TemplateArgs);
llvm::SmallVector<QualType, 16> ParamTys;
for (FunctionDecl::param_iterator P = D->param_begin(),
PEnd = D->param_end();
P != PEnd; ++P) {
if (ParmVarDecl *PInst = ParamInstantiator.VisitParmVarDecl(*P)) {
if (PInst->getType()->isVoidType()) {
SemaRef.Diag(PInst->getLocation(), diag::err_param_with_void_type);
PInst->setInvalidDecl();
}
else if (SemaRef.RequireNonAbstractType(PInst->getLocation(),
PInst->getType(),
diag::err_abstract_type_in_decl,
Sema::AbstractParamType))
PInst->setInvalidDecl();
Params.push_back(PInst);
ParamTys.push_back(PInst->getType());
if (PInst->isInvalidDecl())
InvalidDecl = true;
} else
InvalidDecl = true;
}
// FIXME: Deallocate dead declarations.
if (InvalidDecl)
return QualType();
const FunctionProtoType *Proto = D->getType()->getAsFunctionProtoType();
assert(Proto && "Missing prototype?");
QualType ResultType
= SemaRef.InstantiateType(Proto->getResultType(), TemplateArgs,
D->getLocation(), D->getDeclName());
if (ResultType.isNull())
return QualType();
return SemaRef.BuildFunctionType(ResultType, ParamTys.data(), ParamTys.size(),
Proto->isVariadic(), Proto->getTypeQuals(),
D->getLocation(), D->getDeclName());
}
/// \brief Initializes common fields of an instantiated method
/// declaration (New) from the corresponding fields of its template
/// (Tmpl).
///
/// \returns true if there was an error
bool
TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
CXXMethodDecl *Tmpl) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
New->setAccess(Tmpl->getAccess());
if (Tmpl->isVirtualAsWritten()) {
New->setVirtualAsWritten(true);
Record->setAggregate(false);
Record->setPOD(false);
Record->setPolymorphic(true);
}
if (Tmpl->isDeleted())
New->setDeleted();
if (Tmpl->isPure()) {
New->setPure();
Record->setAbstract(true);
}
// FIXME: attributes
// FIXME: New needs a pointer to Tmpl
return false;
}
/// \brief Instantiate the definition of the given function from its
/// template.
///
/// \param Function the already-instantiated declaration of a
/// function.
void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function) {
// FIXME: make this work for function template specializations, too.
if (Function->isInvalidDecl())
return;
// Find the function body that we'll be substituting.
const FunctionDecl *PatternDecl
= Function->getInstantiatedFromMemberFunction();
Stmt *Pattern = 0;
if (PatternDecl)
Pattern = PatternDecl->getBody(Context, PatternDecl);
if (!Pattern)
return;
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst)
return;
ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function));
// Introduce a new scope where local variable instantiations will be
// recorded.
LocalInstantiationScope Scope(*this);
// Introduce the instantiated function parameters into the local
// instantiation scope.
for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I)
Scope.InstantiatedLocal(PatternDecl->getParamDecl(I),
Function->getParamDecl(I));
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
DeclContext *PreviousContext = CurContext;
CurContext = Function;
// Instantiate the function body.
OwningStmtResult Body
= InstantiateStmt(Pattern, getTemplateInstantiationArgs(Function));
ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body),
/*IsInstantiation=*/true);
CurContext = PreviousContext;
DeclGroupRef DG(Function);
Consumer.HandleTopLevelDecl(DG);
}
/// \brief Instantiate the definition of the given variable from its
/// template.
///
/// \param Var the already-instantiated declaration of a variable.
void Sema::InstantiateVariableDefinition(VarDecl *Var) {
// FIXME: Implement this!
}
static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
if (D->getKind() != Other->getKind())
return false;
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Other))
return Ctx.getCanonicalDecl(Record->getInstantiatedFromMemberClass())
== Ctx.getCanonicalDecl(D);
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Other))
return Ctx.getCanonicalDecl(Function->getInstantiatedFromMemberFunction())
== Ctx.getCanonicalDecl(D);
if (EnumDecl *Enum = dyn_cast<EnumDecl>(Other))
return Ctx.getCanonicalDecl(Enum->getInstantiatedFromMemberEnum())
== Ctx.getCanonicalDecl(D);
// FIXME: How can we find instantiations of anonymous unions?
return D->getDeclName() && isa<NamedDecl>(Other) &&
D->getDeclName() == cast<NamedDecl>(Other)->getDeclName();
}
template<typename ForwardIterator>
static NamedDecl *findInstantiationOf(ASTContext &Ctx,
NamedDecl *D,
ForwardIterator first,
ForwardIterator last) {
for (; first != last; ++first)
if (isInstantiationOf(Ctx, D, *first))
return cast<NamedDecl>(*first);
return 0;
}
/// \brief Find the instantiation of the given declaration within the
/// current instantiation.
///
/// This routine is intended to be used when \p D is a declaration
/// referenced from within a template, that needs to mapped into the
/// corresponding declaration within an instantiation. For example,
/// given:
///
/// \code
/// template<typename T>
/// struct X {
/// enum Kind {
/// KnownValue = sizeof(T)
/// };
///
/// bool getKind() const { return KnownValue; }
/// };
///
/// template struct X<int>;
/// \endcode
///
/// In the instantiation of X<int>::getKind(), we need to map the
/// EnumConstantDecl for KnownValue (which refers to
/// X<T>::<Kind>::KnownValue) to its instantiation
/// (X<int>::<Kind>::KnownValue). InstantiateCurrentDeclRef() performs
/// this mapping from within the instantiation of X<int>.
NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) {
DeclContext *ParentDC = D->getDeclContext();
if (isa<ParmVarDecl>(D) || ParentDC->isFunctionOrMethod()) {
// D is a local of some kind. Look into the map of local
// declarations to their instantiations.
return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D));
}
if (NamedDecl *ParentDecl = dyn_cast<NamedDecl>(ParentDC)) {
ParentDecl = InstantiateCurrentDeclRef(ParentDecl);
if (!ParentDecl)
return 0;
ParentDC = cast<DeclContext>(ParentDecl);
}
if (ParentDC != D->getDeclContext()) {
// We performed some kind of instantiation in the parent context,
// so now we need to look into the instantiated parent context to
// find the instantiation of the declaration D.
NamedDecl *Result = 0;
if (D->getDeclName()) {
DeclContext::lookup_result Found
= ParentDC->lookup(Context, D->getDeclName());
Result = findInstantiationOf(Context, D, Found.first, Found.second);
} else {
// Since we don't have a name for the entity we're looking for,
// our only option is to walk through all of the declarations to
// find that name. This will occur in a few cases:
//
// - anonymous struct/union within a template
// - unnamed class/struct/union/enum within a template
//
// FIXME: Find a better way to find these instantiations!
Result = findInstantiationOf(Context, D,
ParentDC->decls_begin(Context),
ParentDC->decls_end(Context));
}
assert(Result && "Unable to find instantiation of declaration!");
D = Result;
}
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D))
if (ClassTemplateDecl *ClassTemplate
= Record->getDescribedClassTemplate()) {
// When the declaration D was parsed, it referred to the current
// instantiation. Therefore, look through the current context,
// which contains actual instantiations, to find the
// instantiation of the "current instantiation" that D refers
// to. Alternatively, we could just instantiate the
// injected-class-name with the current template arguments, but
// such an instantiation is far more expensive.
for (DeclContext *DC = CurContext; !DC->isFileContext();
DC = DC->getParent()) {
if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(DC))
if (Context.getCanonicalDecl(Spec->getSpecializedTemplate())
== Context.getCanonicalDecl(ClassTemplate))
return Spec;
}
assert(false &&
"Unable to find declaration for the current instantiation");
}
return D;
}