Created attachment 45972 [details] minimal example of incorrect behavior (static member B::a should be initialized before first usage). In the bug example, there are 3 uses of a static thread_local member. From my understanding to the C++ Standard, the compiler should initialize the member before first use (ODR Rule). Clang and Intel C++ Compiler behave correct from my understanding. GNU C++ initializes too late. ~/gcc_bug$ g++ test.cpp; ./a.out 0 constructing A. 42 42 ~/gcc_bug$ icc test.cpp; ./a.out constructing A. 42 42 42 ~/gcc_bug$ clang++ test.cpp; ./a.out constructing A. 42 42 42
.original shows the difference: struct B b; <<cleanup_point <<< Unknown tree: expr_stmt (void) std::basic_ostream<char>::operator<< ((struct __ostream_type *) std::basic_ostream<char>::operator<< ((struct basic_ostream *) std::basic_ostream<char>::operator<< (&cout, a.i), endl), flush) >>>>>; <<cleanup_point <<< Unknown tree: expr_stmt (void) std::basic_ostream<char>::operator<< ((struct basic_ostream *) std::basic_ostream<char>::operator<< (&cout, _ZTWN1B1aE ()->i), endl) >>>>>; <<cleanup_point <<< Unknown tree: expr_stmt (void) std::basic_ostream<char>::operator<< ((struct basic_ostream *) std::basic_ostream<char>::operator<< (&cout, a.i), endl) >>>>>; note how we perform the access differently for B::a.i vs. b.a.i, unexpected to me.
So from Richard Biener's post (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89727#c1), it looks like _ZTWN1B1aE [ $>c++filt "_ZTWN1B1aE" TLS wrapper function for B::a ] is the correct accessor (which internally will call the initializer) and a.i is a direct reference without the wrapper? So this looks a frontend problem, right?
Yes, and it's a dup of an existing bug.
Found it. *** This bug has been marked as a duplicate of bug 60702 ***