diff --git a/Cargo.lock b/Cargo.lock index 45fa73ab..58b49e1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,6 +117,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", + "syn", ] [[package]] @@ -131,9 +132,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] @@ -210,9 +211,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.58" +version = "2.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" dependencies = [ "proc-macro2", "quote", diff --git a/internal/Cargo.lock b/internal/Cargo.lock index d0a730fe..42b1c239 100644 --- a/internal/Cargo.lock +++ b/internal/Cargo.lock @@ -9,22 +9,23 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", + "syn", ] [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -44,6 +45,17 @@ version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" +[[package]] +name = "syn" +version = "2.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "unicode-ident" version = "1.0.8" diff --git a/internal/Cargo.toml b/internal/Cargo.toml index 747c0b21..48c37160 100644 --- a/internal/Cargo.toml +++ b/internal/Cargo.toml @@ -15,6 +15,7 @@ proc-macro = true [dependencies] quote = "1.0" proc-macro2 = "1.0" +syn = { version = "2.0.98", features = ["full", "visit", "visit-mut"] } [build-dependencies] rustc_version = "0.4" diff --git a/internal/src/init.rs b/internal/src/init.rs new file mode 100644 index 00000000..4d325cd3 --- /dev/null +++ b/internal/src/init.rs @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use proc_macro2::{Ident, Span, TokenStream}; +use quote::{format_ident, quote, quote_spanned}; +use syn::{ + braced, + parse::{Parse, ParseStream}, + parse_quote, + punctuated::Punctuated, + spanned::Spanned, + token, Error, Expr, ExprCall, ExprPath, Path, Result, Token, Type, +}; + +pub(crate) struct InPlaceInitializer { + this: Option, + path: Path, + brace_token: token::Brace, + fields: Punctuated, + rest: Option<(Token![..], Expr)>, + error: Option<(Token![?], Type)>, +} + +struct This { + _and_token: Token![&], + ident: Ident, + _in_token: Token![in], +} + +enum FieldInitializer { + Value { + ident: Ident, + value: Option<(Token![:], Expr)>, + }, + Init { + ident: Ident, + _larrow: Token![<-], + value: Expr, + }, +} + +impl FieldInitializer { + fn ident(&self) -> &Ident { + match self { + FieldInitializer::Value { ident, .. } | FieldInitializer::Init { ident, .. } => ident, + } + } +} + +enum InitKind { + Normal, + Zeroing, +} + +pub(crate) fn init( + InPlaceInitializer { + this, + path, + fields, + rest, + mut error, + brace_token, + .. + }: InPlaceInitializer, + default_error: bool, + pin: bool, +) -> Result { + if default_error { + error.get_or_insert(( + Default::default(), + parse_quote!(::core::convert::Infallible), + )); + } + let Some((_, error)) = error else { + return Err(Error::new( + brace_token.span.close(), + "expected `? ` after `}`", + )); + }; + let use_data = pin; + let (has_data_trait, data_trait, get_data, from_closure) = match pin { + true => ( + format_ident!("HasPinData"), + format_ident!("PinData"), + format_ident!("__pin_data"), + format_ident!("pin_init_from_closure"), + ), + false => ( + format_ident!("HasInitData"), + format_ident!("InitData"), + format_ident!("__init_data"), + format_ident!("init_from_closure"), + ), + }; + + let init_kind = get_init_kind(rest)?; + let zeroable_check = match init_kind { + InitKind::Normal => quote! {}, + InitKind::Zeroing => quote! { + // The user specified `..Zeroable::zeroed()` at the end of the list of fields. + // Therefore we check if the struct implements `Zeroable` and then zero the memory. + // This allows us to also remove the check that all fields are present (since we + // already set the memory to zero and that is a valid bit pattern). + fn assert_zeroable(_: *mut T) + where T: ::pin_init::Zeroable + {} + // Ensure that the struct is indeed `Zeroable`. + assert_zeroable(slot); + // SAFETY: The type implements `Zeroable` by the check above. + unsafe { ::core::ptr::write_bytes(slot, 0, 1) }; + }, + }; + + let this = match this { + None => quote!(), + Some(This { ident, .. }) => quote! { + // Create the `this` so it can be referenced by the user inside of the + // expressions creating the individual fields. + let #ident = unsafe { ::core::ptr::NonNull::new_unchecked(slot) }; + }, + }; + let data = format_ident!("data", span = Span::mixed_site()); + let init_fields = init_fields(&fields, use_data, &data); + let field_check = make_field_check(&fields, init_kind, &path); + Ok(quote! {{ + // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return + // type and shadow it later when we insert the arbitrary user code. That way there will be + // no possibility of returning without `unsafe`. + struct __InitOk; + // Get the data about fields from the supplied type. + let #data = unsafe { + use ::pin_init::__internal::#has_data_trait; + // Can't use `<#path as #has_data_trait>::#get_data`, since the user is able to omit + // generics (which need to be present with that syntax). + #path::#get_data() + }; + // Ensure that `#data` really is of type `#data` and help with type inference: + let init = ::pin_init::__internal::#data_trait::make_closure::<_, __InitOk, #error>( + #data, + move |slot| { + { + // Shadow the structure so it cannot be used to return early. + struct __InitOk; + + #zeroable_check + + #this + + #init_fields + + #field_check + } + Ok(__InitOk) + } + ); + let init = move |slot| -> ::core::result::Result<(), #error> { + init(slot).map(|__InitOk| ()) + }; + let init = unsafe { ::pin_init::#from_closure::<_, #error>(init) }; + init + }}) +} + +fn get_init_kind(rest: Option<(Token![..], Expr)>) -> Result { + let Some((dotdot, expr)) = rest else { + return Ok(InitKind::Normal); + }; + let error = Error::new_spanned( + quote!(#dotdot #expr), + "Expected one of the following:\n- Nothing.\n- `..Zeroable::zeroed()`.", + ); + let Expr::Call(ExprCall { + func, args, attrs, .. + }) = expr + else { + return Err(error); + }; + if !args.is_empty() || !attrs.is_empty() { + return Err(error); + } + match *func { + Expr::Path(ExprPath { + attrs, + qself: None, + path: + Path { + leading_colon: None, + segments, + }, + }) if attrs.is_empty() + && segments.len() == 2 + && segments[0].ident == "Zeroable" + && segments[0].arguments.is_none() + && segments[1].ident == "zeroed" + && segments[1].arguments.is_none() => + { + Ok(InitKind::Zeroing) + } + _ => Err(error), + } +} + +/// Generate the code that initializes the fields of the struct using the initializers in `field`. +fn init_fields( + fields: &Punctuated, + use_data: bool, + data: &Ident, +) -> TokenStream { + let mut guards = vec![]; + let mut res = TokenStream::new(); + for field in fields { + let ident = field.ident(); + let guard = format_ident!("__{ident}_guard", span = Span::mixed_site()); + guards.push(guard.clone()); + let init = match field { + FieldInitializer::Value { ident, value } => { + let mut value_ident = ident.clone(); + let value = value.as_ref().map(|value| &value.1).map(|value| { + // Setting the span of `value_ident` to `value`'s span improves error messages + // when the type of `value` is wrong. + value_ident.set_span(value.span()); + quote!(let #value_ident = #value;) + }); + // Again span for better diagnostics + let write = quote_spanned! {ident.span()=> + ::core::ptr::write + }; + quote! { + { + #value + // Initialize the field. + // + // SAFETY: The memory at `slot` is uninitialized. + unsafe { #write(::core::ptr::addr_of_mut!((*slot).#ident), #value_ident) }; + } + } + } + FieldInitializer::Init { ident, value, .. } => { + if use_data { + quote! { + let init = #value; + // Call the initializer. + // + // SAFETY: `slot` is valid, because we are inside of an initializer closure, + // we return when an error/panic occurs. + // We also use the `#data` to require the correct trait (`Init` or `PinInit`) + // for `#ident`. + unsafe { #data.#ident(::core::ptr::addr_of_mut!((*slot).#ident), init)? }; + } + } else { + quote! { + let init = #value; + // Call the initializer. + // + // SAFETY: `slot` is valid, because we are inside of an initializer closure, + // we return when an error/panic occurs. + unsafe { + ::pin_init::Init::__init( + init, + ::core::ptr::addr_of_mut!((*slot).#ident), + )? + }; + } + } + } + }; + res.extend(init); + res.extend(quote! { + // Create the drop guard: + // + // We rely on macro hygiene to make it impossible for users to access this local + // variable. + // SAFETY: We forget the guard later when initialization has succeeded. + let #guard = unsafe { + ::pin_init::__internal::DropGuard::new( + ::core::ptr::addr_of_mut!((*slot).#ident) + ) + }; + }); + } + quote! { + #res + // If execution reaches this point, all fields have been initialized. Therefore we can now + // dismiss the guards by forgetting them. + #(::core::mem::forget(#guards);)* + } +} + +/// Generate the check for ensuring that every field has been initialized. +fn make_field_check( + fields: &Punctuated, + init_kind: InitKind, + path: &Path, +) -> TokenStream { + let fields = fields.iter().map(|f| f.ident()); + match init_kind { + InitKind::Normal => quote! { + // We use unreachable code to ensure that all fields have been mentioned exactly once, + // this struct initializer will still be type-checked and complain with a very natural + // error message if a field is forgotten/mentioned more than once. + #[allow(unreachable_code, clippy::diverging_sub_expression)] + // SAFETY: this code is never executed. + let _ = || unsafe { + ::core::ptr::write(slot, #path { + #( + #fields: ::core::panic!(), + )* + }) + }; + }, + InitKind::Zeroing => quote! { + // We use unreachable code to ensure that all fields have been mentioned at most once. + // Since the user specified `..Zeroable::zeroed()` at the end, all missing fields will + // be zeroed. This struct initializer will still be type-checked and complain with a + // very natural error message if a field is mentioned more than once, or doesn't exist. + #[allow(unreachable_code, clippy::diverging_sub_expression, unused_assignments)] + // SAFETY: this code is never executed. + let _ = || unsafe { + let mut zeroed = ::core::mem::zeroed(); + ::core::ptr::write(slot, zeroed); + zeroed = ::core::mem::zeroed(); + ::core::ptr::write(slot, #path { + #( + #fields: ::core::panic!(), + )* + ..zeroed + }) + }; + }, + } +} + +impl Parse for InPlaceInitializer { + fn parse(input: ParseStream) -> Result { + let content; + Ok(Self { + this: input.peek(Token![&]).then(|| input.parse()).transpose()?, + path: input.parse()?, + brace_token: braced!(content in input), + fields: { + let mut fields = Punctuated::new(); + loop { + let lookahead = content.lookahead1(); + if content.is_empty() || lookahead.peek(Token![..]) { + break; + } else if lookahead.peek(syn::Ident) { + fields.push_value(content.parse()?); + let lookahead = content.lookahead1(); + if lookahead.peek(Token![,]) { + fields.push_punct(content.parse()?); + } else if content.is_empty() { + break; + } else { + return Err(lookahead.error()); + } + } else { + return Err(lookahead.error()); + } + } + fields + }, + rest: content + .peek(Token![..]) + .then(|| -> Result<_> { Ok((content.parse()?, content.parse()?)) }) + .transpose()?, + error: input + .peek(Token![?]) + .then(|| -> Result<_> { Ok((input.parse()?, input.parse()?)) }) + .transpose()?, + }) + } +} + +impl Parse for This { + fn parse(input: ParseStream) -> Result { + Ok(Self { + _and_token: input.parse()?, + ident: input.parse()?, + _in_token: input.parse()?, + }) + } +} + +impl Parse for FieldInitializer { + fn parse(input: ParseStream) -> Result { + let ident = input.parse()?; + let lookahead = input.lookahead1(); + Ok(if lookahead.peek(Token![<-]) { + Self::Init { + ident, + _larrow: input.parse()?, + value: input.parse()?, + } + } else if lookahead.peek(Token![:]) { + Self::Value { + ident, + value: Some((input.parse()?, input.parse()?)), + } + } else if lookahead.peek(Token![,]) || input.is_empty() { + Self::Value { ident, value: None } + } else { + return Err(lookahead.error()); + }) + } +} diff --git a/internal/src/lib.rs b/internal/src/lib.rs index 56aa9ecc..e4918405 100644 --- a/internal/src/lib.rs +++ b/internal/src/lib.rs @@ -24,13 +24,25 @@ use proc_macro::TokenStream; #[macro_use] #[cfg_attr(not(kernel), rustfmt::skip)] mod quote; -#[cfg(not(kernel))] -#[macro_use] -extern crate quote; - +#[cfg(kernel)] mod helpers; +#[cfg(kernel)] +mod pin_data; +#[cfg(kernel)] +mod pinned_drop; +#[cfg(kernel)] +mod zeroable; + +#[cfg(not(kernel))] +mod init; +#[cfg(not(kernel))] +#[path = "syn_pin_data.rs"] mod pin_data; +#[cfg(not(kernel))] +#[path = "syn_pinned_drop.rs"] mod pinned_drop; +#[cfg(not(kernel))] +#[path = "syn_zeroable.rs"] mod zeroable; #[proc_macro_attribute] @@ -47,3 +59,79 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { pub fn derive_zeroable(input: TokenStream) -> TokenStream { zeroable::derive(input.into()).into() } + +#[cfg(kernel)] +#[proc_macro] +pub fn pin_init(input: TokenStream) -> TokenStream { + quote!(::pin_init::__internal_pin_init!(#input)) +} + +#[cfg(not(kernel))] +#[proc_macro] +pub fn pin_init(input: TokenStream) -> TokenStream { + use syn::parse_macro_input; + init::init( + parse_macro_input!(input as init::InPlaceInitializer), + true, + true, + ) + .unwrap_or_else(|e| e.into_compile_error()) + .into() +} + +#[cfg(kernel)] +#[proc_macro] +pub fn init(input: TokenStream) -> TokenStream { + quote!(::pin_init::__internal_init!(#input)) +} + +#[cfg(not(kernel))] +#[proc_macro] +pub fn init(input: TokenStream) -> TokenStream { + use syn::parse_macro_input; + init::init( + parse_macro_input!(input as init::InPlaceInitializer), + true, + false, + ) + .unwrap_or_else(|e| e.into_compile_error()) + .into() +} + +#[cfg(kernel)] +#[proc_macro] +pub fn try_pin_init(input: TokenStream) -> TokenStream { + quote!(::pin_init::__internal_try_pin_init!(#input)) +} + +#[cfg(not(kernel))] +#[proc_macro] +pub fn try_pin_init(input: TokenStream) -> TokenStream { + use syn::parse_macro_input; + init::init( + parse_macro_input!(input as init::InPlaceInitializer), + false, + true, + ) + .unwrap_or_else(|e| e.into_compile_error()) + .into() +} + +#[cfg(kernel)] +#[proc_macro] +pub fn try_init(input: TokenStream) -> TokenStream { + quote!(::pin_init::__internal_try_init!(#input)) +} + +#[cfg(not(kernel))] +#[proc_macro] +pub fn try_init(input: TokenStream) -> TokenStream { + use syn::parse_macro_input; + init::init( + parse_macro_input!(input as init::InPlaceInitializer), + false, + false, + ) + .unwrap_or_else(|e| e.into_compile_error()) + .into() +} diff --git a/internal/src/syn_pin_data.rs b/internal/src/syn_pin_data.rs new file mode 100644 index 00000000..30cd4bc3 --- /dev/null +++ b/internal/src/syn_pin_data.rs @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use proc_macro2::TokenStream; +use quote::quote; +use syn::{ + parse_macro_input, parse_quote, + visit_mut::{visit_path_segment_mut, VisitMut}, + Error, Field, ItemStruct, PathSegment, Result, Type, TypePath, WhereClause, +}; + +pub(crate) fn pin_data( + inner: proc_macro::TokenStream, + item: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + do_impl(inner.into(), parse_macro_input!(item as ItemStruct)) + .unwrap_or_else(|e| e.into_compile_error()) + .into() +} + +fn do_impl(args: TokenStream, mut struct_: ItemStruct) -> Result { + // The generics might contain the `Self` type. Since this macro will define a new type with the + // same generics and bounds, this poses a problem: `Self` will refer to the new type as opposed + // to this struct definition. Therefore we have to replace `Self` with the concrete name. + let mut replacer = { + let name = &struct_.ident; + let (_, ty_generics, _) = struct_.generics.split_for_impl(); + SelfReplacer(parse_quote!(#name #ty_generics)) + }; + replacer.visit_generics_mut(&mut struct_.generics); + + let the_pin_data = generate_the_pin_data(&struct_); + let unpin_impl = unpin_impl(&struct_); + let drop_impl = drop_impl(&struct_, args)?; + + let mut errors = TokenStream::new(); + for field in &mut struct_.fields { + if !is_pinned(field) && is_phantom_pinned(&field.ty) { + let message = format!("The field `{}` of type `PhantomPinned` only has an effect, if it has the `#[pin]` attribute", field.ident.as_ref().unwrap() ); + errors.extend(quote!(::core::compile_error!(#message);)); + } + field.attrs.retain(|a| !a.path().is_ident("pin")); + } + Ok(quote! { + #struct_ + #errors + const _: () = { + #the_pin_data + #unpin_impl + #drop_impl + }; + }) +} + +struct SelfReplacer(PathSegment); + +impl VisitMut for SelfReplacer { + fn visit_path_segment_mut(&mut self, seg: &mut PathSegment) { + if seg.ident == "Self" { + *seg = self.0.clone(); + } else { + visit_path_segment_mut(self, seg); + } + } + + fn visit_item_mut(&mut self, _: &mut syn::Item) { + // Do not descend into items, since items reset/change what `Self` refers to. + } +} + +fn is_pinned(field: &Field) -> bool { + field.attrs.iter().any(|a| a.path().is_ident("pin")) +} + +fn is_phantom_pinned(ty: &Type) -> bool { + match ty { + Type::Path(TypePath { qself: None, path }) => { + // Cannot possibly refer to `PhantomPinned`. + if path.segments.len() > 3 { + return false; + } + // If there is a `::`, then the path needs to be `::core::marker::PhantomPinned` or + // `::std::marker::PhantomPinned`. + if path.leading_colon.is_some() && path.segments.len() != 3 { + return false; + } + let expected: Vec<&[&str]> = vec![&["PhantomPinned"], &["marker"], &["core", "std"]]; + for (actual, expected) in path.segments.iter().rev().zip(expected) { + if !actual.arguments.is_empty() || expected.iter().all(|e| actual.ident != e) { + return false; + } + } + true + } + _ => false, + } +} + +fn generate_the_pin_data( + ItemStruct { + vis, + ident, + generics, + fields, + .. + }: &ItemStruct, +) -> TokenStream { + let (impl_generics, ty_generics, whr) = generics.split_for_impl(); + + // For every field, we create a projection function according to its projection type. If a + // field is structurally pinned, then it must be initialized via `PinInit`, if it is not + // structurally pinned, then it must be initialized via `Init`. + let pinned_field_accessors = fields + .iter() + .filter(|f| is_pinned(f)) + .map(|Field { vis, ident, ty, .. }| { + quote! { + #vis unsafe fn #ident( + self, + slot: *mut #ty, + init: impl ::pin_init::PinInit<#ty, E>, + ) -> ::core::result::Result<(), E> { + unsafe { ::pin_init::PinInit::__pinned_init(init, slot) } + } + } + }) + .collect::(); + let not_pinned_field_accessors = fields + .iter() + .filter(|f| !is_pinned(f)) + .map(|Field { vis, ident, ty, .. }| { + quote! { + #vis unsafe fn #ident( + self, + slot: *mut #ty, + init: impl ::pin_init::Init<#ty, E>, + ) -> ::core::result::Result<(), E> { + unsafe { ::pin_init::Init::__init(init, slot) } + } + } + }) + .collect::(); + quote! { + // We declare this struct which will host all of the projection function for our type. It + // will be invariant over all generic parameters which are inherited from the struct. + #vis struct __ThePinData #generics + #whr + { + __phantom: ::core::marker::PhantomData< + fn(#ident #ty_generics) -> #ident #ty_generics + >, + } + + impl #impl_generics ::core::clone::Clone for __ThePinData #ty_generics + #whr + { + fn clone(&self) -> Self { *self } + } + + impl #impl_generics ::core::marker::Copy for __ThePinData #ty_generics + #whr + {} + + #[allow(dead_code)] // Some functions might never be used and private. + #[expect(clippy::missing_safety_doc)] + impl #impl_generics __ThePinData #ty_generics + #whr + { + #pinned_field_accessors + #not_pinned_field_accessors + } + + // SAFETY: We have added the correct projection functions above to `__ThePinData` and + // we also use the least restrictive generics possible. + unsafe impl #impl_generics + ::pin_init::__internal::HasPinData for #ident #ty_generics + #whr + { + type PinData = __ThePinData #ty_generics; + + unsafe fn __pin_data() -> Self::PinData { + __ThePinData { __phantom: ::core::marker::PhantomData } + } + } + + unsafe impl #impl_generics + ::pin_init::__internal::PinData for __ThePinData #ty_generics + #whr + { + type Datee = #ident #ty_generics; + } + } +} + +fn unpin_impl( + ItemStruct { + ident, + generics, + fields, + .. + }: &ItemStruct, +) -> TokenStream { + let generics_with_pinlt = { + let mut g = generics.clone(); + g.params.insert(0, parse_quote!('__pin)); + let _ = g.make_where_clause(); + g + }; + let ( + impl_generics_with_pinlt, + ty_generics_with_pinlt, + Some(WhereClause { + where_token, + predicates, + }), + ) = generics_with_pinlt.split_for_impl() + else { + unreachable!() + }; + let (_, ty_generics, _) = generics.split_for_impl(); + let mut pinned_fields = fields + .iter() + .filter(|f| is_pinned(f)) + .cloned() + .collect::>(); + for field in &mut pinned_fields { + field.attrs.retain(|a| !a.path().is_ident("pin")); + } + quote! { + // This struct will be used for the unpin analysis. It is needed, because only structurally + // pinned fields are relevant whether the struct should implement `Unpin`. + #[allow(dead_code)] // The fields below are never used. + struct __Unpin #generics_with_pinlt + #where_token + #predicates + { + __phantom_pin: ::core::marker::PhantomData &'__pin ()>, + __phantom: ::core::marker::PhantomData< + fn(#ident #ty_generics) -> #ident #ty_generics + >, + #(#pinned_fields),* + } + + #[doc(hidden)] + impl #impl_generics_with_pinlt ::core::marker::Unpin for #ident #ty_generics + #where_token + __Unpin #ty_generics_with_pinlt: ::core::marker::Unpin, + #predicates + {} + } +} + +fn drop_impl( + ItemStruct { + ident, generics, .. + }: &ItemStruct, + args: TokenStream, +) -> Result { + let (impl_generics, ty_generics, whr) = generics.split_for_impl(); + let has_pinned_drop = match syn::parse2::>(args.clone()) { + Ok(None) => false, + Ok(Some(ident)) if ident == "PinnedDrop" => true, + _ => { + return Err(Error::new_spanned( + args, + "Expected nothing or `PinnedDrop` as arguments to `#[pin_data]`.", + )) + } + }; + // We need to disallow normal `Drop` implementation, the exact behavior depends on whether + // `PinnedDrop` was specified in `args`. + Ok(if has_pinned_drop { + // When `PinnedDrop` was specified we just implement `Drop` and delegate. + quote! { + impl #impl_generics ::core::ops::Drop for #ident #ty_generics + #whr + { + fn drop(&mut self) { + // SAFETY: Since this is a destructor, `self` will not move after this function + // terminates, since it is inaccessible. + let pinned = unsafe { ::core::pin::Pin::new_unchecked(self) }; + // SAFETY: Since this is a drop function, we can create this token to call the + // pinned destructor of this type. + let token = unsafe { ::pin_init::__internal::OnlyCallFromDrop::new() }; + ::pin_init::PinnedDrop::drop(pinned, token); + } + } + } + } else { + // When no `PinnedDrop` was specified, then we have to prevent implementing drop. + quote! { + // We prevent this by creating a trait that will be implemented for all types implementing + // `Drop`. Additionally we will implement this trait for the struct leading to a conflict, + // if it also implements `Drop` + trait MustNotImplDrop {} + #[expect(drop_bounds)] + impl MustNotImplDrop for T {} + impl #impl_generics MustNotImplDrop for #ident #ty_generics + #whr + {} + // We also take care to prevent users from writing a useless `PinnedDrop` implementation. + // They might implement `PinnedDrop` correctly for the struct, but forget to give + // `PinnedDrop` as the parameter to `#[pin_data]`. + #[expect(non_camel_case_types)] + trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} + impl + UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} + impl #impl_generics + UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for #ident #ty_generics + #whr + {} + } + }) +} diff --git a/internal/src/syn_pinned_drop.rs b/internal/src/syn_pinned_drop.rs new file mode 100644 index 00000000..1e70ee29 --- /dev/null +++ b/internal/src/syn_pinned_drop.rs @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use proc_macro2::TokenStream; +use quote::quote; +use syn::{ + parse_macro_input, parse_quote, spanned::Spanned, Error, ImplItem, ImplItemFn, ItemImpl, + Result, Token, +}; + +pub(crate) fn pinned_drop( + args: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + parse_macro_input!(args as syn::parse::Nothing); + do_impl(parse_macro_input!(input as ItemImpl)) + .unwrap_or_else(|e| e.into_compile_error()) + .into() +} + +fn do_impl(mut input: ItemImpl) -> Result { + let Some((_, path, _)) = &mut input.trait_ else { + return Err(Error::new_spanned( + input, + "expected an `impl` block implementing `PinnedDrop`", + )); + }; + if !is_pinned_drop(path) { + return Err(Error::new_spanned( + input, + "expected an `impl` block implementing `PinnedDrop`", + )); + } + let mut error = None; + if let Some(unsafety) = input.unsafety.take() { + error = Some( + Error::new_spanned( + unsafety, + "implementing the trait `PinnedDrop` via `#[pinned_drop]` is not unsafe", + ) + .into_compile_error(), + ); + } + input.unsafety = Some(Token![unsafe](input.impl_token.span())); + if path.segments.len() != 2 { + path.segments.insert(0, parse_quote!(pin_init)); + } + path.leading_colon.get_or_insert(Token![::](path.span())); + for item in &mut input.items { + match item { + ImplItem::Fn(ImplItemFn { sig, .. }) if sig.ident == "drop" => { + sig.inputs + .push(parse_quote!(_: ::pin_init::__internal::OnlyCallFromDrop)); + } + _ => {} + } + } + Ok(quote! { + #error + #input + }) +} + +fn is_pinned_drop(path: &syn::Path) -> bool { + if path.segments.len() > 2 { + return false; + } + // If there is a `::`, then the path needs to be `::pin_init::PinnedDrop`. + if path.leading_colon.is_some() && path.segments.len() != 2 { + return false; + } + for (actual, expected) in path.segments.iter().rev().zip(["PinnedDrop", "pin_init"]) { + if actual.ident != expected { + return false; + } + } + true +} diff --git a/internal/src/syn_zeroable.rs b/internal/src/syn_zeroable.rs new file mode 100644 index 00000000..90ea8fa6 --- /dev/null +++ b/internal/src/syn_zeroable.rs @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use proc_macro2::TokenStream; +use quote::quote; +use syn::{ + parse_macro_input, parse_quote, Data, DataStruct, DeriveInput, Error, GenericParam, Result, + TypeParam, WherePredicate, +}; + +pub(crate) fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let raw = input.clone().into(); + do_derive(parse_macro_input!(input as DeriveInput), raw) + .unwrap_or_else(|e| e.into_compile_error()) + .into() +} + +fn do_derive( + DeriveInput { + ident, + mut generics, + data, + .. + }: DeriveInput, + raw_input: TokenStream, +) -> Result { + let Data::Struct(DataStruct { fields, .. }) = data else { + return Err(Error::new_spanned( + raw_input, + "`Zeroable` can only be derived for structs.", + )); + }; + let field_ty = fields.iter().map(|f| &f.ty); + let zeroable_bounds = generics + .params + .iter() + .filter_map(|p| match p { + GenericParam::Type(TypeParam { ident, .. }) => { + Some(parse_quote!(#ident: ::pin_init::Zeroable)) + } + _ => None, + }) + .collect::>(); + generics + .make_where_clause() + .predicates + .extend(zeroable_bounds); + let (impl_generics, ty_generics, whr) = generics.split_for_impl(); + Ok(quote! { + // SAFETY: Every field type implements `Zeroable` and padding bytes may be zero. + #[automatically_derived] + unsafe impl #impl_generics ::pin_init::Zeroable for #ident #ty_generics + #whr + {} + const _: () = { + fn assert_zeroable() {} + fn ensure_zeroable #impl_generics () + #whr + { + #(assert_zeroable::<#field_ty>();)* + } + }; + }) +} diff --git a/src/__internal.rs b/src/__internal.rs index 557b5948..76989e82 100644 --- a/src/__internal.rs +++ b/src/__internal.rs @@ -290,3 +290,65 @@ unsafe impl PinInit for AlwaysFail { Err(()) } } + +#[cfg(kernel)] +#[macro_export] +macro_rules! __internal_init { + ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { + $($fields:tt)* + }) => { + $crate::try_init!($(&$this in)? $t $(::<$($generics),*>)? { + $($fields)* + }? ::core::convert::Infallible) + }; +} + +#[cfg(kernel)] +#[macro_export] +macro_rules! __internal_pin_init { + ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { + $($fields:tt)* + }) => { + $crate::try_pin_init!($(&$this in)? $t $(::<$($generics),*>)? { + $($fields)* + }? ::core::convert::Infallible) + }; +} + +#[cfg(kernel)] +#[macro_export] +macro_rules! __internal_try_init { + ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { + $($fields:tt)* + }? $err:ty) => { + $crate::__init_internal!( + @this($($this)?), + @typ($t $(::<$($generics),*>)?), + @fields($($fields)*), + @error($err), + @data(InitData, /*no use_data*/), + @has_data(HasInitData, __init_data), + @construct_closure(init_from_closure), + @munch_fields($($fields)*), + ) + }; +} + +#[cfg(kernel)] +#[macro_export] +macro_rules! __internal_try_pin_init { + ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { + $($fields:tt)* + }? $err:ty) => { + $crate::__init_internal!( + @this($($this)?), + @typ($t $(::<$($generics),*>)? ), + @fields($($fields)*), + @error($err), + @data(PinData, use_data), + @has_data(HasPinData, __pin_data), + @construct_closure(pin_init_from_closure), + @munch_fields($($fields)*), + ) + }; +} diff --git a/src/lib.rs b/src/lib.rs index 0806c689..78d4f4dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -290,6 +290,9 @@ mod alloc; #[cfg(any(feature = "std", feature = "alloc"))] pub use alloc::InPlaceInit; +#[allow(unused_extern_crates)] +extern crate self as pin_init; + /// Used to specify the pinning information of the fields of a struct. /// /// This is somewhat similar in purpose as @@ -722,18 +725,7 @@ macro_rules! stack_try_pin_init { /// ``` /// /// [`NonNull`]: core::ptr::NonNull -// For a detailed example of how this macro works, see the module documentation of the hidden -// module `macros` inside of `macros.rs`. -#[macro_export] -macro_rules! pin_init { - ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { - $($fields:tt)* - }) => { - $crate::try_pin_init!($(&$this in)? $t $(::<$($generics),*>)? { - $($fields)* - }? ::core::convert::Infallible) - }; -} +pub use pin_init_internal::pin_init; /// Construct an in-place, fallible pinned initializer for `struct`s. /// @@ -773,25 +765,7 @@ macro_rules! pin_init { /// } /// # let _ = Box::pin_init(BigBuf::new()); /// ``` -// For a detailed example of how this macro works, see the module documentation of the hidden -// module `macros` inside of `macros.rs`. -#[macro_export] -macro_rules! try_pin_init { - ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { - $($fields:tt)* - }? $err:ty) => { - $crate::__init_internal!( - @this($($this)?), - @typ($t $(::<$($generics),*>)? ), - @fields($($fields)*), - @error($err), - @data(PinData, use_data), - @has_data(HasPinData, __pin_data), - @construct_closure(pin_init_from_closure), - @munch_fields($($fields)*), - ) - } -} +pub use pin_init_internal::try_pin_init; /// Construct an in-place initializer for `struct`s. /// @@ -829,18 +803,7 @@ macro_rules! try_pin_init { /// } /// # let _ = Box::init(BigBuf::new()); /// ``` -// For a detailed example of how this macro works, see the module documentation of the hidden -// module `macros` inside of `macros.rs`. -#[macro_export] -macro_rules! init { - ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { - $($fields:tt)* - }) => { - $crate::try_init!($(&$this in)? $t $(::<$($generics),*>)? { - $($fields)* - }? ::core::convert::Infallible) - } -} +pub use pin_init_internal::init; /// Construct an in-place fallible initializer for `struct`s. /// @@ -878,25 +841,7 @@ macro_rules! init { /// } /// # let _ = Box::init(BigBuf::new()); /// ``` -// For a detailed example of how this macro works, see the module documentation of the hidden -// module `macros` inside of `macros.rs`. -#[macro_export] -macro_rules! try_init { - ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { - $($fields:tt)* - }? $err:ty) => { - $crate::__init_internal!( - @this($($this)?), - @typ($t $(::<$($generics),*>)?), - @fields($($fields)*), - @error($err), - @data(InitData, /*no use_data*/), - @has_data(HasInitData, __init_data), - @construct_closure(init_from_closure), - @munch_fields($($fields)*), - ) - } -} +pub use pin_init_internal::try_init; /// Asserts that a field on a struct using `#[pin_data]` is marked with `#[pin]` ie. that it is /// structurally pinned. diff --git a/src/macros.rs b/src/macros.rs index 36162332..03e25884 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -931,7 +931,7 @@ macro_rules! __pin_data { // if it also implements `Drop` trait MustNotImplDrop {} #[expect(drop_bounds)] - impl MustNotImplDrop for T {} + impl MustNotImplDrop for T {} impl<$($impl_generics)*> MustNotImplDrop for $name<$($ty_generics)*> where $($whr)* {} // We also take care to prevent users from writing a useless `PinnedDrop` implementation. @@ -939,7 +939,7 @@ macro_rules! __pin_data { // `PinnedDrop` as the parameter to `#[pin_data]`. #[expect(non_camel_case_types)] trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} - impl + impl UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} impl<$($impl_generics)*> UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for $name<$($ty_generics)*> diff --git a/tests/many_generics.rs b/tests/many_generics.rs index 2cad6421..9fdc3eb0 100644 --- a/tests/many_generics.rs +++ b/tests/many_generics.rs @@ -12,7 +12,7 @@ struct Foo<'a, 'b: 'a, T: Bar<'b> + ?Sized + 'a, const SIZE: usize = 0> where T: Bar<'a, 1>, { - array: [u8; 1024 * 1024], + _array: [u8; 1024 * 1024], r: &'b mut [&'a mut T; SIZE], #[pin] _pin: PhantomPinned, diff --git a/tests/ui/compile-fail/init/colon_instead_of_arrow.stderr b/tests/ui/compile-fail/init/colon_instead_of_arrow.stderr index f7be4a2f..f5d9ee7b 100644 --- a/tests/ui/compile-fail/init/colon_instead_of_arrow.stderr +++ b/tests/ui/compile-fail/init/colon_instead_of_arrow.stderr @@ -1,14 +1,13 @@ error[E0308]: mismatched types - --> tests/ui/compile-fail/init/colon_instead_of_arrow.rs:21:9 + --> tests/ui/compile-fail/init/colon_instead_of_arrow.rs:21:31 | 14 | fn new() -> impl PinInit { | ------------------ the found opaque type ... 21 | pin_init!(Self { bar: Bar::new() }) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected `Bar`, found opaque type - | arguments to this function are incorrect + | --- ^^^^^^^^^^ expected `Bar`, found opaque type + | | + | arguments to this function are incorrect | = note: expected struct `Bar` found opaque type `impl pin_init::PinInit` @@ -17,4 +16,3 @@ note: function defined here | | pub const unsafe fn write(dst: *mut T, src: T) { | ^^^^^ - = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `pin_init` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/init/field_value_wrong_type.stderr b/tests/ui/compile-fail/init/field_value_wrong_type.stderr index 5b91b5c7..f6470767 100644 --- a/tests/ui/compile-fail/init/field_value_wrong_type.stderr +++ b/tests/ui/compile-fail/init/field_value_wrong_type.stderr @@ -1,15 +1,13 @@ error[E0308]: mismatched types - --> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:13 + --> tests/ui/compile-fail/init/field_value_wrong_type.rs:8:28 | 8 | let _ = init!(Foo { a: () }); - | ^^^^^^^^^^^^^^^^^^^^ - | | - | expected `usize`, found `()` - | arguments to this function are incorrect + | - ^^ expected `usize`, found `()` + | | + | arguments to this function are incorrect | note: function defined here --> $RUST/core/src/ptr/mod.rs | | pub const unsafe fn write(dst: *mut T, src: T) { | ^^^^^ - = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/init/invalid_init.stderr b/tests/ui/compile-fail/init/invalid_init.stderr index 7731bc31..f8581d49 100644 --- a/tests/ui/compile-fail/init/invalid_init.stderr +++ b/tests/ui/compile-fail/init/invalid_init.stderr @@ -5,10 +5,7 @@ error[E0277]: the trait bound `impl pin_init::PinInit: Init` is not sa | _____________^ 19 | | bar <- Bar::new(), 20 | | }); - | | ^ - | | | - | |______the trait `Init` is not implemented for `impl pin_init::PinInit` - | required by a bound introduced by this call + | |______^ the trait `Init` is not implemented for `impl pin_init::PinInit` | = help: the trait `Init` is implemented for `ChainInit` - = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/init/missing_comma.stderr b/tests/ui/compile-fail/init/missing_comma.stderr index 9e4c25db..6681634f 100644 --- a/tests/ui/compile-fail/init/missing_comma.stderr +++ b/tests/ui/compile-fail/init/missing_comma.stderr @@ -1,23 +1,5 @@ -error: no rules expected `c` +error: expected `,` --> tests/ui/compile-fail/init/missing_comma.rs:16:9 | 16 | c: Bar, - | ^ no rules expected this token in macro call - | -note: while trying to match `,` - --> src/macros.rs - | - | @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - | ^ - -error: no rules expected `c` - --> tests/ui/compile-fail/init/missing_comma.rs:16:9 - | -16 | c: Bar, - | ^ no rules expected this token in macro call - | -note: while trying to match `,` - --> src/macros.rs - | - | @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - | ^ + | ^ diff --git a/tests/ui/compile-fail/init/missing_comma_with_zeroable.stderr b/tests/ui/compile-fail/init/missing_comma_with_zeroable.stderr index 4ffb89c6..53cf5b85 100644 --- a/tests/ui/compile-fail/init/missing_comma_with_zeroable.stderr +++ b/tests/ui/compile-fail/init/missing_comma_with_zeroable.stderr @@ -10,16 +10,12 @@ help: you can add the `dyn` keyword if you want a trait object | ++++ + error[E0308]: mismatched types - --> tests/ui/compile-fail/init/missing_comma_with_zeroable.rs:11:13 + --> tests/ui/compile-fail/init/missing_comma_with_zeroable.rs:12:12 | -11 | let _ = init!(Foo { - | _____________^ -12 | | a: 0..Zeroable::zeroed() -13 | | }); - | | ^ - | | | - | |______expected `usize`, found `Range<{integer}>` - | arguments to this function are incorrect +12 | a: 0..Zeroable::zeroed() + | - ^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `Range<{integer}>` + | | + | arguments to this function are incorrect | = note: expected type `usize` found struct `std::ops::Range<{integer}>` @@ -28,7 +24,6 @@ note: function defined here | | pub const unsafe fn write(dst: *mut T, src: T) { | ^^^^^ - = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0063]: missing field `b` in initializer of `Foo` --> tests/ui/compile-fail/init/missing_comma_with_zeroable.rs:11:19 diff --git a/tests/ui/compile-fail/init/missing_error_type.stderr b/tests/ui/compile-fail/init/missing_error_type.stderr index 8f9f3ef3..5669cc4b 100644 --- a/tests/ui/compile-fail/init/missing_error_type.stderr +++ b/tests/ui/compile-fail/init/missing_error_type.stderr @@ -1,11 +1,7 @@ -error: unexpected end of macro invocation - --> tests/ui/compile-fail/init/missing_error_type.rs:8:47 +error: unexpected end of input, expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, `dyn`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime + --> tests/ui/compile-fail/init/missing_error_type.rs:8:13 | 8 | let _ = try_init!(Foo { x: Box::new(0)? }?); - | ^ missing tokens in macro arguments + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: while trying to match meta-variable `$err:ty` - --> src/lib.rs - | - | }? $err:ty) => { - | ^^^^^^^ + = note: this error originates in the macro `try_init` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/init/missing_pin_data.stderr b/tests/ui/compile-fail/init/missing_pin_data.stderr index e9806dd5..58f0013e 100644 --- a/tests/ui/compile-fail/init/missing_pin_data.stderr +++ b/tests/ui/compile-fail/init/missing_pin_data.stderr @@ -10,10 +10,9 @@ error[E0599]: no associated item named `__pin_data` found for struct `Foo` in th = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `__pin_data`, perhaps you need to implement it: candidate #1: `HasPinData` - = note: this error originates in the macro `$crate::try_pin_init` which comes from the expansion of the macro `pin_init` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `pin_init` (in Nightly builds, run with -Z macro-backtrace for more info) help: there is an associated function `__init_data` with a similar name - --> src/lib.rs | - - @has_data(HasPinData, __pin_data), - + @has_data(HasPinData, __init_data), +9 - pin_init!(Self { a: 42 }) +9 + __init_data | diff --git a/tests/ui/compile-fail/init/no_error_coercion.stderr b/tests/ui/compile-fail/init/no_error_coercion.stderr index dae2783e..275e2cb4 100644 --- a/tests/ui/compile-fail/init/no_error_coercion.stderr +++ b/tests/ui/compile-fail/init/no_error_coercion.stderr @@ -1,5 +1,5 @@ error[E0277]: `?` couldn't convert the error to `std::alloc::AllocError` - --> tests/ui/compile-fail/init/no_error_coercion.rs:16:9 + --> tests/ui/compile-fail/init/no_error_coercion.rs:19:22 | 16 | / try_init!(Self { 17 | | a: Box::new(42), @@ -7,8 +7,8 @@ error[E0277]: `?` couldn't convert the error to `std::alloc::AllocError` 19 | | }? AllocError) | | ^ | | | - | |______________________this can't be annotated with `?` because it has type `Result<_, Infallible>` - | the trait `From` is not implemented for `std::alloc::AllocError` + | |______________________the trait `From` is not implemented for `std::alloc::AllocError` + | this can't be annotated with `?` because it has type `Result<_, Infallible>` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `try_init` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `try_init` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/init/wrong_generics.stderr b/tests/ui/compile-fail/init/wrong_generics.stderr index cb1b1ef5..03960aa1 100644 --- a/tests/ui/compile-fail/init/wrong_generics.stderr +++ b/tests/ui/compile-fail/init/wrong_generics.stderr @@ -1,11 +1,19 @@ -error: no rules expected `<` +error: comparison operators cannot be chained --> tests/ui/compile-fail/init/wrong_generics.rs:7:22 | 7 | let _ = init!(Foo<()> { - | ^ no rules expected this token in macro call + | ^ ^ | -note: while trying to match `{` - --> src/lib.rs +help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments | - | ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { - | ^ +7 | let _ = init!(Foo::<()> { + | ++ + +error: comparison operators cannot be chained + --> tests/ui/compile-fail/init/wrong_generics.rs:7:22 + | +7 | let _ = init!(Foo<()> { + | ^ ^ + | + = help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments + = help: or use `(...)` if you meant to specify fn arguments diff --git a/tests/ui/compile-fail/init/wrong_generics2.stderr b/tests/ui/compile-fail/init/wrong_generics2.stderr index d1b1e7a2..66edc9c3 100644 --- a/tests/ui/compile-fail/init/wrong_generics2.stderr +++ b/tests/ui/compile-fail/init/wrong_generics2.stderr @@ -1,51 +1,3 @@ -error: struct literal body without path - --> tests/ui/compile-fail/init/wrong_generics2.rs:7:13 - | -7 | let _ = init!(Foo::<(), ()> { - | _____________^ -8 | | value <- (), -9 | | }); - | |______^ - | - = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) -help: you might have forgotten to add the struct literal inside the block - --> src/macros.rs - | - ~ ::core::ptr::write($slot, $t { SomeStruct { - |9 $($acc)* - ~ } }); - | - -error: expected one of `)`, `,`, `.`, `?`, or an operator, found `{` - --> tests/ui/compile-fail/init/wrong_generics2.rs:7:13 - | -7 | let _ = init!(Foo::<(), ()> { - | _____________^ -8 | | value <- (), -9 | | }); - | | ^ - | | | - | |______expected one of `)`, `,`, `.`, `?`, or an operator - | help: missing `,` - | - = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0423]: expected value, found struct `Foo` - --> tests/ui/compile-fail/init/wrong_generics2.rs:7:13 - | -3 | / struct Foo { -4 | | value: T, -5 | | } - | |_- `Foo` defined here -6 | fn main() { -7 | let _ = init!(Foo::<(), ()> { - | _____________^ -8 | | value <- (), -9 | | }); - | |______^ help: use struct literal syntax instead: `Foo { value: val }` - | - = note: this error originates in the macro `$crate::try_init` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied --> tests/ui/compile-fail/init/wrong_generics2.rs:7:19 | @@ -59,19 +11,3 @@ note: struct defined here, with 1 generic parameter: `T` | 3 | struct Foo { | ^^^ - - -error[E0061]: this function takes 2 arguments but 3 arguments were supplied - --> tests/ui/compile-fail/init/wrong_generics2.rs:7:13 - | -7 | let _ = init!(Foo::<(), ()> { - | _____________^ -8 | | value <- (), -9 | | }); - | |______^ unexpected argument #3 - | -note: function defined here - --> $RUST/core/src/ptr/mod.rs - | - | pub const unsafe fn write(dst: *mut T, src: T) { - | ^^^^^ - = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/pin_data/missing_comma.rs b/tests/ui/compile-fail/pin_data/missing_comma.rs index b7d11f54..9b068dd7 100644 --- a/tests/ui/compile-fail/pin_data/missing_comma.rs +++ b/tests/ui/compile-fail/pin_data/missing_comma.rs @@ -5,3 +5,5 @@ struct Foo { a: Box b: Box } + +fn main() {} diff --git a/tests/ui/compile-fail/pin_data/missing_comma.stderr b/tests/ui/compile-fail/pin_data/missing_comma.stderr index 5e296742..49a749ed 100644 --- a/tests/ui/compile-fail/pin_data/missing_comma.stderr +++ b/tests/ui/compile-fail/pin_data/missing_comma.stderr @@ -4,11 +4,8 @@ error: expected `,`, or `}`, found `b` 5 | a: Box | ^ help: try adding a comma: `,` -error: recursion limit reached while expanding `$crate::__pin_data!` - --> tests/ui/compile-fail/pin_data/missing_comma.rs:3:1 +error: expected `,` + --> tests/ui/compile-fail/pin_data/missing_comma.rs:6:5 | -3 | #[pin_data] - | ^^^^^^^^^^^ - | - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`$CRATE`) - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) +6 | b: Box + | ^ diff --git a/tests/ui/compile-fail/pin_data/missing_pin.stderr b/tests/ui/compile-fail/pin_data/missing_pin.stderr index 5d98a04c..cc146200 100644 --- a/tests/ui/compile-fail/pin_data/missing_pin.stderr +++ b/tests/ui/compile-fail/pin_data/missing_pin.stderr @@ -18,4 +18,4 @@ note: required by a bound in `__ThePinData::a` 5 | struct Foo { 6 | a: usize, | - required by a bound in this associated function - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/pin_data/no_pin_on_phantompinned.stderr b/tests/ui/compile-fail/pin_data/no_pin_on_phantompinned.stderr index a99db630..3a9496dc 100644 --- a/tests/ui/compile-fail/pin_data/no_pin_on_phantompinned.stderr +++ b/tests/ui/compile-fail/pin_data/no_pin_on_phantompinned.stderr @@ -1,39 +1,31 @@ -error: The field `pin1` of type `PhantomPinned` only has an effect, if it has the `#[pin]` attribute. +error: The field `pin1` of type `PhantomPinned` only has an effect, if it has the `#[pin]` attribute --> tests/ui/compile-fail/pin_data/no_pin_on_phantompinned.rs:4:1 | 4 | #[pin_data] | ^^^^^^^^^^^ | - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) -error: The field `pin2` of type `PhantomPinned` only has an effect, if it has the `#[pin]` attribute. +error: The field `pin2` of type `PhantomPinned` only has an effect, if it has the `#[pin]` attribute --> tests/ui/compile-fail/pin_data/no_pin_on_phantompinned.rs:4:1 | 4 | #[pin_data] | ^^^^^^^^^^^ | - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) -error: The field `pin3` of type `PhantomPinned` only has an effect, if it has the `#[pin]` attribute. +error: The field `pin3` of type `PhantomPinned` only has an effect, if it has the `#[pin]` attribute --> tests/ui/compile-fail/pin_data/no_pin_on_phantompinned.rs:4:1 | 4 | #[pin_data] | ^^^^^^^^^^^ | - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) -error: The field `pin4` of type `PhantomPinned` only has an effect, if it has the `#[pin]` attribute. +error: The field `pin4` of type `PhantomPinned` only has an effect, if it has the `#[pin]` attribute --> tests/ui/compile-fail/pin_data/no_pin_on_phantompinned.rs:4:1 | 4 | #[pin_data] | ^^^^^^^^^^^ | - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) - -warning: unused imports: `PhantomPinned` and `self` - --> tests/ui/compile-fail/pin_data/no_pin_on_phantompinned.rs:2:19 - | -2 | use std::marker::{self, PhantomPinned}; - | ^^^^ ^^^^^^^^^^^^^ - | - = note: `#[warn(unused_imports)]` on by default + = note: this error originates in the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/pin_data/pin_data_but_drop.stderr b/tests/ui/compile-fail/pin_data/pin_data_but_drop.stderr index 6143d9af..b46a30a1 100644 --- a/tests/ui/compile-fail/pin_data/pin_data_but_drop.stderr +++ b/tests/ui/compile-fail/pin_data/pin_data_but_drop.stderr @@ -7,4 +7,4 @@ error[E0119]: conflicting implementations of trait `MustNotImplDrop` for type `F | first implementation here | conflicting implementation for `Foo` | - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/pin_data/twice.stderr b/tests/ui/compile-fail/pin_data/twice.stderr index 2a89d952..d2a5d75d 100644 --- a/tests/ui/compile-fail/pin_data/twice.stderr +++ b/tests/ui/compile-fail/pin_data/twice.stderr @@ -1,21 +1,19 @@ error[E0119]: conflicting implementations of trait `HasPinData` for type `Foo` - --> tests/ui/compile-fail/pin_data/twice.rs:3:1 + --> tests/ui/compile-fail/pin_data/twice.rs:4:1 | 3 | #[pin_data] - | ^^^^^^^^^^^ - | | - | first implementation here - | conflicting implementation for `Foo` + | ----------- first implementation here +4 | #[pin_data] + | ^^^^^^^^^^^ conflicting implementation for `Foo` | - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0119]: conflicting implementations of trait `Unpin` for type `Foo` - --> tests/ui/compile-fail/pin_data/twice.rs:3:1 + --> tests/ui/compile-fail/pin_data/twice.rs:4:1 | 3 | #[pin_data] - | ^^^^^^^^^^^ - | | - | first implementation here - | conflicting implementation for `Foo` + | ----------- first implementation here +4 | #[pin_data] + | ^^^^^^^^^^^ conflicting implementation for `Foo` | - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/pin_data/unexpected_args.stderr b/tests/ui/compile-fail/pin_data/unexpected_args.stderr index 4744fc12..67cf5bcf 100644 --- a/tests/ui/compile-fail/pin_data/unexpected_args.stderr +++ b/tests/ui/compile-fail/pin_data/unexpected_args.stderr @@ -1,15 +1,5 @@ -error: compile_error! takes 1 argument - --> tests/ui/compile-fail/pin_data/unexpected_args.rs:3:1 +error: Expected nothing or `PinnedDrop` as arguments to `#[pin_data]`. + --> tests/ui/compile-fail/pin_data/unexpected_args.rs:3:12 | 3 | #[pin_data(Bar)] - | ^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: Wrong parameters to `#[pin_data]`, expected nothing or `PinnedDrop`, got '{}'. - --> tests/ui/compile-fail/pin_data/unexpected_args.rs:3:1 - | -3 | #[pin_data(Bar)] - | ^^^^^^^^^^^^^^^^ - | - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^^ diff --git a/tests/ui/compile-fail/pin_data/unexpected_item.stderr b/tests/ui/compile-fail/pin_data/unexpected_item.stderr index 1772f228..70a35e15 100644 --- a/tests/ui/compile-fail/pin_data/unexpected_item.stderr +++ b/tests/ui/compile-fail/pin_data/unexpected_item.stderr @@ -1,19 +1,5 @@ -error: no rules expected keyword `fn` +error: expected `struct` --> tests/ui/compile-fail/pin_data/unexpected_item.rs:4:1 | 4 | fn foo() {} - | ^^ no rules expected this token in macro call - | -note: while trying to match keyword `struct` - --> src/macros.rs - | - | $vis:vis struct $name:ident - | ^^^^^^ - -error: Could not locate type name. - --> tests/ui/compile-fail/pin_data/unexpected_item.rs:3:1 - | -3 | #[pin_data] - | ^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^^ diff --git a/tests/ui/compile-fail/pinned_drop/no_fn.stderr b/tests/ui/compile-fail/pinned_drop/no_fn.stderr index f2520adf..f82b3006 100644 --- a/tests/ui/compile-fail/pinned_drop/no_fn.stderr +++ b/tests/ui/compile-fail/pinned_drop/no_fn.stderr @@ -1,23 +1,7 @@ -error: no rules expected `)` - --> tests/ui/compile-fail/pinned_drop/no_fn.rs:6:1 +error[E0046]: not all trait items implemented, missing: `drop` + --> tests/ui/compile-fail/pinned_drop/no_fn.rs:7:1 | -6 | #[pinned_drop] - | ^^^^^^^^^^^^^^ no rules expected this token in macro call +7 | impl PinnedDrop for Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation | -note: while trying to match keyword `fn` - --> src/macros.rs - | - | fn drop($($sig:tt)*) { - | ^^ - = note: this error originates in the attribute macro `pinned_drop` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0277]: the trait bound `Foo: PinnedDrop` is not satisfied - --> tests/ui/compile-fail/pinned_drop/no_fn.rs:3:1 - | -3 | #[pin_data(PinnedDrop)] - | ^^^^^^^^^^^^^^^^^^^^^^^ - | | - | the trait `PinnedDrop` is not implemented for `Foo` - | required by a bound introduced by this call - | - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: implement the missing item: `fn drop(self: Pin<&mut Self>, _: OnlyCallFromDrop) { todo!() }` diff --git a/tests/ui/compile-fail/pinned_drop/unexpected_additional_item.stderr b/tests/ui/compile-fail/pinned_drop/unexpected_additional_item.stderr index 5a1ad504..2e4d4aec 100644 --- a/tests/ui/compile-fail/pinned_drop/unexpected_additional_item.stderr +++ b/tests/ui/compile-fail/pinned_drop/unexpected_additional_item.stderr @@ -1,22 +1,16 @@ -error: no rules expected keyword `const` +error[E0438]: const `BAZ` is not a member of trait `pin_init::PinnedDrop` --> tests/ui/compile-fail/pinned_drop/unexpected_additional_item.rs:10:5 | 10 | const BAZ: usize = 0; - | ^^^^^ no rules expected this token in macro call - | -note: while trying to match `)` - --> src/macros.rs - | - | ), - | ^ + | ^^^^^^^^^^^^^^^^^^^^^ not a member of trait `pin_init::PinnedDrop` -error[E0277]: the trait bound `Foo: PinnedDrop` is not satisfied - --> tests/ui/compile-fail/pinned_drop/unexpected_additional_item.rs:3:1 +error[E0412]: cannot find type `Pin` in this scope + --> tests/ui/compile-fail/pinned_drop/unexpected_additional_item.rs:8:19 + | +8 | fn drop(self: Pin<&mut Self>) {} + | ^^^ not found in this scope + | +help: consider importing this struct | -3 | #[pin_data(PinnedDrop)] - | ^^^^^^^^^^^^^^^^^^^^^^^ - | | - | the trait `PinnedDrop` is not implemented for `Foo` - | required by a bound introduced by this call +1 + use std::pin::Pin; | - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/pinned_drop/unexpected_item.stderr b/tests/ui/compile-fail/pinned_drop/unexpected_item.stderr index 5b8fbb70..6f564a2b 100644 --- a/tests/ui/compile-fail/pinned_drop/unexpected_item.stderr +++ b/tests/ui/compile-fail/pinned_drop/unexpected_item.stderr @@ -1,22 +1,13 @@ -error: no rules expected keyword `const` +error[E0438]: const `BAZ` is not a member of trait `pin_init::PinnedDrop` --> tests/ui/compile-fail/pinned_drop/unexpected_item.rs:8:5 | 8 | const BAZ: usize = 0; - | ^^^^^ no rules expected this token in macro call - | -note: while trying to match keyword `fn` - --> src/macros.rs - | - | fn drop($($sig:tt)*) { - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^ not a member of trait `pin_init::PinnedDrop` -error[E0277]: the trait bound `Foo: PinnedDrop` is not satisfied - --> tests/ui/compile-fail/pinned_drop/unexpected_item.rs:3:1 +error[E0046]: not all trait items implemented, missing: `drop` + --> tests/ui/compile-fail/pinned_drop/unexpected_item.rs:7:1 | -3 | #[pin_data(PinnedDrop)] - | ^^^^^^^^^^^^^^^^^^^^^^^ - | | - | the trait `PinnedDrop` is not implemented for `Foo` - | required by a bound introduced by this call +7 | impl PinnedDrop for Foo { + | ^^^^^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation | - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) + = help: implement the missing item: `fn drop(self: Pin<&mut Self>, _: OnlyCallFromDrop) { todo!() }` diff --git a/tests/ui/compile-fail/pinned_drop/useless_pinned_drop.stderr b/tests/ui/compile-fail/pinned_drop/useless_pinned_drop.stderr index 95c4a757..d54aeb01 100644 --- a/tests/ui/compile-fail/pinned_drop/useless_pinned_drop.stderr +++ b/tests/ui/compile-fail/pinned_drop/useless_pinned_drop.stderr @@ -7,4 +7,4 @@ error[E0119]: conflicting implementations of trait `UselessPinnedDropImpl_you_ne | first implementation here | conflicting implementation for `Foo` | - = note: this error originates in the macro `$crate::__pin_data` which comes from the expansion of the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the attribute macro `pin_data` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/compile-fail/zeroable/with_comma.rs b/tests/ui/compile-fail/zeroable/with_comma.rs index e490b891..6ecd1d56 100644 --- a/tests/ui/compile-fail/zeroable/with_comma.rs +++ b/tests/ui/compile-fail/zeroable/with_comma.rs @@ -1,4 +1,3 @@ -extern crate pin_init; use pin_init::*; #[derive(Zeroable)] diff --git a/tests/ui/compile-fail/zeroable/with_comma.stderr b/tests/ui/compile-fail/zeroable/with_comma.stderr index df6263a4..09800cf9 100644 --- a/tests/ui/compile-fail/zeroable/with_comma.stderr +++ b/tests/ui/compile-fail/zeroable/with_comma.stderr @@ -1,33 +1,5 @@ -error: no rules expected `,` - --> tests/ui/compile-fail/zeroable/with_comma.rs:11:13 +error: unexpected token, expected `}` + --> tests/ui/compile-fail/zeroable/with_comma.rs:12:29 | -11 | let _ = init!(Foo { - | _____________^ -12 | | a: 0, -13 | | ..Zeroable::zeroed(), -14 | | }); - | |______^ no rules expected this token in macro call - | -note: while trying to match `)` - --> src/macros.rs - | - | @munch_fields($(..Zeroable::zeroed())? $(,)?), - | ^ - = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: no rules expected `,` - --> tests/ui/compile-fail/zeroable/with_comma.rs:11:13 - | -11 | let _ = init!(Foo { - | _____________^ -12 | | a: 0, -13 | | ..Zeroable::zeroed(), -14 | | }); - | |______^ no rules expected this token in macro call - | -note: while trying to match `)` - --> src/macros.rs - | - | @munch_fields(..Zeroable::zeroed() $(,)?), - | ^ - = note: this error originates in the macro `$crate::__init_internal` which comes from the expansion of the macro `init` (in Nightly builds, run with -Z macro-backtrace for more info) +12 | ..Zeroable::zeroed(), + | ^ diff --git a/tests/ui/expand/many_generics.expanded.rs b/tests/ui/expand/many_generics.expanded.rs index f22ef125..84db2561 100644 --- a/tests/ui/expand/many_generics.expanded.rs +++ b/tests/ui/expand/many_generics.expanded.rs @@ -8,12 +8,12 @@ struct Foo<'a, 'b: 'a, T: Bar<'b> + ?Sized + 'a, const SIZE: usize = 0> where T: Bar<'a, 1>, { - array: [u8; 1024 * 1024], + _array: [u8; 1024 * 1024], r: &'b mut [&'a mut T; SIZE], _pin: PhantomPinned, } const _: () = { - struct __ThePinData<'a, 'b: 'a, T: Bar<'b> + ?Sized + 'a, const SIZE: usize> + struct __ThePinData<'a, 'b: 'a, T: Bar<'b> + ?Sized + 'a, const SIZE: usize = 0> where T: Bar<'a, 1>, { @@ -53,7 +53,7 @@ const _: () = { ) -> ::core::result::Result<(), E> { unsafe { ::pin_init::PinInit::__pinned_init(init, slot) } } - unsafe fn array( + unsafe fn _array( self, slot: *mut [u8; 1024 * 1024], init: impl ::pin_init::Init<[u8; 1024 * 1024], E>, @@ -96,7 +96,7 @@ const _: () = { type Datee = Foo<'a, 'b, T, SIZE>; } #[allow(dead_code)] - struct __Unpin<'__pin, 'a, 'b: 'a, T: Bar<'b> + ?Sized + 'a, const SIZE: usize> + struct __Unpin<'__pin, 'a, 'b: 'a, T: Bar<'b> + ?Sized + 'a, const SIZE: usize = 0> where T: Bar<'a, 1>, { diff --git a/tests/ui/expand/pin-data.expanded.rs b/tests/ui/expand/pin-data.expanded.rs index 58b8f532..5f3946b3 100644 --- a/tests/ui/expand/pin-data.expanded.rs +++ b/tests/ui/expand/pin-data.expanded.rs @@ -56,11 +56,12 @@ const _: () = { {} trait MustNotImplDrop {} #[expect(drop_bounds)] - impl MustNotImplDrop for T {} + impl MustNotImplDrop for T {} impl MustNotImplDrop for Foo {} #[expect(non_camel_case_types)] trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} - impl UselessPinnedDropImpl_you_need_to_specify_PinnedDrop - for T {} + impl< + T: ::pin_init::PinnedDrop + ?::core::marker::Sized, + > UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} impl UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for Foo {} }; diff --git a/tests/ui/expand/simple-init.expanded.rs b/tests/ui/expand/simple-init.expanded.rs index 320efc95..0689a65d 100644 --- a/tests/ui/expand/simple-init.expanded.rs +++ b/tests/ui/expand/simple-init.expanded.rs @@ -17,11 +17,7 @@ fn main() { { struct __InitOk; #[allow(unreachable_code, clippy::diverging_sub_expression)] - let _ = || { - unsafe { - ::core::ptr::write(slot, Foo {}); - }; - }; + let _ = || unsafe { ::core::ptr::write(slot, Foo {}) }; } Ok(__InitOk) }, diff --git a/tests/zeroing.rs b/tests/zeroing.rs index d722d728..4cc776f3 100644 --- a/tests/zeroing.rs +++ b/tests/zeroing.rs @@ -11,7 +11,7 @@ const MARKS: usize = 64; pub struct Foo { buf: [u8; 1024 * 1024], marks: [*mut u8; MARKS], - pos: usize, + _pos: usize, #[pin] _pin: PhantomPinned, }