https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63486
Andrew Pinski <pinskia at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |RESOLVED Resolution|--- |INVALID --- Comment #1 from Andrew Pinski <pinskia at gcc dot gnu.org> --- It is easier to understand the code this way: <bb 2>: _1 = __atomic_load_1 (&_ZGVZ4testvE1x, 2); _2 = (int) _1; _3 = _2 & 1; retval.0_8 = _3 == 0; if (retval.0_8 != 0) goto <bb 3>; else goto <bb 5>; <bb 3>: _4 = __cxa_guard_acquire (&_ZGVZ4testvE1x); retval.1_10 = _4 != 0; if (retval.1_10 != 0) goto <bb 4>; else goto <bb 5>; <bb 4>: _11 = 0; std::__cxx11::basic_string<char>::basic_string (&x); _13 = 1; __cxa_guard_release (&_ZGVZ4testvE1x); __cxa_atexit (__comp_dtor , &x, &__dso_handle); ---- CUT ---- So if the variable was initialized, __cxa_atexit is never called. __cxa_guard_acquire is not exactly a lock. it is rather a check to see if the variable has been initialized, if not then see if someone is initializing it right now. If someone is initializing, then wait for the initializing to be finished before return. Return nonzero if this thread is going to be the thread which initializes the variable. So the cxa_atexit is done after the release which is fine as if someone decides to do exit right after the __cxa_guard_acquire on another thread, you might leak some memory but the decl will never be destructed multiple times.