Skip to content

Commit b861f72

Browse files
asavonicIanWood1
authored andcommitted
[clang] Handle instantiated members to determine visibility (llvm#136128)
As reported in issue llvm#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 llvm#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 llvm#103477 and llvm#31462 are added as LIT tests `test72` and `test73` respectively.
1 parent 29aa965 commit b861f72

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

clang/lib/AST/Decl.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,9 +400,9 @@ void LinkageComputer::mergeTemplateLV(
400400
FunctionTemplateDecl *temp = specInfo->getTemplate();
401401
// Merge information from the template declaration.
402402
LinkageInfo tempLV = getLVForDecl(temp, computation);
403-
// The linkage of the specialization should be consistent with the
404-
// template declaration.
405-
LV.setLinkage(tempLV.getLinkage());
403+
// The linkage and visibility of the specialization should be
404+
// consistent with the template declaration.
405+
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
406406

407407
// Merge information from the template parameters.
408408
LinkageInfo paramsLV =
@@ -1051,6 +1051,13 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D,
10511051
if (const auto *redeclTemp = dyn_cast<RedeclarableTemplateDecl>(temp)) {
10521052
if (isExplicitMemberSpecialization(redeclTemp)) {
10531053
explicitSpecSuppressor = temp->getTemplatedDecl();
1054+
} else if (const RedeclarableTemplateDecl *from =
1055+
redeclTemp->getInstantiatedFromMemberTemplate()) {
1056+
// If no explicit visibility is specified yet, and this is an
1057+
// instantiated member of a template, look up visibility there
1058+
// as well.
1059+
LinkageInfo fromLV = from->getLinkageAndVisibility();
1060+
LV.mergeMaybeWithVisibility(fromLV, considerVisibility);
10541061
}
10551062
}
10561063
}

clang/test/CodeGenCXX/visibility.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1457,9 +1457,45 @@ namespace test71 {
14571457
// CHECK-LABEL: declare hidden noundef i32 @_ZN6test713fooIiE3zedEv(
14581458
// CHECK-LABEL: define linkonce_odr noundef i32 @_ZN6test713fooIiE3barIiEET_v(
14591459
// CHECK-LABEL: define linkonce_odr hidden noundef i64 @_ZN6test713fooIlE3zedEv(
1460-
// CHECK-LABEL: define linkonce_odr noundef i32 @_ZN6test713fooIlE3barIiEET_v(
1460+
// CHECK-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIlE3barIiEET_v(
14611461
// CHECK-HIDDEN-LABEL: declare hidden noundef i32 @_ZN6test713fooIiE3zedEv(
14621462
// CHECK-HIDDEN-LABEL: define linkonce_odr noundef i32 @_ZN6test713fooIiE3barIiEET_v(
14631463
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden noundef i64 @_ZN6test713fooIlE3zedEv(
14641464
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden noundef i32 @_ZN6test713fooIlE3barIiEET_v(
14651465
}
1466+
1467+
// https://github.com/llvm/llvm-project/issues/103477
1468+
namespace test72 {
1469+
template <class a>
1470+
struct t {
1471+
template <int>
1472+
static HIDDEN void bar() {}
1473+
};
1474+
1475+
void test() {
1476+
t<char>::bar<1>();
1477+
}
1478+
// CHECK-LABEL: define linkonce_odr hidden void @_ZN6test721tIcE3barILi1EEEvv(
1479+
// CHECK-HIDDEN-LABEL: define linkonce_odr hidden void @_ZN6test721tIcE3barILi1EEEvv(
1480+
}
1481+
1482+
// https://github.com/llvm/llvm-project/issues/31462
1483+
namespace test73 {
1484+
template <class T> struct s {
1485+
template <class U>
1486+
__attribute__((__visibility__("hidden"))) U should_not_be_exported();
1487+
};
1488+
1489+
template <class T> template <class U> U s<T>::should_not_be_exported() {
1490+
return U();
1491+
}
1492+
1493+
extern template struct __attribute__((__visibility__("default"))) s<int>;
1494+
1495+
int f() {
1496+
s<int> o;
1497+
return o.should_not_be_exported<int>();
1498+
}
1499+
// CHECK-LABEL: define linkonce_odr noundef i32 @_ZN6test731sIiE22should_not_be_exportedIiEET_v(
1500+
// CHECK-HIDDEN-LABEL: define linkonce_odr noundef i32 @_ZN6test731sIiE22should_not_be_exportedIiEET_v(
1501+
}

0 commit comments

Comments
 (0)