@@ -173,200 +173,6 @@ macro_rules! thread_local {
173173 ) ;
174174}
175175
176- #[ doc( hidden) ]
177- #[ unstable( feature = "thread_local_internals" , reason = "should not be necessary" , issue = "none" ) ]
178- #[ macro_export]
179- #[ allow_internal_unstable( thread_local_internals, cfg_target_thread_local, thread_local) ]
180- #[ allow_internal_unsafe]
181- macro_rules! __thread_local_inner {
182- // used to generate the `LocalKey` value for const-initialized thread locals
183- ( @key $t: ty, const $init: expr) => { {
184- #[ cfg_attr( not( windows) , inline) ] // see comments below
185- #[ deny( unsafe_op_in_unsafe_fn) ]
186- unsafe fn __getit(
187- _init: $crate:: option:: Option <& mut $crate:: option:: Option <$t>>,
188- ) -> $crate:: option:: Option <& ' static $t> {
189- const INIT_EXPR : $t = $init;
190-
191- // wasm without atomics maps directly to `static mut`, and dtors
192- // aren't implemented because thread dtors aren't really a thing
193- // on wasm right now
194- //
195- // FIXME(#84224) this should come after the `target_thread_local`
196- // block.
197- #[ cfg( all( target_family = "wasm" , not( target_feature = "atomics" ) ) ) ]
198- {
199- static mut VAL : $t = INIT_EXPR ;
200- unsafe { $crate:: option:: Option :: Some ( & VAL ) }
201- }
202-
203- // If the platform has support for `#[thread_local]`, use it.
204- #[ cfg( all(
205- target_thread_local,
206- not( all( target_family = "wasm" , not( target_feature = "atomics" ) ) ) ,
207- ) ) ]
208- {
209- #[ thread_local]
210- static mut VAL : $t = INIT_EXPR ;
211-
212- // If a dtor isn't needed we can do something "very raw" and
213- // just get going.
214- if !$crate:: mem:: needs_drop:: <$t>( ) {
215- unsafe {
216- return $crate:: option:: Option :: Some ( & VAL )
217- }
218- }
219-
220- // 0 == dtor not registered
221- // 1 == dtor registered, dtor not run
222- // 2 == dtor registered and is running or has run
223- #[ thread_local]
224- static mut STATE : $crate:: primitive:: u8 = 0 ;
225-
226- unsafe extern "C" fn destroy( ptr: * mut $crate:: primitive:: u8 ) {
227- let ptr = ptr as * mut $t;
228-
229- unsafe {
230- $crate:: debug_assert_eq!( STATE , 1 ) ;
231- STATE = 2 ;
232- $crate:: ptr:: drop_in_place( ptr) ;
233- }
234- }
235-
236- unsafe {
237- match STATE {
238- // 0 == we haven't registered a destructor, so do
239- // so now.
240- 0 => {
241- $crate:: thread:: __FastLocalKeyInner:: <$t>:: register_dtor(
242- $crate:: ptr:: addr_of_mut!( VAL ) as * mut $crate:: primitive:: u8 ,
243- destroy,
244- ) ;
245- STATE = 1 ;
246- $crate:: option:: Option :: Some ( & VAL )
247- }
248- // 1 == the destructor is registered and the value
249- // is valid, so return the pointer.
250- 1 => $crate:: option:: Option :: Some ( & VAL ) ,
251- // otherwise the destructor has already run, so we
252- // can't give access.
253- _ => $crate:: option:: Option :: None ,
254- }
255- }
256- }
257-
258- // On platforms without `#[thread_local]` we fall back to the
259- // same implementation as below for os thread locals.
260- #[ cfg( all(
261- not( target_thread_local) ,
262- not( all( target_family = "wasm" , not( target_feature = "atomics" ) ) ) ,
263- ) ) ]
264- {
265- #[ inline]
266- const fn __init( ) -> $t { INIT_EXPR }
267- static __KEY: $crate:: thread:: __OsLocalKeyInner<$t> =
268- $crate:: thread:: __OsLocalKeyInner:: new( ) ;
269- #[ allow( unused_unsafe) ]
270- unsafe {
271- __KEY. get( move || {
272- if let $crate:: option:: Option :: Some ( init) = _init {
273- if let $crate:: option:: Option :: Some ( value) = init. take( ) {
274- return value;
275- } else if $crate:: cfg!( debug_assertions) {
276- $crate:: unreachable!( "missing initial value" ) ;
277- }
278- }
279- __init( )
280- } )
281- }
282- }
283- }
284-
285- unsafe {
286- $crate:: thread:: LocalKey :: new( __getit)
287- }
288- } } ;
289-
290- // used to generate the `LocalKey` value for `thread_local!`
291- ( @key $t: ty, $init: expr) => {
292- {
293- #[ inline]
294- fn __init( ) -> $t { $init }
295-
296- // When reading this function you might ask "why is this inlined
297- // everywhere other than Windows?", and that's a very reasonable
298- // question to ask. The short story is that it segfaults rustc if
299- // this function is inlined. The longer story is that Windows looks
300- // to not support `extern` references to thread locals across DLL
301- // boundaries. This appears to at least not be supported in the ABI
302- // that LLVM implements.
303- //
304- // Because of this we never inline on Windows, but we do inline on
305- // other platforms (where external references to thread locals
306- // across DLLs are supported). A better fix for this would be to
307- // inline this function on Windows, but only for "statically linked"
308- // components. For example if two separately compiled rlibs end up
309- // getting linked into a DLL then it's fine to inline this function
310- // across that boundary. It's only not fine to inline this function
311- // across a DLL boundary. Unfortunately rustc doesn't currently
312- // have this sort of logic available in an attribute, and it's not
313- // clear that rustc is even equipped to answer this (it's more of a
314- // Cargo question kinda). This means that, unfortunately, Windows
315- // gets the pessimistic path for now where it's never inlined.
316- //
317- // The issue of "should enable on Windows sometimes" is #84933
318- #[ cfg_attr( not( windows) , inline) ]
319- unsafe fn __getit(
320- init: $crate:: option:: Option <& mut $crate:: option:: Option <$t>>,
321- ) -> $crate:: option:: Option <& ' static $t> {
322- #[ cfg( all( target_family = "wasm" , not( target_feature = "atomics" ) ) ) ]
323- static __KEY: $crate:: thread:: __StaticLocalKeyInner<$t> =
324- $crate:: thread:: __StaticLocalKeyInner:: new( ) ;
325-
326- #[ thread_local]
327- #[ cfg( all(
328- target_thread_local,
329- not( all( target_family = "wasm" , not( target_feature = "atomics" ) ) ) ,
330- ) ) ]
331- static __KEY: $crate:: thread:: __FastLocalKeyInner<$t> =
332- $crate:: thread:: __FastLocalKeyInner:: new( ) ;
333-
334- #[ cfg( all(
335- not( target_thread_local) ,
336- not( all( target_family = "wasm" , not( target_feature = "atomics" ) ) ) ,
337- ) ) ]
338- static __KEY: $crate:: thread:: __OsLocalKeyInner<$t> =
339- $crate:: thread:: __OsLocalKeyInner:: new( ) ;
340-
341- // FIXME: remove the #[allow(...)] marker when macros don't
342- // raise warning for missing/extraneous unsafe blocks anymore.
343- // See https://github.com/rust-lang/rust/issues/74838.
344- #[ allow( unused_unsafe) ]
345- unsafe {
346- __KEY. get( move || {
347- if let $crate:: option:: Option :: Some ( init) = init {
348- if let $crate:: option:: Option :: Some ( value) = init. take( ) {
349- return value;
350- } else if $crate:: cfg!( debug_assertions) {
351- $crate:: unreachable!( "missing default value" ) ;
352- }
353- }
354- __init( )
355- } )
356- }
357- }
358-
359- unsafe {
360- $crate:: thread:: LocalKey :: new( __getit)
361- }
362- }
363- } ;
364- ( $( #[ $attr: meta] ) * $vis: vis $name: ident, $t: ty, $( $init: tt) * ) => {
365- $( #[ $attr] ) * $vis const $name: $crate:: thread:: LocalKey <$t> =
366- $crate:: __thread_local_inner!( @key $t, $( $init) * ) ;
367- }
368- }
369-
370176/// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with).
371177#[ stable( feature = "thread_local_try_with" , since = "1.26.0" ) ]
372178#[ non_exhaustive]
0 commit comments