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