11use crate :: cell:: UnsafeCell ;
22use crate :: ptr;
33use crate :: sync:: atomic:: {
4- AtomicBool , AtomicPtr , AtomicU32 ,
4+ AtomicPtr , AtomicU32 ,
55 Ordering :: { AcqRel , Acquire , Relaxed , Release } ,
66} ;
77use crate :: sys:: c;
88
99#[ cfg( test) ]
1010mod tests;
1111
12- /// An optimization hint. The compiler is often smart enough to know if an atomic
13- /// is never set and can remove dead code based on that fact.
14- static HAS_DTORS : AtomicBool = AtomicBool :: new ( false ) ;
15-
1612// Using a per-thread list avoids the problems in synchronizing global state.
1713#[ thread_local]
1814#[ cfg( target_thread_local) ]
@@ -24,12 +20,11 @@ static DESTRUCTORS: crate::cell::RefCell<Vec<(*mut u8, unsafe extern "C" fn(*mut
2420#[ inline( never) ]
2521#[ cfg( target_thread_local) ]
2622pub unsafe fn register_keyless_dtor ( t : * mut u8 , dtor : unsafe extern "C" fn ( * mut u8 ) ) {
23+ dtors_used ( ) ;
2724 match DESTRUCTORS . try_borrow_mut ( ) {
2825 Ok ( mut dtors) => dtors. push ( ( t, dtor) ) ,
2926 Err ( _) => rtabort ! ( "global allocator may not use TLS" ) ,
3027 }
31-
32- HAS_DTORS . store ( true , Relaxed ) ;
3328}
3429
3530#[ inline( never) ] // See comment above
@@ -130,6 +125,7 @@ impl StaticKey {
130125 #[ cold]
131126 unsafe fn init ( & ' static self ) -> Key {
132127 if self . dtor . is_some ( ) {
128+ dtors_used ( ) ;
133129 let mut pending = c:: FALSE ;
134130 let r = c:: InitOnceBeginInitialize ( self . once . get ( ) , 0 , & mut pending, ptr:: null_mut ( ) ) ;
135131 assert_eq ! ( r, c:: TRUE ) ;
@@ -215,7 +211,6 @@ unsafe fn register_dtor(key: &'static StaticKey) {
215211 Err ( new) => head = new,
216212 }
217213 }
218- HAS_DTORS . store ( true , Release ) ;
219214}
220215
221216// -------------------------------------------------------------------------
@@ -281,17 +276,16 @@ unsafe fn register_dtor(key: &'static StaticKey) {
281276// the address of the symbol to ensure it sticks around.
282277
283278#[ link_section = ".CRT$XLB" ]
284- #[ allow( dead_code, unused_variables) ]
285- #[ used] // we don't want LLVM eliminating this symbol for any reason, and
286- // when the symbol makes it to the linker the linker will take over
287279pub static p_thread_callback: unsafe extern "system" fn ( c:: LPVOID , c:: DWORD , c:: LPVOID ) =
288280 on_tls_callback;
289281
290- #[ allow( dead_code, unused_variables) ]
291- unsafe extern "system" fn on_tls_callback ( h : c:: LPVOID , dwReason : c:: DWORD , pv : c:: LPVOID ) {
292- if !HAS_DTORS . load ( Acquire ) {
293- return ;
294- }
282+ fn dtors_used ( ) {
283+ // we don't want LLVM eliminating p_thread_callback when destructors are used.
284+ // when the symbol makes it to the linker the linker will take over
285+ unsafe { crate :: intrinsics:: volatile_load ( & p_thread_callback) } ;
286+ }
287+
288+ unsafe extern "system" fn on_tls_callback ( _h : c:: LPVOID , dwReason : c:: DWORD , _pv : c:: LPVOID ) {
295289 if dwReason == c:: DLL_THREAD_DETACH || dwReason == c:: DLL_PROCESS_DETACH {
296290 #[ cfg( not( target_thread_local) ) ]
297291 run_dtors ( ) ;
@@ -313,7 +307,7 @@ unsafe extern "system" fn on_tls_callback(h: c::LPVOID, dwReason: c::DWORD, pv:
313307 unsafe fn reference_tls_used ( ) { }
314308}
315309
316- #[ allow ( dead_code ) ] // actually called below
310+ #[ cfg ( not ( target_thread_local ) ) ]
317311unsafe fn run_dtors ( ) {
318312 for _ in 0 ..5 {
319313 let mut any_run = false ;
0 commit comments