@@ -160,6 +160,19 @@ impl Closure {
160
160
}
161
161
}
162
162
163
+ unsafe extern "C" fn trampoline_zst < T : FnOnce ( ) > ( _: ClosureEnv ) {
164
+ let func: T = unsafe { transmute ( ( ) ) } ;
165
+ func ( )
166
+ }
167
+
168
+ unsafe extern "C" fn trampoline_indirect < T : FnOnce ( ) > ( env : ClosureEnv ) {
169
+ let p_func: * const T = unsafe { transmute ( env) } ;
170
+ // FIXME: Since there's no trait indicating the lack of interior mutability,
171
+ // we have to copy `T` onto stack
172
+ let func: T = unsafe { p_func. read ( ) } ;
173
+ func ( )
174
+ }
175
+
163
176
/// A trait for converting a value into a [`Closure`] at compile time.
164
177
///
165
178
/// The conversion may involve compile-time heap allocation
@@ -174,6 +187,9 @@ impl Closure {
174
187
///
175
188
/// // `impl FnOnce()` → `Closure`
176
189
/// const _: Closure = (|| {}).into_closure_const();
190
+ ///
191
+ /// // `(&'static P0, impl FnOnce(&'static P0))` → `Closure`
192
+ /// const _: Closure = (&42, |_: &i32| {}).into_closure_const();
177
193
/// ```
178
194
pub trait IntoClosureConst {
179
195
/// Perform conversion to [`Closure`], potentially using a compile-time
@@ -188,17 +204,29 @@ impl<T: FnOnce() + Copy + Send + 'static> const IntoClosureConst for T {
188
204
}
189
205
}
190
206
191
- unsafe extern "C" fn trampoline_zst < T : FnOnce ( ) > ( _: ClosureEnv ) {
192
- let func: T = unsafe { transmute ( ( ) ) } ;
193
- func ( )
194
- }
207
+ /// Packs `&P0` directly in [`ClosureEnv`][] if `T` is zero-sized.
208
+ ///
209
+ /// Due to compiler restrictions, this optimization is currently impossible
210
+ /// to do in the generic constructor ([`Closure::from_fn_const`]).
211
+ // FIXME: See above
212
+ impl < T : FnOnce ( & ' static P0 ) + Copy + Send + ' static , P0 : Sync + ' static > const IntoClosureConst
213
+ for ( & ' static P0 , T )
214
+ {
215
+ fn into_closure_const ( self ) -> Closure {
216
+ unsafe extern "C" fn trampoline_ptr_spec < T : FnOnce ( & ' static P0 ) , P0 : ' static > (
217
+ env : ClosureEnv ,
218
+ ) {
219
+ let p0: & ' static P0 = unsafe { transmute ( env) } ;
220
+ let func: T = unsafe { transmute ( ( ) ) } ;
221
+ func ( p0)
222
+ }
195
223
196
- unsafe extern "C" fn trampoline_indirect < T : FnOnce ( ) > ( env : ClosureEnv ) {
197
- let p_func : * const T = unsafe { transmute ( env ) } ;
198
- // FIXME: Since there's no trait indicating the lack of interior mutability,
199
- // we have to copy `T` onto stack
200
- let func : T = unsafe { p_func . read ( ) } ;
201
- func ( )
224
+ if size_of :: < T > ( ) == 0 {
225
+ unsafe { Closure :: from_raw_parts ( trampoline_zst_param :: < T , P0 > , transmute ( self . 0 ) ) }
226
+ } else {
227
+ ( move || ( self . 1 ) ( self . 0 ) ) . into_closure_const ( )
228
+ }
229
+ }
202
230
}
203
231
204
232
#[ cfg( test) ]
@@ -269,4 +297,10 @@ mod tests {
269
297
ADD2 . call ( ) ;
270
298
assert_eq ! ( STATE . load( Ordering :: Relaxed ) , 1 + 4 + 2 ) ;
271
299
}
300
+
301
+ #[ test]
302
+ fn ptr_env_spec ( ) {
303
+ const C : Closure = ( & 42 , |x : & i32 | assert_eq ! ( * x, 42 ) ) . into_closure_const ( ) ;
304
+ C . call ( ) ;
305
+ }
272
306
}
0 commit comments