@@ -22,7 +22,6 @@ unsafe impl DestroyedState for () {
2222#[ derive( Copy , Clone ) ]
2323enum State < D > {
2424 Uninitialized ,
25- Initializing ,
2625 Alive ,
2726 Destroyed ( D ) ,
2827}
@@ -64,36 +63,31 @@ where
6463
6564 #[ cold]
6665 fn get_or_init_slow ( & self , i : Option < & mut Option < T > > , f : impl FnOnce ( ) -> T ) -> * const T {
67- // Ensure we have unique access to an uninitialized value.
6866 match self . state . get ( ) {
69- State :: Uninitialized => self . state . set ( State :: Initializing ) ,
70- State :: Initializing => panic ! ( "thread_local initializer recursively depends on itself" ) ,
67+ State :: Uninitialized => { }
7168 State :: Alive => return self . value . get ( ) . cast ( ) ,
7269 State :: Destroyed ( _) => return ptr:: null ( ) ,
7370 }
7471
75- struct BackToUninitOnPanic < ' a , D > ( & ' a Cell < State < D > > ) ;
76- impl < ' a , D > Drop for BackToUninitOnPanic < ' a , D > {
77- fn drop ( & mut self ) {
78- self . 0 . set ( State :: Uninitialized ) ;
79- }
80- }
81-
82- // Get the initial value, making sure that we restore the state to uninitialized
83- // should f panic.
84- let on_panic = BackToUninitOnPanic ( & self . state ) ;
8572 let v = i. and_then ( Option :: take) . unwrap_or_else ( f) ;
86- crate :: mem:: forget ( on_panic) ;
8773
88- // SAFETY: we are !Sync so we have exclusive access to self.value. We also ensured
89- // that the state was uninitialized so we aren't replacing a value we must keep alive.
90- unsafe {
91- self . value . get ( ) . write ( MaybeUninit :: new ( v) ) ;
74+ match self . state . replace ( State :: Alive ) {
75+ State :: Uninitialized => D :: register_dtor ( self ) ,
76+
77+ State :: Alive => {
78+ // An init occurred during a recursive call, this could be a panic in the future.
79+
80+ // SAFETY: we cannot be inside a `LocalKey::with` scope, as the initializer
81+ // has already returned and the next scope only starts after we return
82+ // the pointer. Therefore, there can be no references to the old value.
83+ unsafe { ( * self . value . get ( ) ) . assume_init_drop ( ) }
84+ }
85+
86+ State :: Destroyed ( _) => unreachable ! ( ) ,
9287 }
9388
94- self . state . set ( State :: Alive ) ;
95- D :: register_dtor ( self ) ;
96- self . value . get ( ) . cast ( )
89+ // SAFETY: we are !Sync so we have exclusive access to self.value.
90+ unsafe { ( * self . value . get ( ) ) . write ( v) }
9791 }
9892}
9993
@@ -113,9 +107,7 @@ unsafe extern "C" fn destroy<T>(ptr: *mut u8) {
113107 // We also updated the state to Destroyed to prevent the destructor
114108 // from accessing the thread-local variable, as this would violate
115109 // the exclusive access provided by &mut T in Drop::drop.
116- unsafe {
117- crate :: ptr:: drop_in_place ( storage. value . get ( ) . cast :: < T > ( ) ) ;
118- }
110+ unsafe { ( * storage. value . get ( ) ) . assume_init_drop ( ) }
119111 }
120112 } )
121113}
0 commit comments