[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