The standard ARM C++ ABI dictates that inline functions are
authorJohn McCall <rjmccall@apple.com>
Fri, 25 Jan 2013 22:31:03 +0000 (22:31 +0000)
committerJohn McCall <rjmccall@apple.com>
Fri, 25 Jan 2013 22:31:03 +0000 (22:31 +0000)
never key functions.  We did not implement that rule for the
iOS ABI, which was driven by what was implemented in gcc-4.2.
However, implement it now for other ARM-based platforms.

llvm-svn: 173515

19 files changed:
clang/include/clang/AST/ASTContext.h
clang/include/clang/Basic/TargetCXXABI.h
clang/lib/AST/ASTContext.cpp
clang/lib/AST/RecordLayoutBuilder.cpp
clang/lib/CodeGen/CGCXXABI.h
clang/lib/CodeGen/CGRTTI.cpp
clang/lib/CodeGen/CGVTables.cpp
clang/lib/CodeGen/CGVTables.h
clang/lib/CodeGen/CodeGenModule.cpp
clang/lib/CodeGen/CodeGenModule.h
clang/lib/CodeGen/ItaniumCXXABI.cpp
clang/lib/CodeGen/MicrosoftCXXABI.cpp
clang/lib/Sema/Sema.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/CodeGenCXX/vtable-available-externally.cpp
clang/test/CodeGenCXX/vtable-key-function-arm.cpp [new file with mode: 0644]
clang/test/CodeGenCXX/vtable-key-function-ios.cpp [new file with mode: 0644]

index 05f8182..bf04871 100644 (file)
@@ -1563,14 +1563,27 @@ public:
   const ASTRecordLayout &
   getASTObjCImplementationLayout(const ObjCImplementationDecl *D) const;
 
-  /// \brief Get the key function for the given record decl, or NULL if there
-  /// isn't one.
+  /// \brief Get our current best idea for the key function of the
+  /// given record decl, or NULL if there isn't one.
   ///
   /// The key function is, according to the Itanium C++ ABI section 5.2.3:
+  ///   ...the first non-pure virtual function that is not inline at the
+  ///   point of class definition.
   ///
-  /// ...the first non-pure virtual function that is not inline at the point
-  /// of class definition.
-  const CXXMethodDecl *getKeyFunction(const CXXRecordDecl *RD);
+  /// Other ABIs use the same idea.  However, the ARM C++ ABI ignores
+  /// virtual functions that are defined 'inline', which means that
+  /// the result of this computation can change.
+  const CXXMethodDecl *getCurrentKeyFunction(const CXXRecordDecl *RD);
+
+  /// \brief Observe that the given method cannot be a key function.
+  /// Checks the key-function cache for the method's class and clears it
+  /// if matches the given declaration.
+  ///
+  /// This is used in ABIs where out-of-line definitions marked
+  /// inline are not considered to be key functions.
+  ///
+  /// \param method should be the declaration from the class definition
+  void setNonKeyFunction(const CXXMethodDecl *method);
 
   /// Get the offset of a FieldDecl or IndirectFieldDecl, in bits.
   uint64_t getFieldOffset(const ValueDecl *FD) const;
index 2a8f5d0..1a8e62c 100644 (file)
@@ -142,6 +142,47 @@ public:
     return isItaniumFamily();
   }
 
+  /// \brief Can an out-of-line inline function serve as a key function?
+  ///
+  /// This flag is only useful in ABIs where type data (for example,
+  /// v-tables and type_info objects) are emitted only after processing
+  /// the definition of a special "key" virtual function.  (This is safe
+  /// because the ODR requires that every virtual function be defined
+  /// somewhere in a program.)  This usually permits such data to be
+  /// emitted in only a single object file, as opposed to redundantly
+  /// in every object file that requires it.
+  ///
+  /// One simple and common definition of "key function" is the first
+  /// virtual function in the class definition which is not defined there.
+  /// This rule works very well when that function has a non-inline
+  /// definition in some non-header file.  Unfortunately, when that
+  /// function is defined inline, this rule requires the type data
+  /// to be emitted weakly, as if there were no key function.
+  ///
+  /// The ARM ABI observes that the ODR provides an additional guarantee:
+  /// a virtual function is always ODR-used, so if it is defined inline,
+  /// that definition must appear in every translation unit that defines
+  /// the class.  Therefore, there is no reason to allow such functions
+  /// to serve as key functions.
+  ///
+  /// Because this changes the rules for emitting type data,
+  /// it can cause type data to be emitted with both weak and strong
+  /// linkage, which is not allowed on all platforms.  Therefore,
+  /// exploiting this observation requires an ABI break and cannot be
+  /// done on a generic Itanium platform.
+  bool canKeyFunctionBeInline() const {
+    switch (getKind()) {
+    case GenericARM:
+      return false;
+
+    case GenericItanium:
+    case iOS:   // old iOS compilers did not follow this rule
+    case Microsoft:
+      return true;
+    }
+    llvm_unreachable("bad ABI kind");
+  }
+
   /// Try to parse an ABI name, returning false on error.
   bool tryParse(llvm::StringRef name);
 
index b5d60f5..0b77174 100644 (file)
@@ -7559,13 +7559,16 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
     if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
       return true;
     
-    // The key function for a class is required.
-    if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
-      const CXXRecordDecl *RD = MD->getParent();
-      if (MD->isOutOfLine() && RD->isDynamicClass()) {
-        const CXXMethodDecl *KeyFunc = getKeyFunction(RD);
-        if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl())
-          return true;
+    // The key function for a class is required.  This rule only comes
+    // into play when inline functions can be key functions, though.
+    if (getTargetInfo().getCXXABI().canKeyFunctionBeInline()) {
+      if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+        const CXXRecordDecl *RD = MD->getParent();
+        if (MD->isOutOfLine() && RD->isDynamicClass()) {
+          const CXXMethodDecl *KeyFunc = getCurrentKeyFunction(RD);
+          if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl())
+            return true;
+        }
       }
     }
 
index 08f6d5c..72851df 100644 (file)
@@ -795,8 +795,6 @@ protected:
 
   RecordLayoutBuilder(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
   void operator=(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
-public:
-  static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
 };
 } // end anonymous namespace
 
