about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJacob Pratt <jacob@jhpratt.dev>2025-02-23 02:44:17 -0500
committerGitHub <noreply@github.com>2025-02-23 02:44:17 -0500
commit2ff53a293e6dde5344a1f02c41dc9043816b8271 (patch)
tree70dbc6612065a2bd2abec0e4555fc9b40dffcd81
parent4493159b350f0d61c0eee4ef92fde6e91610ba57 (diff)
parent4742dbc765165dc0ece5e350b3527e697ff871dc (diff)
downloadrust-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.rs2
-rw-r--r--library/std/src/sync/mpmc/mod.rs3
-rw-r--r--library/std/src/sync/mpmc/tests.rs14
-rw-r--r--library/std/src/sync/mpmc/waker.rs2
-rw-r--r--library/std/src/thread/local.rs11
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);