We use the Intel C++ compiler and detected that it miscompiles (?) the following, reduced from a use of boost::function<Ponies()> f(unnamedNamespacedFunctor).
a1.cc:
template<typename T>
int f(T) { static int x = T::x; return x; }
namespace { struct A { static const int x = 1; }; }
int f1() {
return f(A());
}
a2.cc:
template<typename T>
int f(T) { static int x = T::x; return x; }
namespace { struct A { static const int x = 0; }; }
int f2() {
return f(A());
}
main.cc:
#include <cstdio>
int f1();
int f2();
int main() {
std::printf("%d != %d\n", f1(), f2());
}
Command line:
# icpc a1.cc a2.cc main.cc -o main
# ./main
0 != 0
My question is: Is this compliant? Does using static locals in such instantiations produce undefined behavior? When inspecting the produced symbols, I noted that while f is has local linkage, as I suspected, the x static variable receives weak linkage and therefore the two x'es are merged and it becomes lottery which is chosen
# icpc a2.cc a1.cc main.cc -o main
# ./main
1 != 1
I would be grateful for help. Perhaps this is actually a compiler-bug after all and it has already been reported?
This looks like a bug to me. Letting A1 be one of the instantiations of A and A2 be the other:
I presume that the static x has weak linkage so that the linker can merge copies of the static between multiple copies of the same instantiation. (If you managed to instantiate f<A1> in two different translation units, for example.)
Either f<A1> and f<A2> should have different name mangling, which would cause the two versions of x to have different name mangling (I think some compilers actually generate a random value to make names inside anonymous namespaces unique), or else x should not have internal linkage (because a local type was used to instantiate f, which should make it impossible to replicate in another translation unit).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With