Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -1049,7 +1049,9 @@ // If this is a member class of a specialization of a class template // and the corresponding decl has explicit visibility, use that. if (const CXXRecordDecl *RD = dyn_cast(ND)) { - CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); + const CXXRecordDecl *InstantiatedFrom = RD->getTemplateInstantiationPattern(); + if (!InstantiatedFrom) + InstantiatedFrom = RD->getInstantiatedFromMemberClass(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); } @@ -1084,16 +1086,11 @@ } // Also handle function template specializations. if (const FunctionDecl *fn = dyn_cast(ND)) { - // If the function is a specialization of a template with an - // explicit visibility attribute, use that. - if (FunctionTemplateSpecializationInfo *templateInfo - = fn->getTemplateSpecializationInfo()) - return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(), - kind); - - // If the function is a member of a specialization of a class template + // If the function is a member of a specialization of a some template // and the corresponding decl has explicit visibility, use that. - FunctionDecl *InstantiatedFrom = fn->getInstantiatedFromMemberFunction(); + FunctionDecl *InstantiatedFrom = fn->getTemplateInstantiationPattern(); + if (!InstantiatedFrom) + InstantiatedFrom = fn->getInstantiatedFromMemberFunction(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); Index: lib/AST/DeclCXX.cpp =================================================================== --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1261,20 +1261,22 @@ if (auto *TD = dyn_cast(this)) { auto From = TD->getInstantiatedFrom(); if (auto *CTD = From.dyn_cast()) { - while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { + auto *NewCTD = CTD; + do { + CTD = NewCTD; if (NewCTD->isMemberSpecialization()) break; - CTD = NewCTD; - } + } while ((NewCTD = CTD->getInstantiatedFromMemberTemplate())); return CTD->getTemplatedDecl()->getDefinition(); } if (auto *CTPSD = From.dyn_cast()) { - while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { + auto *NewCTPSD = CTPSD; + do { + CTPSD = NewCTPSD; if (NewCTPSD->isMemberSpecialization()) break; - CTPSD = NewCTPSD; - } + } while ((NewCTPSD = CTPSD->getInstantiatedFromMember())); return CTPSD->getDefinition(); } } Index: test/CodeGenCXX/visibility.cpp =================================================================== --- test/CodeGenCXX/visibility.cpp +++ test/CodeGenCXX/visibility.cpp @@ -1314,3 +1314,57 @@ // CHECK-LABEL: define void @_ZN6test693foo1fEv // CHECK-HIDDEN-LABEL: define hidden void @_ZN6test693foo1fEv } + +namespace test70 { + template < typename T > class foo { + public: + T x; + template < typename S > + HIDDEN S AddS(S); + template < typename S > class HIDDEN barS { + public: + static S AddS2(foo x, S); + }; + template < typename S > class HIDDEN barZ { + public: + template < typename Z > + static S AddSZ(foo x, S, Z); + }; + }; + + // CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4AddSIxEET_S3_ + // CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4AddSIxEET_S3_ + template < typename T > + template < typename S > + HIDDEN S foo::AddS(S y) { + return ((S) x) + y; + } + + // CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4barSIxE5AddS2ES1_x + // CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4barSIxE5AddS2ES1_x + template < typename T > + template < typename S > + HIDDEN S foo::barS::AddS2(foo x, S y) { + return ((S) x.x) + y; + } + + // CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4barZIxE5AddSZIcEExS1_xT_ + // CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4barZIxE5AddSZIcEExS1_xT_ + template < typename T > + template < typename S > + template < typename Z > + HIDDEN S foo::barZ::AddSZ(foo x, S y, Z z) { + return ((S) x.x) + y + ((S) z); + } + + extern template struct foo; + template struct foo; + + void f() { + auto var = foo{5}; + auto bar = var.AddS((long long)3); + auto bar2 = decltype(var)::barS::AddS2(var,3); + auto bar3 = decltype(var)::barZ::AddSZ(var,3,(char)0); + } +} +