summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaTemplateInstantiateDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaTemplateInstantiateDecl.cpp')
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp1342
1 files changed, 1033 insertions, 309 deletions
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f59719992066..33fa28866e52 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -15,24 +15,26 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/Compiler.h"
using namespace clang;
namespace {
- class VISIBILITY_HIDDEN TemplateDeclInstantiator
+ class VISIBILITY_HIDDEN TemplateDeclInstantiator
: public DeclVisitor<TemplateDeclInstantiator, Decl *> {
Sema &SemaRef;
DeclContext *Owner;
- const TemplateArgumentList &TemplateArgs;
-
+ const MultiLevelTemplateArgumentList &TemplateArgs;
+
public:
typedef Sema::OwningExprResult OwningExprResult;
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
- const TemplateArgumentList &TemplateArgs)
+ const MultiLevelTemplateArgumentList &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.
@@ -44,26 +46,42 @@ namespace {
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
- Decl *VisitFunctionDecl(FunctionDecl *D);
+ Decl *VisitFriendDecl(FriendDecl *D);
+ Decl *VisitFunctionDecl(FunctionDecl *D,
+ TemplateParameterList *TemplateParams = 0);
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
- Decl *VisitCXXMethodDecl(CXXMethodDecl *D);
+ Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
+ TemplateParameterList *TemplateParams = 0);
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
+ Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
+ Decl *VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D);
+ Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
+ Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
+ Decl *VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D);
// Base case. FIXME: Remove once we can instantiate everything.
- Decl *VisitDecl(Decl *) {
+ Decl *VisitDecl(Decl *) {
assert(false && "Template instantiation of unknown declaration kind!");
return 0;
}
+ const LangOptions &getLangOptions() {
+ return SemaRef.getLangOptions();
+ }
+
// Helper functions for instantiating methods.
- QualType InstantiateFunctionType(FunctionDecl *D,
+ QualType SubstFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params);
bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
+
+ TemplateParameterList *
+ SubstTemplateParams(TemplateParameterList *List);
};
}
@@ -83,14 +101,14 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
bool Invalid = false;
QualType T = D->getUnderlyingType();
if (T->isDependentType()) {
- T = SemaRef.InstantiateType(T, TemplateArgs,
- D->getLocation(), D->getDeclName());
+ T = SemaRef.SubstType(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(),
@@ -99,44 +117,86 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
Typedef->setInvalidDecl();
Owner->addDecl(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());
+ // Do substitution on the type of the declaration
+ QualType T = SemaRef.SubstType(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());
+ T, D->getDeclaratorInfo(),
+ D->getStorageClass());
Var->setThreadSpecified(D->isThreadSpecified());
Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
Var->setDeclaredInCondition(D->isDeclaredInCondition());
-
+
+ // If we are instantiating a static data member defined
+ // out-of-line, the instantiation will have the same lexical
+ // context (which will be a namespace scope) as the template.
+ if (D->isOutOfLine())
+ Var->setLexicalDeclContext(D->getLexicalDeclContext());
+
// 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(Var);
+ if (D->isOutOfLine()) {
+ D->getLexicalDeclContext()->addDecl(Var);
+ Owner->makeDeclVisibleInContext(Var);
+ } else {
+ Owner->addDecl(Var);
+ }
+
+ // Link instantiations of static data members back to the template from
+ // which they were instantiated.
+ if (Var->isStaticDataMember())
+ SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D,
+ TSK_ImplicitInstantiation);
+
if (D->getInit()) {
- OwningExprResult Init
- = SemaRef.InstantiateExpr(D->getInit(), TemplateArgs);
+ OwningExprResult Init
+ = SemaRef.SubstExpr(D->getInit(), TemplateArgs);
if (Init.isInvalid())
Var->setInvalidDecl();
- else
+ else if (ParenListExpr *PLE = dyn_cast<ParenListExpr>((Expr *)Init.get())) {
+ // FIXME: We're faking all of the comma locations, which is suboptimal.
+ // Do we even need these comma locations?
+ llvm::SmallVector<SourceLocation, 4> FakeCommaLocs;
+ if (PLE->getNumExprs() > 0) {
+ FakeCommaLocs.reserve(PLE->getNumExprs() - 1);
+ for (unsigned I = 0, N = PLE->getNumExprs() - 1; I != N; ++I) {
+ Expr *E = PLE->getExpr(I)->Retain();
+ FakeCommaLocs.push_back(
+ SemaRef.PP.getLocForEndOfToken(E->getLocEnd()));
+ }
+ PLE->getExpr(PLE->getNumExprs() - 1)->Retain();
+ }
+
+ // Add the direct initializer to the declaration.
+ SemaRef.AddCXXDirectInitializerToDecl(Sema::DeclPtrTy::make(Var),
+ PLE->getLParenLoc(),
+ Sema::MultiExprArg(SemaRef,
+ (void**)PLE->getExprs(),
+ PLE->getNumExprs()),
+ FakeCommaLocs.data(),
+ PLE->getRParenLoc());
+
+ // When Init is destroyed, it will destroy the instantiated ParenListExpr;
+ // we've explicitly retained all of its subexpressions already.
+ } else
SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init),
D->hasCXXDirectInitializer());
- } else {
- // FIXME: Call ActOnUninitializedDecl? (Not always)
- }
+ } else if (!Var->isStaticDataMember() || Var->isOutOfLine())
+ SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
return Var;
}
@@ -145,8 +205,8 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
bool Invalid = false;
QualType T = D->getType();
if (T->isDependentType()) {
- T = SemaRef.InstantiateType(T, TemplateArgs,
- D->getLocation(), D->getDeclName());
+ T = SemaRef.SubstType(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
@@ -167,9 +227,9 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
else if (BitWidth) {
// The bit-width expression is not potentially evaluated.
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
-
+
OwningExprResult InstantiatedBitWidth
- = SemaRef.InstantiateExpr(BitWidth, TemplateArgs);
+ = SemaRef.SubstExpr(BitWidth, TemplateArgs);
if (InstantiatedBitWidth.isInvalid()) {
Invalid = true;
BitWidth = 0;
@@ -178,44 +238,90 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
}
FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(), T,
- cast<RecordDecl>(Owner),
+ D->getDeclaratorInfo(),
+ cast<RecordDecl>(Owner),
D->getLocation(),
D->isMutable(),
BitWidth,
+ D->getTypeSpecStartLoc(),
D->getAccess(),
0);
- if (Field) {
- if (Invalid)
- Field->setInvalidDecl();
-
- Owner->addDecl(Field);
+ if (!Field)
+ return 0;
+
+ if (Invalid)
+ Field->setInvalidDecl();
+
+ if (!Field->getDeclName()) {
+ // Keep track of where this decl came from.
+ SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D);
}
+ Field->setImplicit(D->isImplicit());
+ Owner->addDecl(Field);
+
return Field;
}
+Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
+ FriendDecl::FriendUnion FU;
+
+ // Handle friend type expressions by simply substituting template
+ // parameters into the pattern type.
+ if (Type *Ty = D->getFriendType()) {
+ QualType T = SemaRef.SubstType(QualType(Ty,0), TemplateArgs,
+ D->getLocation(), DeclarationName());
+ if (T.isNull()) return 0;
+
+ assert(getLangOptions().CPlusPlus0x || T->isRecordType());
+ FU = T.getTypePtr();
+
+ // Handle everything else by appropriate substitution.
+ } else {
+ NamedDecl *ND = D->getFriendDecl();
+ assert(ND && "friend decl must be a decl or a type!");
+
+ // FIXME: We have a problem here, because the nested call to Visit(ND)
+ // will inject the thing that the friend references into the current
+ // owner, which is wrong.
+ Decl *NewND = Visit(ND);
+ if (!NewND) return 0;
+
+ FU = cast<NamedDecl>(NewND);
+ }
+
+ FriendDecl *FD =
+ FriendDecl::Create(SemaRef.Context, Owner, D->getLocation(), FU,
+ D->getFriendLoc());
+ FD->setAccess(AS_public);
+ Owner->addDecl(FD);
+ return FD;
+}
+
Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
Expr *AssertExpr = D->getAssertExpr();
-
+
// The expression in a static assertion is not potentially evaluated.
EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
-
+
OwningExprResult InstantiatedAssertExpr
- = SemaRef.InstantiateExpr(AssertExpr, TemplateArgs);
+ = SemaRef.SubstExpr(AssertExpr, TemplateArgs);
if (InstantiatedAssertExpr.isInvalid())
return 0;
- OwningExprResult Message = SemaRef.Clone(D->getMessage());
- Decl *StaticAssert
- = SemaRef.ActOnStaticAssertDeclaration(D->getLocation(),
+ OwningExprResult Message(SemaRef, D->getMessage());
+ D->getMessage()->Retain();
+ 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,
+ EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner,
D->getLocation(), D->getIdentifier(),
+ D->getTagKeywordLoc(),
/*PrevDecl=*/0);
Enum->setInstantiationOfMemberEnum(D);
Enum->setAccess(D->getAccess());
@@ -232,10 +338,10 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
OwningExprResult Value = SemaRef.Owned((Expr *)0);
if (Expr *UninstValue = EC->getInitExpr()) {
// The enumerator's value expression is not potentially evaluated.
- EnterExpressionEvaluationContext Unevaluated(SemaRef,
+ EnterExpressionEvaluationContext Unevaluated(SemaRef,
Action::Unevaluated);
-
- Value = SemaRef.InstantiateExpr(UninstValue, TemplateArgs);
+
+ Value = SemaRef.SubstExpr(UninstValue, TemplateArgs);
}
// Drop the initial value and continue.
@@ -245,7 +351,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
isInvalid = true;
}
- EnumConstantDecl *EnumConst
+ EnumConstantDecl *EnumConst
= SemaRef.CheckEnumConstant(Enum, LastEnumConst,
EC->getLocation(), EC->getIdentifier(),
move(Value));
@@ -262,11 +368,13 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
LastEnumConst = EnumConst;
}
}
-
+
// FIXME: Fixup LBraceLoc and RBraceLoc
+ // FIXME: Empty Scope and AttributeList (required to handle attribute packed).
SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), SourceLocation(),
Sema::DeclPtrTy::make(Enum),
- &Enumerators[0], Enumerators.size());
+ &Enumerators[0], Enumerators.size(),
+ 0, 0);
return Enum;
}
@@ -276,100 +384,337 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
return 0;
}
+Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ TemplateParameterList *TempParams = D->getTemplateParameters();
+ TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return NULL;
+
+ CXXRecordDecl *Pattern = D->getTemplatedDecl();
+ CXXRecordDecl *RecordInst
+ = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), Owner,
+ Pattern->getLocation(), Pattern->getIdentifier(),
+ Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL,
+ /*DelayTypeCreation=*/true);
+
+ ClassTemplateDecl *Inst
+ = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getIdentifier(), InstParams, RecordInst, 0);
+ RecordInst->setDescribedClassTemplate(Inst);
+ Inst->setAccess(D->getAccess());
+ Inst->setInstantiatedFromMemberTemplate(D);
+
+ // Trigger creation of the type for the instantiation.
+ SemaRef.Context.getTypeDeclType(RecordInst);
+
+ Owner->addDecl(Inst);
+ return Inst;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
+ ClassTemplatePartialSpecializationDecl *D) {
+ assert(false &&"Partial specializations of member templates are unsupported");
+ return 0;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ // FIXME: Dig out the out-of-line definition of this function template?
+
+ TemplateParameterList *TempParams = D->getTemplateParameters();
+ TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return NULL;
+
+ FunctionDecl *Instantiated = 0;
+ if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl()))
+ Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod,
+ InstParams));
+ else
+ Instantiated = cast_or_null<FunctionDecl>(VisitFunctionDecl(
+ D->getTemplatedDecl(),
+ InstParams));
+
+ if (!Instantiated)
+ return 0;
+
+ // Link the instantiated function template declaration to the function
+ // template from which it was instantiated.
+ FunctionTemplateDecl *InstTemplate
+ = Instantiated->getDescribedFunctionTemplate();
+ InstTemplate->setAccess(D->getAccess());
+ assert(InstTemplate &&
+ "VisitFunctionDecl/CXXMethodDecl didn't create a template!");
+ if (!InstTemplate->getInstantiatedFromMemberTemplate())
+ InstTemplate->setInstantiatedFromMemberTemplate(D);
+
+ // Add non-friends into the owner.
+ if (!InstTemplate->getFriendObjectKind())
+ Owner->addDecl(InstTemplate);
+ return InstTemplate;
+}
+
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);
+ = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
+ D->getLocation(), D->getIdentifier(),
+ D->getTagKeywordLoc(), PrevDecl);
Record->setImplicit(D->isImplicit());
- Record->setAccess(D->getAccess());
+ // FIXME: Check against AS_none is an ugly hack to work around the issue that
+ // the tag decls introduced by friend class declarations don't have an access
+ // specifier. Remove once this area of the code gets sorted out.
+ if (D->getAccess() != AS_none)
+ Record->setAccess(D->getAccess());
if (!D->isInjectedClassName())
- Record->setInstantiationOfMemberClass(D);
+ Record->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation);
+
+ // If the original function was part of a friend declaration,
+ // inherit its namespace state.
+ if (Decl::FriendObjectKind FOK = D->getFriendObjectKind())
+ Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared);
+
+ Record->setAnonymousStructOrUnion(D->isAnonymousStructOrUnion());
Owner->addDecl(Record);
return Record;
}
-Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
+/// Normal class members are of more specific types and therefore
+/// don't make it here. This function serves two purposes:
+/// 1) instantiating function templates
+/// 2) substituting friend declarations
+/// FIXME: preserve function definitions in case #2
+ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
+ TemplateParameterList *TemplateParams) {
// Check whether there is already a function template specialization for
// this declaration.
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
void *InsertPos = 0;
- if (FunctionTemplate) {
+ if (FunctionTemplate && !TemplateParams) {
llvm::FoldingSetNodeID ID;
- FunctionTemplateSpecializationInfo::Profile(ID,
- TemplateArgs.getFlatArgumentList(),
- TemplateArgs.flat_size());
-
- FunctionTemplateSpecializationInfo *Info
- = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID,
+ FunctionTemplateSpecializationInfo::Profile(ID,
+ TemplateArgs.getInnermost().getFlatArgumentList(),
+ TemplateArgs.getInnermost().flat_size(),
+ SemaRef.Context);
+
+ FunctionTemplateSpecializationInfo *Info
+ = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID,
InsertPos);
-
+
// If we already have a function template specialization, return it.
if (Info)
return Info->Function;
}
-
+
Sema::LocalInstantiationScope Scope(SemaRef);
-
+
llvm::SmallVector<ParmVarDecl *, 4> Params;
- QualType T = InstantiateFunctionType(D, Params);
+ QualType T = SubstFunctionType(D, Params);
if (T.isNull())
return 0;
-
+
// Build the instantiated method declaration.
- FunctionDecl *Function
- = FunctionDecl::Create(SemaRef.Context, Owner, D->getLocation(),
- D->getDeclName(), T, D->getStorageClass(),
- D->isInline(), D->hasWrittenPrototype(),
- D->getTypeSpecStartLoc());
-
- // FIXME: friend functions
-
+ DeclContext *DC = SemaRef.FindInstantiatedContext(D->getDeclContext(),
+ TemplateArgs);
+ FunctionDecl *Function =
+ FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
+ D->getDeclName(), T, D->getDeclaratorInfo(),
+ D->getStorageClass(),
+ D->isInline(), D->hasWrittenPrototype());
+ Function->setLexicalDeclContext(Owner);
+
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Function);
Function->setParams(SemaRef.Context, Params.data(), Params.size());
-
+
+ if (TemplateParams) {
+ // Our resulting instantiation is actually a function template, since we
+ // are substituting only the outer template parameters. For example, given
+ //
+ // template<typename T>
+ // struct X {
+ // template<typename U> friend void f(T, U);
+ // };
+ //
+ // X<int> x;
+ //
+ // We are instantiating the friend function template "f" within X<int>,
+ // which means substituting int for T, but leaving "f" as a friend function
+ // template.
+ // Build the function template itself.
+ FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Owner,
+ Function->getLocation(),
+ Function->getDeclName(),
+ TemplateParams, Function);
+ Function->setDescribedFunctionTemplate(FunctionTemplate);
+ FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
+ }
+
if (InitFunctionInstantiation(Function, D))
Function->setInvalidDecl();
-
+
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
+
NamedDecl *PrevDecl = 0;
- SemaRef.CheckFunctionDeclaration(Function, PrevDecl, Redeclaration,
+ if (TemplateParams || !FunctionTemplate) {
+ // Look only into the namespace where the friend would be declared to
+ // find a previous declaration. This is the innermost enclosing namespace,
+ // as described in ActOnFriendFunctionDecl.
+ Sema::LookupResult R;
+ SemaRef.LookupQualifiedName(R, DC, Function->getDeclName(),
+ Sema::LookupOrdinaryName, true);
+
+ PrevDecl = R.getAsSingleDecl(SemaRef.Context);
+
+ // 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;
+ }
+
+ SemaRef.CheckFunctionDeclaration(Function, PrevDecl, false, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
- if (FunctionTemplate) {
+ // If the original function was part of a friend declaration,
+ // inherit its namespace state and add it to the owner.
+ NamedDecl *FromFriendD
+ = TemplateParams? cast<NamedDecl>(D->getDescribedFunctionTemplate()) : D;
+ if (FromFriendD->getFriendObjectKind()) {
+ NamedDecl *ToFriendD = 0;
+ if (TemplateParams) {
+ ToFriendD = cast<NamedDecl>(FunctionTemplate);
+ PrevDecl = FunctionTemplate->getPreviousDeclaration();
+ } else {
+ ToFriendD = Function;
+ PrevDecl = Function->getPreviousDeclaration();
+ }
+ ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL);
+ if (!Owner->isDependentContext() && !PrevDecl)
+ DC->makeDeclVisibleInContext(ToFriendD, /* Recoverable = */ false);
+
+ if (!TemplateParams)
+ Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
+ }
+
+ if (FunctionTemplate && !TemplateParams) {
// Record this function template specialization.
Function->setFunctionTemplateSpecialization(SemaRef.Context,
FunctionTemplate,
- &TemplateArgs,
+ &TemplateArgs.getInnermost(),
InsertPos);
- }
+ }
return Function;
}
-Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
- // FIXME: Look for existing, explicit specializations.
+Decl *
+TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
+ TemplateParameterList *TemplateParams) {
+ FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
+ void *InsertPos = 0;
+ if (FunctionTemplate && !TemplateParams) {
+ // We are creating a function template specialization from a function
+ // template. Check whether there is already a function template
+ // specialization for this particular set of template arguments.
+ llvm::FoldingSetNodeID ID;
+ FunctionTemplateSpecializationInfo::Profile(ID,
+ TemplateArgs.getInnermost().getFlatArgumentList(),
+ TemplateArgs.getInnermost().flat_size(),
+ SemaRef.Context);
+
+ FunctionTemplateSpecializationInfo *Info
+ = FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID,
+ InsertPos);
+
+ // If we already have a function template specialization, return it.
+ if (Info)
+ return Info->Function;
+ }
+
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 4> Params;
- QualType T = InstantiateFunctionType(D, Params);
+ QualType T = SubstFunctionType(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);
+ CXXMethodDecl *Method = 0;
+
+ DeclarationName Name = D->getDeclName();
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
+ Name = SemaRef.Context.DeclarationNames.getCXXConstructorName(
+ SemaRef.Context.getCanonicalType(ClassTy));
+ Method = CXXConstructorDecl::Create(SemaRef.Context, Record,
+ Constructor->getLocation(),
+ Name, T,
+ Constructor->getDeclaratorInfo(),
+ Constructor->isExplicit(),
+ Constructor->isInline(), false);
+ } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
+ QualType ClassTy = SemaRef.Context.getTypeDeclType(Record);
+ Name = SemaRef.Context.DeclarationNames.getCXXDestructorName(
+ SemaRef.Context.getCanonicalType(ClassTy));
+ Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
+ Destructor->getLocation(), Name,
+ T, Destructor->isInline(), false);
+ } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
+ CanQualType ConvTy
+ = SemaRef.Context.getCanonicalType(
+ T->getAs<FunctionType>()->getResultType());
+ Name = SemaRef.Context.DeclarationNames.getCXXConversionFunctionName(
+ ConvTy);
+ Method = CXXConversionDecl::Create(SemaRef.Context, Record,
+ Conversion->getLocation(), Name,
+ T, Conversion->getDeclaratorInfo(),
+ Conversion->isInline(),
+ Conversion->isExplicit());
+ } else {
+ Method = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(),
+ D->getDeclName(), T, D->getDeclaratorInfo(),
+ D->isStatic(), D->isInline());
+ }
+
+ if (TemplateParams) {
+ // Our resulting instantiation is actually a function template, since we
+ // are substituting only the outer template parameters. For example, given
+ //
+ // template<typename T>
+ // struct X {
+ // template<typename U> void f(T, U);
+ // };
+ //
+ // X<int> x;
+ //
+ // We are instantiating the member template "f" within X<int>, which means
+ // substituting int for T, but leaving "f" as a member function template.
+ // Build the function template itself.
+ FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Record,
+ Method->getLocation(),
+ Method->getDeclName(),
+ TemplateParams, Method);
+ if (D->isOutOfLine())
+ FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
+ Method->setDescribedFunctionTemplate(FunctionTemplate);
+ } else if (!FunctionTemplate)
+ Method->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
+
+ // If we are instantiating a member function defined
+ // out-of-line, the instantiation will have the same lexical
+ // context (which will be a namespace scope) as the template.
+ if (D->isOutOfLine())
+ Method->setLexicalDeclContext(D->getLexicalDeclContext());
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
@@ -379,167 +724,78 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
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;
+ NamedDecl *PrevDecl = 0;
+
+ if (!FunctionTemplate || TemplateParams) {
+ Sema::LookupResult R;
+ SemaRef.LookupQualifiedName(R, Owner, Name, Sema::LookupOrdinaryName, true);
+ PrevDecl = R.getAsSingleDecl(SemaRef.Context);
+
+ // 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;
+ }
+
+ if (FunctionTemplate && !TemplateParams)
+ // Record this function template specialization.
+ Method->setFunctionTemplateSpecialization(SemaRef.Context,
+ FunctionTemplate,
+ &TemplateArgs.getInnermost(),
+ InsertPos);
+
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
- SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
+ SemaRef.CheckFunctionDeclaration(Method, PrevDecl, false, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
- if (!Method->isInvalidDecl() || !PrevDecl)
+ if (!FunctionTemplate && (!Method->isInvalidDecl() || !PrevDecl) &&
+ !Method->getFriendObjectKind())
Owner->addDecl(Method);
+
return Method;
}
Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
- // FIXME: Look for existing, explicit specializations.
- Sema::LocalInstantiationScope Scope(SemaRef);
-
- llvm::SmallVector<ParmVarDecl *, 4> 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(Constructor);
- return Constructor;
+ return VisitCXXMethodDecl(D);
}
Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
- // FIXME: Look for existing, explicit specializations.
- Sema::LocalInstantiationScope Scope(SemaRef);
-
- llvm::SmallVector<ParmVarDecl *, 4> 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(Destructor);
- return Destructor;
+ return VisitCXXMethodDecl(D);
}
Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
- // FIXME: Look for existing, explicit specializations.
- Sema::LocalInstantiationScope Scope(SemaRef);
-
- llvm::SmallVector<ParmVarDecl *, 4> 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(Conversion);
- return Conversion;
+ return VisitCXXMethodDecl(D);
}
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
- QualType OrigT = SemaRef.InstantiateType(D->getOriginalType(), TemplateArgs,
+ QualType OrigT = SemaRef.SubstType(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);
+ D->getIdentifier(), T, D->getDeclaratorInfo(),
+ D->getStorageClass(), 0);
else
- Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner,
+ Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner,
D->getLocation(), D->getIdentifier(),
- T, OrigT, D->getStorageClass(), 0);
-
+ T, D->getDeclaratorInfo(), OrigT,
+ D->getStorageClass(), 0);
+
+ // Mark the default argument as being uninstantiated.
+ if (D->hasUninstantiatedDefaultArg())
+ Param->setUninstantiatedDefaultArg(D->getUninstantiatedDefaultArg());
+ else if (Expr *Arg = D->getDefaultArg())
+ Param->setUninstantiatedDefaultArg(Arg);
+
// 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.
@@ -556,41 +812,130 @@ TemplateDeclInstantiator::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) {
return VisitParmVarDecl(D);
}
-Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner,
- const TemplateArgumentList &TemplateArgs) {
+Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
+ TemplateTypeParmDecl *D) {
+ // TODO: don't always clone when decls are refcounted.
+ const Type* T = D->getTypeForDecl();
+ assert(T->isTemplateTypeParmType());
+ const TemplateTypeParmType *TTPT = T->getAs<TemplateTypeParmType>();
+
+ TemplateTypeParmDecl *Inst =
+ TemplateTypeParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ TTPT->getDepth(), TTPT->getIndex(),
+ TTPT->getName(),
+ D->wasDeclaredWithTypename(),
+ D->isParameterPack());
+
+ if (D->hasDefaultArgument()) {
+ QualType DefaultPattern = D->getDefaultArgument();
+ QualType DefaultInst
+ = SemaRef.SubstType(DefaultPattern, TemplateArgs,
+ D->getDefaultArgumentLoc(),
+ D->getDeclName());
+
+ Inst->setDefaultArgument(DefaultInst,
+ D->getDefaultArgumentLoc(),
+ D->defaultArgumentWasInherited() /* preserve? */);
+ }
+
+ return Inst;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) {
+ NestedNameSpecifier *NNS =
+ SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(),
+ D->getTargetNestedNameRange(),
+ TemplateArgs);
+ if (!NNS)
+ return 0;
+
+ CXXScopeSpec SS;
+ SS.setRange(D->getTargetNestedNameRange());
+ SS.setScopeRep(NNS);
+
+ NamedDecl *UD =
+ SemaRef.BuildUsingDeclaration(D->getLocation(), SS,
+ D->getTargetNameLocation(),
+ D->getTargetName(), 0, D->isTypeName());
+ if (UD)
+ SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast<UsingDecl>(UD),
+ D);
+ return UD;
+}
+
+Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
+ const MultiLevelTemplateArgumentList &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.
+/// \brief Instantiates a nested template parameter list in the current
+/// instantiation context.
///
-/// \param D The function that we will be instantiated
+/// \param L The parameter list to instantiate
+///
+/// \returns NULL if there was an error
+TemplateParameterList *
+TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
+ // Get errors for all the parameters before bailing out.
+ bool Invalid = false;
+
+ unsigned N = L->size();
+ typedef llvm::SmallVector<NamedDecl *, 8> ParamVector;
+ ParamVector Params;
+ Params.reserve(N);
+ for (TemplateParameterList::iterator PI = L->begin(), PE = L->end();
+ PI != PE; ++PI) {
+ NamedDecl *D = cast_or_null<NamedDecl>(Visit(*PI));
+ Params.push_back(D);
+ Invalid = Invalid || !D;
+ }
+
+ // Clean up if we had an error.
+ if (Invalid) {
+ for (ParamVector::iterator PI = Params.begin(), PE = Params.end();
+ PI != PE; ++PI)
+ if (*PI)
+ (*PI)->Destroy(SemaRef.Context);
+ return NULL;
+ }
+
+ TemplateParameterList *InstL
+ = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(),
+ L->getLAngleLoc(), &Params.front(), N,
+ L->getRAngleLoc());
+ return InstL;
+}
+
+/// \brief Does substitution on the type of the given function, including
+/// all of the function parameters.
+///
+/// \param D The function whose type will be the basis of the substitution
///
/// \param Params the instantiated parameter declarations
-/// \returns the instantiated function's type if successfull, a NULL
+/// \returns the instantiated function's type if successful, a NULL
/// type if there was an error.
-QualType
-TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
+QualType
+TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params) {
bool InvalidDecl = false;
- // Instantiate the function parameters
+ // Substitute all of the function's formal parameter types.
TemplateDeclInstantiator ParamInstantiator(SemaRef, 0, TemplateArgs);
llvm::SmallVector<QualType, 4> ParamTys;
- for (FunctionDecl::param_iterator P = D->param_begin(),
+ 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))
+ } else if (SemaRef.RequireNonAbstractType(PInst->getLocation(),
+ PInst->getType(),
+ diag::err_abstract_type_in_decl,
+ Sema::AbstractParamType))
PInst->setInvalidDecl();
Params.push_back(PInst);
@@ -598,7 +943,7 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
if (PInst->isInvalidDecl())
InvalidDecl = true;
- } else
+ } else
InvalidDecl = true;
}
@@ -606,11 +951,11 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
if (InvalidDecl)
return QualType();
- const FunctionProtoType *Proto = D->getType()->getAsFunctionProtoType();
+ const FunctionProtoType *Proto = D->getType()->getAs<FunctionProtoType>();
assert(Proto && "Missing prototype?");
- QualType ResultType
- = SemaRef.InstantiateType(Proto->getResultType(), TemplateArgs,
- D->getLocation(), D->getDeclName());
+ QualType ResultType
+ = SemaRef.SubstType(Proto->getResultType(), TemplateArgs,
+ D->getLocation(), D->getDeclName());
if (ResultType.isNull())
return QualType();
@@ -619,21 +964,21 @@ TemplateDeclInstantiator::InstantiateFunctionType(FunctionDecl *D,
D->getLocation(), D->getDeclName());
}
-/// \brief Initializes the common fields of an instantiation function
+/// \brief Initializes the common fields of an instantiation function
/// declaration (New) from the corresponding fields of its template (Tmpl).
///
/// \returns true if there was an error
-bool
-TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
+bool
+TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
FunctionDecl *Tmpl) {
if (Tmpl->isDeleted())
New->setDeleted();
-
+
// If we are performing substituting explicitly-specified template arguments
// or deduced template arguments into a function template and we reach this
// point, we are now past the point where SFINAE applies and have committed
- // to keeping the new function template specialization. We therefore
- // convert the active template instantiation for the function template
+ // to keeping the new function template specialization. We therefore
+ // convert the active template instantiation for the function template
// into a template instantiation for this specific function template
// specialization, which is not a SFINAE context, so that we diagnose any
// further errors in the declaration itself.
@@ -641,15 +986,16 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
ActiveInstType &ActiveInst = SemaRef.ActiveTemplateInstantiations.back();
if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution ||
ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) {
- if (FunctionTemplateDecl *FunTmpl
+ if (FunctionTemplateDecl *FunTmpl
= dyn_cast<FunctionTemplateDecl>((Decl *)ActiveInst.Entity)) {
- assert(FunTmpl->getTemplatedDecl() == Tmpl &&
+ assert(FunTmpl->getTemplatedDecl() == Tmpl &&
"Deduction from the wrong function template?");
+ (void) FunTmpl;
ActiveInst.Kind = ActiveInstType::TemplateInstantiation;
ActiveInst.Entity = reinterpret_cast<uintptr_t>(New);
}
}
-
+
return false;
}
@@ -658,18 +1004,19 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
/// (Tmpl).
///
/// \returns true if there was an error
-bool
-TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
+bool
+TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
CXXMethodDecl *Tmpl) {
if (InitFunctionInstantiation(New, Tmpl))
return true;
-
+
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
New->setAccess(Tmpl->getAccess());
if (Tmpl->isVirtualAsWritten()) {
New->setVirtualAsWritten(true);
Record->setAggregate(false);
Record->setPOD(false);
+ Record->setEmpty(false);
Record->setPolymorphic(true);
}
if (Tmpl->isPure()) {
@@ -702,12 +1049,25 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
return;
assert(!Function->getBody() && "Already instantiated!");
+
+ // Never instantiate an explicit specialization.
+ if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return;
// Find the function body that we'll be substituting.
const FunctionDecl *PatternDecl = 0;
- if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate())
+ if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate()) {
+ while (Primary->getInstantiatedFromMemberTemplate()) {
+ // If we have hit a point where the user provided a specialization of
+ // this template, we're done looking.
+ if (Primary->isMemberSpecialization())
+ break;
+
+ Primary = Primary->getInstantiatedFromMemberTemplate();
+ }
+
PatternDecl = Primary->getTemplatedDecl();
- else
+ } else
PatternDecl = Function->getInstantiatedFromMemberFunction();
Stmt *Pattern = 0;
if (PatternDecl)
@@ -716,6 +1076,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
if (!Pattern)
return;
+ // C++0x [temp.explicit]p9:
+ // Except for inline functions, other explicit instantiation declarations
+ // have the effect of suppressing the implicit instantiation of the entity
+ // to which they refer.
+ if (Function->getTemplateSpecializationKind()
+ == TSK_ExplicitInstantiationDeclaration &&
+ PatternDecl->isOutOfLine() && !PatternDecl->isInline())
+ return;
+
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst)
return;
@@ -726,13 +1095,13 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
std::deque<PendingImplicitInstantiation> SavedPendingImplicitInstantiations;
if (Recursive)
PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
-
+
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)
@@ -744,23 +1113,35 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
DeclContext *PreviousContext = CurContext;
CurContext = Function;
+ MultiLevelTemplateArgumentList TemplateArgs =
+ getTemplateInstantiationArgs(Function);
+
+ // If this is a constructor, instantiate the member initializers.
+ if (const CXXConstructorDecl *Ctor =
+ dyn_cast<CXXConstructorDecl>(PatternDecl)) {
+ InstantiateMemInitializers(cast<CXXConstructorDecl>(Function), Ctor,
+ TemplateArgs);
+ }
+
// Instantiate the function body.
- OwningStmtResult Body
- = InstantiateStmt(Pattern, getTemplateInstantiationArgs(Function));
+ OwningStmtResult Body = SubstStmt(Pattern, TemplateArgs);
- ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body),
+ if (Body.isInvalid())
+ Function->setInvalidDecl();
+
+ ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body),
/*IsInstantiation=*/true);
CurContext = PreviousContext;
DeclGroupRef DG(Function);
Consumer.HandleTopLevelDecl(DG);
-
+
if (Recursive) {
// Instantiate any pending implicit instantiations found during the
- // instantiation of this template.
+ // instantiation of this template.
PerformPendingImplicitInstantiations();
-
+
// Restore the set of pending implicit instantiations.
PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
}
@@ -769,35 +1150,296 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
/// \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!
+/// \param PointOfInstantiation the point at which the instantiation was
+/// required. Note that this is not precisely a "point of instantiation"
+/// for the function, but it's close.
+///
+/// \param Var the already-instantiated declaration of a static member
+/// variable of a class template specialization.
+///
+/// \param Recursive if true, recursively instantiates any functions that
+/// are required by this instantiation.
+void Sema::InstantiateStaticDataMemberDefinition(
+ SourceLocation PointOfInstantiation,
+ VarDecl *Var,
+ bool Recursive) {
+ if (Var->isInvalidDecl())
+ return;
+
+ // Find the out-of-line definition of this static data member.
+ VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
+ bool FoundOutOfLineDef = false;
+ assert(Def && "This data member was not instantiated from a template?");
+ assert(Def->isStaticDataMember() && "Not a static data member?");
+ for (VarDecl::redecl_iterator RD = Def->redecls_begin(),
+ RDEnd = Def->redecls_end();
+ RD != RDEnd; ++RD) {
+ if (RD->getLexicalDeclContext()->isFileContext()) {
+ Def = *RD;
+ FoundOutOfLineDef = true;
+ }
+ }
+
+ if (!FoundOutOfLineDef) {
+ // We did not find an out-of-line definition of this static data member,
+ // so we won't perform any instantiation. Rather, we rely on the user to
+ // instantiate this definition (or provide a specialization for it) in
+ // another translation unit.
+ return;
+ }
+
+ // Never instantiate an explicit specialization.
+ if (Def->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+ return;
+
+ // C++0x [temp.explicit]p9:
+ // Except for inline functions, other explicit instantiation declarations
+ // have the effect of suppressing the implicit instantiation of the entity
+ // to which they refer.
+ if (Def->getTemplateSpecializationKind()
+ == TSK_ExplicitInstantiationDeclaration)
+ return;
+
+ InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
+ if (Inst)
+ return;
+
+ // If we're performing recursive template instantiation, create our own
+ // queue of pending implicit instantiations that we will instantiate later,
+ // while we're still within our own instantiation context.
+ std::deque<PendingImplicitInstantiation> SavedPendingImplicitInstantiations;
+ if (Recursive)
+ PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
+
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ DeclContext *PreviousContext = CurContext;
+ CurContext = Var->getDeclContext();
+
+ Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
+ getTemplateInstantiationArgs(Var)));
+
+ CurContext = PreviousContext;
+
+ if (Var) {
+ DeclGroupRef DG(Var);
+ Consumer.HandleTopLevelDecl(DG);
+ }
+
+ if (Recursive) {
+ // Instantiate any pending implicit instantiations found during the
+ // instantiation of this template.
+ PerformPendingImplicitInstantiations();
+
+ // Restore the set of pending implicit instantiations.
+ PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
+ }
+}
+
+void
+Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
+ const CXXConstructorDecl *Tmpl,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+
+ llvm::SmallVector<MemInitTy*, 4> NewInits;
+
+ // Instantiate all the initializers.
+ for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(),
+ InitsEnd = Tmpl->init_end();
+ Inits != InitsEnd; ++Inits) {
+ CXXBaseOrMemberInitializer *Init = *Inits;
+
+ ASTOwningVector<&ActionBase::DeleteExpr> NewArgs(*this);
+
+ // Instantiate all the arguments.
+ for (ExprIterator Args = Init->arg_begin(), ArgsEnd = Init->arg_end();
+ Args != ArgsEnd; ++Args) {
+ OwningExprResult NewArg = SubstExpr(*Args, TemplateArgs);
+
+ if (NewArg.isInvalid())
+ New->setInvalidDecl();
+ else
+ NewArgs.push_back(NewArg.takeAs<Expr>());
+ }
+
+ MemInitResult NewInit;
+
+ if (Init->isBaseInitializer()) {
+ QualType BaseType(Init->getBaseClass(), 0);
+ BaseType = SubstType(BaseType, TemplateArgs, Init->getSourceLocation(),
+ New->getDeclName());
+
+ NewInit = BuildBaseInitializer(BaseType,
+ (Expr **)NewArgs.data(),
+ NewArgs.size(),
+ Init->getSourceLocation(),
+ Init->getRParenLoc(),
+ New->getParent());
+ } else if (Init->isMemberInitializer()) {
+ FieldDecl *Member;
+
+ // Is this an anonymous union?
+ if (FieldDecl *UnionInit = Init->getAnonUnionMember())
+ Member = cast<FieldDecl>(FindInstantiatedDecl(UnionInit, TemplateArgs));
+ else
+ Member = cast<FieldDecl>(FindInstantiatedDecl(Init->getMember(),
+ TemplateArgs));
+
+ NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(),
+ NewArgs.size(),
+ Init->getSourceLocation(),
+ Init->getRParenLoc());
+ }
+
+ if (NewInit.isInvalid())
+ New->setInvalidDecl();
+ else {
+ // FIXME: It would be nice if ASTOwningVector had a release function.
+ NewArgs.take();
+
+ NewInits.push_back((MemInitTy *)NewInit.get());
+ }
+ }
+
+ // Assign all the initializers to the new constructor.
+ ActOnMemInitializers(DeclPtrTy::make(New),
+ /*FIXME: ColonLoc */
+ SourceLocation(),
+ NewInits.data(), NewInits.size());
+}
+
+// TODO: this could be templated if the various decl types used the
+// same method name.
+static bool isInstantiationOf(ClassTemplateDecl *Pattern,
+ ClassTemplateDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberTemplate();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(FunctionTemplateDecl *Pattern,
+ FunctionTemplateDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberTemplate();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(CXXRecordDecl *Pattern,
+ CXXRecordDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberClass();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(FunctionDecl *Pattern,
+ FunctionDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberFunction();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(EnumDecl *Pattern,
+ EnumDecl *Instance) {
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromMemberEnum();
+ } while (Instance);
+
+ return false;
+}
+
+static bool isInstantiationOf(UnresolvedUsingDecl *Pattern,
+ UsingDecl *Instance,
+ ASTContext &C) {
+ return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern;
+}
+
+static bool isInstantiationOfStaticDataMember(VarDecl *Pattern,
+ VarDecl *Instance) {
+ assert(Instance->isStaticDataMember());
+
+ Pattern = Pattern->getCanonicalDecl();
+
+ do {
+ Instance = Instance->getCanonicalDecl();
+ if (Pattern == Instance) return true;
+ Instance = Instance->getInstantiatedFromStaticDataMember();
+ } while (Instance);
+
+ return false;
}
static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
- if (D->getKind() != Other->getKind())
+ if (D->getKind() != Other->getKind()) {
+ if (UnresolvedUsingDecl *UUD = dyn_cast<UnresolvedUsingDecl>(D)) {
+ if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) {
+ return isInstantiationOf(UUD, UD, Ctx);
+ }
+ }
+
return false;
+ }
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Other))
- return Ctx.getCanonicalDecl(Record->getInstantiatedFromMemberClass())
- == Ctx.getCanonicalDecl(D);
+ return isInstantiationOf(cast<CXXRecordDecl>(D), Record);
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Other))
- return Ctx.getCanonicalDecl(Function->getInstantiatedFromMemberFunction())
- == Ctx.getCanonicalDecl(D);
+ return isInstantiationOf(cast<FunctionDecl>(D), Function);
if (EnumDecl *Enum = dyn_cast<EnumDecl>(Other))
- return Ctx.getCanonicalDecl(Enum->getInstantiatedFromMemberEnum())
- == Ctx.getCanonicalDecl(D);
+ return isInstantiationOf(cast<EnumDecl>(D), Enum);
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(Other))
+ if (Var->isStaticDataMember())
+ return isInstantiationOfStaticDataMember(cast<VarDecl>(D), Var);
+
+ if (ClassTemplateDecl *Temp = dyn_cast<ClassTemplateDecl>(Other))
+ return isInstantiationOf(cast<ClassTemplateDecl>(D), Temp);
+
+ if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(Other))
+ return isInstantiationOf(cast<FunctionTemplateDecl>(D), Temp);
- // FIXME: How can we find instantiations of anonymous unions?
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) {
+ if (!Field->getDeclName()) {
+ // This is an unnamed field.
+ return Ctx.getInstantiatedFromUnnamedFieldDecl(Field) ==
+ cast<FieldDecl>(D);
+ }
+ }
return D->getDeclName() && isa<NamedDecl>(Other) &&
D->getDeclName() == cast<NamedDecl>(Other)->getDeclName();
}
template<typename ForwardIterator>
-static NamedDecl *findInstantiationOf(ASTContext &Ctx,
+static NamedDecl *findInstantiationOf(ASTContext &Ctx,
NamedDecl *D,
ForwardIterator first,
ForwardIterator last) {
@@ -808,6 +1450,18 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx,
return 0;
}
+/// \brief Finds the instantiation of the given declaration context
+/// within the current instantiation.
+///
+/// \returns NULL if there was an error
+DeclContext *Sema::FindInstantiatedContext(DeclContext* DC,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (NamedDecl *D = dyn_cast<NamedDecl>(DC)) {
+ Decl* ID = FindInstantiatedDecl(D, TemplateArgs);
+ return cast_or_null<DeclContext>(ID);
+ } else return DC;
+}
+
/// \brief Find the instantiation of the given declaration within the
/// current instantiation.
///
@@ -834,7 +1488,24 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx,
/// 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) {
+NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D)) {
+ // Transform all of the elements of the overloaded function set.
+ OverloadedFunctionDecl *Result
+ = OverloadedFunctionDecl::Create(Context, CurContext, Ovl->getDeclName());
+
+ for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
+ FEnd = Ovl->function_end();
+ F != FEnd; ++F) {
+ Result->addOverload(
+ AnyFunctionDecl::getFromNamedDecl(FindInstantiatedDecl(*F,
+ TemplateArgs)));
+ }
+
+ return Result;
+ }
+
DeclContext *ParentDC = D->getDeclContext();
if (isa<ParmVarDecl>(D) || ParentDC->isFunctionOrMethod()) {
// D is a local of some kind. Look into the map of local
@@ -842,14 +1513,71 @@ NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) {
return cast<NamedDecl>(CurrentInstantiationScope->getInstantiationOf(D));
}
- if (NamedDecl *ParentDecl = dyn_cast<NamedDecl>(ParentDC)) {
- ParentDecl = InstantiateCurrentDeclRef(ParentDecl);
- if (!ParentDecl)
- return 0;
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
+ if (!Record->isDependentContext())
+ return D;
+
+ // If the RecordDecl is actually the injected-class-name or a "templated"
+ // declaration for a class template or class template partial
+ // specialization, substitute into the injected-class-name of the
+ // class template or partial specialization to find the new DeclContext.
+ QualType T;
+ ClassTemplateDecl *ClassTemplate = Record->getDescribedClassTemplate();
+
+ if (ClassTemplate) {
+ T = ClassTemplate->getInjectedClassNameType(Context);
+ } else if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) {
+ T = Context.getTypeDeclType(Record);
+ ClassTemplate = PartialSpec->getSpecializedTemplate();
+ }
+
+ if (!T.isNull()) {
+ // Substitute into the injected-class-name to get the type corresponding
+ // to the instantiation we want. This substitution should never fail,
+ // since we know we can instantiate the injected-class-name or we wouldn't
+ // have gotten to the injected-class-name!
+ // FIXME: Can we use the CurrentInstantiationScope to avoid this extra
+ // instantiation in the common case?
+ T = SubstType(T, TemplateArgs, SourceLocation(), DeclarationName());
+ assert(!T.isNull() && "Instantiation of injected-class-name cannot fail.");
+
+ if (!T->isDependentType()) {
+ assert(T->isRecordType() && "Instantiation must produce a record type");
+ return T->getAs<RecordType>()->getDecl();
+ }
+
+ // We are performing "partial" template instantiation to create the
+ // member declarations for the members of a class template
+ // specialization. Therefore, D is actually referring to something in
+ // the current instantiation. Look through the current context,
+ // which contains actual instantiations, to find the instantiation of
+ // the "current instantiation" that D refers to.
+ for (DeclContext *DC = CurContext; !DC->isFileContext();
+ DC = DC->getParent()) {
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(DC))
+ if (isInstantiationOf(ClassTemplate,
+ Spec->getSpecializedTemplate()))
+ return Spec;
+ }
- ParentDC = cast<DeclContext>(ParentDecl);
+ assert(false &&
+ "Unable to find declaration for the current instantiation");
+ return Record;
+ }
+
+ // Fall through to deal with other dependent record types (e.g.,
+ // anonymous unions in class templates).
}
+ if (!ParentDC->isDependentContext())
+ return D;
+
+ ParentDC = FindInstantiatedContext(ParentDC, TemplateArgs);
+ if (!ParentDC)
+ return 0;
+
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
@@ -867,51 +1595,47 @@ NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) {
// - unnamed class/struct/union/enum within a template
//
// FIXME: Find a better way to find these instantiations!
- Result = findInstantiationOf(Context, D,
+ Result = findInstantiationOf(Context, D,
ParentDC->decls_begin(),
ParentDC->decls_end());
}
+
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;
}
-/// \brief Performs template instantiation for all implicit template
+/// \brief Performs template instantiation for all implicit template
/// instantiations we have seen until this point.
void Sema::PerformPendingImplicitInstantiations() {
while (!PendingImplicitInstantiations.empty()) {
PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front();
PendingImplicitInstantiations.pop_front();
-
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first))
+
+ // Instantiate function definitions
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) {
+ PrettyStackTraceActionsDecl CrashInfo(DeclPtrTy::make(Function),
+ Function->getLocation(), *this,
+ Context.getSourceManager(),
+ "instantiating function definition");
+
if (!Function->getBody())
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);
-
- // FIXME: instantiate static member variables
+ continue;
+ }
+
+ // Instantiate static data member definitions.
+ VarDecl *Var = cast<VarDecl>(Inst.first);
+ assert(Var->isStaticDataMember() && "Not a static data member?");
+
+ PrettyStackTraceActionsDecl CrashInfo(DeclPtrTy::make(Var),
+ Var->getLocation(), *this,
+ Context.getSourceManager(),
+ "instantiating static data member "
+ "definition");
+
+ InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true);
}
}