Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4305769
Tweak handling of "struct like start" where a struct isn't supported
estebank Sep 24, 2025
a4e87e9
Support `#[rustc_align_static]` inside `thread_local!`
Jules-Bertholet Sep 10, 2025
bb48c16
Simplify logic slightly
estebank Sep 24, 2025
4d32b9a
Hoist non-platform-specific code out of `thread_local_inner!`
Jules-Bertholet Sep 27, 2025
86f2d42
indexing: reword help
hkBst Sep 15, 2025
5b809b3
Don't enable shared memory with Wasm atomics
daxpedda Oct 1, 2025
8dfea22
implement `Box::take`
edwloef Oct 1, 2025
6961953
Switch `citool` to 2024 edition
GuillaumeGomez Oct 1, 2025
4baf920
Initialize llvm submodule if not already the case to run citool
GuillaumeGomez Oct 1, 2025
3e8ce2b
Adjust WASI and WALI targets
daxpedda Oct 1, 2025
94f00f4
Fix memory leak in `os` impl
Jules-Bertholet Oct 1, 2025
5991c87
Update books
rustbot Oct 1, 2025
30d57ab
mbe: Rename a local variable to match corresponding field names
joshtriplett Sep 14, 2025
6bff1ab
mbe: Support `unsafe` attribute rules
joshtriplett Sep 14, 2025
05c5b87
mbe: Add parsing tests for `unsafe` macro rules
joshtriplett Sep 14, 2025
ea0e00c
mbe: Add tests for `unsafe` attr invocation
joshtriplett Sep 14, 2025
4fc0a0d
mbe: `expand_invoc`: Add comment about not needing to check safety of…
joshtriplett Sep 28, 2025
59c4dfe
Forbid `//@ compile-flags: -Cincremental=` in tests
Zalathar Oct 1, 2025
92aac1b
Rollup merge of #146281 - Jules-Bertholet:static-align-thread-local, …
matthiaskrgr Oct 2, 2025
ac7beab
Rollup merge of #146535 - joshtriplett:mbe-unsafe-attr, r=petrochenkov
matthiaskrgr Oct 2, 2025
7320d3e
Rollup merge of #146585 - hkBst:indexing-1, r=jdonszelmann
matthiaskrgr Oct 2, 2025
e041b2c
Rollup merge of #147004 - estebank:ascription-in-pat, r=fee1-dead
matthiaskrgr Oct 2, 2025
b78b107
Rollup merge of #147221 - Zalathar:incremental, r=lqd
matthiaskrgr Oct 2, 2025
8a18176
Rollup merge of #147225 - daxpedda:wasm-u-u-atomics-threads, r=alexcr…
matthiaskrgr Oct 2, 2025
fbe6834
Rollup merge of #147227 - edwloef:box_take, r=joboet
matthiaskrgr Oct 2, 2025
f4dcfa6
Rollup merge of #147233 - GuillaumeGomez:citool-submodule-init, r=Kobzol
matthiaskrgr Oct 2, 2025
2d1efe7
Rollup merge of #147236 - rustbot:docs-update, r=ehuss
matthiaskrgr Oct 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion library/std/src/sys/thread_local/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ cfg_select! {
}
_ => {
mod os;
pub use os::{Storage, thread_local_inner};
pub use os::{Storage, thread_local_inner, value_align};
pub(crate) use os::{LocalPointer, local_pointer};
}
}
Expand Down
4 changes: 3 additions & 1 deletion library/std/src/sys/thread_local/native/eager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ enum State {
}

#[allow(missing_debug_implementations)]
#[repr(C)]
pub struct Storage<T> {
state: Cell<State>,
// This field must be first, for correctness of `#[rustc_align_static]`
val: UnsafeCell<T>,
state: Cell<State>,
}

impl<T> Storage<T> {
Expand Down
4 changes: 3 additions & 1 deletion library/std/src/sys/thread_local/native/lazy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ enum State<D> {
}

#[allow(missing_debug_implementations)]
#[repr(C)]
pub struct Storage<T, D> {
state: Cell<State<D>>,
// This field must be first, for correctness of `#[rustc_align_static]`
value: UnsafeCell<MaybeUninit<T>>,
state: Cell<State<D>>,
}

impl<T, D> Storage<T, D>
Expand Down
12 changes: 6 additions & 6 deletions library/std/src/sys/thread_local/native/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,23 @@ pub macro thread_local_inner {
// test in `tests/thread.rs` if these types are renamed.

// Used to generate the `LocalKey` value for const-initialized thread locals.
(@key $t:ty, const $init:expr) => {{
(@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{
const __INIT: $t = $init;

unsafe {
$crate::thread::LocalKey::new(const {
if $crate::mem::needs_drop::<$t>() {
|_| {
#[thread_local]
$(#[$align_attr])*
static VAL: $crate::thread::local_impl::EagerStorage<$t>
= $crate::thread::local_impl::EagerStorage::new(__INIT);
VAL.get()
}
} else {
|_| {
#[thread_local]
$(#[$align_attr])*
static VAL: $t = __INIT;
&VAL
}
Expand All @@ -78,7 +80,7 @@ pub macro thread_local_inner {
}},

// used to generate the `LocalKey` value for `thread_local!`
(@key $t:ty, $init:expr) => {{
(@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{
#[inline]
fn __init() -> $t {
$init
Expand All @@ -89,13 +91,15 @@ pub macro thread_local_inner {
if $crate::mem::needs_drop::<$t>() {
|init| {
#[thread_local]
$(#[$align_attr])*
static VAL: $crate::thread::local_impl::LazyStorage<$t, ()>
= $crate::thread::local_impl::LazyStorage::new();
VAL.get_or_init(init, __init)
}
} else {
|init| {
#[thread_local]
$(#[$align_attr])*
static VAL: $crate::thread::local_impl::LazyStorage<$t, !>
= $crate::thread::local_impl::LazyStorage::new();
VAL.get_or_init(init, __init)
Expand All @@ -104,10 +108,6 @@ pub macro thread_local_inner {
})
}
}},
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
$(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
$crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
},
}

#[rustc_macro_transparency = "semitransparent"]
Expand Down
69 changes: 47 additions & 22 deletions library/std/src/sys/thread_local/no_threads.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! thread locals and we can instead just use plain statics!

use crate::cell::{Cell, UnsafeCell};
use crate::mem::MaybeUninit;
use crate::ptr;

#[doc(hidden)]
Expand All @@ -11,12 +12,13 @@ use crate::ptr;
#[rustc_macro_transparency = "semitransparent"]
pub macro thread_local_inner {
// used to generate the `LocalKey` value for const-initialized thread locals
(@key $t:ty, const $init:expr) => {{
(@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{
const __INIT: $t = $init;

// NOTE: Please update the shadowing test in `tests/thread.rs` if these types are renamed.
unsafe {
$crate::thread::LocalKey::new(|_| {
$(#[$align_attr])*
static VAL: $crate::thread::local_impl::EagerStorage<$t> =
$crate::thread::local_impl::EagerStorage { value: __INIT };
&VAL.value
Expand All @@ -25,42 +27,50 @@ pub macro thread_local_inner {
}},

// used to generate the `LocalKey` value for `thread_local!`
(@key $t:ty, $init:expr) => {{
(@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{
#[inline]
fn __init() -> $t { $init }

unsafe {
use $crate::thread::LocalKey;
use $crate::thread::local_impl::LazyStorage;

LocalKey::new(|init| {
static VAL: LazyStorage<$t> = LazyStorage::new();
$crate::thread::LocalKey::new(|init| {
$(#[$align_attr])*
static VAL: $crate::thread::local_impl::LazyStorage<$t> = $crate::thread::local_impl::LazyStorage::new();
VAL.get(init, __init)
})
}
}},
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
$(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
$crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
},
}

#[allow(missing_debug_implementations)]
#[repr(transparent)] // Required for correctness of `#[rustc_align_static]`
pub struct EagerStorage<T> {
pub value: T,
}

// SAFETY: the target doesn't have threads.
unsafe impl<T> Sync for EagerStorage<T> {}

#[derive(Clone, Copy, PartialEq, Eq)]
enum State {
Initial,
Alive,
Destroying,
}

#[allow(missing_debug_implementations)]
#[repr(C)]
pub struct LazyStorage<T> {
value: UnsafeCell<Option<T>>,
// This field must be first, for correctness of `#[rustc_align_static]`
value: UnsafeCell<MaybeUninit<T>>,
state: Cell<State>,
}

impl<T> LazyStorage<T> {
pub const fn new() -> LazyStorage<T> {
LazyStorage { value: UnsafeCell::new(None) }
LazyStorage {
value: UnsafeCell::new(MaybeUninit::uninit()),
state: Cell::new(State::Initial),
}
}

/// Gets a pointer to the TLS value, potentially initializing it with the
Expand All @@ -70,24 +80,39 @@ impl<T> LazyStorage<T> {
/// has occurred.
#[inline]
pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
let value = unsafe { &*self.value.get() };
match value {
Some(v) => v,
None => self.initialize(i, f),
if self.state.get() == State::Alive {
self.value.get() as *const T
} else {
self.initialize(i, f)
}
}

#[cold]
fn initialize(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
let value = i.and_then(Option::take).unwrap_or_else(f);
// Destroy the old value, after updating the TLS variable as the
// destructor might reference it.

// Destroy the old value if it is initialized
// FIXME(#110897): maybe panic on recursive initialization.
if self.state.get() == State::Alive {
self.state.set(State::Destroying);
// Safety: we check for no initialization during drop below
unsafe {
ptr::drop_in_place(self.value.get() as *mut T);
}
self.state.set(State::Initial);
}

// Guard against initialization during drop
if self.state.get() == State::Destroying {
panic!("Attempted to initialize thread-local while it is being dropped");
}

unsafe {
self.value.get().replace(Some(value));
self.value.get().write(MaybeUninit::new(value));
}
// SAFETY: we just set this to `Some`.
unsafe { (*self.value.get()).as_ref().unwrap_unchecked() }
self.state.set(State::Alive);

self.value.get() as *const T
}
}

Expand Down
Loading