[clang] Fix computeTypeLinkageInfo for dependent member pointers (#136689)
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
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 111a642..d298f1c 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4793,8 +4793,12 @@
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 e1061f3..b4c6fdc 100644
--- a/clang/test/CodeGenCXX/visibility.cpp
+++ b/clang/test/CodeGenCXX/visibility.cpp
@@ -1463,3 +1463,40 @@
// 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_(
+}