Skip to content

Commit 07a1833

Browse files
authored
Unrolled build for #146281
Rollup merge of #146281 - Jules-Bertholet:static-align-thread-local, r=Mark-Simulacrum Support `#[rustc_align_static]` inside `thread_local!` Tracking issue: #146177 ```rust thread_local! { #[rustc_align_static(64)] static SO_ALIGNED: u64 = const { 0 }; } ``` This increases the amount of recursion the macro performs (once per attribute in addition to the previous once per item), making it easier to hit the recursion limit. I’ve added workarounds to limit the impact in the case of long doc comments, but this still needs a crater run just in case. r? libs ``@rustbot`` label A-attributes A-macros A-thread-locals F-static_align T-libs
2 parents 4b9c62b + 94f00f4 commit 07a1833

File tree

18 files changed

+917
-75
lines changed

18 files changed

+917
-75
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ cfg_select! {
4242
}
4343
_ => {
4444
mod os;
45-
pub use os::{Storage, thread_local_inner};
45+
pub use os::{Storage, thread_local_inner, value_align};
4646
pub(crate) use os::{LocalPointer, local_pointer};
4747
}
4848
}

library/std/src/sys/thread_local/native/eager.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ enum State {
1010
}
1111

1212
#[allow(missing_debug_implementations)]
13+
#[repr(C)]
1314
pub struct Storage<T> {
14-
state: Cell<State>,
15+
// This field must be first, for correctness of `#[rustc_align_static]`
1516
val: UnsafeCell<T>,
17+
state: Cell<State>,
1618
}
1719

