Instantiate member and base initializers. Patch by Anders Johnsen! (tweaked slightly by me)


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80422 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e2ebd09..ba5c786 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -992,9 +992,18 @@
   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 
-    = SubstStmt(Pattern, getTemplateInstantiationArgs(Function));
+  OwningStmtResult Body = SubstStmt(Pattern, TemplateArgs);
 
   ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body), 
                           /*IsInstantiation=*/true);
@@ -1092,6 +1101,71 @@
   }  
 }
 
+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()) {
+      // FIXME: Type needs to be instantiated.
+      QualType BaseType = 
+        Context.getCanonicalType(QualType(Init->getBaseClass(), 0));
+
+      NewInit = BuildBaseInitializer(BaseType,
+                                     (Expr **)NewArgs.data(), 
+                                     NewArgs.size(),
+                                     Init->getSourceLocation(),
+                                     Init->getRParenLoc(),
+                                     New->getParent());
+    } else if (Init->isMemberInitializer()) {
+      FieldDecl *Member = 
+        cast<FieldDecl>(FindInstantiatedDecl(Init->getMember()));
+      
+      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()); 
+}
+
 static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
   if (D->getKind() != Other->getKind())
     return false;