xref: /linux/rust/pin-init/internal/src/init.rs (revision 1f1cd6964bbc37f2cc82a0adc8a0acec34af1afb)
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 
32d26732e5SBenno Lossin struct InitializerField {
33d26732e5SBenno Lossin     attrs: Vec<Attribute>,
34d26732e5SBenno Lossin     kind: InitializerKind,
35d26732e5SBenno Lossin }
36d26732e5SBenno Lossin 
37d26732e5SBenno 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 
54d26732e5SBenno 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),
65ceca298cSBenno Lossin     DisableInitializedFieldAccess,
66aeabc92eSBenno Lossin }
67aeabc92eSBenno Lossin 
68aeabc92eSBenno Lossin struct DefaultErrorAttribute {
69aeabc92eSBenno Lossin     ty: Box<Type>,
70aeabc92eSBenno Lossin }
71aeabc92eSBenno Lossin 
724883830eSBenno Lossin pub(crate) fn expand(
734883830eSBenno Lossin     Initializer {
74aeabc92eSBenno Lossin         attrs,
754883830eSBenno Lossin         this,
764883830eSBenno Lossin         path,
774883830eSBenno Lossin         brace_token,
784883830eSBenno Lossin         fields,
794883830eSBenno Lossin         rest,
804883830eSBenno Lossin         error,
814883830eSBenno Lossin     }: Initializer,
824883830eSBenno Lossin     default_error: Option<&'static str>,
834883830eSBenno Lossin     pinned: bool,
844883830eSBenno Lossin     dcx: &mut DiagCtxt,
854883830eSBenno Lossin ) -> Result<TokenStream, ErrorGuaranteed> {
864883830eSBenno Lossin     let error = error.map_or_else(
874883830eSBenno Lossin         || {
88aeabc92eSBenno Lossin             if let Some(default_error) = attrs.iter().fold(None, |acc, attr| {
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());
148ceca298cSBenno Lossin     let init_fields = init_fields(
149ceca298cSBenno Lossin         &fields,
150ceca298cSBenno Lossin         pinned,
151ceca298cSBenno Lossin         !attrs
152ceca298cSBenno Lossin             .iter()
153ceca298cSBenno Lossin             .any(|attr| matches!(attr, InitializerAttribute::DisableInitializedFieldAccess)),
154ceca298cSBenno Lossin         &data,
155ceca298cSBenno Lossin         &slot,
156ceca298cSBenno Lossin     );
1574883830eSBenno Lossin     let field_check = make_field_check(&fields, init_kind, &path);
1584883830eSBenno Lossin     Ok(quote! {{
1594883830eSBenno Lossin         // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return
1604883830eSBenno Lossin         // type and shadow it later when we insert the arbitrary user code. That way there will be
1614883830eSBenno Lossin         // no possibility of returning without `unsafe`.
1624883830eSBenno Lossin         struct __InitOk;
1634883830eSBenno Lossin 
1644883830eSBenno Lossin         // Get the data about fields from the supplied type.
1654883830eSBenno Lossin         // SAFETY: TODO
1664883830eSBenno Lossin         let #data = unsafe {
1674883830eSBenno Lossin             use ::pin_init::__internal::#has_data_trait;
1684883830eSBenno Lossin             // Can't use `<#path as #has_data_trait>::#get_data`, since the user is able to omit
1694883830eSBenno Lossin             // generics (which need to be present with that syntax).
1704883830eSBenno Lossin             #path::#get_data()
1714883830eSBenno Lossin         };
1724883830eSBenno Lossin         // Ensure that `#data` really is of type `#data` and help with type inference:
1734883830eSBenno Lossin         let init = ::pin_init::__internal::#data_trait::make_closure::<_, __InitOk, #error>(
1744883830eSBenno Lossin             #data,
1754883830eSBenno Lossin             move |slot| {
1764883830eSBenno Lossin                 {
1774883830eSBenno Lossin                     // Shadow the structure so it cannot be used to return early.
1784883830eSBenno Lossin                     struct __InitOk;
1794883830eSBenno Lossin                     #zeroable_check
1804883830eSBenno Lossin                     #this
1814883830eSBenno Lossin                     #init_fields
1824883830eSBenno Lossin                     #field_check
1834883830eSBenno Lossin                 }
1844883830eSBenno Lossin                 Ok(__InitOk)
1854883830eSBenno Lossin             }
1864883830eSBenno Lossin         );
1874883830eSBenno Lossin         let init = move |slot| -> ::core::result::Result<(), #error> {
1884883830eSBenno Lossin             init(slot).map(|__InitOk| ())
1894883830eSBenno Lossin         };
1904883830eSBenno Lossin         // SAFETY: TODO
1914883830eSBenno Lossin         let init = unsafe { ::pin_init::#init_from_closure::<_, #error>(init) };
1924883830eSBenno Lossin         init
1934883830eSBenno Lossin     }})
1944883830eSBenno Lossin }
1954883830eSBenno Lossin 
1964883830eSBenno Lossin enum InitKind {
1974883830eSBenno Lossin     Normal,
1984883830eSBenno Lossin     Zeroing,
1994883830eSBenno Lossin }
2004883830eSBenno Lossin 
2014883830eSBenno Lossin fn get_init_kind(rest: Option<(Token![..], Expr)>, dcx: &mut DiagCtxt) -> InitKind {
2024883830eSBenno Lossin     let Some((dotdot, expr)) = rest else {
2034883830eSBenno Lossin         return InitKind::Normal;
2044883830eSBenno Lossin     };
2054883830eSBenno Lossin     match &expr {
2064883830eSBenno Lossin         Expr::Call(ExprCall { func, args, .. }) if args.is_empty() => match &**func {
2074883830eSBenno Lossin             Expr::Path(ExprPath {
2084883830eSBenno Lossin                 attrs,
2094883830eSBenno Lossin                 qself: None,
2104883830eSBenno Lossin                 path:
2114883830eSBenno Lossin                     Path {
2124883830eSBenno Lossin                         leading_colon: None,
2134883830eSBenno Lossin                         segments,
2144883830eSBenno Lossin                     },
2154883830eSBenno Lossin             }) if attrs.is_empty()
2164883830eSBenno Lossin                 && segments.len() == 2
2174883830eSBenno Lossin                 && segments[0].ident == "Zeroable"
2184883830eSBenno Lossin                 && segments[0].arguments.is_none()
2194883830eSBenno Lossin                 && segments[1].ident == "init_zeroed"
2204883830eSBenno Lossin                 && segments[1].arguments.is_none() =>
2214883830eSBenno Lossin             {
2224883830eSBenno Lossin                 return InitKind::Zeroing;
2234883830eSBenno Lossin             }
2244883830eSBenno Lossin             _ => {}
2254883830eSBenno Lossin         },
2264883830eSBenno Lossin         _ => {}
2274883830eSBenno Lossin     }
2284883830eSBenno Lossin     dcx.error(
2294883830eSBenno Lossin         dotdot.span().join(expr.span()).unwrap_or(expr.span()),
2304883830eSBenno Lossin         "expected nothing or `..Zeroable::init_zeroed()`.",
2314883830eSBenno Lossin     );
2324883830eSBenno Lossin     InitKind::Normal
2334883830eSBenno Lossin }
2344883830eSBenno Lossin 
2354883830eSBenno Lossin /// Generate the code that initializes the fields of the struct using the initializers in `field`.
2364883830eSBenno Lossin fn init_fields(
2374883830eSBenno Lossin     fields: &Punctuated<InitializerField, Token![,]>,
2384883830eSBenno Lossin     pinned: bool,
239ceca298cSBenno Lossin     generate_initialized_accessors: bool,
2404883830eSBenno Lossin     data: &Ident,
2414883830eSBenno Lossin     slot: &Ident,
2424883830eSBenno Lossin ) -> TokenStream {
2434883830eSBenno Lossin     let mut guards = vec![];
244d26732e5SBenno Lossin     let mut guard_attrs = vec![];
2454883830eSBenno Lossin     let mut res = TokenStream::new();
246d26732e5SBenno Lossin     for InitializerField { attrs, kind } in fields {
247d26732e5SBenno Lossin         let cfgs = {
248d26732e5SBenno Lossin             let mut cfgs = attrs.clone();
249d26732e5SBenno Lossin             cfgs.retain(|attr| attr.path().is_ident("cfg"));
250d26732e5SBenno Lossin             cfgs
251d26732e5SBenno Lossin         };
252d26732e5SBenno Lossin         let init = match kind {
253d26732e5SBenno Lossin             InitializerKind::Value { ident, value } => {
2544883830eSBenno Lossin                 let mut value_ident = ident.clone();
2554883830eSBenno Lossin                 let value_prep = value.as_ref().map(|value| &value.1).map(|value| {
2564883830eSBenno Lossin                     // Setting the span of `value_ident` to `value`'s span improves error messages
2574883830eSBenno Lossin                     // when the type of `value` is wrong.
2584883830eSBenno Lossin                     value_ident.set_span(value.span());
2594883830eSBenno Lossin                     quote!(let #value_ident = #value;)
2604883830eSBenno Lossin                 });
2614883830eSBenno Lossin                 // Again span for better diagnostics
2624883830eSBenno Lossin                 let write = quote_spanned!(ident.span()=> ::core::ptr::write);
2634883830eSBenno Lossin                 let accessor = if pinned {
2644883830eSBenno Lossin                     let project_ident = format_ident!("__project_{ident}");
2654883830eSBenno Lossin                     quote! {
2664883830eSBenno Lossin                         // SAFETY: TODO
2674883830eSBenno Lossin                         unsafe { #data.#project_ident(&mut (*#slot).#ident) }
2684883830eSBenno Lossin                     }
2694883830eSBenno Lossin                 } else {
2704883830eSBenno Lossin                     quote! {
2714883830eSBenno Lossin                         // SAFETY: TODO
2724883830eSBenno Lossin                         unsafe { &mut (*#slot).#ident }
2734883830eSBenno Lossin                     }
2744883830eSBenno Lossin                 };
275ceca298cSBenno Lossin                 let accessor = generate_initialized_accessors.then(|| {
276ceca298cSBenno Lossin                     quote! {
277ceca298cSBenno Lossin                         #(#cfgs)*
278ceca298cSBenno Lossin                         #[allow(unused_variables)]
279ceca298cSBenno Lossin                         let #ident = #accessor;
280ceca298cSBenno Lossin                     }
281ceca298cSBenno Lossin                 });
2824883830eSBenno Lossin                 quote! {
283d26732e5SBenno Lossin                     #(#attrs)*
2844883830eSBenno Lossin                     {
2854883830eSBenno Lossin                         #value_prep
2864883830eSBenno Lossin                         // SAFETY: TODO
2874883830eSBenno Lossin                         unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) };
2884883830eSBenno Lossin                     }
289ceca298cSBenno Lossin                     #accessor
2904883830eSBenno Lossin                 }
2914883830eSBenno Lossin             }
292d26732e5SBenno Lossin             InitializerKind::Init { ident, value, .. } => {
2934883830eSBenno Lossin                 // Again span for better diagnostics
2944883830eSBenno Lossin                 let init = format_ident!("init", span = value.span());
295ceca298cSBenno Lossin                 let (value_init, accessor) = if pinned {
2964883830eSBenno Lossin                     let project_ident = format_ident!("__project_{ident}");
297ceca298cSBenno Lossin                     (
2984883830eSBenno Lossin                         quote! {
2994883830eSBenno Lossin                             // SAFETY:
3004883830eSBenno Lossin                             // - `slot` is valid, because we are inside of an initializer closure, we
3014883830eSBenno Lossin                             //   return when an error/panic occurs.
3024883830eSBenno Lossin                             // - We also use `#data` to require the correct trait (`Init` or `PinInit`)
3034883830eSBenno Lossin                             //   for `#ident`.
3044883830eSBenno Lossin                             unsafe { #data.#ident(::core::ptr::addr_of_mut!((*#slot).#ident), #init)? };
305ceca298cSBenno Lossin                         },
3064883830eSBenno Lossin                         quote! {
307ceca298cSBenno Lossin                             // SAFETY: TODO
308ceca298cSBenno Lossin                             unsafe { #data.#project_ident(&mut (*#slot).#ident) }
309ceca298cSBenno Lossin                         },
310ceca298cSBenno Lossin                     )
311ceca298cSBenno Lossin                 } else {
312ceca298cSBenno Lossin                     (
313ceca298cSBenno Lossin                         quote! {
3144883830eSBenno Lossin                             // SAFETY: `slot` is valid, because we are inside of an initializer
3154883830eSBenno Lossin                             // closure, we return when an error/panic occurs.
3164883830eSBenno Lossin                             unsafe {
3174883830eSBenno Lossin                                 ::pin_init::Init::__init(
3184883830eSBenno Lossin                                     #init,
3194883830eSBenno Lossin                                     ::core::ptr::addr_of_mut!((*#slot).#ident),
3204883830eSBenno Lossin                                 )?
3214883830eSBenno Lossin                             };
322ceca298cSBenno Lossin                         },
323ceca298cSBenno Lossin                         quote! {
3244883830eSBenno Lossin                             // SAFETY: TODO
325ceca298cSBenno Lossin                             unsafe { &mut (*#slot).#ident }
326ceca298cSBenno Lossin                         },
327ceca298cSBenno Lossin                     )
328ceca298cSBenno Lossin                 };
329ceca298cSBenno Lossin                 let accessor = generate_initialized_accessors.then(|| {
330ceca298cSBenno Lossin                     quote! {
331ceca298cSBenno Lossin                         #(#cfgs)*
3324883830eSBenno Lossin                         #[allow(unused_variables)]
333ceca298cSBenno Lossin                         let #ident = #accessor;
3344883830eSBenno Lossin                     }
335ceca298cSBenno Lossin                 });
336ceca298cSBenno Lossin                 quote! {
337ceca298cSBenno Lossin                     #(#attrs)*
338ceca298cSBenno Lossin                     {
339ceca298cSBenno Lossin                         let #init = #value;
340ceca298cSBenno Lossin                         #value_init
341ceca298cSBenno Lossin                     }
342ceca298cSBenno Lossin                     #accessor
3434883830eSBenno Lossin                 }
3444883830eSBenno Lossin             }
345d26732e5SBenno Lossin             InitializerKind::Code { block: value, .. } => quote! {
346d26732e5SBenno Lossin                 #(#attrs)*
347d26732e5SBenno Lossin                 #[allow(unused_braces)]
348d26732e5SBenno Lossin                 #value
349d26732e5SBenno Lossin             },
3504883830eSBenno Lossin         };
3514883830eSBenno Lossin         res.extend(init);
352d26732e5SBenno Lossin         if let Some(ident) = kind.ident() {
3534883830eSBenno Lossin             // `mixed_site` ensures that the guard is not accessible to the user-controlled code.
3544883830eSBenno Lossin             let guard = format_ident!("__{ident}_guard", span = Span::mixed_site());
3554883830eSBenno Lossin             res.extend(quote! {
356d26732e5SBenno Lossin                 #(#cfgs)*
3574883830eSBenno Lossin                 // Create the drop guard:
3584883830eSBenno Lossin                 //
3594883830eSBenno Lossin                 // We rely on macro hygiene to make it impossible for users to access this local
3604883830eSBenno Lossin                 // variable.
3614883830eSBenno Lossin                 // SAFETY: We forget the guard later when initialization has succeeded.
3624883830eSBenno Lossin                 let #guard = unsafe {
3634883830eSBenno Lossin                     ::pin_init::__internal::DropGuard::new(
3644883830eSBenno Lossin                         ::core::ptr::addr_of_mut!((*slot).#ident)
3654883830eSBenno Lossin                     )
3664883830eSBenno Lossin                 };
3674883830eSBenno Lossin             });
368d26732e5SBenno Lossin             guards.push(guard);
369d26732e5SBenno Lossin             guard_attrs.push(cfgs);
3704883830eSBenno Lossin         }
3714883830eSBenno Lossin     }
3724883830eSBenno Lossin     quote! {
3734883830eSBenno Lossin         #res
3744883830eSBenno Lossin         // If execution reaches this point, all fields have been initialized. Therefore we can now
3754883830eSBenno Lossin         // dismiss the guards by forgetting them.
376d26732e5SBenno Lossin         #(
377d26732e5SBenno Lossin             #(#guard_attrs)*
378d26732e5SBenno Lossin             ::core::mem::forget(#guards);
379d26732e5SBenno Lossin         )*
3804883830eSBenno Lossin     }
3814883830eSBenno Lossin }
3824883830eSBenno Lossin 
3834883830eSBenno Lossin /// Generate the check for ensuring that every field has been initialized.
3844883830eSBenno Lossin fn make_field_check(
3854883830eSBenno Lossin     fields: &Punctuated<InitializerField, Token![,]>,
3864883830eSBenno Lossin     init_kind: InitKind,
3874883830eSBenno Lossin     path: &Path,
3884883830eSBenno Lossin ) -> TokenStream {
389d26732e5SBenno Lossin     let field_attrs = fields
390d26732e5SBenno Lossin         .iter()
391d26732e5SBenno Lossin         .filter_map(|f| f.kind.ident().map(|_| &f.attrs));
392d26732e5SBenno Lossin     let field_name = fields.iter().filter_map(|f| f.kind.ident());
3934883830eSBenno Lossin     match init_kind {
3944883830eSBenno Lossin         InitKind::Normal => quote! {
3954883830eSBenno Lossin             // We use unreachable code to ensure that all fields have been mentioned exactly once,
3964883830eSBenno Lossin             // this struct initializer will still be type-checked and complain with a very natural
3974883830eSBenno Lossin             // error message if a field is forgotten/mentioned more than once.
3984883830eSBenno Lossin             #[allow(unreachable_code, clippy::diverging_sub_expression)]
3994883830eSBenno Lossin             // SAFETY: this code is never executed.
4004883830eSBenno Lossin             let _ = || unsafe {
4014883830eSBenno Lossin                 ::core::ptr::write(slot, #path {
4024883830eSBenno Lossin                     #(
403d26732e5SBenno Lossin                         #(#field_attrs)*
404d26732e5SBenno Lossin                         #field_name: ::core::panic!(),
4054883830eSBenno Lossin                     )*
4064883830eSBenno Lossin                 })
4074883830eSBenno Lossin             };
4084883830eSBenno Lossin         },
4094883830eSBenno Lossin         InitKind::Zeroing => quote! {
4104883830eSBenno Lossin             // We use unreachable code to ensure that all fields have been mentioned at most once.
4114883830eSBenno Lossin             // Since the user specified `..Zeroable::zeroed()` at the end, all missing fields will
4124883830eSBenno Lossin             // be zeroed. This struct initializer will still be type-checked and complain with a
4134883830eSBenno Lossin             // very natural error message if a field is mentioned more than once, or doesn't exist.
4144883830eSBenno Lossin             #[allow(unreachable_code, clippy::diverging_sub_expression, unused_assignments)]
4154883830eSBenno Lossin             // SAFETY: this code is never executed.
4164883830eSBenno Lossin             let _ = || unsafe {
4174883830eSBenno Lossin                 ::core::ptr::write(slot, #path {
4184883830eSBenno Lossin                     #(
419d26732e5SBenno Lossin                         #(#field_attrs)*
420d26732e5SBenno Lossin                         #field_name: ::core::panic!(),
4214883830eSBenno Lossin                     )*
422*1f1cd696SBenno Lossin                     ..::core::mem::zeroed()
4234883830eSBenno Lossin                 })
4244883830eSBenno Lossin             };
4254883830eSBenno Lossin         },
4264883830eSBenno Lossin     }
4274883830eSBenno Lossin }
4284883830eSBenno Lossin 
4294883830eSBenno Lossin impl Parse for Initializer {
4304883830eSBenno Lossin     fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
431aeabc92eSBenno Lossin         let attrs = input.call(Attribute::parse_outer)?;
4324883830eSBenno Lossin         let this = input.peek(Token![&]).then(|| input.parse()).transpose()?;
4334883830eSBenno Lossin         let path = input.parse()?;
4344883830eSBenno Lossin         let content;
4354883830eSBenno Lossin         let brace_token = braced!(content in input);
4364883830eSBenno Lossin         let mut fields = Punctuated::new();
4374883830eSBenno Lossin         loop {
4384883830eSBenno Lossin             let lh = content.lookahead1();
4394883830eSBenno Lossin             if lh.peek(End) || lh.peek(Token![..]) {
4404883830eSBenno Lossin                 break;
441d26732e5SBenno Lossin             } else if lh.peek(Ident) || lh.peek(Token![_]) || lh.peek(Token![#]) {
4424883830eSBenno Lossin                 fields.push_value(content.parse()?);
4434883830eSBenno Lossin                 let lh = content.lookahead1();
4444883830eSBenno Lossin                 if lh.peek(End) {
4454883830eSBenno Lossin                     break;
4464883830eSBenno Lossin                 } else if lh.peek(Token![,]) {
4474883830eSBenno Lossin                     fields.push_punct(content.parse()?);
4484883830eSBenno Lossin                 } else {
4494883830eSBenno Lossin                     return Err(lh.error());
4504883830eSBenno Lossin                 }
4514883830eSBenno Lossin             } else {
4524883830eSBenno Lossin                 return Err(lh.error());
4534883830eSBenno Lossin             }
4544883830eSBenno Lossin         }
4554883830eSBenno Lossin         let rest = content
4564883830eSBenno Lossin             .peek(Token![..])
4574883830eSBenno Lossin             .then(|| Ok::<_, syn::Error>((content.parse()?, content.parse()?)))
4584883830eSBenno Lossin             .transpose()?;
4594883830eSBenno Lossin         let error = input
4604883830eSBenno Lossin             .peek(Token![?])
4614883830eSBenno Lossin             .then(|| Ok::<_, syn::Error>((input.parse()?, input.parse()?)))
4624883830eSBenno Lossin             .transpose()?;
463aeabc92eSBenno Lossin         let attrs = attrs
464aeabc92eSBenno Lossin             .into_iter()
465aeabc92eSBenno Lossin             .map(|a| {
466aeabc92eSBenno Lossin                 if a.path().is_ident("default_error") {
467aeabc92eSBenno Lossin                     a.parse_args::<DefaultErrorAttribute>()
468aeabc92eSBenno Lossin                         .map(InitializerAttribute::DefaultError)
469ceca298cSBenno Lossin                 } else if a.path().is_ident("disable_initialized_field_access") {
470ceca298cSBenno Lossin                     a.meta
471ceca298cSBenno Lossin                         .require_path_only()
472ceca298cSBenno Lossin                         .map(|_| InitializerAttribute::DisableInitializedFieldAccess)
473aeabc92eSBenno Lossin                 } else {
474aeabc92eSBenno Lossin                     Err(syn::Error::new_spanned(a, "unknown initializer attribute"))
475aeabc92eSBenno Lossin                 }
476aeabc92eSBenno Lossin             })
477aeabc92eSBenno Lossin             .collect::<Result<Vec<_>, _>>()?;
4784883830eSBenno Lossin         Ok(Self {
479aeabc92eSBenno Lossin             attrs,
4804883830eSBenno Lossin             this,
4814883830eSBenno Lossin             path,
4824883830eSBenno Lossin             brace_token,
4834883830eSBenno Lossin             fields,
4844883830eSBenno Lossin             rest,
4854883830eSBenno Lossin             error,
4864883830eSBenno Lossin         })
4874883830eSBenno Lossin     }
4884883830eSBenno Lossin }
4894883830eSBenno Lossin 
490aeabc92eSBenno Lossin impl Parse for DefaultErrorAttribute {
491aeabc92eSBenno Lossin     fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
492aeabc92eSBenno Lossin         Ok(Self { ty: input.parse()? })
493aeabc92eSBenno Lossin     }
494aeabc92eSBenno Lossin }
495aeabc92eSBenno Lossin 
4964883830eSBenno Lossin impl Parse for This {
4974883830eSBenno Lossin     fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
4984883830eSBenno Lossin         Ok(Self {
4994883830eSBenno Lossin             _and_token: input.parse()?,
5004883830eSBenno Lossin             ident: input.parse()?,
5014883830eSBenno Lossin             _in_token: input.parse()?,
5024883830eSBenno Lossin         })
5034883830eSBenno Lossin     }
5044883830eSBenno Lossin }
5054883830eSBenno Lossin 
5064883830eSBenno Lossin impl Parse for InitializerField {
5074883830eSBenno Lossin     fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
508d26732e5SBenno Lossin         let attrs = input.call(Attribute::parse_outer)?;
509d26732e5SBenno Lossin         Ok(Self {
510d26732e5SBenno Lossin             attrs,
511d26732e5SBenno Lossin             kind: input.parse()?,
512d26732e5SBenno Lossin         })
513d26732e5SBenno Lossin     }
514d26732e5SBenno Lossin }
515d26732e5SBenno Lossin 
516d26732e5SBenno Lossin impl Parse for InitializerKind {
517d26732e5SBenno Lossin     fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
5184883830eSBenno Lossin         let lh = input.lookahead1();
5194883830eSBenno Lossin         if lh.peek(Token![_]) {
5204883830eSBenno Lossin             Ok(Self::Code {
5214883830eSBenno Lossin                 _underscore_token: input.parse()?,
5224883830eSBenno Lossin                 _colon_token: input.parse()?,
5234883830eSBenno Lossin                 block: input.parse()?,
5244883830eSBenno Lossin             })
5254883830eSBenno Lossin         } else if lh.peek(Ident) {
5264883830eSBenno Lossin             let ident = input.parse()?;
5274883830eSBenno Lossin             let lh = input.lookahead1();
5284883830eSBenno Lossin             if lh.peek(Token![<-]) {
5294883830eSBenno Lossin                 Ok(Self::Init {
5304883830eSBenno Lossin                     ident,
5314883830eSBenno Lossin                     _left_arrow_token: input.parse()?,
5324883830eSBenno Lossin                     value: input.parse()?,
5334883830eSBenno Lossin                 })
5344883830eSBenno Lossin             } else if lh.peek(Token![:]) {
5354883830eSBenno Lossin                 Ok(Self::Value {
5364883830eSBenno Lossin                     ident,
5374883830eSBenno Lossin                     value: Some((input.parse()?, input.parse()?)),
5384883830eSBenno Lossin                 })
5394883830eSBenno Lossin             } else if lh.peek(Token![,]) || lh.peek(End) {
5404883830eSBenno Lossin                 Ok(Self::Value { ident, value: None })
5414883830eSBenno Lossin             } else {
5424883830eSBenno Lossin                 Err(lh.error())
5434883830eSBenno Lossin             }
5444883830eSBenno Lossin         } else {
5454883830eSBenno Lossin             Err(lh.error())
5464883830eSBenno Lossin         }
5474883830eSBenno Lossin     }
5484883830eSBenno Lossin }
549