|
1 | 1 | // SPDX-License-Identifier: Apache-2.0 OR MIT |
2 | 2 |
|
3 | 3 | use proc_macro2::{Span, TokenStream}; |
4 | | -use quote::{format_ident, quote, quote_spanned}; |
| 4 | +use quote::{format_ident, quote}; |
5 | 5 | use syn::{ |
6 | 6 | braced, |
7 | 7 | parse::{End, Parse}, |
@@ -103,17 +103,15 @@ pub(crate) fn expand( |
103 | 103 | |(_, err)| Box::new(err), |
104 | 104 | ); |
105 | 105 | let slot = format_ident!("slot"); |
106 | | - let (has_data_trait, data_trait, get_data, init_from_closure) = if pinned { |
| 106 | + let (has_data_trait, get_data, init_from_closure) = if pinned { |
107 | 107 | ( |
108 | 108 | format_ident!("HasPinData"), |
109 | | - format_ident!("PinData"), |
110 | 109 | format_ident!("__pin_data"), |
111 | 110 | format_ident!("pin_init_from_closure"), |
112 | 111 | ) |
113 | 112 | } else { |
114 | 113 | ( |
115 | 114 | format_ident!("HasInitData"), |
116 | | - format_ident!("InitData"), |
117 | 115 | format_ident!("__init_data"), |
118 | 116 | format_ident!("init_from_closure"), |
119 | 117 | ) |
@@ -157,8 +155,7 @@ pub(crate) fn expand( |
157 | 155 | #path::#get_data() |
158 | 156 | }; |
159 | 157 | // Ensure that `#data` really is of type `#data` and help with type inference: |
160 | | - let init = ::pin_init::__internal::#data_trait::make_closure::<_, #error>( |
161 | | - #data, |
| 158 | + let init = #data.__make_closure::<_, #error>( |
162 | 159 | move |slot| { |
163 | 160 | #zeroable_check |
164 | 161 | #this |
@@ -231,107 +228,80 @@ fn init_fields( |
231 | 228 | cfgs.retain(|attr| attr.path().is_ident("cfg")); |
232 | 229 | cfgs |
233 | 230 | }; |
| 231 | + |
| 232 | + let ident = match kind { |
| 233 | + InitializerKind::Value { ident, .. } => ident, |
| 234 | + InitializerKind::Init { ident, .. } => ident, |
| 235 | + InitializerKind::Code { block, .. } => { |
| 236 | + res.extend(quote! { |
| 237 | + #(#attrs)* |
| 238 | + #[allow(unused_braces)] |
| 239 | + #block |
| 240 | + }); |
| 241 | + continue; |
| 242 | + } |
| 243 | + }; |
| 244 | + |
| 245 | + let slot = if pinned { |
| 246 | + quote! { |
| 247 | + // SAFETY: |
| 248 | + // - `slot` is valid and properly aligned. |
| 249 | + // - `make_field_check` checks that `&raw mut (*slot).#ident` is properly aligned. |
| 250 | + // - `make_field_check` prevents `#ident` from being used twice, therefore |
| 251 | + // `(*slot).#ident` is exclusively accessed and has not been initialized. |
| 252 | + (unsafe { #data.#ident(#slot) }) |
| 253 | + } |
| 254 | + } else { |
| 255 | + quote! { |
| 256 | + // For `init!()` macro, everything is unpinned. |
| 257 | + // SAFETY: |
| 258 | + // - `&raw mut (*slot).#ident` is valid. |
| 259 | + // - `make_field_check` checks that `&raw mut (*slot).#ident` is properly aligned. |
| 260 | + // - `make_field_check` prevents `#ident` from being used twice, therefore |
| 261 | + // `(*slot).#ident` is exclusively accessed and has not been initialized. |
| 262 | + (unsafe { |
| 263 | + ::pin_init::__internal::Slot::<::pin_init::__internal::Unpinned, _>::new( |
| 264 | + &raw mut (*#slot).#ident |
| 265 | + ) |
| 266 | + }) |
| 267 | + } |
| 268 | + }; |
| 269 | + |
| 270 | + // `mixed_site` ensures that the guard is not accessible to the user-controlled code. |
| 271 | + let guard = format_ident!("__{ident}_guard", span = Span::mixed_site()); |
| 272 | + |
234 | 273 | let init = match kind { |
235 | 274 | InitializerKind::Value { ident, value } => { |
236 | | - let mut value_ident = ident.clone(); |
237 | | - let value_prep = value.as_ref().map(|value| &value.1).map(|value| { |
238 | | - // Setting the span of `value_ident` to `value`'s span improves error messages |
239 | | - // when the type of `value` is wrong. |
240 | | - value_ident.set_span(value.span()); |
241 | | - quote!(let #value_ident = #value;) |
242 | | - }); |
243 | | - // Again span for better diagnostics |
244 | | - let write = quote_spanned!(ident.span()=> ::core::ptr::write); |
| 275 | + let value = value |
| 276 | + .as_ref() |
| 277 | + .map(|(_, value)| quote!(#value)) |
| 278 | + .unwrap_or_else(|| quote!(#ident)); |
| 279 | + |
245 | 280 | quote! { |
246 | 281 | #(#attrs)* |
247 | | - { |
248 | | - #value_prep |
249 | | - // SAFETY: TODO |
250 | | - unsafe { #write(&raw mut (*#slot).#ident, #value_ident) }; |
251 | | - } |
| 282 | + let mut #guard = #slot.write(#value); |
| 283 | + |
252 | 284 | } |
253 | 285 | } |
254 | | - InitializerKind::Init { ident, value, .. } => { |
255 | | - // Again span for better diagnostics |
256 | | - let init = format_ident!("init", span = value.span()); |
257 | | - let value_init = if pinned { |
258 | | - quote! { |
259 | | - // SAFETY: |
260 | | - // - `slot` is valid, because we are inside of an initializer closure, we |
261 | | - // return when an error/panic occurs. |
262 | | - // - We also use `#data` to require the correct trait (`Init` or `PinInit`) |
263 | | - // for `#ident`. |
264 | | - unsafe { #data.#ident(&raw mut (*#slot).#ident, #init)? }; |
265 | | - } |
266 | | - } else { |
267 | | - quote! { |
268 | | - // SAFETY: `slot` is valid, because we are inside of an initializer |
269 | | - // closure, we return when an error/panic occurs. |
270 | | - unsafe { |
271 | | - ::pin_init::Init::__init( |
272 | | - #init, |
273 | | - &raw mut (*#slot).#ident, |
274 | | - )? |
275 | | - }; |
276 | | - } |
277 | | - }; |
| 286 | + InitializerKind::Init { value, .. } => { |
278 | 287 | quote! { |
279 | 288 | #(#attrs)* |
280 | | - { |
281 | | - let #init = #value; |
282 | | - #value_init |
283 | | - } |
| 289 | + let mut #guard = #slot.init(#value)?; |
284 | 290 | } |
285 | 291 | } |
286 | | - InitializerKind::Code { block: value, .. } => quote! { |
287 | | - #(#attrs)* |
288 | | - #[allow(unused_braces)] |
289 | | - #value |
290 | | - }, |
| 292 | + InitializerKind::Code { .. } => unreachable!(), |
291 | 293 | }; |
292 | | - res.extend(init); |
293 | | - if let Some(ident) = kind.ident() { |
294 | | - // `mixed_site` ensures that the guard is not accessible to the user-controlled code. |
295 | | - let guard = format_ident!("__{ident}_guard", span = Span::mixed_site()); |
296 | 294 |
|
297 | | - // NOTE: The reference is derived from the guard so that it only lives as long as the |
298 | | - // guard does and cannot escape the scope. If it's created via `&mut (*#slot).#ident` |
299 | | - // like the unaligned field guard, it will become effectively `'static`. |
300 | | - let accessor = if pinned { |
301 | | - let project_ident = format_ident!("__project_{ident}"); |
302 | | - quote! { |
303 | | - // SAFETY: the initialization is pinned. |
304 | | - unsafe { #data.#project_ident(#guard.let_binding()) } |
305 | | - } |
306 | | - } else { |
307 | | - quote! { |
308 | | - #guard.let_binding() |
309 | | - } |
310 | | - }; |
| 295 | + res.extend(quote! { |
| 296 | + #init |
311 | 297 |
|
312 | | - res.extend(quote! { |
313 | | - #(#cfgs)* |
314 | | - // Create the drop guard. |
315 | | - // |
316 | | - // SAFETY: |
317 | | - // - `&raw mut (*slot).#ident` is valid. |
318 | | - // - `make_field_check` checks that `&raw mut (*slot).#ident` is properly aligned. |
319 | | - // - `(*slot).#ident` has been initialized above. |
320 | | - // - We only need the ownership to the pointee back when initialization has |
321 | | - // succeeded, where we `forget` the guard. |
322 | | - let mut #guard = unsafe { |
323 | | - ::pin_init::__internal::DropGuard::new( |
324 | | - &raw mut (*slot).#ident |
325 | | - ) |
326 | | - }; |
| 298 | + #(#cfgs)* |
| 299 | + #[allow(unused_variables)] |
| 300 | + let #ident = #guard.let_binding(); |
| 301 | + }); |
327 | 302 |
|
328 | | - #(#cfgs)* |
329 | | - #[allow(unused_variables)] |
330 | | - let #ident = #accessor; |
331 | | - }); |
332 | | - guards.push(guard); |
333 | | - guard_attrs.push(cfgs); |
334 | | - } |
| 303 | + guards.push(guard); |
| 304 | + guard_attrs.push(cfgs); |
335 | 305 | } |
336 | 306 | quote! { |
337 | 307 | #res |
|
0 commit comments