@@ -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 ) ]
119120struct 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