1820
impl<T> Storage<T> {

library/std/src/sys/thread_local/native/lazy.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ enum State<D> {
2727
}
2828

2929
#[allow(missing_debug_implementations)]
30+
#[repr(C)]
3031
pub struct Storage<T, D> {
31-
state: Cell<State<D>>,
32+
// This field must be first, for correctness of `#[rustc_align_static]`
3233
value: UnsafeCell<MaybeUninit<T>>,
34+
state: Cell<State<D>>,
3335
}
3436

3537
impl<T, D> Storage<T, D>

library/std/src/sys/thread_local/native/mod.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,23 @@ pub macro thread_local_inner {
5454
// test in `tests/thread.rs` if these types are renamed.
5555

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

6060
unsafe {
6161
$crate::thread::LocalKey::new(const {
6262
if $crate::mem::needs_drop::<$t>() {
6363
|_| {
6464
#[thread_local]
65+
$(#[$align_attr])*
6566
static VAL: $crate::thread::local_impl::EagerStorage<$t>
6667
= $crate::thread::local_impl::EagerStorage::new(__INIT);
6768
VAL.get()
6869
}
6970
} else {
7071
|_| {
7172
#[thread_local]
73+
$(#[$align_attr])*
7274
static VAL: $t = __INIT;
7375
&VAL
7476
}
@@ -78,7 +80,7 @@ pub macro thread_local_inner {
7880
}},
7981

8082
// used to generate the `LocalKey` value for `thread_local!`
81-
(@key $t:ty, $init:expr) => {{
83+
(@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{
8284
#[inline]
8385
fn __init() -> $t {
8486
$init
@@ -89,13 +91,15 @@ pub macro thread_local_inner {
8991
if $crate::mem::needs_drop::<$t>() {
9092
|init| {
9193
#[thread_local]
94+
$(#[$align_attr])*
9295
static VAL: $crate::thread::local_impl::LazyStorage<$t, ()>
9396
= $crate::thread::local_impl::LazyStorage::new();
9497
VAL.get_or_init(init, __init)
9598
}
9699
} else {
97100
|init| {
98101
#[thread_local]
102+
$(#[$align_attr])*
99103
static VAL: $crate::thread::local_impl::LazyStorage<$t, !>
100104
= $crate::thread::local_impl::LazyStorage::new();
101105
VAL.get_or_init(init, __init)
@@ -104,10 +108,6 @@ pub macro thread_local_inner {
104108
})
105109
}
106110
}},
107-
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
108-
$(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
109-
$crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
110-
},
111111
}
112112

113113
#[rustc_macro_transparency = "semitransparent"]

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

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! thread locals and we can instead just use plain statics!
33
44
use crate::cell::{Cell, UnsafeCell};
5+
use crate::mem::MaybeUninit;
56
use crate::ptr;
67

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

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

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

3234
unsafe {
33-
use $crate::thread::LocalKey;
34-
use $crate::thread::local_impl::LazyStorage;
35-
36-
LocalKey::new(|init| {
37-
static VAL: LazyStorage<$t> = LazyStorage::new();
35+
$crate::thread::LocalKey::new(|init| {
36+
$(#[$align_attr])*
37+
static VAL: $crate::thread::local_impl::LazyStorage<$t> = $crate::thread::local_impl::LazyStorage::new();
3838
VAL.get(init, __init)
3939
})
4040
}
4141
}},
42-
($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
43-
$(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
44-
$crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
45-
},
4642
}
4743

4844
#[allow(missing_debug_implementations)]
45+
#[repr(transparent)] // Required for correctness of `#[rustc_align_static]`
4946
pub struct EagerStorage<T> {
5047
pub value: T,
5148
}
5249

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

53+
#[derive(Clone, Copy, PartialEq, Eq)]
54+
enum State {
55+
Initial,
56+
Alive,
57+
Destroying,
58+
}
59+
5660
#[allow(missing_debug_implementations)]
61+
#[repr(C)]
5762
pub struct LazyStorage<T> {
58-
value: UnsafeCell<Option<T>>,
63+
// This field must be first, for correctness of `#[rustc_align_static]`
64+
value: UnsafeCell<MaybeUninit<T>>,
65+
state: Cell<State>,
5966
}
6067

6168
impl<T> LazyStorage<T> {
6269
pub const fn new() -> LazyStorage<T> {
63-
LazyStorage { value: UnsafeCell::new(None) }
70+
LazyStorage {
71+
value: UnsafeCell::new(MaybeUninit::uninit()),
72+
state: Cell::new(State::Initial),
73+
}
6474
}
6575

6676
/// Gets a pointer to the TLS value, potentially initializing it with the
@@ -70,24 +80,39 @@ impl<T> LazyStorage<T> {
7080
/// has occurred.
7181
#[inline]
7282
pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
73-
let value = unsafe { &*self.value.get() };
74-
match value {
75-
Some(v) => v,
76-
None => self.initialize(i, f),
83+
if self.state.get() == State::Alive {
84+
self.value.get() as *const T
85+
} else {
86+
self.initialize(i, f)
7787
}
7888
}
7989

8090
#[cold]
8191
fn initialize(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
8292
let value = i.and_then(Option::take).unwrap_or_else(f);
83-
// Destroy the old value, after updating the TLS variable as the
84-
// destructor might reference it.
93+
94+
// Destroy the old value if it is initialized
8595
// FIXME(#110897): maybe panic on recursive initialization.
96+
if self.state.get() == State::Alive {
97+
self.state.set(State::Destroying);
98+
// Safety: we check for no initialization during drop below
99+
unsafe {
100+
ptr::drop_in_place(self.value.get() as *mut T);
101+
}
102+
self.state.set(State::Initial);
103+
}
104+
105+
// Guard against initialization during drop
106+
if self.state.get() == State::Destroying {
107+
panic!("Attempted to initialize thread-local while it is being dropped");
108+
}
109+
86110
unsafe {
87-
self.value.get().replace(Some(value));
111+
self.value.get().write(MaybeUninit::new(value));
88112
}
89-
// SAFETY: we just set this to `Some`.
90-
unsafe { (*self.value.get()).as_ref().unwrap_unchecked() }
113+
self.state.set(State::Alive);
114+
115+
self.value.get() as *const T
91116
}
92117
}
93118

0 commit comments

Comments
 (0)