Index: cfe/trunk/lib/AST/Decl.cpp =================================================================== --- cfe/trunk/lib/AST/Decl.cpp +++ cfe/trunk/lib/AST/Decl.cpp @@ -1092,9 +1092,18 @@ // If there wasn't explicit visibility there, and this is a // specialization of a class template, check for visibility // on the pattern. - if (const auto *spec = dyn_cast(ND)) - return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(), - kind); + if (const auto *spec = dyn_cast(ND)) { + // Walk all the template decl till this point to see if there are + // explicit visibility attributes. + const auto *TD = spec->getSpecializedTemplate()->getTemplatedDecl(); + while (TD != nullptr) { + auto Vis = getVisibilityOf(TD, kind); + if (Vis != None) + return Vis; + TD = TD->getPreviousDecl(); + } + return None; + } // Use the most recent declaration. if (!IsMostRecent && !isa(ND)) { Index: cfe/trunk/test/CodeGenCXX/visibility-pr36810.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/visibility-pr36810.cpp +++ cfe/trunk/test/CodeGenCXX/visibility-pr36810.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx -std=c++11 -fvisibility hidden -emit-llvm -o - %s -O2 -disable-llvm-passes | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-macosx -DUNDEF_G -std=c++11 -fvisibility hidden -emit-llvm -o - %s -O2 -disable-llvm-passes | FileCheck %s + +namespace std { +template +class __attribute__((__type_visibility__("default"))) shared_ptr { + template friend class shared_ptr; +}; +} +struct dict; +#ifndef UNDEF_G +std::shared_ptr g; +#endif +class __attribute__((visibility("default"))) Bar; +template > +class __attribute__((visibility("default"))) i { + std::shared_ptr foo() const; +}; + +// CHECK: define void @_ZNK1iISt10shared_ptrI3BarEE3fooEv +template <> std::shared_ptr i<>::foo() const { + return std::shared_ptr(); +}