I'm currently working on a massive overhaul of the visibility code to
make it play nice with C++. One of the issues I've run into is the
question of priority of #pragma visibility versus other sources of
visibility information.
Consider:
#pragma GCC visibility push(hidden)
class __attribute((visibility("default"))) A
{
void f ();
};
void A::f() { }
Here I think we'd all agree that f should get default visibility.
class A
{
void f ();
};
#pragma GCC visibility push(hidden)
void A::f() { }
#pragma GCC visibility pop
This case is less clear; A does not have a specified visibility, but the
context of f's definition does. However, we don't want to encourage
this kind of code; the visibility should be specified as early as
possible so that callers use the right calling convention. Waiting
until the definition to specify visibility is bad practice. Also, the
status quo is that f gets A's visibility. I would preserve that and
possibly give a warning to tell the user that they might want to add
__attribute((visibility)) to the declaration of f in A.
Now, templates:
template<class T> __attribute((visibility ("hidden")) T f(T);
#pragma GCC visibility push(default)
extern template int f(int);
#pragma GCC visibility pop
This could really go either way. It could be considered similar to the
above case in that f<int> is in a way "part" of f<T>, but there isn't
the same scoping relationship. Also, there isn't the
declaration/definition problem, as the extern template directive is the
first declaration of the instantiation. In this case I am inclined to
respect the #pragma rather than the attribute on the template.
Using an attribute would be less ambiguous:
extern template __attribute ((visibility ("default")) int f(int);
In a PR Geoff asked if we really want to allow different visibility for
different instantiations. I think we do; perhaps one instantiation is
part of the interface of an exported class, but we want other
instantiations to be generated locally in each shared object.
Jason