diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-10-14 21:29:40 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-10-14 21:29:40 +0000 |
commit | 1028c9f0afc1cc5f4951b39b7067fa57c1fea07b (patch) | |
tree | 67145dd0903f4a08427f127d015b5f7ebdceaf1e | |
parent | 663b5a0be7261c29bc4c526a71cffcfa02d4153e (diff) |
Give explicit and implicit instantiations of static data members of
class templates the proper linkage.
Daniel, please look over the CodeGenModule bits.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84140 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/Decl.h | 8 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 21 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 45 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 | ||||
-rw-r--r-- | test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp | 26 |
5 files changed, 97 insertions, 11 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 972e1f6900..f21541c3e7 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -584,10 +584,14 @@ public: return getDeclContext()->isRecord(); } + /// \brief Determine whether this is or was instantiated from an out-of-line + /// definition of a static data member. + bool isOutOfLine() const; + /// \brief If this variable is an instantiated static data member of a /// class template specialization, returns the templated static data member /// from which it was instantiated. - VarDecl *getInstantiatedFromStaticDataMember(); + VarDecl *getInstantiatedFromStaticDataMember() const; /// \brief If this variable is a static data member, determine what kind of /// template specialization or instantiation this is. @@ -596,7 +600,7 @@ public: /// \brief If this variable is an instantiation of a static data member of a /// class template specialization, retrieves the member specialization /// information. - MemberSpecializationInfo *getMemberSpecializationInfo(); + MemberSpecializationInfo *getMemberSpecializationInfo() const; /// \brief For a static data member that was instantiated from a static /// data member of a class template, set the template specialiation kind. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index a908299bfe..da7959b16f 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -373,7 +373,23 @@ SourceRange VarDecl::getSourceRange() const { return SourceRange(getLocation(), getLocation()); } -VarDecl *VarDecl::getInstantiatedFromStaticDataMember() { +bool VarDecl::isOutOfLine() const { + if (!isStaticDataMember()) + return false; + + if (Decl::isOutOfLine()) + return true; + + // If this static data member was instantiated from a static data member of + // a class template, check whether that static data member was defined + // out-of-line. + if (VarDecl *VD = getInstantiatedFromStaticDataMember()) + return VD->isOutOfLine(); + + return false; +} + +VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return cast<VarDecl>(MSI->getInstantiatedFrom()); @@ -388,7 +404,7 @@ TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const { return TSK_Undeclared; } -MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() { +MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const { return getASTContext().getInstantiatedFromStaticDataMember(this); } @@ -809,7 +825,6 @@ FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { } bool FunctionDecl::isOutOfLine() const { - // FIXME: Should we restrict this to member functions? if (Decl::isOutOfLine()) return true; diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 36ad7f514e..ecf8eb0d27 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -541,7 +541,12 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { } } - return VD->getStorageClass() == VarDecl::Static; + // Static data may be deferred, but out-of-line static data members + // cannot be. + // FIXME: What if the initializer has side effects? + return VD->isInAnonymousNamespace() || + (VD->getStorageClass() == VarDecl::Static && + !(VD->isStaticDataMember() && VD->isOutOfLine())); } void CodeGenModule::EmitGlobal(GlobalDecl GD) { @@ -928,6 +933,37 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { EmitGlobalVarDefinition(D); } +static CodeGenModule::GVALinkage +GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { + // Everything located semantically within an anonymous namespace is + // always internal. + if (VD->isInAnonymousNamespace()) + return CodeGenModule::GVA_Internal; + + // Handle linkage for static data members. + if (VD->isStaticDataMember()) { + switch (VD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + case TSK_ExplicitInstantiationDefinition: + return CodeGenModule::GVA_StrongExternal; + + case TSK_ExplicitInstantiationDeclaration: + assert(false && "Variable should not be instantiated"); + // Fall through to treat this like any other instantiation. + + case TSK_ImplicitInstantiation: + return CodeGenModule::GVA_TemplateInstantiation; + } + } + + // Static variables get internal linkage. + if (VD->getStorageClass() == VarDecl::Static) + return CodeGenModule::GVA_Internal; + + return CodeGenModule::GVA_StrongExternal; +} + void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { llvm::Constant *Init = 0; QualType ASTTy = D->getType(); @@ -1021,9 +1057,10 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { GV->setAlignment(getContext().getDeclAlignInBytes(D)); // Set the llvm linkage type as appropriate. + GVALinkage Linkage = GetLinkageForVariable(getContext(), D); if (D->isInAnonymousNamespace()) GV->setLinkage(llvm::Function::InternalLinkage); - else if (D->getStorageClass() == VarDecl::Static) + else if (Linkage == GVA_Internal) GV->setLinkage(llvm::Function::InternalLinkage); else if (D->hasAttr<DLLImportAttr>()) GV->setLinkage(llvm::Function::DLLImportLinkage); @@ -1034,7 +1071,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { GV->setLinkage(llvm::GlobalVariable::WeakODRLinkage); else GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); - } else if (!CompileOpts.NoCommon && + } else if (Linkage == GVA_TemplateInstantiation) + GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); + else if (!CompileOpts.NoCommon && !D->hasExternalStorage() && !D->getInit() && !D->getAttr<SectionAttr>()) { GV->setLinkage(llvm::GlobalVariable::CommonLinkage); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 28c0fa6ab9..060cc55983 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1191,14 +1191,14 @@ void Sema::InstantiateStaticDataMemberDefinition( } // Never instantiate an explicit specialization. - if (Def->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + if (Var->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) return; // C++0x [temp.explicit]p9: // Except for inline functions, other explicit instantiation declarations // have the effect of suppressing the implicit instantiation of the entity // to which they refer. - if (Def->getTemplateSpecializationKind() + if (Var->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDeclaration) return; @@ -1218,12 +1218,14 @@ void Sema::InstantiateStaticDataMemberDefinition( DeclContext *PreviousContext = CurContext; CurContext = Var->getDeclContext(); + VarDecl *OldVar = Var; Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(), getTemplateInstantiationArgs(Var))); - CurContext = PreviousContext; if (Var) { + Var->setPreviousDeclaration(OldVar); + Var->setTemplateSpecializationKind(OldVar->getTemplateSpecializationKind()); DeclGroupRef DG(Var); Consumer.HandleTopLevelDecl(DG); } diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp new file mode 100644 index 0000000000..f2282a2395 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp @@ -0,0 +1,26 @@ +// RUN: clang-cc -emit-llvm -triple x86_64-apple-darwin10 -o - %s | FileCheck %s +template<typename T> +struct X { + static T member1; + static T member2; + static T member3; +}; + +template<typename T> +T X<T>::member1; + +template<typename T> +T X<T>::member2 = 17; + +// CHECK: @_ZN1XIiE7member1E = global i32 0 +template int X<int>::member1; + +// CHECK: @_ZN1XIiE7member2E = global i32 17 +template int X<int>::member2; + +// For implicit instantiation of +long& get(bool Cond) { + // CHECK: @_ZN1XIlE7member1E = weak global i64 0 + // CHECK: @_ZN1XIlE7member2E = weak global i64 17 + return Cond? X<long>::member1 : X<long>::member2; +}
\ No newline at end of file |