From 72d03bee6497a80e70ffbf43a6e28cd55bf3527b Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 15 Oct 2014 16:38:00 +0000 Subject: [PATCH] Don't use a global_ctors comdat for globals that aren't externally visible In particular, if you have two identical templates in different TUs in anonymous namespaces, we would use the same global_ctors comdat key for both. As a result, only one would be run. llvm-svn: 219806 --- clang/lib/CodeGen/CGDeclCXX.cpp | 18 +++++++++--------- ...member-variable-explicit-specialization.cpp | 16 +++++++++++++++- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index ee3172ebc545..dcfc45ff84fc 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -292,7 +292,8 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr, PerformInit); - llvm::GlobalVariable *Key = supportsCOMDAT() ? Addr : nullptr; + llvm::GlobalVariable *COMDATKey = + supportsCOMDAT() && D->isExternallyVisible() ? Addr : nullptr; if (D->getTLSKind()) { // FIXME: Should we support init_priority for thread_local? @@ -310,8 +311,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, OrderGlobalInits Key(IPA->getPriority(), PrioritizedCXXGlobalInits.size()); PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn)); DelayedCXXInitPosition.erase(D); - } else if (D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization && - D->getTemplateSpecializationKind() != TSK_Undeclared) { + } else if (isTemplateInstantiation(D->getTemplateSpecializationKind())) { // C++ [basic.start.init]p2: // Definitions of explicitly specialized class template static data // members have ordered initialization. Other class template static data @@ -320,16 +320,16 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, // // As a consequence, we can put them into their own llvm.global_ctors entry. // - // In addition, put the initializer into a COMDAT group with the global - // being initialized. On most platforms, this is a minor startup time - // optimization. In the MS C++ ABI, there are no guard variables, so this - // COMDAT key is required for correctness. - AddGlobalCtor(Fn, 65535, Key); + // If the global is externally visible, put the initializer into a COMDAT + // group with the global being initialized. On most platforms, this is a + // minor startup time optimization. In the MS C++ ABI, there are no guard + // variables, so this COMDAT key is required for correctness. + AddGlobalCtor(Fn, 65535, COMDATKey); DelayedCXXInitPosition.erase(D); } else if (D->hasAttr()) { // SelectAny globals will be comdat-folded. Put the initializer into a COMDAT // group associated with the global, so the initializers get folded too. - AddGlobalCtor(Fn, 65535, Key); + AddGlobalCtor(Fn, 65535, COMDATKey); DelayedCXXInitPosition.erase(D); } else { llvm::DenseMap::iterator I = diff --git a/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp b/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp index 04bf79fd1559..430fa2b08d5d 100644 --- a/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp +++ b/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp @@ -14,7 +14,7 @@ template<> int A::a; // ALL: @_ZN1AIbE1aE = global i32 10 template<> int A::a = 10; -// ALL: @llvm.global_ctors = appending global [7 x { i32, void ()*, i8* }] +// ALL: @llvm.global_ctors = appending global [8 x { i32, void ()*, i8* }] // ELF: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* bitcast (i32* @_ZN1AIsE1aE to i8*) }, // MACHO: [{ i32, void ()*, i8* } { i32 65535, void ()* @[[unordered1:[^,]*]], i8* null }, @@ -34,6 +34,8 @@ template<> int A::a = 10; // ELF: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered6:[^,]*]], i8* @_Z1xIcE }, // MACHO: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered6:[^,]*]], i8* null }, +// ALL: { i32, void ()*, i8* } { i32 65535, void ()* @[[unordered7:[^,]*]], i8* null }, + // ALL: { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I_static_member_variable_explicit_specialization.cpp, i8* null }] template int A::a; // Unordered @@ -67,6 +69,13 @@ struct b { template T b::i = foo(); template int b::i; } + +namespace { +template struct Internal { static int a; }; +template int Internal::a = foo(); +} +int *use_internal_a = &Internal::a; + // ALL: define internal void @[[unordered1]] // ALL: call i32 @foo() // ALL: store {{.*}} @_ZN1AIsE1aE @@ -97,6 +106,11 @@ template int b::i; // ALL: store {{.*}} @_Z1xIcE // ALL: ret +// ALL: define internal void @[[unordered7]] +// ALL: call i32 @foo() +// ALL: store {{.*}} @_ZN12_GLOBAL__N_18InternalIiE1aE +// ALL: ret + // ALL: define internal void @_GLOBAL__sub_I_static_member_variable_explicit_specialization.cpp() // We call unique stubs for every ordered dynamic initializer in the TU. // ALL: call