[cfe-commits] r84140 - in /cfe/trunk: include/clang/AST/Decl.h lib/AST/Decl.cpp lib/CodeGen/CodeGenModule.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp
Douglas Gregor
dgregor at apple.com
Wed Oct 14 14:29:40 PDT 2009
Author: dgregor
Date: Wed Oct 14 16:29:40 2009
New Revision: 84140
URL: http://llvm.org/viewvc/llvm-project?rev=84140&view=rev
Log:
Give explicit and implicit instantiations of static data members of
class templates the proper linkage.
Daniel, please look over the CodeGenModule bits.
Added:
cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp
Modified:
cfe/trunk/include/clang/AST/Decl.h
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/CodeGen/CodeGenModule.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=84140&r1=84139&r2=84140&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Oct 14 16:29:40 2009
@@ -584,10 +584,14 @@
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 @@
/// \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.
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=84140&r1=84139&r2=84140&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed Oct 14 16:29:40 2009
@@ -373,7 +373,23 @@
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 @@
return TSK_Undeclared;
}
-MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() {
+MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const {
return getASTContext().getInstantiatedFromStaticDataMember(this);
}
@@ -809,7 +825,6 @@
}
bool FunctionDecl::isOutOfLine() const {
- // FIXME: Should we restrict this to member functions?
if (Decl::isOutOfLine())
return true;
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=84140&r1=84139&r2=84140&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Wed Oct 14 16:29:40 2009
@@ -541,7 +541,12 @@
}
}
- 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 @@
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 @@
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 @@
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);
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=84140&r1=84139&r2=84140&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Oct 14 16:29:40 2009
@@ -1191,14 +1191,14 @@
}
// 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 @@
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);
}
Added: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp?rev=84140&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-emit.cpp Wed Oct 14 16:29:40 2009
@@ -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
More information about the cfe-commits
mailing list