Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are static locals of function template specializations with T=<unnamed namespaced class> required to be unique?

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?

like image 411
Johannes Schaub - litb Avatar asked Oct 21 '15 14:10

Johannes Schaub - litb


1 Answers

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).

like image 50
John Calsbeek Avatar answered Sep 30 '22 12:09

John Calsbeek