Propagation of storage/linkage specifiers to explicit (variable) template specializations

Clang’s (at least 13 to 15) behavior in regards to storage specifiers of variable templates (C++17) seems to significantly differ from that of GCC (tested 9 and 12). While GCC correctly propagates storage specifier in the base template to its explicit specialization (and disallows storage specifier in the specialization), Clang seems to do the opposite. It allows to specify storage specifier of the specialization, but does not propagate base template specifier to the specializations. This leads to linking errors or code that is invalid in GCC.

Lets have two translation units:

template<typename T>
static const std::string test = "Hello World A<T>";

template<> const std::string test<int> = "Hello World A<int>";

and

template<typename T>
static const std::string test = "Hello World B<T>";

template<> const std::string test<int> = "Hello World B<int>";

This compiles perfectly fine with GCC, but leads to linker errors (multiple definitions of test<int>) when compiled with Clang. If we change both explicit specializations by adding “static” storage:

template<> static const std::string test<int> = ...

the code no longer compiles with GCC, but compiles and links fine with Clang. This can be worked around by using anonymous namespace, but it seems like Clang does not adhere to standard here.