@@ -2347,8 +2345,8 @@ void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
         << D->getIdentifier();
 }
 
-const CXXMethodDecl *
-RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
+static const CXXMethodDecl *computeKeyFunction(ASTContext &Context,
+                                               const CXXRecordDecl *RD) {
   // If a class isn't polymorphic it doesn't have a key function.
   if (!RD->isPolymorphic())
     return 0;
@@ -2366,6 +2364,9 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
       TSK == TSK_ExplicitInstantiationDefinition)
     return 0;
 
+  bool allowInlineFunctions =
+    Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline();
+
   for (CXXRecordDecl::method_iterator I = RD->method_begin(),
          E = RD->method_end(); I != E; ++I) {
     const CXXMethodDecl *MD = *I;
@@ -2391,6 +2392,13 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
     if (!MD->isUserProvided())
       continue;
 
+    // In certain ABIs, ignore functions with out-of-line inline definitions.
+    if (!allowInlineFunctions) {
+      const FunctionDecl *Def;
+      if (MD->hasBody(Def) && Def->isInlineSpecified())
+        continue;
+    }
+
     // We found it.
     return MD;
   }
@@ -2496,15 +2504,37 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
   return *NewEntry;
 }
 
-const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
+const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) {
+  assert(RD->getDefinition() && "Cannot get key function for forward decl!");
   RD = cast<CXXRecordDecl>(RD->getDefinition());
-  assert(RD && "Cannot get key function for forward declarations!");
 
-  const CXXMethodDecl *&Entry = KeyFunctions[RD];
-  if (!Entry)
-    Entry = RecordLayoutBuilder::ComputeKeyFunction(RD);
+  const CXXMethodDecl *&entry = KeyFunctions[RD];
+  if (!entry) {
+    entry = computeKeyFunction(*this, RD);
+  }
+
+  return entry;
+}
+
+void ASTContext::setNonKeyFunction(const CXXMethodDecl *method) {
+  assert(method == method->getFirstDeclaration() &&
+         "not working with method declaration from class definition");
 
-  return Entry;
+  // Look up the cache entry.  Since we're working with the first
+  // declaration, its parent must be the class definition, which is
+  // the correct key for the KeyFunctions hash.
+  llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*>::iterator
+    i = KeyFunctions.find(method->getParent());
+
+  // If it's not cached, there's nothing to do.
+  if (i == KeyFunctions.end()) return;
+
+  // If it is cached, check whether it's the target method, and if so,
+  // remove it from the cache.
+  if (i->second == method) {
+    // FIXME: remember that we did this for module / chained PCH state?
+    KeyFunctions.erase(i);
+  }
 }
 
 static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD) {
index a3e49d8..60e1020 100644 (file)
@@ -294,11 +294,6 @@ public:
   /// \param addr - a pointer to pass to the destructor function.
   virtual void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor,
                                   llvm::Constant *addr);
-
-  /***************************** Virtual Tables *******************************/
-
-  /// Generates and emits the virtual tables for a class.
-  virtual void EmitVTables(const CXXRecordDecl *Class) = 0;
 };
 
 /// Creates an instance of a C++ ABI class.
index 3d65892..366ce29 100644 (file)
@@ -251,10 +251,12 @@ static bool IsStandardLibraryRTTIDescriptor(QualType Ty) {
 /// the given type exists somewhere else, and that we should not emit the type
 /// information in this translation unit.  Assumes that it is not a
 /// standard-library type.
-static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) {
+static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM,
+                                            QualType Ty) {
   ASTContext &Context = CGM.getContext();
 
-  // If RTTI is disabled, don't consider key functions.
+  // If RTTI is disabled, assume it might be disabled in the
+  // translation unit that defines any potential key function, too.
   if (!Context.getLangOpts().RTTI) return false;
 
   if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
@@ -265,7 +267,9 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) {
     if (!RD->isDynamicClass())
       return false;
 
-    return !CGM.getVTables().ShouldEmitVTableInThisTU(RD);
+    // FIXME: this may need to be reconsidered if the key function
+    // changes.
+    return CGM.getVTables().isVTableExternal(RD);
   }
   
   return false;
index 64c7939..6d40219 100644 (file)
@@ -31,33 +31,6 @@ using namespace CodeGen;
 CodeGenVTables::CodeGenVTables(CodeGenModule &CGM)
   : CGM(CGM), VTContext(CGM.getContext()) { }
 
-bool CodeGenVTables::ShouldEmitVTableInThisTU(const CXXRecordDecl *RD) {
-  assert(RD->isDynamicClass() && "Non dynamic classes have no VTable.");
-
-  TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind();
-  if (TSK == TSK_ExplicitInstantiationDeclaration)
-    return false;
-
-  const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD);
-  if (!KeyFunction)
-    return true;
-
-  // Itanium C++ ABI, 5.2.6 Instantiated Templates:
-  //    An instantiation of a class template requires:
-  //        - In the object where instantiated, the virtual table...
-  if (TSK == TSK_ImplicitInstantiation ||
-      TSK == TSK_ExplicitInstantiationDefinition)
-    return true;
-
-  // If we're building with optimization, we always emit VTables since that
-  // allows for virtual function calls to be devirtualized.
-  // (We don't want to do this in -fapple-kext mode however).
-  if (CGM.getCodeGenOpts().OptimizationLevel && !CGM.getLangOpts().AppleKext)
-    return true;
-
-  return KeyFunction->hasBody();
-}
-
 llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, 
                                               const ThunkInfo &Thunk) {
   const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
@@ -645,9 +618,8 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
   if (VTable)
     return VTable;
 
-  // We may need to generate a definition for this vtable.
-  if (ShouldEmitVTableInThisTU(RD))
-    CGM.DeferredVTables.push_back(RD);
+  // Queue up this v-table for possible deferred emission.
+  CGM.addDeferredVTable(RD);
 
   SmallString<256> OutName;
   llvm::raw_svector_ostream Out(OutName);
@@ -734,13 +706,108 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
   return VTable;
 }
 
