]> granicus.if.org Git - clang/commitdiff
Instantiate member and base initializers. Patch by Anders Johnsen! (tweaked slightly...
authorAnders Carlsson <andersca@mac.com>
Sat, 29 Aug 2009 05:16:22 +0000 (05:16 +0000)
committerAnders Carlsson <andersca@mac.com>
Sat, 29 Aug 2009 05:16:22 +0000 (05:16 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80422 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/Sema.h
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaTemplate/instantiate-member-initializers.cpp [new file with mode: 0644]

index 1a062b79e832b50f809731c3513214072d9ac8a9..accbcd14790aa68dbd7b9609559ec7e0b38cbd09 100644 (file)
@@ -2960,6 +2960,10 @@ public:
                                      VarDecl *Var,
                                      bool Recursive = false);
 
+  void InstantiateMemInitializers(CXXConstructorDecl *New,
+                                  const CXXConstructorDecl *Tmpl,
+                            const MultiLevelTemplateArgumentList &TemplateArgs);
+  
   NamedDecl *FindInstantiatedDecl(NamedDecl *D);
   DeclContext *FindInstantiatedContext(DeclContext *DC);
     
index e2ebd09954156da45918af4b3845ac413eab6401..ba5c7863668415878949cb9c22bee388912eac5a 100644 (file)
@@ -992,9 +992,18 @@ 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 
-    = SubstStmt(Pattern, getTemplateInstantiationArgs(Function));
+  OwningStmtResult Body = SubstStmt(Pattern, TemplateArgs);
 
   ActOnFinishFunctionBody(DeclPtrTy::make(Function), move(Body), 
                           /*IsInstantiation=*/true);
@@ -1092,6 +1101,71 @@ void Sema::InstantiateStaticDataMemberDefinition(
   }  
 }
 
+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;
diff --git a/test/SemaTemplate/instantiate-member-initializers.cpp b/test/SemaTemplate/instantiate-member-initializers.cpp
new file mode 100644 (file)
index 0000000..66f4d37
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -Wall -verify %s
+
+template<typename T> struct A {
+  A() : a(1) { } // expected-error{{incompatible type passing 'int', expected 'void *'}}
+
+  T a;
+};
+
+A<int> a0;
+A<void*> a1; // expected-note{{in instantiation of member function 'A<void *>::A' requested here}}
+
+template<typename T> struct B {
+  // FIXME: This should warn about initialization order
+  B() : b(1), a(2) { }
+  
+  int a;
+  int b;
+};
+
+B<int> b0;