If we have a partial template specialization of a class, the visibility of its static members is determined by the visibility attribute of the original definition, rather than the partially-templated one:
My expectation is that S<int*>::n should be hidden here, because the partial specialization was declared hidden. This is also what happens if we compile with gcc instead of clang. We get the same issue if we declare S to be HIDDEN in its original definition -- S<int*>::n will be hidden, even if S<T*> is explicitly given default visibility.
Putting a visibility attribute directly on the definition of int S<T*>::n = 4; correctly overrides previously-declared attributes.
This only seems to happen for partial specializations: if we specialize S<int*> explicitly, its visibility attribute is taken into account.
This seems closely related to #103477, though I'm not sure if it's exactly the same issue or not. Oddly, it seems that the visibility of int S<T*>::n; is considered to be hidden at some point during compilation, since it's triggering a warning I'm developing that involves checking for hidden visibility. This indicates that the attribute is getting lost at some point, as mentioned here.
If we have a partial template specialization of a class, the visibility of its static members is determined by the visibility attribute of the original definition, rather than the partially-templated one:
```C++
#define HIDDEN __attribute__((visibility("hidden")))
template<class T>
struct S { static int n; };
template<class T>
struct HIDDEN S<T*> { static int n; };
template <class T>
int S<T*>::n = 4;
template struct S<int*>;
// $ clang++ -c test.cpp
// $ readelf -sW test.o | grep _ZN1
// 2: 0000000000000000 4 OBJECT WEAK DEFAULT 4 _ZN1SIPiE1nE
```
My expectation is that `S<int*>::n` should be hidden here, because the partial specialization was declared hidden. This is also what happens if we compile with gcc instead of clang. We get the same issue if we declare S to be HIDDEN in its original definition -- `S<int*>::n` will be hidden, even if `S<T*>` is explicitly given default visibility.
Putting a visibility attribute directly on the definition of `int S<T*>::n = 4;` correctly overrides previously-declared attributes.
This only seems to happen for partial specializations: if we specialize `S<int*>` explicitly, its visibility attribute is taken into account.
This seems closely related to #103477, though I'm not sure if it's exactly the same issue or not. Oddly, it seems that the visibility of `int S<T*>::n;` is considered to be hidden at some point during compilation, since it's triggering a warning I'm developing that involves checking for hidden visibility. This indicates that the attribute is getting lost at some point, [as mentioned here](https://github.com/llvm/llvm-project/issues/103477#issuecomment-2329253191).
If we have a partial template specialization of a class, the visibility of its static members is determined by the visibility attribute of the original definition, rather than the partially-templated one:
My expectation is that
S<int*>::n
should be hidden here, because the partial specialization was declared hidden. This is also what happens if we compile with gcc instead of clang. We get the same issue if we declare S to be HIDDEN in its original definition --S<int*>::n
will be hidden, even ifS<T*>
is explicitly given default visibility.Putting a visibility attribute directly on the definition of
int S<T*>::n = 4;
correctly overrides previously-declared attributes.This only seems to happen for partial specializations: if we specialize
S<int*>
explicitly, its visibility attribute is taken into account.This seems closely related to #103477, though I'm not sure if it's exactly the same issue or not. Oddly, it seems that the visibility of
int S<T*>::n;
is considered to be hidden at some point during compilation, since it's triggering a warning I'm developing that involves checking for hidden visibility. This indicates that the attribute is getting lost at some point, as mentioned here.