Index: cfe/trunk/lib/AST/ASTContext.cpp =================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp +++ cfe/trunk/lib/AST/ASTContext.cpp @@ -8892,22 +8892,30 @@ return GVA_Internal; if (VD->isStaticLocal()) { - GVALinkage StaticLocalLinkage = GVA_DiscardableODR; const DeclContext *LexicalContext = VD->getParentFunctionOrMethod(); while (LexicalContext && !isa(LexicalContext)) LexicalContext = LexicalContext->getLexicalParent(); - // Let the static local variable inherit its linkage from the nearest - // enclosing function. - if (LexicalContext) - StaticLocalLinkage = - Context.GetGVALinkageForFunction(cast(LexicalContext)); - - // GVA_StrongODR function linkage is stronger than what we need, - // downgrade to GVA_DiscardableODR. - // This allows us to discard the variable if we never end up needing it. - return StaticLocalLinkage == GVA_StrongODR ? GVA_DiscardableODR - : StaticLocalLinkage; + // ObjC Blocks can create local variables that don't have a FunctionDecl + // LexicalContext. + if (!LexicalContext) + return GVA_DiscardableODR; + + // Otherwise, let the static local variable inherit its linkage from the + // nearest enclosing function. + auto StaticLocalLinkage = + Context.GetGVALinkageForFunction(cast(LexicalContext)); + + // Itanium ABI 5.2.2: "Each COMDAT group [for a static local variable] must + // be emitted in any object with references to the symbol for the object it + // contains, whether inline or out-of-line." + // Similar behavior is observed with MSVC. An alternative ABI could use + // StrongODR/AvailableExternally to match the function, but none are + // known/supported currently. + if (StaticLocalLinkage == GVA_StrongODR || + StaticLocalLinkage == GVA_AvailableExternally) + return GVA_DiscardableODR; + return StaticLocalLinkage; } // MSVC treats in-class initialized static data members as definitions. Index: cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp +++ cfe/trunk/test/CodeGenCXX/explicit-instantiation.cpp @@ -5,6 +5,9 @@ // This check logically is attached to 'template int S::i;' below. // CHECK: @_ZN1SIiE1iE = weak_odr global i32 +// This check is logically attached to 'template int ExportedStaticLocal::f()' below. +// CHECK-OPT: @_ZZN19ExportedStaticLocal1fIiEEvvE1i = linkonce_odr global + template struct plus { Result operator()(const T& t, const U& u) const; @@ -153,3 +156,17 @@ template void S::g() {} template int S::i; template void S::S2::h() {} + +namespace ExportedStaticLocal { +void sink(int&); +template +inline void f() { + static int i; + sink(i); +} +// See the check line at the top of the file. +extern template void f(); +void use() { + f(); +} +}