Skip to content

Commit f12ddd7

Browse files
os impl: use const generic for alignment
1 parent 1bfbfbf commit f12ddd7

File tree

2 files changed

+26
-33
lines changed

2 files changed

+26
-33
lines changed

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

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

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

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,30 +30,30 @@ pub macro thread_local_inner {
3030
// in `tests/thread.rs` if these types are renamed.
3131
unsafe {
3232
$crate::thread::LocalKey::new(|init| {
33-
static VAL: $crate::thread::local_impl::Storage<$t>
33+
const ALIGN: usize = $crate::thread::local_impl::thread_local_inner!(@align $t, $(#[$($align_attr)*])*);
34+
static VAL: $crate::thread::local_impl::Storage<$t, ALIGN>
3435
= $crate::thread::local_impl::Storage::new();
35-
VAL.get($crate::thread::local_impl::thread_local_inner!(@align $(#[$($align_attr)*])*), init, __init)
36+
VAL.get(init, __init)
3637
})
3738
}
3839
}},
3940

4041
// Handle `rustc_align_static` attributes,
4142
// by translating them into an argumemt to pass to `Storage::get`:
4243

43-
// fast path for when there are none
44-
(@align) => (1),
45-
4644
// `rustc_align_static` attributes are present,
4745
// translate them into a `const` block that computes the alignment
48-
(@align $(#[$($attr:tt)*])+) => {
46+
(@align $t:ty, $(#[$($attr:tt)*])*) => {
4947
const {
5048
// Ensure that attributes have valid syntax
5149
// and that the proper feature gate is enabled
52-
$(#[$($attr)*])+
50+
$(#[$($attr)*])*
51+
#[allow(unused)]
5352
static DUMMY: () = ();
5453

55-
let mut final_align = 1_usize;
56-
$($crate::thread::local_impl::thread_local_inner!(@align_single final_align, $($attr)*);)+
54+
#[allow(unused_mut)]
55+
let mut final_align = $crate::thread::local_impl::value_align::<$t>();
56+
$($crate::thread::local_impl::thread_local_inner!(@align_single final_align, $($attr)*);)*
5757
final_align
5858
}
5959
},
@@ -107,26 +107,30 @@ pub macro thread_local_inner {
107107

108108
/// Use a regular global static to store this key; the state provided will then be
109109
/// thread-local.
110+
/// INVARIANT: ALIGN must be a valid alignment, and no less than `value_align::<T>`.
110111
#[allow(missing_debug_implementations)]
111-
pub struct Storage<T> {
112+
pub struct Storage<T, const ALIGN: usize> {
112113
key: LazyKey,
113114
marker: PhantomData<Cell<T>>,
114115
}
115116

116-
unsafe impl<T> Sync for Storage<T> {}
117+
unsafe impl<T, const ALIGN: usize> Sync for Storage<T, ALIGN> {}
117118

118119
#[repr(C)]
119120
struct Value<T: 'static> {
120121
// This field must be first, for correctness of `#[rustc_align_static]`
121122
value: T,
122-
align: usize,
123123
// INVARIANT: if this value is stored under a TLS key, `key` must be that `key`.
124124
key: Key,
125125
}
126126

127-
impl<T: 'static> Storage<T> {
128-
pub const fn new() -> Storage<T> {
129-
Storage { key: LazyKey::new(Some(destroy_value::<T>)), marker: PhantomData }
127+
pub const fn value_align<T: 'static>() -> usize {
128+
crate::mem::align_of::<Value<T>>()
129+
}
130+
131+
impl<T: 'static, const ALIGN: usize> Storage<T, ALIGN> {
132+
pub const fn new() -> Storage<T, ALIGN> {
133+
Storage { key: LazyKey::new(Some(destroy_value::<T, ALIGN>)), marker: PhantomData }
130134
}
131135

132136
/// Gets a pointer to the TLS value, potentially initializing it with the
@@ -135,12 +139,7 @@ impl<T: 'static> Storage<T> {
135139
///
136140
/// The resulting pointer may not be used after reentrant inialialization
137141
/// or thread destruction has occurred.
138-
pub fn get(
139-
&'static self,
140-
align: usize,
141-
i: Option<&mut Option<T>>,
142-
f: impl FnOnce() -> T,
143-
) -> *const T {
142+
pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
144143
let key = self.key.force();
145144
let ptr = unsafe { get(key) as *mut Value<T> };
146145
if ptr.addr() > 1 {
@@ -149,7 +148,7 @@ impl<T: 'static> Storage<T> {
149148
unsafe { &(*ptr).value }
150149
} else {
151150
// SAFETY: trivially correct.
152-
unsafe { Self::try_initialize(key, align, ptr, i, f) }
151+
unsafe { Self::try_initialize(key, ptr, i, f) }
153152
}
154153
}
155154

@@ -158,7 +157,6 @@ impl<T: 'static> Storage<T> {
158157
/// * `ptr` must be the current value associated with `key`.
159158
unsafe fn try_initialize(
160159
key: Key,
161-
align: usize,
162160
ptr: *mut Value<T>,
163161
i: Option<&mut Option<T>>,
164162
f: impl FnOnce() -> T,
@@ -169,17 +167,13 @@ impl<T: 'static> Storage<T> {
169167
}
170168

171169
// Manually allocate with the requested alignment
172-
let layout = Layout::new::<Value<T>>().align_to(align).unwrap();
170+
let layout = Layout::new::<Value<T>>().align_to(ALIGN).unwrap();
173171
let ptr: *mut Value<T> = (unsafe { crate::alloc::alloc(layout) }).cast();
174172
if ptr.is_null() {
175173
crate::alloc::handle_alloc_error(layout);
176174
}
177175
unsafe {
178-
ptr.write(Value {
179-
value: i.and_then(Option::take).unwrap_or_else(f),
180-
align: layout.align(),
181-
key,
182-
});
176+
ptr.write(Value { value: i.and_then(Option::take).unwrap_or_else(f), key });
183177
}
184178

185179
// SAFETY:
@@ -209,7 +203,7 @@ impl<T: 'static> Storage<T> {
209203
}
210204
}
211205

212-
unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
206+
unsafe extern "C" fn destroy_value<T: 'static, const ALIGN: usize>(ptr: *mut u8) {
213207
// SAFETY:
214208
//
215209
// The OS TLS ensures that this key contains a null value when this
@@ -223,14 +217,13 @@ unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
223217
let value_ptr: *mut Value<T> = ptr.cast();
224218
unsafe {
225219
let key = (*value_ptr).key;
226-
let align = (*value_ptr).align;
227220

228221
// SAFETY: `key` is the TLS key `ptr` was stored under.
229222
set(key, ptr::without_provenance_mut(1));
230223

231224
// drop and deallocate the value
232225
let layout =
233-
Layout::from_size_align_unchecked(crate::mem::size_of::<Value<T>>(), align);
226+
Layout::from_size_align_unchecked(crate::mem::size_of::<Value<T>>(), ALIGN);
234227
value_ptr.drop_in_place();
235228
crate::alloc::dealloc(ptr, layout);
236229

0 commit comments

Comments
 (0)