forked from OSchip/llvm-project
Give explicit and implicit instantiations of static data members of
class templates the proper linkage. Daniel, please look over the CodeGenModule bits. llvm-svn: 84140
This commit is contained in:
parent
b1d6fde13e
commit
3cc3cdeea9
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue