Bug 89727 - static thread_local ODR use broken
Summary: static thread_local ODR use broken
Status: RESOLVED DUPLICATE of bug 60702
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 8.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2019-03-15 11:21 UTC by Klaus Leppkes
Modified: 2019-03-15 13:59 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-03-15 00:00:00


Attachments
minimal example of incorrect behavior (static member B::a should be initialized before first usage). (193 bytes, text/x-csrc)
2019-03-15 11:21 UTC, Klaus Leppkes
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Klaus Leppkes 2019-03-15 11:21:07 UTC
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
Comment 1 Richard Biener 2019-03-15 11:42:11 UTC
.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.
Comment 2 Klaus Leppkes 2019-03-15 12:22:20 UTC
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?
Comment 3 Jonathan Wakely 2019-03-15 13:56:51 UTC
Yes, and it's a dup of an existing bug.
Comment 4 Jonathan Wakely 2019-03-15 13:59:41 UTC
Found it.

*** This bug has been marked as a duplicate of bug 60702 ***