Fix marking of virtual members for nested classes whose first non-pure virtual function has a body inlined in the class

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92855 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index c04a8fa..d2ba77d 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -1490,52 +1490,8 @@
       return;
   }
 
-  llvm::GlobalVariable::LinkageTypes Linkage =
-    llvm::GlobalVariable::InternalLinkage;
-  if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
-    Linkage = llvm::GlobalVariable::InternalLinkage;
-  else if (KeyFunction && !MD->isInlined()) {
-    switch (MD->getTemplateSpecializationKind()) {
-    case TSK_Undeclared:
-    case TSK_ExplicitSpecialization:
-      Linkage = llvm::GlobalVariable::ExternalLinkage;
-      break;
-
-    case TSK_ImplicitInstantiation:
-    case TSK_ExplicitInstantiationDefinition:
-      Linkage = llvm::GlobalVariable::WeakODRLinkage;
-      break;
-
-    case TSK_ExplicitInstantiationDeclaration:
-      // FIXME: Use available_externally linkage. However, this currently
-      // breaks LLVM's build due to undefined symbols.
-      //      Linkage = llvm::GlobalVariable::AvailableExternallyLinkage;
-      Linkage = llvm::GlobalVariable::WeakODRLinkage;
-      break;
-    }
-  }
-  else if (KeyFunction)
-    Linkage = llvm::GlobalVariable::WeakODRLinkage;
-  else {
-    Linkage = llvm::GlobalVariable::WeakODRLinkage;
-    
-    switch (RD->getTemplateSpecializationKind()) {
-    case TSK_Undeclared:
-    case TSK_ExplicitSpecialization:
-    case TSK_ImplicitInstantiation:
-    case TSK_ExplicitInstantiationDefinition:
-      break;
-
-    case TSK_ExplicitInstantiationDeclaration:
-      // FIXME: Use available_externally linkage. However, this currently
-      // breaks LLVM's build due to undefined symbols.
-      // Linkage = llvm::GlobalVariable::AvailableExternallyLinkage;
-      break;
-    }
-  }
-  
   // Emit the data.
-  GenerateClassData(Linkage, RD);
+  GenerateClassData(CGM.getVtableLinkage(RD), RD);
 
   for (CXXRecordDecl::method_iterator i = RD->method_begin(),
        e = RD->method_end(); i != e; ++i) {
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 85d57e7..e0e8c54 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -887,6 +887,60 @@
   EmitGlobalVarDefinition(D);
 }
 
+llvm::GlobalVariable::LinkageTypes 
+CodeGenModule::getVtableLinkage(const CXXRecordDecl *RD) {
+  // Get the key function.
+  const CXXMethodDecl *KeyFunction = getContext().getKeyFunction(RD);
+  
+  if (KeyFunction) {
+    const FunctionDecl *Def = 0;
+    if (KeyFunction->getBody(Def))
+      KeyFunction = cast<CXXMethodDecl>(Def);
+  }
+  
+  if (RD->isInAnonymousNamespace() || !RD->hasLinkage())
+    return llvm::GlobalVariable::InternalLinkage;
+  else if (KeyFunction) {
+    switch (KeyFunction->getTemplateSpecializationKind()) {
+      case TSK_Undeclared:
+      case TSK_ExplicitSpecialization:
+        if (KeyFunction->isInlined())
+          return llvm::GlobalVariable::WeakODRLinkage;
+        
+        return llvm::GlobalVariable::ExternalLinkage;
+        
+      case TSK_ImplicitInstantiation:
+      case TSK_ExplicitInstantiationDefinition:
+        return llvm::GlobalVariable::WeakODRLinkage;
+        
+      case TSK_ExplicitInstantiationDeclaration:
+        // FIXME: Use available_externally linkage. However, this currently
+        // breaks LLVM's build due to undefined symbols.
+        //      return llvm::GlobalVariable::AvailableExternallyLinkage;
+        return llvm::GlobalVariable::WeakODRLinkage;
+    }
+  } else if (KeyFunction) {
+    return llvm::GlobalVariable::WeakODRLinkage;
+  } else {
+    switch (RD->getTemplateSpecializationKind()) {
+      case TSK_Undeclared:
+      case TSK_ExplicitSpecialization:
+      case TSK_ImplicitInstantiation:
+      case TSK_ExplicitInstantiationDefinition:
+        return llvm::GlobalVariable::WeakODRLinkage;
+        
+      case TSK_ExplicitInstantiationDeclaration:
+        // FIXME: Use available_externally linkage. However, this currently
+        // breaks LLVM's build due to undefined symbols.
+        //   return llvm::GlobalVariable::AvailableExternallyLinkage;
+        return llvm::GlobalVariable::WeakODRLinkage;
+    }
+  }
+  
+  // Silence GCC warning.
+  return llvm::GlobalVariable::WeakODRLinkage;
+}
+
 static CodeGenModule::GVALinkage
 GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
   // Everything located semantically within an anonymous namespace is
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index a31e23b..575b518 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -407,6 +407,10 @@
     GVA_TemplateInstantiation
   };
 
+  /// getVtableLinkage - Return the appropriate linkage for the vtable, VTT,
+  /// and type information of the given class.
+  llvm::GlobalVariable::LinkageTypes getVtableLinkage(const CXXRecordDecl *RD);
+  
 private:
   /// UniqueMangledName - Unique a name by (if necessary) inserting it into the
   /// MangledNames string map.
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index c9757d7..2e6f8bc 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -5693,14 +5693,40 @@
   if (!RD->isDynamicClass())
     return;
 
-  // Only out-of-line definitions matter.
-  if (!MD->isOutOfLine())
+  // Ignore declarations that are not definitions.
+  if (!MD->isThisDeclarationADefinition())
     return;
   
-  const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD);
-  if (!KeyFunction || KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
+  if (isa<CXXConstructorDecl>(MD)) {
+    switch (MD->getParent()->getTemplateSpecializationKind()) {
+    case TSK_Undeclared:
+    case TSK_ExplicitSpecialization:
+      // Classes that aren't instantiations of templates don't need their
+      // virtual methods marked until we see the definition of the key 
+      // function.
+      return;
+        
+    case TSK_ImplicitInstantiation:
+    case TSK_ExplicitInstantiationDeclaration:
+    case TSK_ExplicitInstantiationDefinition:
+      // This is a constructor of a class template; mark all of the virtual
+      // members as referenced to ensure that they get instantiatied.
+      break;
+    }
+  } else if (!MD->isOutOfLine()) {
+    // Consider only out-of-line definitions of member functions. When we see
+    // an inline definition, it's too early to compute the key function.
     return;
-
+  } else if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD)) {
+    // If this is not the key function, we don't need to mark virtual members.
+    if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
+      return;
+  } else {
+    // The class has no key function, so we've already noted that we need to
+    // mark the virtual members of this class.
+    return;
+  }
+  
   // We will need to mark all of the virtual members as referenced to build the
   // vtable.
   ClassesWithUnmarkedVirtualMembers.push_back(std::make_pair(RD, Loc));