@@ -133,6 +133,15 @@ macro_rules! thread_local {
133133 // empty (base case for the recursion)
134134 ( ) => { } ;
135135
136+ ( $( #[ $attr: meta] ) * $vis: vis static $name: ident: $t: ty = const { $init: expr } ; $( $rest: tt) * ) => (
137+ $crate:: __thread_local_inner!( $( #[ $attr] ) * $vis $name, $t, const $init) ;
138+ $crate:: thread_local!( $( $rest) * ) ;
139+ ) ;
140+
141+ ( $( #[ $attr: meta] ) * $vis: vis static $name: ident: $t: ty = const { $init: expr } ) => (
142+ $crate:: __thread_local_inner!( $( #[ $attr] ) * $vis $name, $t, const $init) ;
143+ ) ;
144+
136145 // process multiple declarations
137146 ( $( #[ $attr: meta] ) * $vis: vis static $name: ident: $t: ty = $init: expr; $( $rest: tt) * ) => (
138147 $crate:: __thread_local_inner!( $( #[ $attr] ) * $vis $name, $t, $init) ;
@@ -151,6 +160,101 @@ macro_rules! thread_local {
151160#[ allow_internal_unstable( thread_local_internals, cfg_target_thread_local, thread_local) ]
152161#[ allow_internal_unsafe]
153162macro_rules! __thread_local_inner {
163+ // used to generate the `LocalKey` value for const-initialized thread locals
164+ ( @key $t: ty, const $init: expr) => { {
165+ unsafe fn __getit( ) -> $crate:: option:: Option <& ' static $t> {
166+ const _REQUIRE_UNSTABLE: ( ) = $crate:: thread:: require_unstable_const_init_thread_local( ) ;
167+
168+ // wasm without atomics maps directly to `static mut`, and dtors
169+ // aren't implemented because thread dtors aren't really a thing
170+ // on wasm right now
171+ //
172+ // FIXME(#84224) this should come after the `target_thread_local`
173+ // block.
174+ #[ cfg( all( target_arch = "wasm32" , not( target_feature = "atomics" ) ) ) ]
175+ {
176+ static mut VAL : $t = $init;
177+ Some ( & VAL )
178+ }
179+
180+ // If the platform has support for `#[thread_local]`, use it.
181+ #[ cfg( all(
182+ target_thread_local,
183+ not( all( target_arch = "wasm32" , not( target_feature = "atomics" ) ) ) ,
184+ ) ) ]
185+ {
186+ // If a dtor isn't needed we can do something "very raw" and
187+ // just get going.
188+ if !$crate:: mem:: needs_drop:: <$t>( ) {
189+ #[ thread_local]
190+ static mut VAL : $t = $init;
191+ unsafe {
192+ return Some ( & VAL )
193+ }
194+ }
195+
196+ #[ thread_local]
197+ static mut VAL : $t = $init;
198+ // 0 == dtor not registered
199+ // 1 == dtor registered, dtor not run
200+ // 2 == dtor registered and is running or has run
201+ #[ thread_local]
202+ static mut STATE : u8 = 0 ;
203+
204+ unsafe extern "C" fn destroy( ptr: * mut u8 ) {
205+ let ptr = ptr as * mut $t;
206+
207+ unsafe {
208+ debug_assert_eq!( STATE , 1 ) ;
209+ STATE = 2 ;
210+ $crate:: ptr:: drop_in_place( ptr) ;
211+ }
212+ }
213+
214+ unsafe {
215+ match STATE {
216+ // 0 == we haven't registered a destructor, so do
217+ // so now.
218+ 0 => {
219+ $crate:: thread:: __FastLocalKeyInner:: <$t>:: register_dtor(
220+ & VAL as * const _ as * mut u8 ,
221+ destroy,
222+ ) ;
223+ STATE = 1 ;
224+ Some ( & VAL )
225+ }
226+ // 1 == the destructor is registered and the value
227+ // is valid, so return the pointer.
228+ 1 => Some ( & VAL ) ,
229+ // otherwise the destructor has already run, so we
230+ // can't give access.
231+ _ => None ,
232+ }
233+ }
234+ }
235+
236+ // On platforms without `#[thread_local]` we fall back to the
237+ // same implementation as below for os thread locals.
238+ #[ cfg( all(
239+ not( target_thread_local) ,
240+ not( all( target_arch = "wasm32" , not( target_feature = "atomics" ) ) ) ,
241+ ) ) ]
242+ {
243+ #[ inline]
244+ const fn __init( ) -> $t { $init }
245+ static __KEY: $crate:: thread:: __OsLocalKeyInner<$t> =
246+ $crate:: thread:: __OsLocalKeyInner:: new( ) ;
247+ #[ allow( unused_unsafe) ]
248+ unsafe { __KEY. get( __init) }
249+ }
250+ }
251+
252+ unsafe {
253+ $crate:: thread:: LocalKey :: new( __getit)
254+ }
255+ } } ;
256+
257+ // used to generate the `LocalKey` value for `thread_local!`
154258 ( @key $t: ty, $init: expr) => {
155259 {
156260 #[ inline]
@@ -188,9 +292,9 @@ macro_rules! __thread_local_inner {
188292 }
189293 }
190294 } ;
191- ( $( #[ $attr: meta] ) * $vis: vis $name: ident, $t: ty, $init: expr ) => {
295+ ( $( #[ $attr: meta] ) * $vis: vis $name: ident, $t: ty, $( $ init: tt ) * ) => {
192296 $( #[ $attr] ) * $vis const $name: $crate:: thread:: LocalKey <$t> =
193- $crate:: __thread_local_inner!( @key $t, $init) ;
297+ $crate:: __thread_local_inner!( @key $t, $( $ init) * ) ;
194298 }
195299}
196300
@@ -442,6 +546,15 @@ pub mod fast {
442546 Key { inner : LazyKeyInner :: new ( ) , dtor_state : Cell :: new ( DtorState :: Unregistered ) }
443547 }
444548
549+ // note that this is just a publically-callable function only for the
550+ // const-initialized form of thread locals, basically a way to call the
551+ // free `register_dtor` function defined elsewhere in libstd.
552+ pub unsafe fn register_dtor ( a : * mut u8 , dtor : unsafe extern "C" fn ( * mut u8 ) ) {
553+ unsafe {
554+ register_dtor ( a, dtor) ;
555+ }
556+ }
557+
445558 pub unsafe fn get < F : FnOnce ( ) -> T > ( & self , init : F ) -> Option < & ' static T > {
446559 // SAFETY: See the definitions of `LazyKeyInner::get` and
447560 // `try_initialize` for more informations.
0 commit comments