22//! thread locals and we can instead just use plain statics! 
33
44use  crate :: cell:: { Cell ,  UnsafeCell } ; 
5+ use  crate :: mem:: MaybeUninit ; 
56use  crate :: ptr; 
67
78#[ doc( hidden) ]  
@@ -11,12 +12,13 @@ use crate::ptr;
1112#[ rustc_macro_transparency = "semitransparent" ]  
1213pub  macro thread_local_inner  { 
1314    // used to generate the `LocalKey` value for const-initialized thread locals 
14-     ( @key  $t: ty,  const  $init: expr)  => { { 
15+     ( @key  $t: ty,  $ ( # [ $align_attr : meta ] ) * ,   const  $init: expr)  => { { 
1516        const  __INIT:  $t = $init; 
1617
1718        // NOTE: Please update the shadowing test in `tests/thread.rs` if these types are renamed. 
1819        unsafe  { 
1920            $crate:: thread:: LocalKey :: new ( |_| { 
21+                 $( #[ $align_attr]  ) * 
2022                static  VAL :  $crate:: thread:: local_impl:: EagerStorage <$t> =
2123                    $crate:: thread:: local_impl:: EagerStorage  {  value :  __INIT } ; 
2224                & VAL . value 
@@ -25,42 +27,50 @@ pub macro thread_local_inner {
2527    } } , 
2628
2729    // used to generate the `LocalKey` value for `thread_local!` 
28-     ( @key  $t: ty,  $init: expr)  => { { 
30+     ( @key  $t: ty,  $( # [ $align_attr : meta ] ) * ,  $ init: expr)  => { { 
2931        #[ inline]  
3032        fn __init( )  -> $t {  $init } 
3133
3234        unsafe  { 
33-             use  $crate:: thread:: LocalKey ; 
34-             use  $crate:: thread:: local_impl:: LazyStorage ; 
35- 
36-             LocalKey :: new ( |init| { 
37-                 static  VAL :  LazyStorage < $t>  = LazyStorage :: new ( ) ; 
35+             $crate:: thread:: LocalKey :: new ( |init| { 
36+                 $( #[ $align_attr]  ) * 
37+                 static  VAL :  $crate:: thread:: local_impl:: LazyStorage <$t> = $crate:: thread:: local_impl:: LazyStorage :: new ( ) ; 
3838                VAL . get ( init,  __init) 
3939            } ) 
4040        } 
4141    } } , 
42-     ( $( #[ $attr: meta]  ) *  $vis: vis $name: ident,  $t: ty,  $( $init: tt) * )  => { 
43-         $( #[ $attr]  ) *  $vis const $name:  $crate:: thread:: LocalKey <$t> =
44-             $crate:: thread:: local_impl:: thread_local_inner!( @key $t,  $( $init) * ) ; 
45-     } , 
4642} 
4743
4844#[ allow( missing_debug_implementations) ]  
45+ #[ repr( transparent) ]   // Required for correctness of `#[rustc_align_static]` 
4946pub  struct  EagerStorage < T >  { 
5047    pub  value :  T , 
5148} 
5249
5350// SAFETY: the target doesn't have threads. 
5451unsafe  impl < T >  Sync  for  EagerStorage < T >  { } 
5552
53+ #[ derive( Clone ,  Copy ,  PartialEq ,  Eq ) ]  
54+ enum  State  { 
55+     Initial , 
56+     Alive , 
57+     Destroying , 
58+ } 
59+ 
5660#[ allow( missing_debug_implementations) ]  
61+ #[ repr( C ) ]  
5762pub  struct  LazyStorage < T >  { 
58-     value :  UnsafeCell < Option < T > > , 
63+     // This field must be first, for correctness of `#[rustc_align_static]` 
64+     value :  UnsafeCell < MaybeUninit < T > > , 
65+     state :  Cell < State > , 
5966} 
6067
6168impl < T >  LazyStorage < T >  { 
6269    pub  const  fn  new ( )  -> LazyStorage < T >  { 
63-         LazyStorage  {  value :  UnsafeCell :: new ( None )  } 
70+         LazyStorage  { 
71+             value :  UnsafeCell :: new ( MaybeUninit :: uninit ( ) ) , 
72+             state :  Cell :: new ( State :: Initial ) , 
73+         } 
6474    } 
6575
6676    /// Gets a pointer to the TLS value, potentially initializing it with the 
@@ -70,24 +80,39 @@ impl<T> LazyStorage<T> {
7080     /// has occurred. 
7181     #[ inline]  
7282    pub  fn  get ( & ' static  self ,  i :  Option < & mut  Option < T > > ,  f :  impl  FnOnce ( )  -> T )  -> * const  T  { 
73-         let  value =  unsafe   {   & * self . value . get ( )  } ; 
74-         match   value  { 
75-              Some ( v )  => v , 
76-             None  =>  self . initialize ( i,  f) , 
83+         if   self . state . get ( )  ==  State :: Alive   { 
84+              self . value . get ( )   as   * const   T 
85+         }   else   { 
86+             self . initialize ( i,  f) 
7787        } 
7888    } 
7989
8090    #[ cold]  
8191    fn  initialize ( & ' static  self ,  i :  Option < & mut  Option < T > > ,  f :  impl  FnOnce ( )  -> T )  -> * const  T  { 
8292        let  value = i. and_then ( Option :: take) . unwrap_or_else ( f) ; 
83-          // Destroy the old value, after updating the TLS variable as the 
84-         // destructor might reference it.  
93+ 
94+         // Destroy the old value if it is initialized  
8595        // FIXME(#110897): maybe panic on recursive initialization. 
96+         if  self . state . get ( )  == State :: Alive  { 
97+             self . state . set ( State :: Destroying ) ; 
98+             // Safety: we check for no initialization during drop below 
99+             unsafe  { 
100+                 ptr:: drop_in_place ( self . value . get ( )  as  * mut  T ) ; 
101+             } 
102+             self . state . set ( State :: Initial ) ; 
103+         } 
104+ 
105+         // Guard against initialization during drop 
106+         if  self . state . get ( )  == State :: Destroying  { 
107+             panic ! ( "Attempted to initialize thread-local while it is being dropped" ) ; 
108+         } 
109+ 
86110        unsafe  { 
87-             self . value . get ( ) . replace ( Some ( value) ) ; 
111+             self . value . get ( ) . write ( MaybeUninit :: new ( value) ) ; 
88112        } 
89-         // SAFETY: we just set this to `Some`. 
90-         unsafe  {  ( * self . value . get ( ) ) . as_ref ( ) . unwrap_unchecked ( )  } 
113+         self . state . set ( State :: Alive ) ; 
114+ 
115+         self . value . get ( )  as  * const  T 
91116    } 
92117} 
93118
0 commit comments