Template instantiation for static data members that are defined out-of-line.

Note that this also fixes a bug that affects non-template code, where we 
were not treating out-of-line static data members are "file-scope" variables,
and therefore not checking their initializers.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77002 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 5572b7a..4684a80 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -220,6 +220,25 @@
   InitBuiltinType(NullPtrTy,           BuiltinType::NullPtr);
 }
 
+VarDecl *ASTContext::getInstantiatedFromStaticDataMember(VarDecl *Var) {
+  assert(Var->isStaticDataMember() && "Not a static data member");
+  llvm::DenseMap<VarDecl *, VarDecl *>::iterator Pos
+    = InstantiatedFromStaticDataMember.find(Var);
+  if (Pos == InstantiatedFromStaticDataMember.end())
+    return 0;
+  
+  return Pos->second;
+}
+
+void 
+ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl) {
+  assert(Inst->isStaticDataMember() && "Not a static data member");
+  assert(Tmpl->isStaticDataMember() && "Not a static data member");
+  assert(!InstantiatedFromStaticDataMember[Inst] &&
+         "Already noted what static data member was instantiated from");
+  InstantiatedFromStaticDataMember[Inst] = Tmpl;
+}
+
 namespace {
   class BeforeInTranslationUnit 
     : std::binary_function<SourceRange, SourceRange, bool> {
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index b4710c2..9701f6c 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -341,6 +341,10 @@
   return SourceRange(getLocation(), getLocation());
 }
 
+VarDecl *VarDecl::getInstantiatedFromStaticDataMember() {
+  return getASTContext().getInstantiatedFromStaticDataMember(this);
+}
+
 bool VarDecl::isTentativeDefinition(ASTContext &Context) const {
   if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus)
     return false;
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 3f14c49..164c65f 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2732,7 +2732,10 @@
   void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
                                      FunctionDecl *Function,
                                      bool Recursive = false);
-  void InstantiateVariableDefinition(VarDecl *Var);
+  void InstantiateStaticDataMemberDefinition(
+                                          SourceLocation PointOfInstantiation,
+                                             VarDecl *Var,
+                                             bool Recursive = false);
 
   NamedDecl *InstantiateCurrentDeclRef(NamedDecl *D);
     
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 66e73f9..98d1f4c 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -5780,10 +5780,17 @@
   }
   
   if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
-    (void)Var;
-    // FIXME: implicit template instantiation
+    // Implicit instantiation of static data members of class templates.
+    // FIXME: distinguish between implicit instantiations (which we need to
+    // actually instantiate) and explicit specializations.
+    if (Var->isStaticDataMember() && 
+        Var->getInstantiatedFromStaticDataMember())
+      PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc));
+    
     // FIXME: keep track of references to static data?
+
     D->setUsed(true);
-  }
+    return;
+}
 }
 
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index a75a858..cb43f1c 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -189,8 +189,7 @@
                      DiagID)
           << Context.getTypeDeclType(Record)
           << Active->InstantiationRange;
-      } else {
-        FunctionDecl *Function = cast<FunctionDecl>(D);
+      } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
         unsigned DiagID;
         if (Function->getPrimaryTemplate())
           DiagID = diag::note_function_template_spec_here;
@@ -200,6 +199,11 @@
                      DiagID)
           << Function
           << Active->InstantiationRange;
+      } else {
+        Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
+                     diag::note_template_static_data_member_def_here)
+          << cast<VarDecl>(D)
+          << Active->InstantiationRange;
       }
       break;
     }
@@ -1059,9 +1063,8 @@
       if (!Function->getBody())
         InstantiateFunctionDefinition(PointOfInstantiation, Function);
     } else if (VarDecl *Var = dyn_cast<VarDecl>(*D)) {
-      const VarDecl *Def = 0;
-      if (!Var->getDefinition(Def))
-        InstantiateVariableDefinition(Var);
+      if (Var->isStaticDataMember())
+        InstantiateStaticDataMemberDefinition(PointOfInstantiation, Var);
     } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(*D)) {
       if (!Record->isInjectedClassName() && !Record->getDefinition(Context)) {
         assert(Record->getInstantiatedFromMemberClass() && 
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 5718e9b..a6513f1 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -120,12 +120,24 @@
   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);
+  }
+  
   if (D->getInit()) {
     OwningExprResult Init 
       = SemaRef.InstantiateExpr(D->getInit(), TemplateArgs);
@@ -138,6 +150,11 @@
     // FIXME: Call ActOnUninitializedDecl? (Not always)
   }
 
+  // Link instantiations of static data members back to the template from
+  // which they were instantiated.
+  if (Var->isStaticDataMember())
+    SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D);
+    
   return Var;
 }
 
@@ -374,6 +391,12 @@
                             D->isInline());
   Method->setInstantiationOfMemberFunction(D);
 
+  // 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)
     Params[P]->setOwningFunction(Method);
@@ -773,9 +796,103 @@
 /// \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.
+  // FIXME: Do we have to look for specializations separately?
+  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;
+  }
+
+  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();
+  
+#if 0
+  // Instantiate the initializer of this static data member.
+  OwningExprResult Init 
+    = InstantiateExpr(Def->getInit(), getTemplateInstantiationArgs(Var));
+  if (Init.isInvalid()) {
+    // If instantiation of the initializer failed, mark the declaration invalid
+    // and don't instantiate anything else that was triggered by this 
+    // instantiation.
+    Var->setInvalidDecl();
+
+    // Restore the set of pending implicit instantiations.
+    PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
+    
+    return;
+  } 
+  
+  // Type-check the initializer.
+  if (Init.get())
+    AddInitializerToDecl(DeclPtrTy::make(Var), move(Init),
+                         Def->hasCXXDirectInitializer());
+  else 
+    ActOnUninitializedDecl(DeclPtrTy::make(Var), false);
+#else
+  Var = cast_or_null<VarDecl>(InstantiateDecl(Def, Var->getDeclContext(),
+                                          getTemplateInstantiationArgs(Var)));
+#endif
+  
+  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);
+  }  
 }
 
 static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
@@ -794,6 +911,11 @@
     return Enum->getInstantiatedFromMemberEnum()->getCanonicalDecl()
              == D->getCanonicalDecl();
 
+  if (VarDecl *Var = dyn_cast<VarDecl>(Other))
+    if (Var->isStaticDataMember())
+      return Var->getInstantiatedFromStaticDataMember()->getCanonicalDecl()
+               == D->getCanonicalDecl();
+      
   // FIXME: How can we find instantiations of anonymous unions?
 
   return D->getDeclName() && isa<NamedDecl>(Other) &&
@@ -912,10 +1034,16 @@
     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)) {
       if (!Function->getBody())
         InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);
+      continue;
+    }
     
-    // FIXME: instantiate static member variables
+    // Instantiate static data member definitions.
+    VarDecl *Var = cast<VarDecl>(Inst.first);
+    assert(Var->isStaticDataMember() && "Not a static data member?");
+    InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true);
   }
 }