summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/std/src/sys/thread_local/fast_local.rs15
1 files changed, 7 insertions, 8 deletions
diff --git a/library/std/src/sys/thread_local/fast_local.rs b/library/std/src/sys/thread_local/fast_local.rs
index 646dcd7f3a3..69ee70de30c 100644
--- a/library/std/src/sys/thread_local/fast_local.rs
+++ b/library/std/src/sys/thread_local/fast_local.rs
@@ -13,22 +13,21 @@ pub macro thread_local_inner {
     (@key $t:ty, const $init:expr) => {{
         #[inline]
         #[deny(unsafe_op_in_unsafe_fn)]
-        // FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
-        #[cfg_attr(bootstrap, allow(static_mut_ref))]
-        #[cfg_attr(not(bootstrap), allow(static_mut_refs))]
         unsafe fn __getit(
             _init: $crate::option::Option<&mut $crate::option::Option<$t>>,
         ) -> $crate::option::Option<&'static $t> {
             const INIT_EXPR: $t = $init;
             // If the platform has support for `#[thread_local]`, use it.
             #[thread_local]
-            static mut VAL: $t = INIT_EXPR;
+            // We use `UnsafeCell` here instead of `static mut` to ensure any generated TLS shims
+            // have a nonnull attribute on their return value.
+            static VAL: $crate::cell::UnsafeCell<$t> = $crate::cell::UnsafeCell::new(INIT_EXPR);
 
             // If a dtor isn't needed we can do something "very raw" and
             // just get going.
             if !$crate::mem::needs_drop::<$t>() {
                 unsafe {
-                    return $crate::option::Option::Some(&VAL)
+                    return $crate::option::Option::Some(&*VAL.get())
                 }
             }
 
@@ -55,15 +54,15 @@ pub macro thread_local_inner {
                     //   so now.
                     0 => {
                         $crate::thread::local_impl::Key::<$t>::register_dtor(
-                            $crate::ptr::addr_of_mut!(VAL) as *mut $crate::primitive::u8,
+                            VAL.get() as *mut $crate::primitive::u8,
                             destroy,
                         );
                         STATE.set(1);
-                        $crate::option::Option::Some(&VAL)
+                        $crate::option::Option::Some(&*VAL.get())
                     }
                     // 1 == the destructor is registered and the value
                     //   is valid, so return the pointer.
-                    1 => $crate::option::Option::Some(&VAL),
+                    1 => $crate::option::Option::Some(&*VAL.get()),
                     // otherwise the destructor has already run, so we
                     // can't give access.
                     _ => $crate::option::Option::None,