+/// Compute the required linkage of the v-table for the given class.
+///
+/// Note that we only call this at the end of the translation unit.
+llvm::GlobalVariable::LinkageTypes 
+CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
+  if (RD->getLinkage() != ExternalLinkage)
+    return llvm::GlobalVariable::InternalLinkage;
+
+  // We're at the end of the translation unit, so the current key
+  // function is fully correct.
+  if (const CXXMethodDecl *keyFunction = Context.getCurrentKeyFunction(RD)) {
+    // If this class has a key function, use that to determine the
+    // linkage of the vtable.
+    const FunctionDecl *def = 0;
+    if (keyFunction->hasBody(def))
+      keyFunction = cast<CXXMethodDecl>(def);
+    
+    switch (keyFunction->getTemplateSpecializationKind()) {
+      case TSK_Undeclared:
+      case TSK_ExplicitSpecialization:
+        // When compiling with optimizations turned on, we emit all vtables,
+        // even if the key function is not defined in the current translation
+        // unit. If this is the case, use available_externally linkage.
+        if (!def && CodeGenOpts.OptimizationLevel)
+          return llvm::GlobalVariable::AvailableExternallyLinkage;
+
+        if (keyFunction->isInlined())
+          return !Context.getLangOpts().AppleKext ?
+                   llvm::GlobalVariable::LinkOnceODRLinkage :
+                   llvm::Function::InternalLinkage;
+        
+        return llvm::GlobalVariable::ExternalLinkage;
+        
+      case TSK_ImplicitInstantiation:
+        return !Context.getLangOpts().AppleKext ?
+                 llvm::GlobalVariable::LinkOnceODRLinkage :
+                 llvm::Function::InternalLinkage;
+
+      case TSK_ExplicitInstantiationDefinition:
+        return !Context.getLangOpts().AppleKext ?
+                 llvm::GlobalVariable::WeakODRLinkage :
+                 llvm::Function::InternalLinkage;
+  
+      case TSK_ExplicitInstantiationDeclaration:
+        // FIXME: Use available_externally linkage. However, this currently
+        // breaks LLVM's build due to undefined symbols.
+        //      return llvm::GlobalVariable::AvailableExternallyLinkage;
+        return !Context.getLangOpts().AppleKext ?
+                 llvm::GlobalVariable::LinkOnceODRLinkage :
+                 llvm::Function::InternalLinkage;
+    }
+  }
+
+  // -fapple-kext mode does not support weak linkage, so we must use
+  // internal linkage.
+  if (Context.getLangOpts().AppleKext)
+    return llvm::Function::InternalLinkage;
+  
+  switch (RD->getTemplateSpecializationKind()) {
+  case TSK_Undeclared:
+  case TSK_ExplicitSpecialization:
+  case TSK_ImplicitInstantiation:
+    return llvm::GlobalVariable::LinkOnceODRLinkage;
+
+  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::LinkOnceODRLinkage;
+
+  case TSK_ExplicitInstantiationDefinition:
+      return llvm::GlobalVariable::WeakODRLinkage;
+  }
+
+  llvm_unreachable("Invalid TemplateSpecializationKind!");
+}
+
+/// This is a callback from Sema to tell us that it believes that a
+/// particular v-table is required to be emitted in this translation
+/// unit.
+///
+/// The reason we don't simply trust this callback is because Sema
+/// will happily report that something is used even when it's used
+/// only in code that we don't actually have to emit.
+///
+/// \param isRequired - if true, the v-table is mandatory, e.g.
+///   because the translation unit defines the key function
+void CodeGenModule::EmitVTable(CXXRecordDecl *theClass, bool isRequired) {
+  if (!isRequired) return;
+
+  VTables.GenerateClassData(theClass);
+}
+
 void 
-CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
-                                  const CXXRecordDecl *RD) {
+CodeGenVTables::GenerateClassData(const CXXRecordDecl *RD) {
+  // First off, check whether we've already emitted the v-table and
+  // associated stuff.
   llvm::GlobalVariable *VTable = GetAddrOfVTable(RD);
   if (VTable->hasInitializer())
     return;
 
+  llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
   EmitVTableDefinition(VTable, Linkage, RD);
 
   if (RD->getNumVBases()) {
@@ -760,3 +827,80 @@ CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
       DC->getParent()->isTranslationUnit())
     CGM.EmitFundamentalRTTIDescriptors();
 }
+
+/// At this point in the translation unit, does it appear that can we
+/// rely on the vtable being defined elsewhere in the program?
+///
+/// The response is really only definitive when called at the end of
+/// the translation unit.
+///
+/// The only semantic restriction here is that the object file should
+/// not contain a v-table definition when that v-table is defined
+/// strongly elsewhere.  Otherwise, we'd just like to avoid emitting
+/// v-tables when unnecessary.
+bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
+  assert(RD->isDynamicClass() && "Non dynamic classes have no VTable.");
+
+  // If we have an explicit instantiation declaration (and not a
+  // definition), the v-table is defined elsewhere.
+  TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind();
+  if (TSK == TSK_ExplicitInstantiationDeclaration)
+    return true;
+
+  // Otherwise, if the class is an instantiated template, the
+  // v-table must be defined here.
+  if (TSK == TSK_ImplicitInstantiation ||
+      TSK == TSK_ExplicitInstantiationDefinition)
+    return false;
+
+  // Otherwise, if the class doesn't have a key function (possibly
+  // anymore), the v-table must be defined here.
+  const CXXMethodDecl *keyFunction = CGM.getContext().getCurrentKeyFunction(RD);
+  if (!keyFunction)
+    return false;
+
+  // Otherwise, if we don't have a definition of the key function, the
+  // v-table must be defined somewhere else.
+  return !keyFunction->hasBody();
+}
+
+/// Given that we're currently at the end of the translation unit, and
+/// we've emitted a reference to the v-table for this class, should
+/// we define that v-table?
+static bool shouldEmitVTableAtEndOfTranslationUnit(CodeGenModule &CGM,
+                                                   const CXXRecordDecl *RD) {
+  // If we're building with optimization, we always emit v-tables
+  // since that allows for virtual function calls to be devirtualized.
+  // If the v-table is defined strongly elsewhere, this definition
+  // will be emitted available_externally.
+  //
+  // However, we don't want to do this in -fapple-kext mode, because
+  // kext mode does not permit devirtualization.
+  if (CGM.getCodeGenOpts().OptimizationLevel && !CGM.getLangOpts().AppleKext)
+    return true;
+
+  return !CGM.getVTables().isVTableExternal(RD);
+}
+
+/// Given that at some point we emitted a reference to one or more
+/// v-tables, and that we are now at the end of the translation unit,
+/// decide whether we should emit them.
+void CodeGenModule::EmitDeferredVTables() {
+#ifndef NDEBUG
+  // Remember the size of DeferredVTables, because we're going to assume
+  // that this entire operation doesn't modify it.
+  size_t savedSize = DeferredVTables.size();
+#endif
+
+  typedef std::vector<const CXXRecordDecl *>::const_iterator const_iterator;
+  for (const_iterator i = DeferredVTables.begin(),
+                      e = DeferredVTables.end(); i != e; ++i) {
+    const CXXRecordDecl *RD = *i;
+    if (shouldEmitVTableAtEndOfTranslationUnit(*this, RD))
+      VTables.GenerateClassData(RD);
+  }
+
+  assert(savedSize == DeferredVTables.size() &&
+         "deferred extra v-tables during v-table emission?");
+  DeferredVTables.clear();
+}
index 5f3d814..bd3bdb1 100644 (file)
@@ -77,10 +77,6 @@ public:
 
   VTableContext &getVTableContext() { return VTContext; }
 
