Basic nested-template implementation.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79504 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index f3ec417..12ab47c 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2847,6 +2847,10 @@
const TemplateArgumentList &TemplateArgs);
bool
+ InstantiateTemplatePattern(SourceLocation PointOfInstantiation,
+ CXXRecordDecl *Pattern);
+
+ bool
InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
const TemplateArgumentList &TemplateArgs,
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 4d164ea..45214bf 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -568,6 +568,38 @@
return Invalid;
}
+/// \brief Force a template's pattern class to be instantiated.
+///
+/// \returns true if an error occurred
+bool Sema::InstantiateTemplatePattern(SourceLocation PointOfInstantiation,
+ CXXRecordDecl *Pattern) {
+ if (Pattern->getDefinition(Context)) return false;
+
+ ClassTemplateDecl *PatternTemp = Pattern->getDescribedClassTemplate();
+ if (!PatternTemp) return false;
+
+ // Check whether this template is a lazy instantiation of a
+ // dependent member template, e.g. Inner<U> in
+ // Outer<int>::Inner<U>.
+ ClassTemplateDecl *PatternPatternTemp
+ = PatternTemp->getInstantiatedFromMemberTemplate();
+ if (!PatternPatternTemp) return false;
+
+ ClassTemplateSpecializationDecl *Spec = 0;
+ for (DeclContext *Parent = Pattern->getDeclContext();
+ Parent && !Spec; Parent = Parent->getParent())
+ Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent);
+ assert(Spec && "Not a member of a class template specialization?");
+
+ // TODO: the error message from a nested failure here is probably
+ // not ideal.
+ return InstantiateClass(PointOfInstantiation,
+ Pattern,
+ PatternPatternTemp->getTemplatedDecl(),
+ Spec->getTemplateArgs(),
+ /* ExplicitInstantiation = */ false);
+}
+
/// \brief Instantiate the definition of a class from a given pattern.
///
/// \param PointOfInstantiation The point of instantiation within the
@@ -591,6 +623,10 @@
const TemplateArgumentList &TemplateArgs,
bool ExplicitInstantiation) {
bool Invalid = false;
+
+ // Lazily instantiate member templates here.
+ if (InstantiateTemplatePattern(PointOfInstantiation, Pattern))
+ return true;
CXXRecordDecl *PatternDef
= cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 30d7b6a..23256a8 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -53,6 +53,8 @@
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
+ Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
+ Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
// Base case. FIXME: Remove once we can instantiate everything.
Decl *VisitDecl(Decl *) {
@@ -69,6 +71,9 @@
llvm::SmallVectorImpl<ParmVarDecl *> &Params);
bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
+
+ TemplateParameterList *
+ InstantiateTemplateParams(TemplateParameterList *List);
};
}
@@ -322,6 +327,28 @@
return 0;
}
+Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ TemplateParameterList *TempParams = D->getTemplateParameters();
+ TemplateParameterList *InstParams = InstantiateTemplateParams(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);
+
+ ClassTemplateDecl *Inst
+ = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getIdentifier(), InstParams, RecordInst, 0);
+ RecordInst->setDescribedClassTemplate(Inst);
+ Inst->setAccess(D->getAccess());
+ Inst->setInstantiatedFromMemberTemplate(D);
+
+ Owner->addDecl(Inst);
+ return Inst;
+}
+
Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
CXXRecordDecl *PrevDecl = 0;
if (D->isInjectedClassName())
@@ -639,12 +666,79 @@
return VisitParmVarDecl(D);
}
+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.InstantiateType(DefaultPattern, TemplateArgs,
+ D->getDefaultArgumentLoc(),
+ D->getDeclName());
+
+ Inst->setDefaultArgument(DefaultInst,
+ D->getDefaultArgumentLoc(),
+ D->defaultArgumentWasInherited() /* preserve? */);
+ }
+
+ return Inst;
+}
+
Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner,
const TemplateArgumentList &TemplateArgs) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
return Instantiator.Visit(D);
}
+/// \brief Instantiates a nested template parameter list in the current
+/// instantiation context.
+///
+/// \param L The parameter list to instantiate
+///
+/// \returns NULL if there was an error
+TemplateParameterList *
+TemplateDeclInstantiator::InstantiateTemplateParams(TemplateParameterList *L) {
+ // Get errors for all the parameters before bailing out.
+ bool Invalid = false;
+
+ unsigned N = L->size();
+ typedef llvm::SmallVector<Decl*,8> ParamVector;
+ ParamVector Params;
+ Params.reserve(N);
+ for (TemplateParameterList::iterator PI = L->begin(), PE = L->end();
+ PI != PE; ++PI) {
+ Decl *D = 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 Instantiates the type of the given function, including
/// instantiating all of the function parameters.
///