diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -375,7 +375,9 @@ if (!specInfo->isExplicitInstantiationOrSpecialization()) return true; - return !fn->hasAttr(); + return !fn->hasAttr() && !specInfo->getTemplate() + ->getTemplatedDecl() + ->hasAttr(); } /// Merge in template-related linkage and visibility for the given @@ -1274,12 +1276,20 @@ } // 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 specialization of a template, + if (FunctionTemplateSpecializationInfo *templateInfo = + fn->getTemplateSpecializationInfo()) { + // ... If the template has an explicit visibility attribute, use that. + if (auto Vis = getVisibilityOf( + templateInfo->getTemplate()->getTemplatedDecl(), kind)) + return Vis; + // ... If the template instantiates from a member template with an + // explicit visibility attribute, use that. + if (auto *InstantiatedFrom = + templateInfo->getTemplate()->getInstantiatedFromMemberTemplate()) + return getVisibilityOf(InstantiatedFrom->getTemplatedDecl(), kind); + return std::nullopt; + } // If the function is a member of a specialization of a class template // and the corresponding decl has explicit visibility, use that. diff --git a/clang/test/CodeGenCXX/visibility.cpp b/clang/test/CodeGenCXX/visibility.cpp --- a/clang/test/CodeGenCXX/visibility.cpp +++ b/clang/test/CodeGenCXX/visibility.cpp @@ -1017,8 +1017,8 @@ void DEFAULT zed() { } template void zed<&da>(); - // CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2daEEEEEvv( - // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2daEEEEEvv( + // CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2daEEEEEvv( + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2daEEEEEvv( template void DEFAULT zed<&db>(); // CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2dbEEEEEvv( @@ -1029,8 +1029,8 @@ // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2dcEEEEEvv( template void zed<&ha>(); - // CHECK-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2haEEEEEvv( - // CHECK-HIDDEN-LABEL: define weak_odr hidden void @_ZN6test513zedIXadL_ZNS_2haEEEEEvv( + // CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2haEEEEEvv( + // CHECK-HIDDEN-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2haEEEEEvv( template void DEFAULT zed<&hb>(); // CHECK-LABEL: define weak_odr void @_ZN6test513zedIXadL_ZNS_2hbEEEEEvv( @@ -1429,6 +1429,7 @@ template template U foo::bar() { return {}; } + /// foo::{zed,bar} get the instantiated-from member's HIDDEN, overriding DEFAULT. extern template struct DEFAULT foo; int use() { @@ -1436,13 +1437,12 @@ foo p; return o.zed() + o.bar() + p.zed() + p.bar(); } - /// FIXME: foo::bar is hidden in GCC w/ or w/o -fvisibility=hidden. // CHECK-LABEL: declare hidden noundef i32 @_ZN6test713fooIiE3zedEv( - // CHECK-LABEL: define linkonce_odr noundef i32 @_ZN6test713fooIiE3barIiEET_v( + // CHECK-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIiE3barIiEET_v( // CHECK-LABEL: define linkonce_odr hidden noundef i64 @_ZN6test713fooIlE3zedEv( - // CHECK-LABEL: define linkonce_odr noundef i32 @_ZN6test713fooIlE3barIiEET_v( + // CHECK-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIlE3barIiEET_v( // CHECK-HIDDEN-LABEL: declare hidden noundef i32 @_ZN6test713fooIiE3zedEv( - // CHECK-HIDDEN-LABEL: define linkonce_odr noundef i32 @_ZN6test713fooIiE3barIiEET_v( + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIiE3barIiEET_v( // CHECK-HIDDEN-LABEL: define linkonce_odr hidden noundef i64 @_ZN6test713fooIlE3zedEv( // CHECK-HIDDEN-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIlE3barIiEET_v( }