-  /// \brief True if the VTable of this record must be emitted in the
-  /// translation unit.
-  bool ShouldEmitVTableInThisTU(const CXXRecordDecl *RD);
-
   /// needsVTTParameter - Return whether the given global decl needs a VTT
   /// parameter, which it does if it's a base constructor or destructor with
   /// virtual bases.
@@ -127,13 +123,13 @@ public:
   /// EmitThunks - Emit the associated thunks for the given global decl.
   void EmitThunks(GlobalDecl GD);
     
-  /// GenerateClassData - Generate all the class data required to be generated
-  /// upon definition of a KeyFunction.  This includes the vtable, the
-  /// rtti data structure and the VTT.
-  ///
-  /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT.
-  void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
-                         const CXXRecordDecl *RD);
+  /// GenerateClassData - Generate all the class data required to be
+  /// generated upon definition of a KeyFunction.  This includes the
+  /// vtable, the RTTI data structure (if RTTI is enabled) and the VTT
+  /// (if the class has virtual bases).
+  void GenerateClassData(const CXXRecordDecl *RD);
+
+  bool isVTableExternal(const CXXRecordDecl *RD);
 };
 
 } // end namespace CodeGen
index 2da9dba..9d78549 100644 (file)
@@ -371,7 +371,9 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV,
   // that don't have the key function's definition.  But ignore
   // this if we're emitting RTTI under -fno-rtti.
   if (!(TVK != TVK_ForRTTI) || LangOpts.RTTI) {
-    if (Context.getKeyFunction(RD))
+    // FIXME: what should we do if we "lose" the key function during
+    // the emission of the file?
+    if (Context.getCurrentKeyFunction(RD))
       return;
   }
 
@@ -836,14 +838,19 @@ void CodeGenModule::EmitDeferred() {
   // previously unused static decl may become used during the generation of code
   // for a static function, iterate until no changes are made.
 
-  while (!DeferredDeclsToEmit.empty() || !DeferredVTables.empty()) {
+  while (true) {
     if (!DeferredVTables.empty()) {
-      const CXXRecordDecl *RD = DeferredVTables.back();
-      DeferredVTables.pop_back();
-      getCXXABI().EmitVTables(RD);
-      continue;
+      EmitDeferredVTables();
+
+      // Emitting a v-table doesn't directly cause more v-tables to
+      // become deferred, although it can cause functions to be
+      // emitted that then need those v-tables.
+      assert(DeferredVTables.empty());
     }
 
+    // Stop if we're out of both deferred v-tables and deferred declarations.
+    if (DeferredDeclsToEmit.empty()) break;
+
     GlobalDecl D = DeferredDeclsToEmit.back();
     DeferredDeclsToEmit.pop_back();
 
@@ -1526,80 +1533,6 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
   EmitGlobalVarDefinition(D);
 }
 
-void CodeGenModule::EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired) {
-  if (DefinitionRequired)
-    getCXXABI().EmitVTables(Class);
-}
-
-llvm::GlobalVariable::LinkageTypes 
-CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
-  if (RD->getLinkage() != ExternalLinkage)
-    return llvm::GlobalVariable::InternalLinkage;
-
-  if (const CXXMethodDecl *KeyFunction
-                                    = RD->getASTContext().getKeyFunction(RD)) {
-    // If this class has a key function, use that to determine the linkage of
-    // the vtable.
-    const FunctionDecl *Def = 0;
-    if (KeyFunction->hasBody(Def))
-      KeyFunction = cast<CXXMethodDecl>(Def);
-    
-    switch (KeyFunction->getTemplateSpecializationKind()) {
-      case TSK_Undeclared:
-      case TSK_ExplicitSpecialization:
-        // When compiling with optimizations turned on, we emit all vtables,
-        // even if the key function is not defined in the current translation
-        // unit. If this is the case, use available_externally linkage.
-        if (!Def && CodeGenOpts.OptimizationLevel)
-          return llvm::GlobalVariable::AvailableExternallyLinkage;
-
-        if (KeyFunction->isInlined())
-          return !Context.getLangOpts().AppleKext ?
-                   llvm::GlobalVariable::LinkOnceODRLinkage :
-                   llvm::Function::InternalLinkage;
-        
-        return llvm::GlobalVariable::ExternalLinkage;
-        
-      case TSK_ImplicitInstantiation:
-        return !Context.getLangOpts().AppleKext ?
-                 llvm::GlobalVariable::LinkOnceODRLinkage :
-                 llvm::Function::InternalLinkage;
-
-      case TSK_ExplicitInstantiationDefinition:
-        return !Context.getLangOpts().AppleKext ?
-                 llvm::GlobalVariable::WeakODRLinkage :
-                 llvm::Function::InternalLinkage;
-  
-      case TSK_ExplicitInstantiationDeclaration:
-        // FIXME: Use available_externally linkage. However, this currently
-        // breaks LLVM's build due to undefined symbols.
-        //      return llvm::GlobalVariable::AvailableExternallyLinkage;
-        return !Context.getLangOpts().AppleKext ?
-                 llvm::GlobalVariable::LinkOnceODRLinkage :
-                 llvm::Function::InternalLinkage;
-    }
-  }
-  
-  if (Context.getLangOpts().AppleKext)
-    return llvm::Function::InternalLinkage;
-  
-  switch (RD->getTemplateSpecializationKind()) {
-  case TSK_Undeclared:
-  case TSK_ExplicitSpecialization:
-  case TSK_ImplicitInstantiation:
-    // FIXME: Use available_externally linkage. However, this currently
-    // breaks LLVM's build due to undefined symbols.
-    //   return llvm::GlobalVariable::AvailableExternallyLinkage;
-  case TSK_ExplicitInstantiationDeclaration:
-    return llvm::GlobalVariable::LinkOnceODRLinkage;
-
-  case TSK_ExplicitInstantiationDefinition:
-      return llvm::GlobalVariable::WeakODRLinkage;
-  }
-
-  llvm_unreachable("Invalid TemplateSpecializationKind!");
-}
-
 CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
     return Context.toCharUnitsFromBits(
       TheDataLayout.getTypeStoreSizeInBits(Ty));
