Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -1052,7 +1052,10 @@ // If this is a member class of a specialization of a class template // and the corresponding decl has explicit visibility, use that. if (const auto *RD = dyn_cast(ND)) { - CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass(); + const CXXRecordDecl *InstantiatedFrom = + RD->getTemplateInstantiationPattern(); + if (!InstantiatedFrom) + InstantiatedFrom = RD->getInstantiatedFromMemberClass(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); } @@ -1086,16 +1089,13 @@ } // Also handle function template specializations. if (const auto *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 template specialization or a member of + // a specialized class template and the corresponding decl has + // explicit visibility, use that. + FunctionDecl *InstantiatedFrom = fn->getTemplateInstantiationPattern(); + if (!InstantiatedFrom) + InstantiatedFrom = fn->getInstantiatedFromMemberFunction(); - // If the function is a member of a specialization of a class template - // and the corresponding decl has explicit visibility, use that. - FunctionDecl *InstantiatedFrom = fn->getInstantiatedFromMemberFunction(); if (InstantiatedFrom) return getVisibilityOf(InstantiatedFrom, kind); Index: lib/AST/DeclCXX.cpp =================================================================== --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1346,8 +1346,9 @@ if (auto *TD = dyn_cast(this)) { auto From = TD->getInstantiatedFrom(); if (auto *CTD = From.dyn_cast()) { - while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { - if (NewCTD->isMemberSpecialization()) + while (!CTD->isMemberSpecialization()) { + auto *NewCTD = CTD->getInstantiatedFromMemberTemplate(); + if (!NewCTD) break; CTD = NewCTD; } @@ -1355,8 +1356,9 @@ } if (auto *CTPSD = From.dyn_cast()) { - while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { - if (NewCTPSD->isMemberSpecialization()) + while (!CTPSD->isMemberSpecialization()) { + auto *NewCTPSD = CTPSD->getInstantiatedFromMember(); + if (!NewCTPSD) break; CTPSD = NewCTPSD; } Index: test/CodeGenCXX/visibility.cpp =================================================================== --- test/CodeGenCXX/visibility.cpp +++ test/CodeGenCXX/visibility.cpp @@ -1317,3 +1317,59 @@ // CHECK-LABEL: define void @_ZN6test693foo1fEv // CHECK-HIDDEN-LABEL: define hidden void @_ZN6test693foo1fEv } + +namespace test70 { +template +class foo { +public: + T x; + template + HIDDEN S AddS(S); + template + class HIDDEN barS { + public: + static S AddS2(foo x, S); + }; + template + class HIDDEN barZ { + public: + template + static S AddSZ(foo x, S, Z); + }; +}; + +// CHECK: define linkonce_odr hidden i64 @_ZN6test703fooIiE4AddSIxEET_S3_ +// CHECK-NOT: define linkonce_odr i64 @_ZN6test703fooIiE4AddSIxEET_S3_ +template +template +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 +template +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 +template +template +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); +} +} Index: test/Modules/cxx-templates.cpp =================================================================== --- test/Modules/cxx-templates.cpp +++ test/Modules/cxx-templates.cpp @@ -199,7 +199,7 @@ cls uk4; // expected-error 1+{{partial specialization of 'cls' must be imported}} expected-error 1+{{definition of}} cls::nested_cls unk1; // expected-error 1+{{explicit specialization of 'nested_cls' must be imported}} expected-error 1+{{definition of}} cls::nested_cls_t unk2; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}} - cls::nested_cls_t unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} + cls::nested_cls_t unk3; // expected-error 1+{{explicit specialization of 'nested_cls_t' must be imported}} expected-error 1+{{definition of}} // For enums, uses that would trigger instantiations of definitions are not // allowed.