Give explicit and implicit instantiations of static data members of
class templates the proper linkage. 

Daniel, please look over the CodeGenModule bits.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84140 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index a908299..da7959b 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -373,7 +373,23 @@
   return SourceRange(getLocation(), getLocation());
 }
 
-VarDecl *VarDecl::getInstantiatedFromStaticDataMember() {
+bool VarDecl::isOutOfLine() const {
+  if (!isStaticDataMember())
+    return false;
+  
+  if (Decl::isOutOfLine())
+    return true;
+  
+  // If this static data member was instantiated from a static data member of
+  // a class template, check whether that static data member was defined 
+  // out-of-line.
+  if (VarDecl *VD = getInstantiatedFromStaticDataMember())
+    return VD->isOutOfLine();
+  
+  return false;
+}
+
+VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
   if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
     return cast<VarDecl>(MSI->getInstantiatedFrom());
   
@@ -388,7 +404,7 @@
   return TSK_Undeclared;
 }
 
-MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() {
+MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const {
   return getASTContext().getInstantiatedFromStaticDataMember(this);
 }
 
@@ -809,7 +825,6 @@
 }
 
 bool FunctionDecl::isOutOfLine() const {
-  // FIXME: Should we restrict this to member functions?
   if (Decl::isOutOfLine())
     return true;
   
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 36ad7f5..ecf8eb0 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -541,7 +541,12 @@
     }
   }
       
-  return VD->getStorageClass() == VarDecl::Static;
+  // Static data may be deferred, but out-of-line static data members
+  // cannot be.
+  // FIXME: What if the initializer has side effects?
+  return VD->isInAnonymousNamespace() ||
+         (VD->getStorageClass() == VarDecl::Static &&
+          !(VD->isStaticDataMember() && VD->isOutOfLine()));
 }
 
 void CodeGenModule::EmitGlobal(GlobalDecl GD) {
@@ -928,6 +933,37 @@
   EmitGlobalVarDefinition(D);
 }
 
+static CodeGenModule::GVALinkage
+GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
+  // Everything located semantically within an anonymous namespace is
+  // always internal.
+  if (VD->isInAnonymousNamespace())
+    return CodeGenModule::GVA_Internal;
+
+  // Handle linkage for static data members.
+  if (VD->isStaticDataMember()) {
+    switch (VD->getTemplateSpecializationKind()) {
+    case TSK_Undeclared:
+    case TSK_ExplicitSpecialization:
+    case TSK_ExplicitInstantiationDefinition:
+      return CodeGenModule::GVA_StrongExternal;
+      
+    case TSK_ExplicitInstantiationDeclaration:
+      assert(false && "Variable should not be instantiated");
+      // Fall through to treat this like any other instantiation.
+        
+    case TSK_ImplicitInstantiation:
+      return CodeGenModule::GVA_TemplateInstantiation;
+    }
+  }
+  
+  // Static variables get internal linkage.
+  if (VD->getStorageClass() == VarDecl::Static)
+    return CodeGenModule::GVA_Internal;
+
+  return CodeGenModule::GVA_StrongExternal;
+}
+
 void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
   llvm::Constant *Init = 0;
   QualType ASTTy = D->getType();
@@ -1021,9 +1057,10 @@
   GV->setAlignment(getContext().getDeclAlignInBytes(D));
 
   // Set the llvm linkage type as appropriate.
+  GVALinkage Linkage = GetLinkageForVariable(getContext(), D);
   if (D->isInAnonymousNamespace())
     GV->setLinkage(llvm::Function::InternalLinkage);
-  else if (D->getStorageClass() == VarDecl::Static)
+  else if (Linkage == GVA_Internal)
     GV->setLinkage(llvm::Function::InternalLinkage);
   else if (D->hasAttr<DLLImportAttr>())
     GV->setLinkage(llvm::Function::DLLImportLinkage);
@@ -1034,7 +1071,9 @@
       GV->setLinkage(llvm::GlobalVariable::WeakODRLinkage);
     else
       GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
-  } else if (!CompileOpts.NoCommon &&
+  } else if (Linkage == GVA_TemplateInstantiation)
+    GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);   
+  else if (!CompileOpts.NoCommon &&
            !D->hasExternalStorage() && !D->getInit() &&
            !D->getAttr<SectionAttr>()) {
     GV->setLinkage(llvm::GlobalVariable::CommonLinkage);
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 28c0fa6..060cc55 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1191,14 +1191,14 @@
   }
 
   // Never instantiate an explicit specialization.
-  if (Def->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
+  if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
     return;
   
   // C++0x [temp.explicit]p9:
   //   Except for inline functions, other explicit instantiation declarations
   //   have the effect of suppressing the implicit instantiation of the entity
   //   to which they refer.
-  if (Def->getTemplateSpecializationKind() 
+  if (Var->getTemplateSpecializationKind() 
         == TSK_ExplicitInstantiationDeclaration)
     return;
 
@@ -1218,12 +1218,14 @@
   DeclContext *PreviousContext = CurContext;
   CurContext = Var->getDeclContext();
 
+  VarDecl *OldVar = Var;
   Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
                                           getTemplateInstantiationArgs(Var)));
-
   CurContext = PreviousContext;
 
   if (Var) {
+    Var->setPreviousDeclaration(OldVar);
+    Var->setTemplateSpecializationKind(OldVar->getTemplateSpecializationKind());
     DeclGroupRef DG(Var);
     Consumer.HandleTopLevelDecl(DG);
   }