index 0f01120..75c5e93 100644 (file)
@@ -258,6 +258,9 @@ class CodeGenModule : public CodeGenTypeCache {
   /// is done.
   std::vector<GlobalDecl> DeferredDeclsToEmit;
 
+  /// DeferredVTables - A queue of (optional) vtables to consider emitting.
+  std::vector<const CXXRecordDecl*> DeferredVTables;
+
   /// LLVMUsed - List of global values which are required to be
   /// present in the object file; bitcast to i8*. This is used for
   /// forcing visibility of symbols which may otherwise be optimized
@@ -865,8 +868,6 @@ public:
   GetLLVMLinkageVarDefinition(const VarDecl *D,
                               llvm::GlobalVariable *GV);
   
-  std::vector<const CXXRecordDecl*> DeferredVTables;
-
   /// Emit all the global annotations.
   void EmitGlobalAnnotations();
 
@@ -900,6 +901,10 @@ public:
 
   const SanitizerOptions &getSanOpts() const { return SanOpts; }
 
+  void addDeferredVTable(const CXXRecordDecl *RD) {
+    DeferredVTables.push_back(RD);
+  }
+
 private:
   llvm::GlobalValue *GetGlobalValue(StringRef Ref);
 
@@ -1002,6 +1007,10 @@ private:
   /// was deferred.
   void EmitDeferred();
 
+  /// EmitDeferredVTables - Emit any vtables which we deferred and
+  /// still have a use for.
+  void EmitDeferredVTables();
+
   /// EmitLLVMUsed - Emit the llvm.used metadata used to force
   /// references to global which may otherwise be optimized out.
   void EmitLLVMUsed();
index b761055..9fce392 100644 (file)
@@ -129,8 +129,6 @@ public:
                        llvm::GlobalVariable *DeclPtr, bool PerformInit);
   void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor,
                           llvm::Constant *addr);
-
-  void EmitVTables(const CXXRecordDecl *Class);
 };
 
 class ARMCXXABI : public ItaniumCXXABI {
@@ -1180,8 +1178,3 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
 
   CGF.registerGlobalDtorWithAtExit(dtor, addr);
 }
-
-/// Generate and emit virtual tables for the given class.
-void ItaniumCXXABI::EmitVTables(const CXXRecordDecl *Class) {
-  CGM.getVTables().GenerateClassData(CGM.getVTableLinkage(Class), Class);
-}
index 8e49292..477720b 100644 (file)
@@ -60,9 +60,6 @@ public:
                        llvm::GlobalVariable *DeclPtr,
                        bool PerformInit);
 
-  void EmitVTables(const CXXRecordDecl *Class);
-
-
   // ==== Notes on array cookies =========
   //
   // MSVC seems to only use cookies when the class has a destructor; a
@@ -206,10 +203,6 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
   CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit);
 }
 
-void MicrosoftCXXABI::EmitVTables(const CXXRecordDecl *Class) {
-  CGM.getVTables().GenerateClassData(CGM.getVTableLinkage(Class), Class);
-}
-
 CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
   return new MicrosoftCXXABI(CGM);
 }
index 19da55c..c03d41e 100644 (file)
@@ -543,7 +543,7 @@ void Sema::ActOnEndOfTranslationUnit() {
          I != E; ++I) {
       assert(!(*I)->isDependentType() &&
              "Should not see dependent types here!");
-      if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(*I)) {
+      if (const CXXMethodDecl *KeyFunction = Context.getCurrentKeyFunction(*I)) {
         const FunctionDecl *Definition = 0;
         if (KeyFunction->hasBody(Definition))
           MarkVTableUsed(Definition->getLocation(), *I, true);
index 9efcb52..d584ed8 100644 (file)
@@ -6362,9 +6362,31 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
       }
       
     } else {
-      if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions
-        NewFD->setAccess(OldDecl->getAccess());
+      // This needs to happen first so that 'inline' propagates.
       NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
+
+      if (isa<CXXMethodDecl>(NewFD)) {
+        // A valid redeclaration of a C++ method must be out-of-line,
+        // but (unfortunately) it's not necessarily a definition
+        // because of templates, which means that the previous
+        // declaration is not necessarily from the class definition.
+
+        // For just setting the access, that doesn't matter.
+        CXXMethodDecl *oldMethod = cast<CXXMethodDecl>(OldDecl);
+        NewFD->setAccess(oldMethod->getAccess());
+
+        // Update the key-function state if necessary for this ABI.
+        if (NewFD->isInlined() &&
+            !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) {
+          // setNonKeyFunction needs to work with the original
+          // declaration from the class definition, and isVirtual() is
+          // just faster in that case, so map back to that now.
+          oldMethod = cast<CXXMethodDecl>(oldMethod->getFirstDeclaration());
+          if (oldMethod->isVirtual()) {
+            Context.setNonKeyFunction(oldMethod);
+          }
+        }
+      }
     }
   }
 
