@@ -30,33 +30,34 @@ 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 ) ,
44+ // fast path
45+ ( @align $t : ty , ) => { $crate :: thread :: local_impl :: value_align :: < $t > ( ) } ,
4546
4647 // `rustc_align_static` attributes are present,
4748 // translate them into a `const` block that computes the alignment
48- ( @align $( #[ $( $attr: tt) * ] ) +) => {
49- const {
50- // Ensure that attributes have valid syntax
51- // and that the proper feature gate is enabled
52- $ ( # [ $ ( $attr ) * ] ) +
53- static DUMMY : ( ) = ( ) ;
54-
55- let mut final_align = 1_usize ;
56- $ ( $ crate:: thread:: local_impl:: thread_local_inner! ( @align_single final_align , $ ( $attr ) * ) ; ) +
57- final_align
58- }
59- } ,
49+ ( @align $t : ty , $ ( #[ $( $attr: tt) * ] ) +) => { {
50+ // Ensure that attributes have valid syntax
51+ // and that the proper feature gate is enabled
52+ $ ( # [ $ ( $attr ) * ] ) *
53+ # [ allow ( unused ) ]
54+ static DUMMY : ( ) = ( ) ;
55+
56+ # [ allow ( unused_mut ) ]
57+ let mut final_align = $ crate:: thread:: local_impl:: value_align :: < $t > ( ) ;
58+ $ ( $crate :: thread :: local_impl :: thread_local_inner! ( @align_single final_align, $ ( $attr ) * ) ; ) +
59+ final_align
60+ } } ,
6061
6162 // process a single `rustc_align_static` attribute
6263 ( @align_single $final_align: ident, rustc_align_static( $( $align: tt) * ) $( , $( $attr_rest: tt) +) ?) => {
@@ -107,26 +108,30 @@ pub macro thread_local_inner {
107108
108109/// Use a regular global static to store this key; the state provided will then be
109110 /// thread-local.
111+ /// INVARIANT: ALIGN must be a valid alignment, and no less than `value_align::<T>`.
110112 #[ allow( missing_debug_implementations) ]
111- pub struct Storage <T > {
113+ pub struct Storage <T , const ALIGN : usize > {
112114 key: LazyKey ,
113115 marker: PhantomData <Cell <T >>,
114116}
115117
116- unsafe impl <T > Sync for Storage <T > { }
118+ unsafe impl <T , const ALIGN : usize > Sync for Storage <T , ALIGN > { }
117119
118120#[ repr( C ) ]
119121struct Value <T : ' static > {
120122 // This field must be first, for correctness of `#[rustc_align_static]`
121123 value: T ,
122- align: usize ,
123124 // INVARIANT: if this value is stored under a TLS key, `key` must be that `key`.
124125 key: Key ,
125126}
126127
127- impl <T : ' static > Storage <T > {
128- pub const fn new( ) -> Storage <T > {
129- Storage { key: LazyKey :: new( Some ( destroy_value:: <T >) ) , marker: PhantomData }
128+ pub const fn value_align<T : ' static >( ) -> usize {
129+ crate :: mem:: align_of:: <Value <T >>( )
130+ }
131+
132+ impl <T : ' static , const ALIGN : usize > Storage <T , ALIGN > {
133+ pub const fn new( ) -> Storage <T , ALIGN > {
134+ Storage { key: LazyKey :: new( Some ( destroy_value:: <T , ALIGN >) ) , marker: PhantomData }
130135 }
131136
132137 /// Gets a pointer to the TLS value, potentially initializing it with the
@@ -135,12 +140,7 @@ impl<T: 'static> Storage<T> {
135140 ///
136141 /// The resulting pointer may not be used after reentrant inialialization
137142 /// 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 {
143+ pub fn get( & ' static self , i: Option <& mut Option <T >>, f: impl FnOnce ( ) -> T ) -> * const T {
144144 let key = self . key. force( ) ;
145145 let ptr = unsafe { get( key) as * mut Value <T > } ;
146146 if ptr. addr( ) > 1 {
@@ -149,7 +149,7 @@ impl<T: 'static> Storage<T> {
149149 unsafe { & ( * ptr) . value }
150150 } else {
151151 // SAFETY: trivially correct.
152- unsafe { Self :: try_initialize( key, align , ptr, i, f) }
152+ unsafe { Self :: try_initialize( key, ptr, i, f) }
153153 }
154154 }
155155
@@ -158,7 +158,6 @@ impl<T: 'static> Storage<T> {
158158 /// * `ptr` must be the current value associated with `key`.
159159 unsafe fn try_initialize(
160160 key: Key ,
161- align: usize ,
162161 ptr: * mut Value <T >,
163162 i: Option <& mut Option <T >>,
164163 f: impl FnOnce ( ) -> T ,
@@ -169,17 +168,13 @@ impl<T: 'static> Storage<T> {
169168 }
170169
171170 // Manually allocate with the requested alignment
172- let layout = Layout :: new:: <Value <T >>( ) . align_to( align ) . unwrap( ) ;
171+ let layout = Layout :: new:: <Value <T >>( ) . align_to( ALIGN ) . unwrap( ) ;
173172 let ptr: * mut Value <T > = ( unsafe { crate :: alloc:: alloc( layout) } ) . cast( ) ;
174173 if ptr. is_null( ) {
175174 crate :: alloc:: handle_alloc_error( layout) ;
176175 }
177176 unsafe {
178- ptr. write( Value {
179- value: i. and_then( Option :: take) . unwrap_or_else( f) ,
180- align: layout. align( ) ,
181- key,
182- } ) ;
177+ ptr. write( Value { value: i. and_then( Option :: take) . unwrap_or_else( f) , key } ) ;
183178 }
184179
185180 // SAFETY:
@@ -209,7 +204,7 @@ impl<T: 'static> Storage<T> {
209204 }
210205}
211206
212- unsafe extern "C " fn destroy_value<T : ' static >( ptr: * mut u8 ) {
207+ unsafe extern "C " fn destroy_value<T : ' static , const ALIGN : usize >( ptr: * mut u8 ) {
213208 // SAFETY:
214209 //
215210 // The OS TLS ensures that this key contains a null value when this
@@ -223,14 +218,13 @@ unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
223218 let value_ptr: * mut Value <T > = ptr. cast( ) ;
224219 unsafe {
225220 let key = ( * value_ptr) . key;
226- let align = ( * value_ptr) . align;
227221
228222 // SAFETY: `key` is the TLS key `ptr` was stored under.
229223 set( key, ptr:: without_provenance_mut( 1 ) ) ;
230224
231225 // drop and deallocate the value
232226 let layout =
233- Layout :: from_size_align_unchecked( crate :: mem:: size_of:: <Value <T >>( ) , align ) ;
227+ Layout :: from_size_align_unchecked( crate :: mem:: size_of:: <Value <T >>( ) , ALIGN ) ;
234228 value_ptr. drop_in_place( ) ;
235229 crate :: alloc:: dealloc( ptr, layout) ;
236230
0 commit comments