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