index 515fd91..448d083 100644 (file)
@@ -11217,7 +11217,7 @@ bool Sema::DefineUsedVTables() {
     // If this class has a key function, but that key function is
     // defined in another translation unit, we don't need to emit the
     // vtable even though we're using it.
-    const CXXMethodDecl *KeyFunction = Context.getKeyFunction(Class);
+    const CXXMethodDecl *KeyFunction = Context.getCurrentKeyFunction(Class);
     if (KeyFunction && !KeyFunction->hasBody()) {
       switch (KeyFunction->getTemplateSpecializationKind()) {
       case TSK_Undeclared:
index dca93f7..cd4eb31 100644 (file)
@@ -942,10 +942,10 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
     Record.push_back(CXXRecNotTemplate);
   }
 
-  // Store the key function to avoid deserializing every method so we can
-  // compute it.
+  // Store (what we currently believe to be) the key function to avoid
+  // deserializing every method so we can compute it.
   if (D->IsCompleteDefinition)
-    Writer.AddDeclRef(Context.getKeyFunction(D), Record);
+    Writer.AddDeclRef(Context.getCurrentKeyFunction(D), Record);
 
   Code = serialization::DECL_CXX_RECORD;
 }
index 23baac9..693b36a 100644 (file)
@@ -6,13 +6,14 @@
 
 #include <typeinfo>
 
-// Test1::A's key function (f) is not defined in this translation unit, but in
-// order to devirtualize calls, we emit the class related data with
+// Test1::A's key function (f) is not defined in this translation
+// unit, but in order to devirtualize calls, we emit the v-table with
 // available_externally linkage.
+//
+// There's no real reason to do this to the RTTI, though.
 
 // CHECK-TEST1: @_ZTVN5Test11AE = available_externally
-// CHECK-TEST1: @_ZTSN5Test11AE = available_externally
-// CHECK-TEST1: @_ZTIN5Test11AE = available_externally
+// CHECK-TEST1: @_ZTIN5Test11AE = external constant i8*
 namespace Test1 {
 
 struct A {
diff --git a/clang/test/CodeGenCXX/vtable-key-function-arm.cpp b/clang/test/CodeGenCXX/vtable-key-function-arm.cpp
new file mode 100644 (file)
index 0000000..08efe8a
--- /dev/null
@@ -0,0 +1,307 @@
+// RUN: %clang_cc1 %s -triple=armv7-unknown-unknown -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=armv7-unknown-unknown -emit-llvm -o - | FileCheck -check-prefix=CHECK-LATE %s
+
+// The 'a' variants ask for the v-table first.
+// The 'b' variants ask for the v-table second.
+// The 'c' variants ask for the v-table third.
+// We do a separate CHECK-LATE pass because the RTTI defintion gets
+// changed after the fact, which causes reordering of the globals.
+
+// These are not separated into namespaces because the way that Sema
+// currently reports namespaces to IR-generation (i.e., en masse for
+// the entire namespace at once) subverts the ordering that we're
+// trying to test.
+
+namespace std { class type_info; }
+extern void use(const std::type_info &rtti);
+
+/*** Test0a ******************************************************************/
+
+struct Test0a {
+  Test0a();
+  virtual inline void foo();
+  virtual void bar();
+};
+
+// V-table should be defined externally.
+Test0a::Test0a() { use(typeid(Test0a)); }
+// CHECK: @_ZTV6Test0a = external unnamed_addr constant 
+// CHECK: @_ZTI6Test0a = external constant
+
+// This is still not a key function.
+void Test0a::foo() {}
+
+/*** Test0b ******************************************************************/
+
+struct Test0b {
+  Test0b();
+  virtual inline void foo();
+  virtual void bar();
+};
+
+// This is still not a key function.
+void Test0b::foo() {}
+
+// V-table should be defined externally.
+Test0b::Test0b() { use(typeid(Test0b)); }
+// CHECK: @_ZTV6Test0b = external unnamed_addr constant 
+// CHECK: @_ZTI6Test0b = external constant
+
+/*** Test1a ******************************************************************/
+
+struct Test1a {
+  Test1a();
+  virtual void foo();
+  virtual void bar();
+};
+
+// V-table should be defined externally.
+Test1a::Test1a() { use(typeid(Test1a)); }
+// CHECK: @_ZTV6Test1a = external unnamed_addr constant 
+// CHECK: @_ZTI6Test1a = external constant
+
+// 'bar' becomes the key function when 'foo' is defined inline.
+inline void Test1a::foo() {}
+
+/*** Test1b ******************************************************************/
+
+struct Test1b {
+  Test1b();
+  virtual void foo();
+  virtual void bar();
+};
+
+// 'bar' becomes the key function when 'foo' is defined inline.
+inline void Test1b::foo() {}
+
+// V-table should be defined externally.
+Test1b::Test1b() { use(typeid(Test1b)); }
+// CHECK: @_ZTV6Test1b = external unnamed_addr constant 
+// CHECK: @_ZTI6Test1b = external constant
+
+/*** Test2a ******************************************************************/
+
+struct Test2a {
+  Test2a();
+  virtual void foo();
+  virtual void bar();
+};
+
+// V-table should be defined with strong linkage.
+Test2a::Test2a() { use(typeid(Test2a)); }
+// CHECK:      @_ZTV6Test2a = unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test2a = constant
+// CHECK-LATE: @_ZTI6Test2a = unnamed_addr constant
+
+// 'bar' becomes the key function when 'foo' is defined inline.
+void Test2a::bar() {}
+inline void Test2a::foo() {}
+
+/*** Test2b ******************************************************************/
+
+struct Test2b {
+  Test2b();
+  virtual void foo();
+  virtual void bar();
+};
+
+// 'bar' becomes the key function when 'foo' is defined inline.
+void Test2b::bar() {}
+
+// V-table should be defined with strong linkage.
+Test2b::Test2b() { use(typeid(Test2b)); }
+// CHECK:      @_ZTV6Test2b = unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test2b = constant
+// CHECK-LATE: @_ZTI6Test2b = unnamed_addr constant
+
+inline void Test2b::foo() {}
+
+/*** Test2c ******************************************************************/
+
+struct Test2c {
+  Test2c();
+  virtual void foo();
+  virtual void bar();
+};
+
+// 'bar' becomes the key function when 'foo' is defined inline.
+void Test2c::bar() {}
+inline void Test2c::foo() {}
+
+// V-table should be defined with strong linkage.
+Test2c::Test2c() { use(typeid(Test2c)); }
+// CHECK: @_ZTV6Test2c = unnamed_addr constant
+// CHECK: @_ZTS6Test2c = constant
+// CHECK: @_ZTI6Test2c = unnamed_addr constant
+
+/*** Test3a ******************************************************************/
+
+struct Test3a {
+  Test3a();
+  virtual void foo();
+  virtual void bar();
+};
+
+// V-table should be defined with weak linkage.
+Test3a::Test3a() { use(typeid(Test3a)); }
+// CHECK:      @_ZTV6Test3a = linkonce_odr unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test3a = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test3a = linkonce_odr unnamed_addr constant
+
+// There ceases to be a key function after these declarations.
+inline void Test3a::bar() {}
+inline void Test3a::foo() {}
+
+/*** Test3b ******************************************************************/
+
+struct Test3b {
+  Test3b();
+  virtual void foo();
+  virtual void bar();
+};
+
+// There ceases to be a key function after these declarations.
+inline void Test3b::bar() {}
+
+// V-table should be defined with weak linkage.
+Test3b::Test3b() { use(typeid(Test3b)); }
+// CHECK:      @_ZTV6Test3b = linkonce_odr unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test3b = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test3b = linkonce_odr unnamed_addr constant
+
+inline void Test3b::foo() {}
+
+/*** Test3c ******************************************************************/
+
+struct Test3c {
+  Test3c();
+  virtual void foo();
+  virtual void bar();
+};
+
+// There ceases to be a key function after these declarations.
+inline void Test3c::bar() {}
+inline void Test3c::foo() {}
+
+// V-table should be defined with weak linkage.
+Test3c::Test3c() { use(typeid(Test3c)); }
+// CHECK: @_ZTV6Test3c = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test3c = linkonce_odr constant
+// CHECK: @_ZTI6Test3c = linkonce_odr unnamed_addr constant
+
+/*** Test4a ******************************************************************/
+
+template <class T> struct Test4a {
+  Test4a();
+  virtual void foo();
+  virtual void bar();
+};
+
+// V-table should be defined with weak linkage.
+template <> Test4a<int>::Test4a() { use(typeid(Test4a)); }
+// CHECK: @_ZTV6Test4aIiE = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test4aIiE = linkonce_odr constant
+// CHECK: @_ZTI6Test4aIiE = linkonce_odr unnamed_addr constant
+
+// There ceases to be a key function after these declarations.
+template <> inline void Test4a<int>::bar() {}
+template <> inline void Test4a<int>::foo() {}
+
+/*** Test4b ******************************************************************/
+
+template <class T> struct Test4b {
+  Test4b();
+  virtual void foo();
+  virtual void bar();
+};
+
+// There ceases to be a key function after these declarations.
+template <> inline void Test4b<int>::bar() {}
+
+// V-table should be defined with weak linkage.
+template <> Test4b<int>::Test4b() { use(typeid(Test4b)); }
+// CHECK: @_ZTV6Test4bIiE = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test4bIiE = linkonce_odr constant
+// CHECK: @_ZTI6Test4bIiE = linkonce_odr unnamed_addr constant
+
+template <> inline void Test4b<int>::foo() {}
+
+/*** Test4c ******************************************************************/
+
+template <class T> struct Test4c {
+  Test4c();
+  virtual void foo();
+  virtual void bar();
+};
+
+// There ceases to be a key function after these declarations.
+template <> inline void Test4c<int>::bar() {}
+template <> inline void Test4c<int>::foo() {}
+
+// V-table should be defined with weak linkage.
+template <> Test4c<int>::Test4c() { use(typeid(Test4c)); }
+// CHECK: @_ZTV6Test4cIiE = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test4cIiE = linkonce_odr constant
+// CHECK: @_ZTI6Test4cIiE = linkonce_odr unnamed_addr constant
+
+/*** Test5a ******************************************************************/
+
+template <class T> struct Test5a {
+  Test5a();
+  virtual void foo();
+  virtual void bar();
+};
+
+template <> inline void Test5a<int>::bar();
+template <> inline void Test5a<int>::foo();
+
+// V-table should be defined with weak linkage.
+template <> Test5a<int>::Test5a() { use(typeid(Test5a)); }
+// CHECK: @_ZTV6Test5aIiE = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test5aIiE = linkonce_odr constant
+// CHECK: @_ZTI6Test5aIiE = linkonce_odr unnamed_addr constant
+
+// There ceases to be a key function after these declarations.
+template <> inline void Test5a<int>::bar() {}
+template <> inline void Test5a<int>::foo() {}
+
+/*** Test5b ******************************************************************/
+
+template <class T> struct Test5b {
+  Test5b();
+  virtual void foo();
+  virtual void bar();
+};
+
+// There ceases to be a key function after these declarations.
+template <> inline void Test5a<int>::bar();
+template <> inline void Test5b<int>::bar() {}
+
+// V-table should be defined with weak linkage.
+template <> Test5b<int>::Test5b() { use(typeid(Test5b)); }
+// CHECK: @_ZTV6Test5bIiE = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test5bIiE = linkonce_odr constant
+// CHECK: @_ZTI6Test5bIiE = linkonce_odr unnamed_addr constant
+
+template <> inline void Test5a<int>::foo();
+template <> inline void Test5b<int>::foo() {}
+
+/*** Test5c ******************************************************************/
+
+template <class T> struct Test5c {
+  Test5c();
+  virtual void foo();
+  virtual void bar();
+};
+
+// There ceases to be a key function after these declarations.
+template <> inline void Test5a<int>::bar();
+template <> inline void Test5a<int>::foo();
+template <> inline void Test5c<int>::bar() {}
+template <> inline void Test5c<int>::foo() {}
+
+// V-table should be defined with weak linkage.
+template <> Test5c<int>::Test5c() { use(typeid(Test5c)); }
+// CHECK: @_ZTV6Test5cIiE = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test5cIiE = linkonce_odr constant
+// CHECK: @_ZTI6Test5cIiE = linkonce_odr unnamed_addr constant
diff --git a/clang/test/CodeGenCXX/vtable-key-function-ios.cpp b/clang/test/CodeGenCXX/vtable-key-function-ios.cpp
new file mode 100644 (file)
index 0000000..bcd3e88
--- /dev/null
@@ -0,0 +1,189 @@
+// RUN: %clang_cc1 %s -triple=armv7-apple-darwin -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=armv7-apple-darwin -emit-llvm -o - | FileCheck -check-prefix=CHECK-LATE %s
+
+// The 'a' variants ask for the v-table first.
+// The 'b' variants ask for the v-table second.
+// The 'c' variants ask for the v-table third.
+// We do a separate CHECK-LATE pass because the RTTI defintion gets
+// changed after the fact, which causes reordering of the globals.
+
+// These are not separated into namespaces because the way that Sema
+// currently reports namespaces to IR-generation (i.e., en masse for
+// the entire namespace at once) subverts the ordering that we're
+// trying to test.
+
+namespace std { class type_info; }
+extern void use(const std::type_info &rtti);
+
+/*** Test0a ******************************************************************/
+
+struct Test0a {
+  Test0a();
+  virtual inline void foo();
+  virtual void bar();
+};
+
+// V-table should be defined externally.
+Test0a::Test0a() { use(typeid(Test0a)); }
+// CHECK: @_ZTV6Test0a = external unnamed_addr constant 
+// CHECK: @_ZTI6Test0a = external constant
+
+// This is not a key function.
+void Test0a::foo() {}
+
+/*** Test0b ******************************************************************/
+
+struct Test0b {
+  Test0b();
+  virtual inline void foo();
+  virtual void bar();
+};
+
+// This is not a key function.
+void Test0b::foo() {}
+
+// V-table should be defined externally.
+Test0b::Test0b() { use(typeid(Test0b)); }
+// CHECK: @_ZTV6Test0b = external unnamed_addr constant 
+// CHECK: @_ZTI6Test0b = external constant
+
+/*** Test1a ******************************************************************/
+
+struct Test1a {
+  Test1a();
+  virtual void foo();
+  virtual void bar();
+};
+
+// V-table needs to be defined weakly.
+Test1a::Test1a() { use(typeid(Test1a)); }
+// CHECK:      @_ZTV6Test1a = linkonce_odr unnamed_addr constant 
+// CHECK-LATE: @_ZTS6Test1a = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test1a = linkonce_odr unnamed_addr constant
+
+// This defines the key function.
+inline void Test1a::foo() {}
+
+/*** Test1b ******************************************************************/
+
+struct Test1b {
+  Test1b();
+  virtual void foo();
+  virtual void bar();
+};
+
+// This defines the key function.
+inline void Test1b::foo() {}
+
+// V-table should be defined weakly..
+Test1b::Test1b() { use(typeid(Test1b)); }
+// CHECK: @_ZTV6Test1b = linkonce_odr unnamed_addr constant 
+// CHECK: @_ZTS6Test1b = linkonce_odr constant
+// CHECK: @_ZTI6Test1b = linkonce_odr unnamed_addr constant
+
+/*** Test2a ******************************************************************/
+
+struct Test2a {
+  Test2a();
+  virtual void foo();
+  virtual void bar();
+};
+
+// V-table should be defined with weak linkage.
+Test2a::Test2a() { use(typeid(Test2a)); }
+// CHECK:      @_ZTV6Test2a = linkonce_odr unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test2a = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test2a = linkonce_odr unnamed_addr constant
+
+void Test2a::bar() {}
+inline void Test2a::foo() {}
+
+/*** Test2b ******************************************************************/
+
+struct Test2b {
+  Test2b();
+  virtual void foo();
+  virtual void bar();
+};
+
+void Test2b::bar() {}
+
+// V-table should be defined with weak linkage.
+Test2b::Test2b() { use(typeid(Test2b)); }
+// CHECK:      @_ZTV6Test2b = linkonce_odr unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test2b = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test2b = linkonce_odr unnamed_addr constant
+
+inline void Test2b::foo() {}
+
+/*** Test2c ******************************************************************/
+
+struct Test2c {
+  Test2c();
+  virtual void foo();
+  virtual void bar();
+};
+
+void Test2c::bar() {}
+inline void Test2c::foo() {}
+
+// V-table should be defined with weak linkage.
+Test2c::Test2c() { use(typeid(Test2c)); }
+// CHECK: @_ZTV6Test2c = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test2c = linkonce_odr constant
+// CHECK: @_ZTI6Test2c = linkonce_odr unnamed_addr constant
+
+/*** Test3a ******************************************************************/
+
+struct Test3a {
+  Test3a();
+  virtual void foo();
+  virtual void bar();
+};
+
+// V-table should be defined with weak linkage.
+Test3a::Test3a() { use(typeid(Test3a)); }
+// CHECK:      @_ZTV6Test3a = linkonce_odr unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test3a = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test3a = linkonce_odr unnamed_addr constant
+
+// This defines the key function.
+inline void Test3a::bar() {}
+inline void Test3a::foo() {}
+
+/*** Test3b ******************************************************************/
+
+struct Test3b {
+  Test3b();
+  virtual void foo();
+  virtual void bar();
+};
+
+inline void Test3b::bar() {}
+
+// V-table should be defined with weak linkage.
+Test3b::Test3b() { use(typeid(Test3b)); }
+// CHECK:      @_ZTV6Test3b = linkonce_odr unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test3b = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test3b = linkonce_odr unnamed_addr constant
+
+// This defines the key function.
+inline void Test3b::foo() {}
+
+/*** Test3c ******************************************************************/
+
+struct Test3c {
+  Test3c();
+  virtual void foo();
+  virtual void bar();
+};
+
+// This defines the key function.
+inline void Test3c::bar() {}
+inline void Test3c::foo() {}
+
+// V-table should be defined with weak linkage.
+Test3c::Test3c() { use(typeid(Test3c)); }
+// CHECK: @_ZTV6Test3c = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test3c = linkonce_odr constant
+// CHECK: @_ZTI6Test3c = linkonce_odr unnamed_addr constant