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.
 ///