https://github.com/asavonic updated https://github.com/llvm/llvm-project/pull/136689
>From 348c94f4ef9b3fda5538813251360ccd8f6ffc44 Mon Sep 17 00:00:00 2001 From: Andrew Savonichev <andrew.savonic...@gmail.com> Date: Mon, 21 Apr 2025 19:45:05 +0900 Subject: [PATCH 1/2] [clang] Fix computeTypeLinkageInfo for dependent member pointers MemberPointerType may refer to a dependent class (qualifier), for which getMostRecentCXXRecordDecl returns NULL. It seems that the compiler never executed this code path before patch #136128 where the issue was reported. LIT tests 74 and 75 are reduced from Chromium and LLVM libc test harness as reported in #136128. Function member (test74): MemberPointerType 'type-parameter-0-0 (type-parameter-0-1::*)(void)' dependent |-TemplateTypeParmType 'type-parameter-0-1' dependent depth 0 index 1 `-FunctionProtoType 'type-parameter-0-0 (void)' dependent cdecl `-TemplateTypeParmType 'type-parameter-0-0' dependent depth 0 index 0 Template parameter (test75): MemberPointerType 'type-parameter-0-1 type-parameter-0-0::*' dependent |-TemplateTypeParmType 'type-parameter-0-0' dependent depth 0 index 0 `-TemplateTypeParmType 'type-parameter-0-1' dependent depth 0 index 1 --- clang/lib/AST/Type.cpp | 8 ++++-- clang/test/CodeGenCXX/visibility.cpp | 37 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index fe1dc7e2fe786..871b0e00f3970 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4787,8 +4787,12 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) { return computeTypeLinkageInfo(cast<ReferenceType>(T)->getPointeeType()); case Type::MemberPointer: { const auto *MPT = cast<MemberPointerType>(T); - LinkageInfo LV = - getDeclLinkageAndVisibility(MPT->getMostRecentCXXRecordDecl()); + LinkageInfo LV; + if (auto *D = MPT->getMostRecentCXXRecordDecl()) { + LV.merge(getDeclLinkageAndVisibility(D)); + } else if (auto *Ty = MPT->getQualifier()->getAsType()) { + LV.merge(computeTypeLinkageInfo(Ty)); + } LV.merge(computeTypeLinkageInfo(MPT->getPointeeType())); return LV; } diff --git a/clang/test/CodeGenCXX/visibility.cpp b/clang/test/CodeGenCXX/visibility.cpp index e1061f3dbd18f..b4c6fdcbcdf33 100644 --- a/clang/test/CodeGenCXX/visibility.cpp +++ b/clang/test/CodeGenCXX/visibility.cpp @@ -1463,3 +1463,40 @@ namespace test71 { // CHECK-HIDDEN-LABEL: define linkonce_odr hidden noundef i64 @_ZN6test713fooIlE3zedEv( // CHECK-HIDDEN-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIlE3barIiEET_v( } + +namespace test74 { + template <typename> struct T; + template <typename R> + struct T<void (R::*)()> { + template <typename M> + static __attribute__((__visibility__("hidden"))) void Invoke(M) { + } + }; + + struct C; + void (C::*MM)(); + + void Fun() { + T<decltype(MM)>::Invoke(0); + } + // CHECK-LABEL: define linkonce_odr void @_ZN6test741TIMNS_1CEFvvEE6InvokeIiEEvT_( + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test741TIMNS_1CEFvvEE6InvokeIiEEvT_( +} + +namespace test75 { + template <class> struct T; + template <class C, class Ret> + struct T<Ret C::*> { + template <class M> + static __attribute__((__visibility__("hidden"))) + void Invoke(M) { + } + }; + + struct A; + void Fun() { + T<void (A::*)()>::Invoke(0); + } + // CHECK-LABEL: define linkonce_odr void @_ZN6test751TIMNS_1AEFvvEE6InvokeIiEEvT_( + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test751TIMNS_1AEFvvEE6InvokeIiEEvT_( +} >From b58ab38fa54eb28da87ce719f57ff12de4f40d54 Mon Sep 17 00:00:00 2001 From: Andrew Savonichev <andrew.savonic...@gmail.com> Date: Thu, 17 Apr 2025 20:18:52 +0900 Subject: [PATCH 2/2] Reland [clang] Handle instantiated members to determine visibility (#136128) As reported in issue #103477, visibility of instantiated member functions used to be ignored when calculating visibility of a specialization. This patch modifies `getLVForClassMember` to look up for a source template for an instantiated member, and changes `mergeTemplateLV` to apply it. A similar issue was reported in #31462, but it seems that `extern` declaration with visibility prevents the function from being emitted as hidden. This behavior seems correct, even though GCC emits it as with default visibility instead. Both tests from #103477 and #31462 are added as LIT tests `test72` and `test73` respectively. --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/AST/Decl.cpp | 13 +++++++-- clang/test/CodeGenCXX/visibility.cpp | 42 ++++++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 86d37f5616356..9ecd78c13d4e5 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -458,6 +458,7 @@ Bug Fixes in This Version - Fixed a crash when ``#embed`` appears as a part of a failed constant evaluation. The crashes were happening during diagnostics emission due to unimplemented statement printer. (#GH132641) +- Fixed visibility calculation for template functions. (#GH103477) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 1d9208f0e1c72..61d497999b669 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -400,9 +400,9 @@ void LinkageComputer::mergeTemplateLV( FunctionTemplateDecl *temp = specInfo->getTemplate(); // Merge information from the template declaration. LinkageInfo tempLV = getLVForDecl(temp, computation); - // The linkage of the specialization should be consistent with the - // template declaration. - LV.setLinkage(tempLV.getLinkage()); + // The linkage and visibility of the specialization should be + // consistent with the template declaration. + LV.mergeMaybeWithVisibility(tempLV, considerVisibility); // Merge information from the template parameters. LinkageInfo paramsLV = @@ -1051,6 +1051,13 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D, if (const auto *redeclTemp = dyn_cast<RedeclarableTemplateDecl>(temp)) { if (isExplicitMemberSpecialization(redeclTemp)) { explicitSpecSuppressor = temp->getTemplatedDecl(); + } else if (const RedeclarableTemplateDecl *from = + redeclTemp->getInstantiatedFromMemberTemplate()) { + // If no explicit visibility is specified yet, and this is an + // instantiated member of a template, look up visibility there + // as well. + LinkageInfo fromLV = from->getLinkageAndVisibility(); + LV.mergeMaybeWithVisibility(fromLV, considerVisibility); } } } diff --git a/clang/test/CodeGenCXX/visibility.cpp b/clang/test/CodeGenCXX/visibility.cpp index b4c6fdcbcdf33..442e2a5aaa2b3 100644 --- a/clang/test/CodeGenCXX/visibility.cpp +++ b/clang/test/CodeGenCXX/visibility.cpp @@ -1457,13 +1457,49 @@ namespace test71 { // CHECK-LABEL: declare hidden noundef i32 @_ZN6test713fooIiE3zedEv( // CHECK-LABEL: define linkonce_odr 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 i64 @_ZN6test713fooIlE3zedEv( // CHECK-HIDDEN-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIlE3barIiEET_v( } +// https://github.com/llvm/llvm-project/issues/103477 +namespace test72 { + template <class a> + struct t { + template <int> + static HIDDEN void bar() {} + }; + + void test() { + t<char>::bar<1>(); + } + // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test721tIcE3barILi1EEEvv( + // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test721tIcE3barILi1EEEvv( +} + +// https://github.com/llvm/llvm-project/issues/31462 +namespace test73 { + template <class T> struct s { + template <class U> + __attribute__((__visibility__("hidden"))) U should_not_be_exported(); + }; + + template <class T> template <class U> U s<T>::should_not_be_exported() { + return U(); + } + + extern template struct __attribute__((__visibility__("default"))) s<int>; + + int f() { + s<int> o; + return o.should_not_be_exported<int>(); + } + // CHECK-LABEL: define linkonce_odr noundef i32 @_ZN6test731sIiE22should_not_be_exportedIiEET_v( + // CHECK-HIDDEN-LABEL: define linkonce_odr noundef i32 @_ZN6test731sIiE22should_not_be_exportedIiEET_v( +} + namespace test74 { template <typename> struct T; template <typename R> @@ -1479,7 +1515,7 @@ namespace test74 { void Fun() { T<decltype(MM)>::Invoke(0); } - // CHECK-LABEL: define linkonce_odr void @_ZN6test741TIMNS_1CEFvvEE6InvokeIiEEvT_( + // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test741TIMNS_1CEFvvEE6InvokeIiEEvT_( // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test741TIMNS_1CEFvvEE6InvokeIiEEvT_( } @@ -1497,6 +1533,6 @@ namespace test75 { void Fun() { T<void (A::*)()>::Invoke(0); } - // CHECK-LABEL: define linkonce_odr void @_ZN6test751TIMNS_1AEFvvEE6InvokeIiEEvT_( + // CHECK-LABEL: define linkonce_odr hidden void @_ZN6test751TIMNS_1AEFvvEE6InvokeIiEEvT_( // CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test751TIMNS_1AEFvvEE6InvokeIiEEvT_( } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits