diff options
| author | Jacob Pratt <jacob@jhpratt.dev> | 2025-02-23 02:44:17 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-23 02:44:17 -0500 |
| commit | 2ff53a293e6dde5344a1f02c41dc9043816b8271 (patch) | |
| tree | 70dbc6612065a2bd2abec0e4555fc9b40dffcd81 | |
| parent | 4493159b350f0d61c0eee4ef92fde6e91610ba57 (diff) | |
| parent | 4742dbc765165dc0ece5e350b3527e697ff871dc (diff) | |
| download | rust-2ff53a293e6dde5344a1f02c41dc9043816b8271.tar.gz rust-2ff53a293e6dde5344a1f02c41dc9043816b8271.zip | |
Rollup merge of #137194 - kornelski:ftls, r=tgross35
More const {} init in thread_local
`const {}` in `thread_local!` gets an optimization just based on the syntax, rather than the expression being const-compatible. This is easy to miss, so I've added more examples to the docs.
I've also added `const {}` in a couple of places in std where this optimization has been missed.
| -rw-r--r-- | library/std/src/io/stdio.rs | 2 | ||||
| -rw-r--r-- | library/std/src/sync/mpmc/mod.rs | 3 | ||||
| -rw-r--r-- | library/std/src/sync/mpmc/tests.rs | 14 | ||||
| -rw-r--r-- | library/std/src/sync/mpmc/waker.rs | 2 | ||||
| -rw-r--r-- | library/std/src/thread/local.rs | 11 |
5 files changed, 25 insertions, 7 deletions
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 661c422811a..017862c7f3a 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -20,7 +20,7 @@ type LocalStream = Arc<Mutex<Vec<u8>>>; thread_local! { /// Used by the test crate to capture the output of the print macros and panics. - static OUTPUT_CAPTURE: Cell<Option<LocalStream>> = { + static OUTPUT_CAPTURE: Cell<Option<LocalStream>> = const { Cell::new(None) } } diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index 8caa2dcfad9..8712332dd27 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -1382,3 +1382,6 @@ impl<T> fmt::Debug for Receiver<T> { f.pad("Receiver { .. }") } } + +#[cfg(test)] +mod tests; diff --git a/library/std/src/sync/mpmc/tests.rs b/library/std/src/sync/mpmc/tests.rs new file mode 100644 index 00000000000..6deb4dc2fe0 --- /dev/null +++ b/library/std/src/sync/mpmc/tests.rs @@ -0,0 +1,14 @@ +// Ensure that thread_local init with `const { 0 }` still has unique address at run-time +#[test] +fn waker_current_thread_id() { + let first = super::waker::current_thread_id(); + let t = crate::thread::spawn(move || { + let second = super::waker::current_thread_id(); + assert_ne!(first, second); + assert_eq!(second, super::waker::current_thread_id()); + }); + + assert_eq!(first, super::waker::current_thread_id()); + t.join().unwrap(); + assert_eq!(first, super::waker::current_thread_id()); +} diff --git a/library/std/src/sync/mpmc/waker.rs b/library/std/src/sync/mpmc/waker.rs index 1895466f95d..f5e764e69bd 100644 --- a/library/std/src/sync/mpmc/waker.rs +++ b/library/std/src/sync/mpmc/waker.rs @@ -204,6 +204,6 @@ impl Drop for SyncWaker { pub fn current_thread_id() -> usize { // `u8` is not drop so this variable will be available during thread destruction, // whereas `thread::current()` would not be - thread_local! { static DUMMY: u8 = 0 } + thread_local! { static DUMMY: u8 = const { 0 } } DUMMY.with(|x| (x as *const u8).addr()) } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index ca04aa4ada4..d5a5d10205d 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -50,7 +50,8 @@ use crate::fmt; /// use std::cell::Cell; /// use std::thread; /// -/// thread_local!(static FOO: Cell<u32> = Cell::new(1)); +/// // explicit `const {}` block enables more efficient initialization +/// thread_local!(static FOO: Cell<u32> = const { Cell::new(1) }); /// /// assert_eq!(FOO.get(), 1); /// FOO.set(2); @@ -138,7 +139,7 @@ impl<T: 'static> fmt::Debug for LocalKey<T> { /// use std::cell::{Cell, RefCell}; /// /// thread_local! { -/// pub static FOO: Cell<u32> = Cell::new(1); +/// pub static FOO: Cell<u32> = const { Cell::new(1) }; /// /// static BAR: RefCell<Vec<f32>> = RefCell::new(vec![1.0, 2.0]); /// } @@ -394,7 +395,7 @@ impl<T: 'static> LocalKey<Cell<T>> { /// use std::cell::Cell; /// /// thread_local! { - /// static X: Cell<i32> = Cell::new(1); + /// static X: Cell<i32> = const { Cell::new(1) }; /// } /// /// assert_eq!(X.get(), 1); @@ -423,7 +424,7 @@ impl<T: 'static> LocalKey<Cell<T>> { /// use std::cell::Cell; /// /// thread_local! { - /// static X: Cell<Option<i32>> = Cell::new(Some(1)); + /// static X: Cell<Option<i32>> = const { Cell::new(Some(1)) }; /// } /// /// assert_eq!(X.take(), Some(1)); @@ -453,7 +454,7 @@ impl<T: 'static> LocalKey<Cell<T>> { /// use std::cell::Cell; /// /// thread_local! { - /// static X: Cell<i32> = Cell::new(1); + /// static X: Cell<i32> = const { Cell::new(1) }; /// } /// /// assert_eq!(X.replace(2), 1); |
