]> granicus.if.org Git - clang/commitdiff
Fix marking of virtual members for nested classes whose first non-pure virtual functi...
authorDouglas Gregor <dgregor@apple.com>
Wed, 6 Jan 2010 20:27:16 +0000 (20:27 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 6 Jan 2010 20:27:16 +0000 (20:27 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92855 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGVtable.cpp
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
lib/Sema/SemaDeclCXX.cpp
test/SemaTemplate/virtual-member-functions.cpp

index c04a8fabf342fbd4c08733ba2fc90647342366a4..d2ba77d3351dd1c90b559d1033517e7905ebfffa 100644 (file)
@@ -1490,52 +1490,8 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
       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) {
index 85d57e7cbec31851c9d36c4834bac021b8322f25..e0e8c54434e5bd588aba88b54897eb0939904a5a 100644 (file)
@@ -887,6 +887,60 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
   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
index a31e23b2c7a5f16a828bca1a4e7c71f559e1028c..575b518767e2bbfaf2f59d2aad41bc06553c1570 100644 (file)
@@ -407,6 +407,10 @@ public:
     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.
index c9757d728a64427c1f2edb47636c5ff6433f8bc0..2e6f8bc68766bfa73ad92e581c0ce1998236a35d 100644 (file)
@@ -5693,14 +5693,40 @@ void Sema::MaybeMarkVirtualMembersReferenced(SourceLocation Loc,
   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));
index a9eb729ed5a1624348125671ca613b3a0f3d2c8c..db243130bb3dd3089d36d81600eb94abb6a75828 100644 (file)
@@ -41,3 +41,15 @@ struct Derived : Base<T> {
 
 template struct Derived<int>; // expected-note{{instantiation}}
 
+template<typename T>
+struct HasOutOfLineKey {
+  HasOutOfLineKey() { } // expected-note{{in instantiation of member function 'HasOutOfLineKey<int>::f' requested here}}
+  virtual T *f(float *fp);
+};
+
+template<typename T>
+T *HasOutOfLineKey<T>::f(float *fp) {
+  return fp; // expected-error{{cannot initialize return object of type 'int *' with an lvalue of type 'float *'}}
+}
+
+HasOutOfLineKey<int> out_of_line;