Skip to content

Commit a9f8f8b

Browse files
authored
Rollup merge of #122583 - Zoxc:tls-non-mut, r=joboet
Use `UnsafeCell` for fast constant thread locals This uses `UnsafeCell` instead of `static mut` for fast constant thread locals. This changes the type of the TLS shims to return `&UnsafeCell<T>` instead of `*mut T` which means they are always non-null so LLVM can optimize away the check for `Some` in `LocalKey::with` if `T` has no destructor. LLVM is currently unable to do this optimization as we lose the fact that `__getit` always returns `Some` as it gets optimized to just returning the value of the TLS shim.
2 parents 42e03fc + b0b2493 commit a9f8f8b

File tree

1 file changed

+7
-8
lines changed

1 file changed

+7
-8
lines changed

library/std/src/sys/thread_local/fast_local.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,21 @@ pub macro thread_local_inner {
1313
(@key $t:ty, const $init:expr) => {{
1414
#[inline]
1515
#[deny(unsafe_op_in_unsafe_fn)]
16-
// FIXME: Use `SyncUnsafeCell` instead of allowing `static_mut_refs` lint
17-
#[cfg_attr(bootstrap, allow(static_mut_ref))]
18-
#[cfg_attr(not(bootstrap), allow(static_mut_refs))]
1916
unsafe fn __getit(
2017
_init: $crate::option::Option<&mut $crate::option::Option<$t>>,
2118
) -> $crate::option::Option<&'static $t> {
2219
const INIT_EXPR: $t = $init;
2320
// If the platform has support for `#[thread_local]`, use it.
2421
#[thread_local]
25-
static mut VAL: $t = INIT_EXPR;
22+
// We use `UnsafeCell` here instead of `static mut` to ensure any generated TLS shims
23+
// have a nonnull attribute on their return value.
24+
static VAL: $crate::cell::UnsafeCell<$t> = $crate::cell::UnsafeCell::new(INIT_EXPR);
2625

2726
// If a dtor isn't needed we can do something "very raw" and
2827
// just get going.
2928
if !$crate::mem::needs_drop::<$t>() {
3029
unsafe {
31-
return $crate::option::Option::Some(&VAL)
30+
return $crate::option::Option::Some(&*VAL.get())
3231
}
3332
}
3433

@@ -55,15 +54,15 @@ pub macro thread_local_inner {
5554
// so now.
5655
0 => {
5756
$crate::thread::local_impl::Key::<$t>::register_dtor(
58-
$crate::ptr::addr_of_mut!(VAL) as *mut $crate::primitive::u8,
57+
VAL.get() as *mut $crate::primitive::u8,
5958
destroy,
6059
);
6160
STATE.set(1);
62-
$crate::option::Option::Some(&VAL)
61+
$crate::option::Option::Some(&*VAL.get())
6362
}
6463
// 1 == the destructor is registered and the value
6564
// is valid, so return the pointer.
66-
1 => $crate::option::Option::Some(&VAL),
65+
1 => $crate::option::Option::Some(&*VAL.get()),
6766
// otherwise the destructor has already run, so we
6867
// can't give access.
6968
_ => $crate::option::Option::None,

0 commit comments

Comments
 (0)