diff --git a/examples/pinned_drop-expanded.rs b/examples/pinned_drop-expanded.rs index 22bc6f1e..f8df7dc0 100644 --- a/examples/pinned_drop-expanded.rs +++ b/examples/pinned_drop-expanded.rs @@ -72,27 +72,22 @@ impl<'a, T> ::core::ops::Drop for Foo<'a, T> { // Safety - we're in 'drop', so we know that 'self' will // never move again. let pinned_self = unsafe { ::core::pin::Pin::new_unchecked(self) }; - // We call `pinned_drop` only once. Since `UnsafePinnedDrop::pinned_drop` + // We call `pinned_drop` only once. Since `UnsafePinnedDrop::drop` // is an unsafe function and a private API, it is never called again in safe // code *unless the user uses a maliciously crafted macro*. unsafe { - ::pin_project::__private::UnsafePinnedDrop::pinned_drop(pinned_self); + ::pin_project::__private::UnsafePinnedDrop::drop(pinned_self); } } } +// Users can implement `Drop` safely using `#[pinned_drop]`. +// **Do not call or implement this trait directly.** unsafe impl ::pin_project::__private::UnsafePinnedDrop for Foo<'_, T> { - unsafe fn pinned_drop(self: ::core::pin::Pin<&mut Self>) { - // Declare the #[pinned_drop] function *inside* our pinned_drop function - // This guarantees that it's impossible for any other user code - // to call it. - fn drop_foo(mut foo: Pin<&mut Foo<'_, T>>) { - **foo.project().was_dropped = true; - } - - // #[pinned_drop] function is a free function - if it were part of a trait impl, - // it would be possible for user code to call it by directly invoking the trait. - drop_foo(self) + // Since calling it twice on the same object would be UB, + // this method is unsafe. + unsafe fn drop(mut self: ::core::pin::Pin<&mut Self>) { + **self.project().was_dropped = true; } } diff --git a/examples/pinned_drop.rs b/examples/pinned_drop.rs index fd57ce42..98f3c48a 100644 --- a/examples/pinned_drop.rs +++ b/examples/pinned_drop.rs @@ -13,8 +13,10 @@ pub struct Foo<'a, T> { } #[pinned_drop] -fn drop_foo(mut this: Pin<&mut Foo<'_, T>>) { - **this.project().was_dropped = true; +impl PinnedDrop for Foo<'_, T> { + fn drop(mut self: Pin<&mut Self>) { + **self.project().was_dropped = true; + } } fn main() {} diff --git a/pin-project-internal/src/lib.rs b/pin-project-internal/src/lib.rs index f95193cf..46d0fc50 100644 --- a/pin-project-internal/src/lib.rs +++ b/pin-project-internal/src/lib.rs @@ -190,18 +190,28 @@ use syn::parse::Nothing; /// times requires using [`.as_mut()`][`Pin::as_mut`] to avoid /// consuming the `Pin`. /// +/// See also [`UnsafeUnpin`] trait. +/// /// ### `#[pinned_drop]` /// /// In order to correctly implement pin projections, a type's `Drop` impl must /// not move out of any stucturally pinned fields. Unfortunately, [`Drop::drop`] /// takes `&mut Self`, not `Pin<&mut Self>`. /// -/// To ensure that this requirement is upheld, the `pin_project` attribute will -/// provide a `Drop` impl for you. This `Drop` impl will delegate to a function -/// annotated with `#[pinned_drop]` if you use the `PinnedDrop` argument to -/// `#[pin_project]`. This function acts just like a normal [`drop`] impl, except -/// for the fact that it takes `Pin<&mut Self>`. In particular, it will never be -/// called more than once, just like [`Drop::drop`]. +/// To ensure that this requirement is upheld, the `#[pin_project]` attribute will +/// provide a [`Drop`] impl for you. This `Drop` impl will delegate to an impl +/// block annotated with `#[pinned_drop]` if you use the `PinnedDrop` argument +/// to `#[pin_project]`. This impl block acts just like a normal [`Drop`] impl, +/// except for the following two: +/// +/// * `drop` method takes `Pin<&mut Self>` +/// * Name of the trait is `PinnedDrop`. +/// +/// `#[pin_project]` implements the actual [`Drop`] trait via `PinnedDrop` you +/// implemented. To drop a type that implements `PinnedDrop`, use the [`drop`] +/// function just like dropping a type that directly implements [`Drop`]. +/// +/// In particular, it will never be called more than once, just like [`Drop::drop`]. /// /// For example: /// @@ -217,10 +227,11 @@ use syn::parse::Nothing; /// } /// /// #[pinned_drop] -/// fn my_drop_fn(mut foo: Pin<&mut Foo>) { -/// let foo = foo.project(); -/// println!("Dropping pinned field: {:?}", foo.pinned_field); -/// println!("Dropping unpin field: {:?}", foo.unpin_field); +/// impl PinnedDrop for Foo { +/// fn drop(self: Pin<&mut Self>) { +/// println!("Dropping pinned field: {:?}", self.pinned_field); +/// println!("Dropping unpin field: {:?}", self.unpin_field); +/// } /// } /// /// fn main() { @@ -338,11 +349,11 @@ pub fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream { } // TODO: Move this doc into pin-project crate when https://github.com/rust-lang/rust/pull/62855 merged. -/// An attribute for annotating a function that implements [`Drop`]. +/// An attribute for annotating an impl block that implements [`Drop`]. /// /// This attribute is only needed when you wish to provide a [`Drop`] -/// impl for your type. The function annotated with `#[pinned_drop]` acts just -/// like a normal [`drop`](Drop::drop) impl, except for the fact that it takes +/// impl for your type. The impl block annotated with `#[pinned_drop]` acts just +/// like a normal [`Drop`] impl, except for the fact that `drop` method takes /// `Pin<&mut Self>`. In particular, it will never be called more than once, /// just like [`Drop::drop`]. /// @@ -358,8 +369,10 @@ pub fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream { /// } /// /// #[pinned_drop] -/// fn my_drop(foo: Pin<&mut Foo>) { -/// println!("Dropping: {}", foo.field); +/// impl PinnedDrop for Foo { +/// fn drop(self: Pin<&mut Self>) { +/// println!("Dropping: {}", self.field); +/// } /// } /// /// fn main() { @@ -374,7 +387,7 @@ pub fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream { pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { let _: Nothing = syn::parse_macro_input!(args); let input = syn::parse_macro_input!(input); - pinned_drop::attribute(&input).into() + pinned_drop::attribute(input).into() } // TODO: Move this doc into pin-project crate when https://github.com/rust-lang/rust/pull/62855 merged. diff --git a/pin-project-internal/src/pin_project/attribute.rs b/pin-project-internal/src/pin_project/attribute.rs index b0c34aee..32a0d1aa 100644 --- a/pin-project-internal/src/pin_project/attribute.rs +++ b/pin-project-internal/src/pin_project/attribute.rs @@ -227,7 +227,7 @@ impl Context { let crate_path = &self.crate_path; let call = quote_spanned! { pinned_drop => - ::#crate_path::__private::UnsafePinnedDrop::pinned_drop(pinned_self) + ::#crate_path::__private::UnsafePinnedDrop::drop(pinned_self) }; quote! { @@ -237,7 +237,7 @@ impl Context { // Safety - we're in 'drop', so we know that 'self' will // never move again. let pinned_self = unsafe { ::core::pin::Pin::new_unchecked(self) }; - // We call `pinned_drop` only once. Since `UnsafePinnedDrop::pinned_drop` + // We call `pinned_drop` only once. Since `UnsafePinnedDrop::drop` // is an unsafe function and a private API, it is never called again in safe // code *unless the user uses a maliciously crafted macro*. unsafe { diff --git a/pin-project-internal/src/pinned_drop.rs b/pin-project-internal/src/pinned_drop.rs index 9527df39..c6c26dfd 100644 --- a/pin-project-internal/src/pinned_drop.rs +++ b/pin-project-internal/src/pinned_drop.rs @@ -1,22 +1,75 @@ use proc_macro2::TokenStream; -use quote::quote; -use syn::{ - FnArg, GenericArgument, ItemFn, PatType, PathArguments, Result, ReturnType, Type, TypePath, - TypeReference, TypeTuple, -}; +use quote::{quote, quote_spanned, ToTokens}; +use syn::{parse::Nothing, spanned::Spanned, *}; use crate::utils::crate_path; -pub(crate) fn attribute(input: &ItemFn) -> TokenStream { - parse(input).unwrap_or_else(|e| e.to_compile_error()) +pub(crate) fn attribute(mut input: ItemImpl) -> TokenStream { + if let Err(e) = parse(&mut input) { + let crate_path = crate_path(); + let self_ty = &input.self_ty; + let (impl_generics, _, where_clause) = input.generics.split_for_impl(); + + let mut tokens = e.to_compile_error(); + // Generate a dummy `UnsafePinnedDrop` implementation. + // In many cases, `#[pinned_drop] impl` is declared after `#[pin_project]`. + // Therefore, if `pinned_drop` compile fails, you will also get an error + // about `UnsafePinnedDrop` not being implemented. + // This can be prevented to some extent by generating a dummy + // `UnsafePinnedDrop` implementation. + // We already know that we will get a compile error, so this won't + // accidentally compile successfully. + tokens.extend(quote! { + unsafe impl #impl_generics ::#crate_path::__private::UnsafePinnedDrop + for #self_ty #where_clause + { + unsafe fn drop(self: ::core::pin::Pin<&mut Self>) {} + } + }); + tokens + } else { + input.into_token_stream() + } } -fn parse_arg(arg: &FnArg) -> Result<&Type> { - if let FnArg::Typed(PatType { ty, .. }) = arg { - if let Type::Path(TypePath { qself: None, path }) = &**ty { - let ty = &path.segments[path.segments.len() - 1]; +fn parse_method(method: &ImplItemMethod) -> Result<()> { + fn get_ty_path(ty: &Type) -> Option<&Path> { + if let Type::Path(TypePath { qself: None, path }) = ty { Some(path) } else { None } + } + + const INVALID_ARGUMENT: &str = "method `drop` must take an argument `self: Pin<&mut Self>`"; + + if method.sig.ident != "drop" { + return Err(error!( + method.sig.ident, + "method `{}` is not a member of trait `PinnedDrop", method.sig.ident, + )); + } + + if let ReturnType::Type(_, ty) = &method.sig.output { + match &**ty { + Type::Tuple(TypeTuple { elems, .. }) if elems.is_empty() => {} + _ => return Err(error!(ty, "method `drop` must return the unit type")), + } + } + + if method.sig.inputs.len() != 1 { + if method.sig.inputs.is_empty() { + return Err(syn::Error::new(method.sig.paren_token.span, INVALID_ARGUMENT)); + } else { + return Err(error!(&method.sig.inputs, INVALID_ARGUMENT)); + } + } + + if let FnArg::Typed(PatType { pat, ty, .. }) = &method.sig.inputs[0] { + // !by_ref (mutability) ident !subpat: path + if let (Pat::Ident(PatIdent { by_ref: None, ident, subpat: None, .. }), Some(path)) = + (&**pat, get_ty_path(ty)) + { + let ty = &path.segments.last().unwrap(); if let PathArguments::AngleBracketed(args) = &ty.arguments { - if args.args.len() == 1 && ty.ident == "Pin" { + // (mut) self: (path::)Pin + if ident == "self" && args.args.len() == 1 && ty.ident == "Pin" { // &mut if let GenericArgument::Type(Type::Reference(TypeReference { mutability: Some(_), @@ -24,46 +77,84 @@ fn parse_arg(arg: &FnArg) -> Result<&Type> { .. })) = &args.args[0] { - return Ok(&**elem); + if get_ty_path(elem).map_or(false, |path| path.is_ident("Self")) { + if method.sig.unsafety.is_some() { + return Err(error!( + method.sig.unsafety, + "implementing the method `drop` is not unsafe" + )); + } + return Ok(()); + } } } } } } - Err(error!(arg, "#[pinned_drop] function must take a argument `Pin<&mut Type>`")) + Err(error!(method.sig.inputs[0], INVALID_ARGUMENT)) } -fn parse(item: &ItemFn) -> Result { - if let ReturnType::Type(_, ty) = &item.sig.output { - match &**ty { - Type::Tuple(TypeTuple { elems, .. }) if elems.is_empty() => {} - _ => return Err(error!(ty, "#[pinned_drop] function must return the unit type")), +fn parse(item: &mut ItemImpl) -> Result<()> { + if let Some((_, path, _)) = &mut item.trait_ { + if path.is_ident("PinnedDrop") { + let crate_path = crate_path(); + + *path = syn::parse2(quote_spanned! { path.span() => + ::#crate_path::__private::UnsafePinnedDrop + }) + .unwrap(); + } else { + return Err(error!( + path, + "#[pinned_drop] may only be used on implementation for the `PinnedDrop` trait" + )); } - } - if item.sig.inputs.len() != 1 { + } else { return Err(error!( - item.sig.inputs, - "#[pinned_drop] function must take exactly one argument" + item.self_ty, + "#[pinned_drop] may only be used on implementation for the `PinnedDrop` trait" )); } - let crate_path = crate_path(); - let type_ = parse_arg(&item.sig.inputs[0])?; - let fn_name = &item.sig.ident; - let (impl_generics, _, where_clause) = item.sig.generics.split_for_impl(); - - Ok(quote! { - unsafe impl #impl_generics ::#crate_path::__private::UnsafePinnedDrop for #type_ #where_clause { - unsafe fn pinned_drop(self: ::core::pin::Pin<&mut Self>) { - // Declare the #[pinned_drop] function *inside* our pinned_drop function - // This guarantees that it's impossible for any other user code - // to call it. - #item - // #[pinned_drop] function is a free function - if it were part of a trait impl, - // it would be possible for user code to call it by directly invoking the trait. - #fn_name(self) + if item.unsafety.is_some() { + return Err(error!(item.unsafety, "implementing the trait `PinnedDrop` is not unsafe")); + } + item.unsafety = Some(token::Unsafe::default()); + + if item.items.is_empty() { + return Err(error!(item, "not all trait items implemented, missing: `drop`")); + } else { + for (i, item) in item.items.iter().enumerate() { + match item { + ImplItem::Const(item) => { + return Err(error!( + item, + "const `{}` is not a member of trait `PinnedDrop`", item.ident + )); + } + ImplItem::Type(item) => { + return Err(error!( + item, + "type `{}` is not a member of trait `PinnedDrop`", item.ident + )); + } + ImplItem::Method(method) => { + parse_method(method)?; + if i != 0 { + return Err(error!(method, "duplicate definitions with name `drop`")); + } + } + _ => { + let _: Nothing = syn::parse2(item.to_token_stream())?; + } } } - }) + } + + if let ImplItem::Method(method) = &mut item.items[0] { + method.sig.unsafety = Some(token::Unsafe::default()); + } + + Ok(()) } diff --git a/pin-project-internal/src/utils.rs b/pin-project-internal/src/utils.rs index c29775fa..bd24f41d 100644 --- a/pin-project-internal/src/utils.rs +++ b/pin-project-internal/src/utils.rs @@ -2,7 +2,7 @@ use quote::format_ident; use syn::{ punctuated::Punctuated, token::{self, Comma}, - Attribute, GenericParam, Generics, Ident, Lifetime, LifetimeDef, + *, }; pub(crate) const DEFAULT_LIFETIME_NAME: &str = "'_pin"; diff --git a/src/lib.rs b/src/lib.rs index ce96e52f..1de9f2ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,7 +139,7 @@ pub mod __private { // Since calling it twice on the same object would be UB, // this method is unsafe. #[doc(hidden)] - unsafe fn pinned_drop(self: Pin<&mut Self>); + unsafe fn drop(self: Pin<&mut Self>); } // This is an internal helper struct used by `pin-project-internal`. diff --git a/tests/pin_project.rs b/tests/pin_project.rs index 48ad0357..dc91e098 100644 --- a/tests/pin_project.rs +++ b/tests/pin_project.rs @@ -236,7 +236,9 @@ fn combine() { } #[pinned_drop] - fn do_drop(_: Pin<&mut Foo>) {} + impl PinnedDrop for Foo { + fn drop(self: Pin<&mut Self>) {} + } #[allow(unsafe_code)] unsafe impl UnsafeUnpin for Foo {} diff --git a/tests/pinned_drop.rs b/tests/pinned_drop.rs index 4ff8b6b4..2c0fbdc8 100644 --- a/tests/pinned_drop.rs +++ b/tests/pinned_drop.rs @@ -15,32 +15,13 @@ fn safe_project() { } #[pinned_drop] - fn do_drop(mut foo: Pin<&mut Foo<'_>>) { - **foo.project().was_dropped = true; + impl PinnedDrop for Foo<'_> { + fn drop(mut self: Pin<&mut Self>) { + **self.project().was_dropped = true; + } } let mut was_dropped = false; drop(Foo { was_dropped: &mut was_dropped, field: 42 }); assert!(was_dropped); } - -#[test] -fn overlapping_drop_fn_names() { - #[pin_project(PinnedDrop)] - pub struct Foo { - #[pin] - field: u8, - } - - #[pinned_drop] - fn do_drop(_: Pin<&mut Foo>) {} - - #[pin_project(PinnedDrop)] - pub struct Bar { - #[pin] - field: u8, - } - - #[pinned_drop] - fn do_drop(_: Pin<&mut Bar>) {} -} diff --git a/tests/ui/pin_project/drop_conflict.rs b/tests/ui/pin_project/drop_conflict.rs index ffd60dd3..8785b28e 100644 --- a/tests/ui/pin_project/drop_conflict.rs +++ b/tests/ui/pin_project/drop_conflict.rs @@ -22,7 +22,9 @@ struct Bar { } #[pinned_drop] -fn do_drop(this: Pin<&mut Bar>) {} +impl PinnedDrop for Bar { + fn drop(self: Pin<&mut Self>) {} +} impl Drop for Bar { fn drop(&mut self) {} diff --git a/tests/ui/pin_project/drop_conflict.stderr b/tests/ui/pin_project/drop_conflict.stderr index 72f1e91e..1c710248 100644 --- a/tests/ui/pin_project/drop_conflict.stderr +++ b/tests/ui/pin_project/drop_conflict.stderr @@ -13,7 +13,7 @@ error[E0119]: conflicting implementations of trait `std::ops::Drop` for type `Ba 17 | #[pin_project(PinnedDrop)] //~ ERROR E0119 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<_, _>` ... -27 | impl Drop for Bar { +29 | impl Drop for Bar { | ----------------------------- first implementation here error: aborting due to 2 previous errors diff --git a/tests/ui/pin_project/packed_sneaky-1.rs b/tests/ui/pin_project/packed_sneaky-1.rs index 7093d345..35e0a7f5 100644 --- a/tests/ui/pin_project/packed_sneaky-1.rs +++ b/tests/ui/pin_project/packed_sneaky-1.rs @@ -31,6 +31,8 @@ struct D { } #[pinned_drop] -fn drop_d(_: Pin<&mut D>) {} +impl PinnedDrop for D { + fn drop(self: Pin<&mut Self>) {} +} fn main() {} diff --git a/tests/ui/pinned_drop/forget-pinned-drop.stderr b/tests/ui/pinned_drop/forget-pinned-drop.stderr index e010f63f..cbd59892 100644 --- a/tests/ui/pinned_drop/forget-pinned-drop.stderr +++ b/tests/ui/pinned_drop/forget-pinned-drop.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `Foo: pin_project::__private::UnsafePinnedDrop` is 6 | #[pin_project(PinnedDrop)] //~ ERROR E0277 | ^^^^^^^^^^ the trait `pin_project::__private::UnsafePinnedDrop` is not implemented for `Foo` | - = note: required by `pin_project::__private::UnsafePinnedDrop::pinned_drop` + = note: required by `pin_project::__private::UnsafePinnedDrop::drop` error: aborting due to previous error diff --git a/tests/ui/pinned_drop/invalid.rs b/tests/ui/pinned_drop/invalid.rs index 9e04c390..dcf1132a 100644 --- a/tests/ui/pinned_drop/invalid.rs +++ b/tests/ui/pinned_drop/invalid.rs @@ -3,22 +3,144 @@ use pin_project::{pin_project, pinned_drop}; use std::pin::Pin; -#[pin_project] -pub struct Foo { +#[pin_project(PinnedDrop)] +pub struct A { #[pin] field: u8, } #[pinned_drop(foo)] //~ ERROR unexpected token -fn do_drop(_x: Pin<&mut Foo>) {} +impl PinnedDrop for A { + fn drop(self: Pin<&mut Self>) {} +} + +#[pin_project(PinnedDrop)] +pub struct B { + #[pin] + field: u8, +} + +#[pinned_drop] +impl Drop for B { + //~^ ERROR #[pinned_drop] may only be used on implementation for the `PinnedDrop` trait + fn drop(&mut self) {} +} + +#[pin_project(PinnedDrop)] +pub struct C { + #[pin] + field: u8, +} + +#[pinned_drop] +impl C { + //~^ ERROR #[pinned_drop] may only be used on implementation for the `PinnedDrop` trait + fn drop(&mut self) {} +} + +#[pin_project(PinnedDrop)] +pub struct D { + #[pin] + field: u8, +} + +#[pinned_drop] +impl PinnedDrop for D { + fn drop(&mut self) {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` +} + +#[pin_project(PinnedDrop)] +pub struct E { + #[pin] + field: u8, +} + +#[pinned_drop] +impl PinnedDrop for E { + fn drop_baz(&mut self) {} //~ ERROR method `drop_baz` is not a member of trait `PinnedDrop +} + +#[pin_project(PinnedDrop)] +pub struct F { + #[pin] + field: u8, +} + +#[pinned_drop] +unsafe impl PinnedDrop for F { + //~^ ERROR implementing the trait `PinnedDrop` is not unsafe + fn drop(self: Pin<&mut Self>) {} +} -#[pin_project] -pub struct Bar { +#[pin_project(PinnedDrop)] +pub struct G { #[pin] field: u8, } #[pinned_drop] -fn do_drop(_x: &mut Bar) {} //~ ERROR #[pinned_drop] function must take a argument `Pin<&mut Type>` +impl PinnedDrop for G { + unsafe fn drop(self: Pin<&mut Self>) {} //~ ERROR implementing the method `drop` is not unsafe +} + +#[pin_project(PinnedDrop)] +pub struct H { + #[pin] + field: u8, +} + +#[pinned_drop] +impl PinnedDrop for H { + const A: u8 = 0; //~ ERROR const `A` is not a member of trait `PinnedDrop` + fn drop(self: Pin<&mut Self>) {} +} + +#[pin_project(PinnedDrop)] +pub struct I { + #[pin] + field: u8, +} + +#[pinned_drop] +impl PinnedDrop for I { + fn drop(self: Pin<&mut Self>) {} + const A: u8 = 0; //~ ERROR const `A` is not a member of trait `PinnedDrop` +} + +#[pin_project(PinnedDrop)] +pub struct J { + #[pin] + field: u8, +} + +#[pinned_drop] +impl PinnedDrop for J { + type A = u8; //~ ERROR type `A` is not a member of trait `PinnedDrop` + fn drop(self: Pin<&mut Self>) {} +} + +#[pin_project(PinnedDrop)] +pub struct K { + #[pin] + field: u8, +} + +#[pinned_drop] +impl PinnedDrop for K { + fn drop(self: Pin<&mut Self>) {} + type A = u8; //~ ERROR type `A` is not a member of trait `PinnedDrop` +} + +#[pin_project(PinnedDrop)] +pub struct L { + #[pin] + field: u8, +} + +#[pinned_drop] +impl PinnedDrop for L { + fn drop(self: Pin<&mut Self>) {} + fn drop(self: Pin<&mut Self>) {} //~ ERROR duplicate definitions with name `drop` +} fn main() {} diff --git a/tests/ui/pinned_drop/invalid.stderr b/tests/ui/pinned_drop/invalid.stderr index b823ea3e..5c71a4fe 100644 --- a/tests/ui/pinned_drop/invalid.stderr +++ b/tests/ui/pinned_drop/invalid.stderr @@ -4,11 +4,80 @@ error: unexpected token 12 | #[pinned_drop(foo)] //~ ERROR unexpected token | ^^^ -error: #[pinned_drop] function must take a argument `Pin<&mut Type>` - --> $DIR/invalid.rs:22:12 +error: #[pinned_drop] may only be used on implementation for the `PinnedDrop` trait + --> $DIR/invalid.rs:24:6 | -22 | fn do_drop(_x: &mut Bar) {} //~ ERROR #[pinned_drop] function must take a argument `Pin<&mut Type>` - | ^^^^^^^^^^^^ +24 | impl Drop for B { + | ^^^^ -error: aborting due to 2 previous errors +error: #[pinned_drop] may only be used on implementation for the `PinnedDrop` trait + --> $DIR/invalid.rs:36:6 + | +36 | impl C { + | ^ + +error: method `drop` must take an argument `self: Pin<&mut Self>` + --> $DIR/invalid.rs:49:13 + | +49 | fn drop(&mut self) {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` + | ^^^^^^^^^ + +error: method `drop_baz` is not a member of trait `PinnedDrop + --> $DIR/invalid.rs:60:8 + | +60 | fn drop_baz(&mut self) {} //~ ERROR method `drop_baz` is not a member of trait `PinnedDrop + | ^^^^^^^^ + +error: implementing the trait `PinnedDrop` is not unsafe + --> $DIR/invalid.rs:70:1 + | +70 | unsafe impl PinnedDrop for F { + | ^^^^^^ + +error: implementing the method `drop` is not unsafe + --> $DIR/invalid.rs:83:5 + | +83 | unsafe fn drop(self: Pin<&mut Self>) {} //~ ERROR implementing the method `drop` is not unsafe + | ^^^^^^ + +error: const `A` is not a member of trait `PinnedDrop` + --> $DIR/invalid.rs:94:5 + | +94 | const A: u8 = 0; //~ ERROR const `A` is not a member of trait `PinnedDrop` + | ^^^^^^^^^^^^^^^^ + +error: const `A` is not a member of trait `PinnedDrop` + --> $DIR/invalid.rs:107:5 + | +107 | const A: u8 = 0; //~ ERROR const `A` is not a member of trait `PinnedDrop` + | ^^^^^^^^^^^^^^^^ + +error: type `A` is not a member of trait `PinnedDrop` + --> $DIR/invalid.rs:118:5 + | +118 | type A = u8; //~ ERROR type `A` is not a member of trait `PinnedDrop` + | ^^^^^^^^^^^^ + +error: type `A` is not a member of trait `PinnedDrop` + --> $DIR/invalid.rs:131:5 + | +131 | type A = u8; //~ ERROR type `A` is not a member of trait `PinnedDrop` + | ^^^^^^^^^^^^ + +error: duplicate definitions with name `drop` + --> $DIR/invalid.rs:143:5 + | +143 | fn drop(self: Pin<&mut Self>) {} //~ ERROR duplicate definitions with name `drop` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `A: pin_project::__private::UnsafePinnedDrop` is not satisfied + --> $DIR/invalid.rs:6:15 + | +6 | #[pin_project(PinnedDrop)] + | ^^^^^^^^^^ the trait `pin_project::__private::UnsafePinnedDrop` is not implemented for `A` + | + = note: required by `pin_project::__private::UnsafePinnedDrop::drop` + +error: aborting due to 13 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/pinned_drop/return-type.rs b/tests/ui/pinned_drop/return-type.rs deleted file mode 100644 index 94490585..00000000 --- a/tests/ui/pinned_drop/return-type.rs +++ /dev/null @@ -1,33 +0,0 @@ -// compile-fail - -use pin_project::{pin_project, pinned_drop}; -use std::pin::Pin; - -#[pin_project] -pub struct A { - #[pin] - field: u8, -} - -#[pinned_drop] -fn do_drop(_x: Pin<&mut A>) -> bool {} //~ ERROR #[pinned_drop] function must return the unit type - -#[pin_project] -pub struct B { - #[pin] - field: u8, -} - -#[pinned_drop] -fn do_drop(_x: Pin<&mut B>) -> ((),) {} //~ ERROR #[pinned_drop] function must return the unit type - -#[pin_project] -pub struct C { - #[pin] - field: u8, -} - -#[pinned_drop] -fn do_drop(_x: Pin<&mut C>) -> () {} // OK - -fn main() {} diff --git a/tests/ui/pinned_drop/return-type.stderr b/tests/ui/pinned_drop/return-type.stderr deleted file mode 100644 index f5e425da..00000000 --- a/tests/ui/pinned_drop/return-type.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: #[pinned_drop] function must return the unit type - --> $DIR/return-type.rs:13:32 - | -13 | fn do_drop(_x: Pin<&mut A>) -> bool {} //~ ERROR #[pinned_drop] function must return the unit type - | ^^^^ - -error: #[pinned_drop] function must return the unit type - --> $DIR/return-type.rs:22:32 - | -22 | fn do_drop(_x: Pin<&mut B>) -> ((),) {} //~ ERROR #[pinned_drop] function must return the unit type - | ^^^^^ - -error: aborting due to 2 previous errors -