xref: /linux/rust/pin-init/internal/src/init.rs (revision d26732e57b06ef32dadfc32d5de9ac39262698cb)
14883830eSBenno Lossin // SPDX-License-Identifier: Apache-2.0 OR MIT
24883830eSBenno Lossin 
34883830eSBenno Lossin use proc_macro2::{Span, TokenStream};
44883830eSBenno Lossin use quote::{format_ident, quote, quote_spanned};
54883830eSBenno Lossin use syn::{
64883830eSBenno Lossin     braced,
74883830eSBenno Lossin     parse::{End, Parse},
84883830eSBenno Lossin     parse_quote,
94883830eSBenno Lossin     punctuated::Punctuated,
104883830eSBenno Lossin     spanned::Spanned,
11aeabc92eSBenno Lossin     token, Attribute, Block, Expr, ExprCall, ExprPath, Ident, Path, Token, Type,
124883830eSBenno Lossin };
134883830eSBenno Lossin 
144883830eSBenno Lossin use crate::diagnostics::{DiagCtxt, ErrorGuaranteed};
154883830eSBenno Lossin 
164883830eSBenno Lossin pub(crate) struct Initializer {
17aeabc92eSBenno Lossin     attrs: Vec<InitializerAttribute>,
184883830eSBenno Lossin     this: Option<This>,
194883830eSBenno Lossin     path: Path,
204883830eSBenno Lossin     brace_token: token::Brace,
214883830eSBenno Lossin     fields: Punctuated<InitializerField, Token![,]>,
224883830eSBenno Lossin     rest: Option<(Token![..], Expr)>,
234883830eSBenno Lossin     error: Option<(Token![?], Type)>,
244883830eSBenno Lossin }
254883830eSBenno Lossin 
264883830eSBenno Lossin struct This {
274883830eSBenno Lossin     _and_token: Token![&],
284883830eSBenno Lossin     ident: Ident,
294883830eSBenno Lossin     _in_token: Token![in],
304883830eSBenno Lossin }
314883830eSBenno Lossin 
32*d26732e5SBenno Lossin struct InitializerField {
33*d26732e5SBenno Lossin     attrs: Vec<Attribute>,
34*d26732e5SBenno Lossin     kind: InitializerKind,
35*d26732e5SBenno Lossin }
36*d26732e5SBenno Lossin 
37*d26732e5SBenno Lossin enum InitializerKind {
384883830eSBenno Lossin     Value {
394883830eSBenno Lossin         ident: Ident,
404883830eSBenno Lossin         value: Option<(Token![:], Expr)>,
414883830eSBenno Lossin     },
424883830eSBenno Lossin     Init {
434883830eSBenno Lossin         ident: Ident,
444883830eSBenno Lossin         _left_arrow_token: Token![<-],
454883830eSBenno Lossin         value: Expr,
464883830eSBenno Lossin     },
474883830eSBenno Lossin     Code {
484883830eSBenno Lossin         _underscore_token: Token![_],
494883830eSBenno Lossin         _colon_token: Token![:],
504883830eSBenno Lossin         block: Block,
514883830eSBenno Lossin     },
524883830eSBenno Lossin }
534883830eSBenno Lossin 
54*d26732e5SBenno Lossin impl InitializerKind {
554883830eSBenno Lossin     fn ident(&self) -> Option<&Ident> {
564883830eSBenno Lossin         match self {
574883830eSBenno Lossin             Self::Value { ident, .. } | Self::Init { ident, .. } => Some(ident),
584883830eSBenno Lossin             Self::Code { .. } => None,
594883830eSBenno Lossin         }
604883830eSBenno Lossin     }
614883830eSBenno Lossin }
624883830eSBenno Lossin 
63aeabc92eSBenno Lossin enum InitializerAttribute {
64aeabc92eSBenno Lossin     DefaultError(DefaultErrorAttribute),
65aeabc92eSBenno Lossin }
66aeabc92eSBenno Lossin 
67aeabc92eSBenno Lossin struct DefaultErrorAttribute {
68aeabc92eSBenno Lossin     ty: Box<Type>,
69aeabc92eSBenno Lossin }
70aeabc92eSBenno Lossin 
714883830eSBenno Lossin pub(crate) fn expand(
724883830eSBenno Lossin     Initializer {
73aeabc92eSBenno Lossin         attrs,
744883830eSBenno Lossin         this,
754883830eSBenno Lossin         path,
764883830eSBenno Lossin         brace_token,
774883830eSBenno Lossin         fields,
784883830eSBenno Lossin         rest,
794883830eSBenno Lossin         error,
804883830eSBenno Lossin     }: Initializer,
814883830eSBenno Lossin     default_error: Option<&'static str>,
824883830eSBenno Lossin     pinned: bool,
834883830eSBenno Lossin     dcx: &mut DiagCtxt,
844883830eSBenno Lossin ) -> Result<TokenStream, ErrorGuaranteed> {
854883830eSBenno Lossin     let error = error.map_or_else(
864883830eSBenno Lossin         || {
87aeabc92eSBenno Lossin             if let Some(default_error) = attrs.iter().fold(None, |acc, attr| {
88aeabc92eSBenno Lossin                 #[expect(irrefutable_let_patterns)]
89aeabc92eSBenno Lossin                 if let InitializerAttribute::DefaultError(DefaultErrorAttribute { ty }) = attr {
90aeabc92eSBenno Lossin                     Some(ty.clone())
91aeabc92eSBenno Lossin                 } else {
92aeabc92eSBenno Lossin                     acc
93aeabc92eSBenno Lossin                 }
94aeabc92eSBenno Lossin             }) {
95aeabc92eSBenno Lossin                 default_error
96aeabc92eSBenno Lossin             } else if let Some(default_error) = default_error {
974883830eSBenno Lossin                 syn::parse_str(default_error).unwrap()
984883830eSBenno Lossin             } else {
994883830eSBenno Lossin                 dcx.error(brace_token.span.close(), "expected `? <type>` after `}`");
1004883830eSBenno Lossin                 parse_quote!(::core::convert::Infallible)
1014883830eSBenno Lossin             }
1024883830eSBenno Lossin         },
103aeabc92eSBenno Lossin         |(_, err)| Box::new(err),
1044883830eSBenno Lossin     );
1054883830eSBenno Lossin     let slot = format_ident!("slot");
1064883830eSBenno Lossin     let (has_data_trait, data_trait, get_data, init_from_closure) = if pinned {
1074883830eSBenno Lossin         (
1084883830eSBenno Lossin             format_ident!("HasPinData"),
1094883830eSBenno Lossin             format_ident!("PinData"),
1104883830eSBenno Lossin             format_ident!("__pin_data"),
1114883830eSBenno Lossin             format_ident!("pin_init_from_closure"),
1124883830eSBenno Lossin         )
1134883830eSBenno Lossin     } else {
1144883830eSBenno Lossin         (
1154883830eSBenno Lossin             format_ident!("HasInitData"),
1164883830eSBenno Lossin             format_ident!("InitData"),
1174883830eSBenno Lossin             format_ident!("__init_data"),
1184883830eSBenno Lossin             format_ident!("init_from_closure"),
1194883830eSBenno Lossin         )
1204883830eSBenno Lossin     };
1214883830eSBenno Lossin     let init_kind = get_init_kind(rest, dcx);
1224883830eSBenno Lossin     let zeroable_check = match init_kind {
1234883830eSBenno Lossin         InitKind::Normal => quote!(),
1244883830eSBenno Lossin         InitKind::Zeroing => quote! {
1254883830eSBenno Lossin             // The user specified `..Zeroable::zeroed()` at the end of the list of fields.
1264883830eSBenno Lossin             // Therefore we check if the struct implements `Zeroable` and then zero the memory.
1274883830eSBenno Lossin             // This allows us to also remove the check that all fields are present (since we
1284883830eSBenno Lossin             // already set the memory to zero and that is a valid bit pattern).
1294883830eSBenno Lossin             fn assert_zeroable<T: ?::core::marker::Sized>(_: *mut T)
1304883830eSBenno Lossin             where T: ::pin_init::Zeroable
1314883830eSBenno Lossin             {}
1324883830eSBenno Lossin             // Ensure that the struct is indeed `Zeroable`.
1334883830eSBenno Lossin             assert_zeroable(#slot);
1344883830eSBenno Lossin             // SAFETY: The type implements `Zeroable` by the check above.
1354883830eSBenno Lossin             unsafe { ::core::ptr::write_bytes(#slot, 0, 1) };
1364883830eSBenno Lossin         },
1374883830eSBenno Lossin     };
1384883830eSBenno Lossin     let this = match this {
1394883830eSBenno Lossin         None => quote!(),
1404883830eSBenno Lossin         Some(This { ident, .. }) => quote! {
1414883830eSBenno Lossin             // Create the `this` so it can be referenced by the user inside of the
1424883830eSBenno Lossin             // expressions creating the individual fields.
1434883830eSBenno Lossin             let #ident = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };
1444883830eSBenno Lossin         },
1454883830eSBenno Lossin     };
1464883830eSBenno Lossin     // `mixed_site` ensures that the data is not accessible to the user-controlled code.
1474883830eSBenno Lossin     let data = Ident::new("__data", Span::mixed_site());
1484883830eSBenno Lossin     let init_fields = init_fields(&fields, pinned, &data, &slot);
1494883830eSBenno Lossin     let field_check = make_field_check(&fields, init_kind, &path);
1504883830eSBenno Lossin     Ok(quote! {{
1514883830eSBenno Lossin         // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return
1524883830eSBenno Lossin         // type and shadow it later when we insert the arbitrary user code. That way there will be
1534883830eSBenno Lossin         // no possibility of returning without `unsafe`.
1544883830eSBenno Lossin         struct __InitOk;
1554883830eSBenno Lossin 
1564883830eSBenno Lossin         // Get the data about fields from the supplied type.
1574883830eSBenno Lossin         // SAFETY: TODO
1584883830eSBenno Lossin         let #data = unsafe {
1594883830eSBenno Lossin             use ::pin_init::__internal::#has_data_trait;
1604883830eSBenno Lossin             // Can't use `<#path as #has_data_trait>::#get_data`, since the user is able to omit
1614883830eSBenno Lossin             // generics (which need to be present with that syntax).
1624883830eSBenno Lossin             #path::#get_data()
1634883830eSBenno Lossin         };
1644883830eSBenno Lossin         // Ensure that `#data` really is of type `#data` and help with type inference:
1654883830eSBenno Lossin         let init = ::pin_init::__internal::#data_trait::make_closure::<_, __InitOk, #error>(
1664883830eSBenno Lossin             #data,
1674883830eSBenno Lossin             move |slot| {
1684883830eSBenno Lossin                 {
1694883830eSBenno Lossin                     // Shadow the structure so it cannot be used to return early.
1704883830eSBenno Lossin                     struct __InitOk;
1714883830eSBenno Lossin                     #zeroable_check
1724883830eSBenno Lossin                     #this
1734883830eSBenno Lossin                     #init_fields
1744883830eSBenno Lossin                     #field_check
1754883830eSBenno Lossin                 }
1764883830eSBenno Lossin                 Ok(__InitOk)
1774883830eSBenno Lossin             }
1784883830eSBenno Lossin         );
1794883830eSBenno Lossin         let init = move |slot| -> ::core::result::Result<(), #error> {
1804883830eSBenno Lossin             init(slot).map(|__InitOk| ())
1814883830eSBenno Lossin         };
1824883830eSBenno Lossin         // SAFETY: TODO
1834883830eSBenno Lossin         let init = unsafe { ::pin_init::#init_from_closure::<_, #error>(init) };
1844883830eSBenno Lossin         init
1854883830eSBenno Lossin     }})
1864883830eSBenno Lossin }
1874883830eSBenno Lossin 
1884883830eSBenno Lossin enum InitKind {
1894883830eSBenno Lossin     Normal,
1904883830eSBenno Lossin     Zeroing,
1914883830eSBenno Lossin }
1924883830eSBenno Lossin 
1934883830eSBenno Lossin fn get_init_kind(rest: Option<(Token![..], Expr)>, dcx: &mut DiagCtxt) -> InitKind {
1944883830eSBenno Lossin     let Some((dotdot, expr)) = rest else {
1954883830eSBenno Lossin         return InitKind::Normal;
1964883830eSBenno Lossin     };
1974883830eSBenno Lossin     match &expr {
1984883830eSBenno Lossin         Expr::Call(ExprCall { func, args, .. }) if args.is_empty() => match &**func {
1994883830eSBenno Lossin             Expr::Path(ExprPath {
2004883830eSBenno Lossin                 attrs,
2014883830eSBenno Lossin                 qself: None,
2024883830eSBenno Lossin                 path:
2034883830eSBenno Lossin                     Path {
2044883830eSBenno Lossin                         leading_colon: None,
2054883830eSBenno Lossin                         segments,
2064883830eSBenno Lossin                     },
2074883830eSBenno Lossin             }) if attrs.is_empty()
2084883830eSBenno Lossin                 && segments.len() == 2
2094883830eSBenno Lossin                 && segments[0].ident == "Zeroable"
2104883830eSBenno Lossin                 && segments[0].arguments.is_none()
2114883830eSBenno Lossin                 && segments[1].ident == "init_zeroed"
2124883830eSBenno Lossin                 && segments[1].arguments.is_none() =>
2134883830eSBenno Lossin             {
2144883830eSBenno Lossin                 return InitKind::Zeroing;
2154883830eSBenno Lossin             }
2164883830eSBenno Lossin             _ => {}
2174883830eSBenno Lossin         },
2184883830eSBenno Lossin         _ => {}
2194883830eSBenno Lossin     }
2204883830eSBenno Lossin     dcx.error(
2214883830eSBenno Lossin         dotdot.span().join(expr.span()).unwrap_or(expr.span()),
2224883830eSBenno Lossin         "expected nothing or `..Zeroable::init_zeroed()`.",
2234883830eSBenno Lossin     );
2244883830eSBenno Lossin     InitKind::Normal
2254883830eSBenno Lossin }
2264883830eSBenno Lossin 
2274883830eSBenno Lossin /// Generate the code that initializes the fields of the struct using the initializers in `field`.
2284883830eSBenno Lossin fn init_fields(
2294883830eSBenno Lossin     fields: &Punctuated<InitializerField, Token![,]>,
2304883830eSBenno Lossin     pinned: bool,
2314883830eSBenno Lossin     data: &Ident,
2324883830eSBenno Lossin     slot: &Ident,
2334883830eSBenno Lossin ) -> TokenStream {
2344883830eSBenno Lossin     let mut guards = vec![];
235*d26732e5SBenno Lossin     let mut guard_attrs = vec![];
2364883830eSBenno Lossin     let mut res = TokenStream::new();
237*d26732e5SBenno Lossin     for InitializerField { attrs, kind } in fields {
238*d26732e5SBenno Lossin         let cfgs = {
239*d26732e5SBenno Lossin             let mut cfgs = attrs.clone();
240*d26732e5SBenno Lossin             cfgs.retain(|attr| attr.path().is_ident("cfg"));
241*d26732e5SBenno Lossin             cfgs
242*d26732e5SBenno Lossin         };
243*d26732e5SBenno Lossin         let init = match kind {
244*d26732e5SBenno Lossin             InitializerKind::Value { ident, value } => {
2454883830eSBenno Lossin                 let mut value_ident = ident.clone();
2464883830eSBenno Lossin                 let value_prep = value.as_ref().map(|value| &value.1).map(|value| {
2474883830eSBenno Lossin                     // Setting the span of `value_ident` to `value`'s span improves error messages
2484883830eSBenno Lossin                     // when the type of `value` is wrong.
2494883830eSBenno Lossin                     value_ident.set_span(value.span());
2504883830eSBenno Lossin                     quote!(let #value_ident = #value;)
2514883830eSBenno Lossin                 });
2524883830eSBenno Lossin                 // Again span for better diagnostics
2534883830eSBenno Lossin                 let write = quote_spanned!(ident.span()=> ::core::ptr::write);
2544883830eSBenno Lossin                 let accessor = if pinned {
2554883830eSBenno Lossin                     let project_ident = format_ident!("__project_{ident}");
2564883830eSBenno Lossin                     quote! {
2574883830eSBenno Lossin                         // SAFETY: TODO
2584883830eSBenno Lossin                         unsafe { #data.#project_ident(&mut (*#slot).#ident) }
2594883830eSBenno Lossin                     }
2604883830eSBenno Lossin                 } else {
2614883830eSBenno Lossin                     quote! {
2624883830eSBenno Lossin                         // SAFETY: TODO
2634883830eSBenno Lossin                         unsafe { &mut (*#slot).#ident }
2644883830eSBenno Lossin                     }
2654883830eSBenno Lossin                 };
2664883830eSBenno Lossin                 quote! {
267*d26732e5SBenno Lossin                     #(#attrs)*
2684883830eSBenno Lossin                     {
2694883830eSBenno Lossin                         #value_prep
2704883830eSBenno Lossin                         // SAFETY: TODO
2714883830eSBenno Lossin                         unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) };
2724883830eSBenno Lossin                     }
273*d26732e5SBenno Lossin                     #(#cfgs)*
2744883830eSBenno Lossin                     #[allow(unused_variables)]
2754883830eSBenno Lossin                     let #ident = #accessor;
2764883830eSBenno Lossin                 }
2774883830eSBenno Lossin             }
278*d26732e5SBenno Lossin             InitializerKind::Init { ident, value, .. } => {
2794883830eSBenno Lossin                 // Again span for better diagnostics
2804883830eSBenno Lossin                 let init = format_ident!("init", span = value.span());
2814883830eSBenno Lossin                 if pinned {
2824883830eSBenno Lossin                     let project_ident = format_ident!("__project_{ident}");
2834883830eSBenno Lossin                     quote! {
284*d26732e5SBenno Lossin                         #(#attrs)*
2854883830eSBenno Lossin                         {
2864883830eSBenno Lossin                             let #init = #value;
2874883830eSBenno Lossin                             // SAFETY:
2884883830eSBenno Lossin                             // - `slot` is valid, because we are inside of an initializer closure, we
2894883830eSBenno Lossin                             //   return when an error/panic occurs.
2904883830eSBenno Lossin                             // - We also use `#data` to require the correct trait (`Init` or `PinInit`)
2914883830eSBenno Lossin                             //   for `#ident`.
2924883830eSBenno Lossin                             unsafe { #data.#ident(::core::ptr::addr_of_mut!((*#slot).#ident), #init)? };
2934883830eSBenno Lossin                         }
294*d26732e5SBenno Lossin                         #(#cfgs)*
2954883830eSBenno Lossin                         // SAFETY: TODO
2964883830eSBenno Lossin                         #[allow(unused_variables)]
2974883830eSBenno Lossin                         let #ident = unsafe { #data.#project_ident(&mut (*#slot).#ident) };
2984883830eSBenno Lossin                     }
2994883830eSBenno Lossin                 } else {
3004883830eSBenno Lossin                     quote! {
301*d26732e5SBenno Lossin                         #(#attrs)*
3024883830eSBenno Lossin                         {
3034883830eSBenno Lossin                             let #init = #value;
3044883830eSBenno Lossin                             // SAFETY: `slot` is valid, because we are inside of an initializer
3054883830eSBenno Lossin                             // closure, we return when an error/panic occurs.
3064883830eSBenno Lossin                             unsafe {
3074883830eSBenno Lossin                                 ::pin_init::Init::__init(
3084883830eSBenno Lossin                                     #init,
3094883830eSBenno Lossin                                     ::core::ptr::addr_of_mut!((*#slot).#ident),
3104883830eSBenno Lossin                                 )?
3114883830eSBenno Lossin                             };
3124883830eSBenno Lossin                         }
313*d26732e5SBenno Lossin                         #(#cfgs)*
3144883830eSBenno Lossin                         // SAFETY: TODO
3154883830eSBenno Lossin                         #[allow(unused_variables)]
3164883830eSBenno Lossin                         let #ident = unsafe { &mut (*#slot).#ident };
3174883830eSBenno Lossin                     }
3184883830eSBenno Lossin                 }
3194883830eSBenno Lossin             }
320*d26732e5SBenno Lossin             InitializerKind::Code { block: value, .. } => quote! {
321*d26732e5SBenno Lossin                 #(#attrs)*
322*d26732e5SBenno Lossin                 #[allow(unused_braces)]
323*d26732e5SBenno Lossin                 #value
324*d26732e5SBenno Lossin             },
3254883830eSBenno Lossin         };
3264883830eSBenno Lossin         res.extend(init);
327*d26732e5SBenno Lossin         if let Some(ident) = kind.ident() {
3284883830eSBenno Lossin             // `mixed_site` ensures that the guard is not accessible to the user-controlled code.
3294883830eSBenno Lossin             let guard = format_ident!("__{ident}_guard", span = Span::mixed_site());
3304883830eSBenno Lossin             res.extend(quote! {
331*d26732e5SBenno Lossin                 #(#cfgs)*
3324883830eSBenno Lossin                 // Create the drop guard:
3334883830eSBenno Lossin                 //
3344883830eSBenno Lossin                 // We rely on macro hygiene to make it impossible for users to access this local
3354883830eSBenno Lossin                 // variable.
3364883830eSBenno Lossin                 // SAFETY: We forget the guard later when initialization has succeeded.
3374883830eSBenno Lossin                 let #guard = unsafe {
3384883830eSBenno Lossin                     ::pin_init::__internal::DropGuard::new(
3394883830eSBenno Lossin                         ::core::ptr::addr_of_mut!((*slot).#ident)
3404883830eSBenno Lossin                     )
3414883830eSBenno Lossin                 };
3424883830eSBenno Lossin             });
343*d26732e5SBenno Lossin             guards.push(guard);
344*d26732e5SBenno Lossin             guard_attrs.push(cfgs);
3454883830eSBenno Lossin         }
3464883830eSBenno Lossin     }
3474883830eSBenno Lossin     quote! {
3484883830eSBenno Lossin         #res
3494883830eSBenno Lossin         // If execution reaches this point, all fields have been initialized. Therefore we can now
3504883830eSBenno Lossin         // dismiss the guards by forgetting them.
351*d26732e5SBenno Lossin         #(
352*d26732e5SBenno Lossin             #(#guard_attrs)*
353*d26732e5SBenno Lossin             ::core::mem::forget(#guards);
354*d26732e5SBenno Lossin         )*
3554883830eSBenno Lossin     }
3564883830eSBenno Lossin }
3574883830eSBenno Lossin 
3584883830eSBenno Lossin /// Generate the check for ensuring that every field has been initialized.
3594883830eSBenno Lossin fn make_field_check(
3604883830eSBenno Lossin     fields: &Punctuated<InitializerField, Token![,]>,
3614883830eSBenno Lossin     init_kind: InitKind,
3624883830eSBenno Lossin     path: &Path,
3634883830eSBenno Lossin ) -> TokenStream {
364*d26732e5SBenno Lossin     let field_attrs = fields
365*d26732e5SBenno Lossin         .iter()
366*d26732e5SBenno Lossin         .filter_map(|f| f.kind.ident().map(|_| &f.attrs));
367*d26732e5SBenno Lossin     let field_name = fields.iter().filter_map(|f| f.kind.ident());
3684883830eSBenno Lossin     match init_kind {
3694883830eSBenno Lossin         InitKind::Normal => quote! {
3704883830eSBenno Lossin             // We use unreachable code to ensure that all fields have been mentioned exactly once,
3714883830eSBenno Lossin             // this struct initializer will still be type-checked and complain with a very natural
3724883830eSBenno Lossin             // error message if a field is forgotten/mentioned more than once.
3734883830eSBenno Lossin             #[allow(unreachable_code, clippy::diverging_sub_expression)]
3744883830eSBenno Lossin             // SAFETY: this code is never executed.
3754883830eSBenno Lossin             let _ = || unsafe {
3764883830eSBenno Lossin                 ::core::ptr::write(slot, #path {
3774883830eSBenno Lossin                     #(
378*d26732e5SBenno Lossin                         #(#field_attrs)*
379*d26732e5SBenno Lossin                         #field_name: ::core::panic!(),
3804883830eSBenno Lossin                     )*
3814883830eSBenno Lossin                 })
3824883830eSBenno Lossin             };
3834883830eSBenno Lossin         },
3844883830eSBenno Lossin         InitKind::Zeroing => quote! {
3854883830eSBenno Lossin             // We use unreachable code to ensure that all fields have been mentioned at most once.
3864883830eSBenno Lossin             // Since the user specified `..Zeroable::zeroed()` at the end, all missing fields will
3874883830eSBenno Lossin             // be zeroed. This struct initializer will still be type-checked and complain with a
3884883830eSBenno Lossin             // very natural error message if a field is mentioned more than once, or doesn't exist.
3894883830eSBenno Lossin             #[allow(unreachable_code, clippy::diverging_sub_expression, unused_assignments)]
3904883830eSBenno Lossin             // SAFETY: this code is never executed.
3914883830eSBenno Lossin             let _ = || unsafe {
3924883830eSBenno Lossin                 let mut zeroed = ::core::mem::zeroed();
3934883830eSBenno Lossin                 // We have to use type inference here to make zeroed have the correct type. This
3944883830eSBenno Lossin                 // does not get executed, so it has no effect.
3954883830eSBenno Lossin                 ::core::ptr::write(slot, zeroed);
3964883830eSBenno Lossin                 zeroed = ::core::mem::zeroed();
3974883830eSBenno Lossin                 ::core::ptr::write(slot, #path {
3984883830eSBenno Lossin                     #(
399*d26732e5SBenno Lossin                         #(#field_attrs)*
400*d26732e5SBenno Lossin                         #field_name: ::core::panic!(),
4014883830eSBenno Lossin                     )*
4024883830eSBenno Lossin                     ..zeroed
4034883830eSBenno Lossin                 })
4044883830eSBenno Lossin             };
4054883830eSBenno Lossin         },
4064883830eSBenno Lossin     }
4074883830eSBenno Lossin }
4084883830eSBenno Lossin 
4094883830eSBenno Lossin impl Parse for Initializer {
4104883830eSBenno Lossin     fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
411aeabc92eSBenno Lossin         let attrs = input.call(Attribute::parse_outer)?;
4124883830eSBenno Lossin         let this = input.peek(Token![&]).then(|| input.parse()).transpose()?;
4134883830eSBenno Lossin         let path = input.parse()?;
4144883830eSBenno Lossin         let content;
4154883830eSBenno Lossin         let brace_token = braced!(content in input);
4164883830eSBenno Lossin         let mut fields = Punctuated::new();
4174883830eSBenno Lossin         loop {
4184883830eSBenno Lossin             let lh = content.lookahead1();
4194883830eSBenno Lossin             if lh.peek(End) || lh.peek(Token![..]) {
4204883830eSBenno Lossin                 break;
421*d26732e5SBenno Lossin             } else if lh.peek(Ident) || lh.peek(Token![_]) || lh.peek(Token![#]) {
4224883830eSBenno Lossin                 fields.push_value(content.parse()?);
4234883830eSBenno Lossin                 let lh = content.lookahead1();
4244883830eSBenno Lossin                 if lh.peek(End) {
4254883830eSBenno Lossin                     break;
4264883830eSBenno Lossin                 } else if lh.peek(Token![,]) {
4274883830eSBenno Lossin                     fields.push_punct(content.parse()?);
4284883830eSBenno Lossin                 } else {
4294883830eSBenno Lossin                     return Err(lh.error());
4304883830eSBenno Lossin                 }
4314883830eSBenno Lossin             } else {
4324883830eSBenno Lossin                 return Err(lh.error());
4334883830eSBenno Lossin             }
4344883830eSBenno Lossin         }
4354883830eSBenno Lossin         let rest = content
4364883830eSBenno Lossin             .peek(Token![..])
4374883830eSBenno Lossin             .then(|| Ok::<_, syn::Error>((content.parse()?, content.parse()?)))
4384883830eSBenno Lossin             .transpose()?;
4394883830eSBenno Lossin         let error = input
4404883830eSBenno Lossin             .peek(Token![?])
4414883830eSBenno Lossin             .then(|| Ok::<_, syn::Error>((input.parse()?, input.parse()?)))
4424883830eSBenno Lossin             .transpose()?;
443aeabc92eSBenno Lossin         let attrs = attrs
444aeabc92eSBenno Lossin             .into_iter()
445aeabc92eSBenno Lossin             .map(|a| {
446aeabc92eSBenno Lossin                 if a.path().is_ident("default_error") {
447aeabc92eSBenno Lossin                     a.parse_args::<DefaultErrorAttribute>()
448aeabc92eSBenno Lossin                         .map(InitializerAttribute::DefaultError)
449aeabc92eSBenno Lossin                 } else {
450aeabc92eSBenno Lossin                     Err(syn::Error::new_spanned(a, "unknown initializer attribute"))
451aeabc92eSBenno Lossin                 }
452aeabc92eSBenno Lossin             })
453aeabc92eSBenno Lossin             .collect::<Result<Vec<_>, _>>()?;
4544883830eSBenno Lossin         Ok(Self {
455aeabc92eSBenno Lossin             attrs,
4564883830eSBenno Lossin             this,
4574883830eSBenno Lossin             path,
4584883830eSBenno Lossin             brace_token,
4594883830eSBenno Lossin             fields,
4604883830eSBenno Lossin             rest,
4614883830eSBenno Lossin             error,
4624883830eSBenno Lossin         })
4634883830eSBenno Lossin     }
4644883830eSBenno Lossin }
4654883830eSBenno Lossin 
466aeabc92eSBenno Lossin impl Parse for DefaultErrorAttribute {
467aeabc92eSBenno Lossin     fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
468aeabc92eSBenno Lossin         Ok(Self { ty: input.parse()? })
469aeabc92eSBenno Lossin     }
470aeabc92eSBenno Lossin }
471aeabc92eSBenno Lossin 
4724883830eSBenno Lossin impl Parse for This {
4734883830eSBenno Lossin     fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
4744883830eSBenno Lossin         Ok(Self {
4754883830eSBenno Lossin             _and_token: input.parse()?,
4764883830eSBenno Lossin             ident: input.parse()?,
4774883830eSBenno Lossin             _in_token: input.parse()?,
4784883830eSBenno Lossin         })
4794883830eSBenno Lossin     }
4804883830eSBenno Lossin }
4814883830eSBenno Lossin 
4824883830eSBenno Lossin impl Parse for InitializerField {
4834883830eSBenno Lossin     fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
484*d26732e5SBenno Lossin         let attrs = input.call(Attribute::parse_outer)?;
485*d26732e5SBenno Lossin         Ok(Self {
486*d26732e5SBenno Lossin             attrs,
487*d26732e5SBenno Lossin             kind: input.parse()?,
488*d26732e5SBenno Lossin         })
489*d26732e5SBenno Lossin     }
490*d26732e5SBenno Lossin }
491*d26732e5SBenno Lossin 
492*d26732e5SBenno Lossin impl Parse for InitializerKind {
493*d26732e5SBenno Lossin     fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
4944883830eSBenno Lossin         let lh = input.lookahead1();
4954883830eSBenno Lossin         if lh.peek(Token![_]) {
4964883830eSBenno Lossin             Ok(Self::Code {
4974883830eSBenno Lossin                 _underscore_token: input.parse()?,
4984883830eSBenno Lossin                 _colon_token: input.parse()?,
4994883830eSBenno Lossin                 block: input.parse()?,
5004883830eSBenno Lossin             })
5014883830eSBenno Lossin         } else if lh.peek(Ident) {
5024883830eSBenno Lossin             let ident = input.parse()?;
5034883830eSBenno Lossin             let lh = input.lookahead1();
5044883830eSBenno Lossin             if lh.peek(Token![<-]) {
5054883830eSBenno Lossin                 Ok(Self::Init {
5064883830eSBenno Lossin                     ident,
5074883830eSBenno Lossin                     _left_arrow_token: input.parse()?,
5084883830eSBenno Lossin                     value: input.parse()?,
5094883830eSBenno Lossin                 })
5104883830eSBenno Lossin             } else if lh.peek(Token![:]) {
5114883830eSBenno Lossin                 Ok(Self::Value {
5124883830eSBenno Lossin                     ident,
5134883830eSBenno Lossin                     value: Some((input.parse()?, input.parse()?)),
5144883830eSBenno Lossin                 })
5154883830eSBenno Lossin             } else if lh.peek(Token![,]) || lh.peek(End) {
5164883830eSBenno Lossin                 Ok(Self::Value { ident, value: None })
5174883830eSBenno Lossin             } else {
5184883830eSBenno Lossin                 Err(lh.error())
5194883830eSBenno Lossin             }
5204883830eSBenno Lossin         } else {
5214883830eSBenno Lossin             Err(lh.error())
5224883830eSBenno Lossin         }
5234883830eSBenno Lossin     }
5244883830eSBenno Lossin }
525