Clang disagrees with gcc at the intersection of explicit template instantiations and visibility

Hi folks,

I’ve been looking at explicit template instantiations lately, and came across the following
corner case where gcc and clang disagree on the visibility of a symbol. I’m inclined to think gcc’s behavior is correct, but I wanted to make sure I’m not missing some reason why AddS needs to be visible.

Consider the following file (test.cpp):

template < typename T > class foo {
public:
T x;
T getX() { return x; }
template < typename S >
attribute ((visibility(“hidden”))) S AddS(S);
};

attribute ((visibility(“hidden”))) S foo::AddS(S y) {
return ((S) x) + y;
}

template < typename T, typename S >
attribute ((visibility(“hidden”))) S AddTS(T x, S y) {
return ((S) x) + y;
}

extern template struct foo;
template struct foo;

int footest() {
auto var = foo{5};
auto bar = var.AddS((long long)3);
auto bar2 = AddTS((int)5,(long long)3);
return var.getX();
}

$ gcc -std=c++11 -c -S -o - test.cpp | grep .hidden
.hidden ZN3fooIiE4AddSIxEET_S2
.hidden Z5AddTSIixET0_T_S0
$ clang-3.5 -std=c++11 -c -S -o - test.cpp | grep .hidden
.hidden Z5AddTSIixET0_T_S0

Proposed patch with more test cases: http://reviews.llvm.org/D13419