[cfe-commits] r173515 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ lib/AST/ lib/CodeGen/ lib/Sema/ lib/Serialization/ test/CodeGenCXX/

NAKAMURA Takumi geek4civic at gmail.com
Sat Jan 26 02:43:54 PST 2013


John, it triggered a failure in CodeGenCXX/key-function-vtable.cpp for
targeting arm.
http://lab.llvm.org:8011/builders/clang-native-arm-cortex-a9/builds/4622

It could be reproducible to add explicit -triple=arm-linux.

2013/1/26 John McCall <rjmccall at apple.com>:
> Author: rjmccall
> Date: Fri Jan 25 16:31:03 2013
> New Revision: 173515
>
> URL: http://llvm.org/viewvc/llvm-project?rev=173515&view=rev
> Log:
> The standard ARM C++ ABI dictates that inline functions are
> 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.
>
> Added:
>     cfe/trunk/test/CodeGenCXX/vtable-key-function-arm.cpp
>     cfe/trunk/test/CodeGenCXX/vtable-key-function-ios.cpp
> Modified:
>     cfe/trunk/include/clang/AST/ASTContext.h
>     cfe/trunk/include/clang/Basic/TargetCXXABI.h
>     cfe/trunk/lib/AST/ASTContext.cpp
>     cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
>     cfe/trunk/lib/CodeGen/CGCXXABI.h
>     cfe/trunk/lib/CodeGen/CGRTTI.cpp
>     cfe/trunk/lib/CodeGen/CGVTables.cpp
>     cfe/trunk/lib/CodeGen/CGVTables.h
>     cfe/trunk/lib/CodeGen/CodeGenModule.cpp
>     cfe/trunk/lib/CodeGen/CodeGenModule.h
>     cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
>     cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
>     cfe/trunk/lib/Sema/Sema.cpp
>     cfe/trunk/lib/Sema/SemaDecl.cpp
>     cfe/trunk/lib/Sema/SemaDeclCXX.cpp
>     cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
>     cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp
>
> Modified: cfe/trunk/include/clang/AST/ASTContext.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/ASTContext.h (original)
> +++ cfe/trunk/include/clang/AST/ASTContext.h Fri Jan 25 16:31:03 2013
> @@ -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;
>
> Modified: cfe/trunk/include/clang/Basic/TargetCXXABI.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetCXXABI.h?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/TargetCXXABI.h (original)
> +++ cfe/trunk/include/clang/Basic/TargetCXXABI.h Fri Jan 25 16:31:03 2013
> @@ -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);
>
>
> Modified: cfe/trunk/lib/AST/ASTContext.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/ASTContext.cpp (original)
> +++ cfe/trunk/lib/AST/ASTContext.cpp Fri Jan 25 16:31:03 2013
> @@ -7559,13 +7559,16 @@ bool ASTContext::DeclMustBeEmitted(const
>      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;
> +        }
>        }
>      }
>
>
> Modified: cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RecordLayoutBuilder.cpp?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/RecordLayoutBuilder.cpp (original)
> +++ cfe/trunk/lib/AST/RecordLayoutBuilder.cpp Fri Jan 25 16:31:03 2013
> @@ -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::CheckFieldPadd
>          << 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(
>        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(
>      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 Rec
>    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;
> +  return entry;
> +}
> +
> +void ASTContext::setNonKeyFunction(const CXXMethodDecl *method) {
> +  assert(method == method->getFirstDeclaration() &&
> +         "not working with method declaration from class definition");
> +
> +  // 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) {
>
> Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
> +++ cfe/trunk/lib/CodeGen/CGCXXABI.h Fri Jan 25 16:31:03 2013
> @@ -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.
>
> Modified: cfe/trunk/lib/CodeGen/CGRTTI.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRTTI.cpp?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGRTTI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGRTTI.cpp Fri Jan 25 16:31:03 2013
> @@ -251,10 +251,12 @@ static bool IsStandardLibraryRTTIDescrip
>  /// 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 ShouldUseExternalRTTIDescrip
>      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;
>
> Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGVTables.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGVTables.cpp Fri Jan 25 16:31:03 2013
> @@ -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::Ge
>    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::GenerateConstructionVTab
>    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::
>        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();
> +}
>
> Modified: cfe/trunk/lib/CodeGen/CGVTables.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.h?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGVTables.h (original)
> +++ cfe/trunk/lib/CodeGen/CGVTables.h Fri Jan 25 16:31:03 2013
> @@ -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
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Fri Jan 25 16:31:03 2013
> @@ -371,7 +371,9 @@ void CodeGenModule::setTypeVisibility(ll
>    // 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::EmitTentativeDefinit
>    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));
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Fri Jan 25 16:31:03 2013
> @@ -258,6 +258,9 @@ class CodeGenModule : public CodeGenType
>    /// 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();
>
> Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Fri Jan 25 16:31:03 2013
> @@ -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(C
>
>    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);
> -}
>
> Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Fri Jan 25 16:31:03 2013
> @@ -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(Co
>    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);
>  }
>
> Modified: cfe/trunk/lib/Sema/Sema.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/Sema.cpp (original)
> +++ cfe/trunk/lib/Sema/Sema.cpp Fri Jan 25 16:31:03 2013
> @@ -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);
>
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Jan 25 16:31:03 2013
> @@ -6362,9 +6362,31 @@ bool Sema::CheckFunctionDeclaration(Scop
>        }
>
>      } 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);
> +          }
> +        }
> +      }
>      }
>    }
>
>
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Jan 25 16:31:03 2013
> @@ -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:
>
> Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Fri Jan 25 16:31:03 2013
> @@ -942,10 +942,10 @@ void ASTDeclWriter::VisitCXXRecordDecl(C
>      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;
>  }
>
> Modified: cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp?rev=173515&r1=173514&r2=173515&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp Fri Jan 25 16:31:03 2013
> @@ -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 {
>
> Added: cfe/trunk/test/CodeGenCXX/vtable-key-function-arm.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-key-function-arm.cpp?rev=173515&view=auto
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/vtable-key-function-arm.cpp (added)
> +++ cfe/trunk/test/CodeGenCXX/vtable-key-function-arm.cpp Fri Jan 25 16:31:03 2013
> @@ -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
>
> Added: cfe/trunk/test/CodeGenCXX/vtable-key-function-ios.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-key-function-ios.cpp?rev=173515&view=auto
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/vtable-key-function-ios.cpp (added)
> +++ cfe/trunk/test/CodeGenCXX/vtable-key-function-ios.cpp Fri Jan 25 16:31:03 2013
> @@ -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
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list