From 1497185c26ad1cce6489541615f2bb42540ad759 Mon Sep 17 00:00:00 2001 From: Frank King Date: Sun, 27 Jul 2025 22:26:58 +0800 Subject: [PATCH] Implement `Drop::pin_drop` for `!Unpin` types --- compiler/rustc_hir_analysis/messages.ftl | 14 + .../src/check/always_applicable.rs | 105 +++- compiler/rustc_hir_analysis/src/errors.rs | 50 ++ compiler/rustc_hir_typeck/src/callee.rs | 8 +- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/ops/drop.rs | 29 +- .../async-await/async-drop/unexpected-sort.rs | 6 +- .../async-drop/unexpected-sort.stderr | 6 +- tests/ui/pin-ergonomics/pinned-drop.rs | 181 +++++++ tests/ui/pin-ergonomics/pinned-drop.stderr | 512 ++++++++++++++++++ 10 files changed, 902 insertions(+), 10 deletions(-) create mode 100644 tests/ui/pin-ergonomics/pinned-drop.rs create mode 100644 tests/ui/pin-ergonomics/pinned-drop.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 2428c1aa29fc8..32eb02f86509b 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -117,6 +117,11 @@ hir_analysis_coercion_between_struct_same_note = expected coercion between the s hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found +hir_analysis_conflict_impl_drop_and_pin_drop = conflict implementation of `Drop::drop` and `Drop::pin_drop` + .drop_label = `drop(&mut self)` implemented here + .pin_drop_label = `pin_drop(&pin mut self)` implemented here + .suggestion = remove this implementation + hir_analysis_const_bound_for_non_const_trait = `{$modifier}` can only be applied to `const` traits .label = can't be applied to `{$trait_name}` .note = `{$trait_name}` can't be used with `{$modifier}` because it isn't `const` @@ -215,6 +220,11 @@ hir_analysis_functions_names_duplicated = functions names are duplicated hir_analysis_generic_args_on_overridden_impl = could not resolve generic parameters on overridden impl +hir_analysis_impl_drop_for_negative_unpin_type = could not impl `Drop::drop(&mut self)` for a type that implements `!Unpin` + .note = `Unpin` implemented for `{$self_ty}` + .help = `impl !Unpin` is intended for pinned projections, which requires the value pinned until it's deallocated + .suggestion = consider implement `Drop::pin_drop(&pin mut self)` instead + hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default` .label = cannot specialize default item `{$ident}` .ok_label = parent `impl` is here @@ -223,6 +233,10 @@ hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a par hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default` .note = parent implementation is in crate `{$cname}` +hir_analysis_impl_pin_drop_for_not_negative_unpin_type = implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + .suggestion = impl `Drop::drop(&mut self)` instead + .impl_negative_unpin_sugg = or impl `!Unpin` for `{$self_ty}` instead + hir_analysis_inherent_dyn = cannot define inherent `impl` for a dyn auto trait .label = impl requires at least one non-auto trait .note = define and implement a new trait or type instead diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index 58c3020f60ede..deaa8012f2360 100644 --- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -7,11 +7,13 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; +use rustc_hir as hir; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::span_bug; use rustc_middle::ty::util::CheckRegions; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode}; +use rustc_span::{Span, sym}; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -70,7 +72,9 @@ pub(crate) fn check_drop_impl( drop_impl_did, adt_def.did(), adt_to_impl_args, - ) + )?; + + ensure_coherent_unpin(tcx, drop_impl_did, adt_def.did(), adt_to_impl_args) } _ => { span_bug!(tcx.def_span(drop_impl_did), "incoherent impl of Drop"); @@ -294,3 +298,102 @@ fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>( Ok(()) } + +/// This function checks whether `Self: !Unpin` for implementation of `Drop`. +/// - If `Drop::drop` is implemented, there must be no `Self: !Unpin` implementation. +/// - If `Drop::pin_drop` is implemented, there must be a `Self: !Unpin` implementation. +fn ensure_coherent_unpin<'tcx>( + tcx: TyCtxt<'tcx>, + drop_impl_did: LocalDefId, + adt_def_id: DefId, + adt_to_impl_args: GenericArgsRef<'tcx>, +) -> Result<(), ErrorGuaranteed> { + let item_impl = tcx.hir_expect_item(drop_impl_did).expect_impl(); + let mut drop_spans = None; + let mut pin_drop_spans = None; + for &impl_item_id in item_impl.items { + let impl_item = tcx.hir_impl_item(impl_item_id); + if let hir::ImplItemKind::Fn(fn_sig, _) = impl_item.kind { + match impl_item.ident.name { + sym::drop => drop_spans = Some((fn_sig.span, impl_item.span)), + sym::pin_drop => pin_drop_spans = Some((fn_sig.span, impl_item.span)), + _ => {} + } + } + } + let self_ty = Ty::new_adt(tcx, tcx.adt_def(adt_def_id), adt_to_impl_args); + let negative_unpin_impl = find_negative_unpin_impl(tcx, self_ty, tcx.def_span(drop_impl_did)); + + match (drop_spans, pin_drop_spans) { + (None, None) => { + return Err(tcx + .dcx() + .span_delayed_bug(tcx.def_span(drop_impl_did), "unexpected empty impl of `Drop`")); + } + (Some((span, _)), None) => { + if let Some(negative_unpin_impl) = negative_unpin_impl { + return Err(tcx.dcx().emit_err(crate::errors::ImplDropForNegativeUnpinType { + span, + negative_unpin_span: tcx.def_span(negative_unpin_impl), + self_ty, + })); + } + } + (None, Some((span, _))) => { + debug_assert!( + tcx.features().pin_ergonomics(), + "`Drop::pin_drop` should be guarded by the library feature gate" + ); + if negative_unpin_impl.is_none() { + return Err(tcx.dcx().emit_err( + crate::errors::ImplPinDropForNotNegativeUnpinType { + span, + impl_sugg_span: tcx.def_span(drop_impl_did).shrink_to_lo(), + impl_generics_snippet: tcx + .sess + .source_map() + .span_to_snippet(item_impl.generics.span) + .unwrap_or_default(), + self_ty, + }, + )); + } + } + ( + Some((drop_span, drop_span_with_body)), + Some((pin_drop_span, pin_drop_span_with_body)), + ) => { + let remove_sugg = match negative_unpin_impl { + // without `impl !Unpin`, should pick `drop(&mut self)`, and remove `pin_drop(&pin mut self)` + None => pin_drop_span_with_body, + // with `impl !Unpin`, should pick `pin_drop(&pin mut self)`, and remove `drop(&mut self)` + Some(_) => drop_span_with_body, + }; + return Err(tcx.dcx().emit_err(crate::errors::ConflictImplDropAndPinDrop { + span: tcx.def_span(drop_impl_did), + drop_span, + pin_drop_span, + remove_sugg, + })); + } + } + Ok(()) +} + +fn find_negative_unpin_impl<'tcx>( + tcx: TyCtxt<'tcx>, + self_ty: Ty<'tcx>, + span: Span, +) -> Option { + let mut negative_unpin_impl_did = None; + tcx.for_each_relevant_impl(tcx.require_lang_item(hir::LangItem::Unpin, span), self_ty, |did| { + if tcx.impl_polarity(did) == ty::ImplPolarity::Negative { + if negative_unpin_impl_did.is_some() { + tcx.dcx() + .span_delayed_bug(tcx.def_span(did), "duplicated `!Unpin` implementations"); + } + negative_unpin_impl_did = Some(did.expect_local()); + } + }); + negative_unpin_impl_did +} diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 26a98722b341e..ebcef5dc2842a 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1717,3 +1717,53 @@ pub(crate) struct AsyncDropWithoutSyncDrop { #[primary_span] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_impl_drop_for_negative_unpin_type)] +#[help] +pub(crate) struct ImplDropForNegativeUnpinType<'tcx> { + #[suggestion( + applicability = "machine-applicable", + code = "fn pin_drop(&pin mut self)", + style = "short" + )] + #[primary_span] + pub span: Span, + #[note] + pub negative_unpin_span: Span, + pub self_ty: Ty<'tcx>, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_impl_pin_drop_for_not_negative_unpin_type)] +pub(crate) struct ImplPinDropForNotNegativeUnpinType<'tcx> { + #[suggestion( + applicability = "machine-applicable", + code = "fn drop(&mut self)", + style = "short" + )] + #[primary_span] + pub span: Span, + #[suggestion( + hir_analysis_impl_negative_unpin_sugg, + applicability = "machine-applicable", + code = "impl{impl_generics_snippet} !Unpin for {self_ty}` {}\n", + style = "short" + )] + pub impl_sugg_span: Span, + pub impl_generics_snippet: String, + pub self_ty: Ty<'tcx>, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_conflict_impl_drop_and_pin_drop)] +pub(crate) struct ConflictImplDropAndPinDrop { + #[primary_span] + pub span: Span, + #[label(hir_analysis_drop_label)] + pub drop_span: Span, + #[label(hir_analysis_pin_drop_label)] + pub pin_drop_span: Span, + #[suggestion(applicability = "machine-applicable", code = "", style = "normal")] + pub remove_sugg: Span, +} diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 48bb45de53eb4..5db2022e5df93 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -36,9 +36,13 @@ pub(crate) fn check_legal_trait_for_method_call( receiver: Option, expr_span: Span, trait_id: DefId, - _body_id: DefId, + body_id: DefId, ) -> Result<(), ErrorGuaranteed> { - if tcx.is_lang_item(trait_id, LangItem::Drop) { + if tcx.is_lang_item(trait_id, LangItem::Drop) + // Allow calling `Drop::pin_drop` in `Drop::drop` + && let Some(parent) = tcx.opt_parent(body_id) + && !tcx.is_lang_item(parent, LangItem::Drop) + { let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) { errors::ExplicitDestructorCallSugg::Snippet { lo: expr_span.shrink_to_lo(), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d54175548e30e..8a8023c1b0a06 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1616,6 +1616,7 @@ symbols! { pic, pie, pin, + pin_drop, pin_ergonomics, pin_macro, platform_intrinsics, diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index bbef702320715..6963c169f186a 100644 --- a/library/core/src/ops/drop.rs +++ b/library/core/src/ops/drop.rs @@ -1,3 +1,5 @@ +use crate::pin::Pin; + /// Custom code within the destructor. /// /// When a value is no longer needed, Rust will run a "destructor" on that value. @@ -205,6 +207,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[const_trait] #[rustc_const_unstable(feature = "const_destruct", issue = "133214")] +#[rustc_must_implement_one_of(drop, pin_drop)] pub trait Drop { /// Executes the destructor for this type. /// @@ -238,5 +241,29 @@ pub trait Drop { /// [`mem::drop`]: drop /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place #[stable(feature = "rust1", since = "1.0.0")] - fn drop(&mut self); + fn drop(&mut self) { + // SAFETY: `self` is pinned till after dropped. + Drop::pin_drop(unsafe { Pin::new_unchecked(self) }) + } + + /// Execute the destructor for this type, but different to [`Drop::drop`], it requires `self` + /// to be pinned. + /// + /// By implementing this method instead of [`Drop::drop`], the receiver type [`Pin<&mut Self>`] + /// makes sure that the value is pinned until it is deallocated (See [`std::pin` module docs] for + /// more details), which enables us to support field projections of `Self` type safely. + /// + /// Currently, this method is used together with a negative implentation of [`Unpin`], which means + /// that the current type is never [`Unpin`]. For a given type `Foo`, you can impl `pin_drop` for it + /// *if and only if* you have `impl !Unpin for Foo`. + /// + /// See also [`Drop::drop`]. + /// + /// [`Drop::drop`]: crate::ops::Drop::drop + /// [`Unpin`]: crate::marker::Unpin + /// [`!Unpin`]: crate::marker::Unpin + /// [`Pin<&mut Self>`]: crate::pin::Pin + /// [`std::pin` module docs]: crate::pin + #[unstable(feature = "pin_ergonomics", issue = "130494")] + fn pin_drop(self: Pin<&mut Self>) {} } diff --git a/tests/ui/async-await/async-drop/unexpected-sort.rs b/tests/ui/async-await/async-drop/unexpected-sort.rs index 659e21eb24119..b0125bf90c920 100644 --- a/tests/ui/async-await/async-drop/unexpected-sort.rs +++ b/tests/ui/async-await/async-drop/unexpected-sort.rs @@ -6,10 +6,12 @@ #![feature(async_drop)] use std::future::AsyncDrop; struct a; -impl Drop for a { //~ ERROR: not all trait items implemented, missing: `drop` +impl Drop for a { + //~ ERROR: not all trait items implemented, missing one of: `drop`, `pin_drop` fn b() {} //~ ERROR: method `b` is not a member of trait `Drop` } -impl AsyncDrop for a { //~ ERROR: not all trait items implemented, missing: `drop` +impl AsyncDrop for a { + //~ ERROR: not all trait items implemented, missing: `drop` type c = (); //~^ ERROR: type `c` is not a member of trait `AsyncDrop` } diff --git a/tests/ui/async-await/async-drop/unexpected-sort.stderr b/tests/ui/async-await/async-drop/unexpected-sort.stderr index a6e4f9fd57307..004439dd59229 100644 --- a/tests/ui/async-await/async-drop/unexpected-sort.stderr +++ b/tests/ui/async-await/async-drop/unexpected-sort.stderr @@ -10,13 +10,11 @@ error[E0437]: type `c` is not a member of trait `AsyncDrop` LL | type c = (); | ^^^^^^^^^^^^ not a member of trait `AsyncDrop` -error[E0046]: not all trait items implemented, missing: `drop` +error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop` --> $DIR/unexpected-sort.rs:9:1 | LL | impl Drop for a { - | ^^^^^^^^^^^^^^^ missing `drop` in implementation - | - = help: implement the missing item: `fn drop(&mut self) { todo!() }` + | ^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation error[E0046]: not all trait items implemented, missing: `drop` --> $DIR/unexpected-sort.rs:12:1 diff --git a/tests/ui/pin-ergonomics/pinned-drop.rs b/tests/ui/pin-ergonomics/pinned-drop.rs new file mode 100644 index 0000000000000..9c25ea29dfb92 --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop.rs @@ -0,0 +1,181 @@ +//@ edition:2024 +#![feature(pin_ergonomics, negative_impls)] +#![allow(incomplete_features)] + +macro_rules! def { + ($name:ident: !Unpin) => { + struct $name; + impl !Unpin for $name {} + }; + ($name:ident: ?Unpin) => { + struct $name(std::marker::PhantomPinned); + }; + ($name:ident: Unpin) => { + struct $name; + const _: crate::AssertUnpin<$name> = crate::AssertUnpin($name); + }; +} + +macro_rules! impl_drop { + ($name:ident: $($impls:tt)*) => { + impl Drop for $name { + $($impls)* + } + }; +} + +struct AssertUnpin(T); + +mod drop { + mod mut_self { + def!(Foo: !Unpin); + def!(Bar: ?Unpin); + def!(Baz: Unpin); + + impl_drop!(Foo: fn drop(&mut self) {}); //~ ERROR could not impl `Drop::drop(&mut self)` for a type that implements `!Unpin` + impl_drop!(Bar: fn drop(&mut self) {}); // ok + impl_drop!(Baz: fn drop(&mut self) {}); // ok + } + + mod pin_mut_self { + use std::pin::Pin; + + def!(Foo: !Unpin); + def!(Bar: ?Unpin); + def!(Baz: Unpin); + + impl_drop!(Foo: fn drop(self: Pin<&mut Self>) {}); //~ ERROR method `drop` has an incompatible type for trait [E0053] + //~^ ERROR could not impl `Drop::drop(&mut self)` for a type that implements `!Unpin` + impl_drop!(Bar: fn drop(self: Pin<&mut Self>) {}); //~ ERROR method `drop` has an incompatible type for trait [E0053] + impl_drop!(Baz: fn drop(self: Pin<&mut Self>) {}); //~ ERROR method `drop` has an incompatible type for trait [E0053] + } + + mod pin_mut_self_sugar { + def!(Foo: !Unpin); + def!(Bar: ?Unpin); + def!(Baz: Unpin); + + impl_drop!(Foo: fn drop(&pin mut self) {}); //~ ERROR method `drop` has an incompatible type for trait [E0053] + //~^ ERROR could not impl `Drop::drop(&mut self)` for a type that implements `!Unpin` + impl_drop!(Bar: fn drop(&pin mut self) {}); //~ ERROR method `drop` has an incompatible type for trait [E0053] + impl_drop!(Baz: fn drop(&pin mut self) {}); //~ ERROR method `drop` has an incompatible type for trait [E0053] + } +} + +mod pin_drop { + mod mut_self { + def!(Foo: !Unpin); + def!(Bar: ?Unpin); + def!(Baz: Unpin); + + impl_drop!(Foo: fn pin_drop(&mut self) {}); //~ ERROR method `pin_drop` has an incompatible type for trait [E0053] + impl_drop!(Bar: fn pin_drop(&mut self) {}); //~ ERROR method `pin_drop` has an incompatible type for trait [E0053] + //~^ ERROR implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + impl_drop!(Baz: fn pin_drop(&mut self) {}); //~ ERROR method `pin_drop` has an incompatible type for trait [E0053] + //~^ ERROR implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + } + + mod pin_mut_self { + use std::pin::Pin; + + def!(Foo: !Unpin); + def!(Bar: ?Unpin); + def!(Baz: Unpin); + + impl_drop!(Foo: fn pin_drop(self: Pin<&mut Self>) {}); // ok + impl_drop!(Bar: fn pin_drop(self: Pin<&mut Self>) {}); //~ ERROR implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + impl_drop!(Baz: fn pin_drop(self: Pin<&mut Self>) {}); //~ ERROR implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + } + + mod pin_mut_self_sugar { + def!(Foo: !Unpin); + def!(Bar: ?Unpin); + def!(Baz: Unpin); + + impl_drop!(Foo: fn pin_drop(&pin mut self) {}); // ok + impl_drop!(Bar: fn pin_drop(&pin mut self) {}); //~ ERROR implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + impl_drop!(Baz: fn pin_drop(&pin mut self) {}); //~ ERROR implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + } +} + +mod both { + def!(Foo: !Unpin); + def!(Bar: ?Unpin); + def!(Baz: Unpin); + + impl Drop for Foo { + //~^ ERROR conflict implementation of `Drop::drop` and `Drop::pin_drop` + fn drop(&mut self) {} + fn pin_drop(&pin mut self) {} + } + impl Drop for Bar { + //~^ ERROR conflict implementation of `Drop::drop` and `Drop::pin_drop` + fn drop(&mut self) {} + fn pin_drop(&pin mut self) {} + } + impl Drop for Baz { + //~^ ERROR conflict implementation of `Drop::drop` and `Drop::pin_drop` + fn drop(&mut self) {} + fn pin_drop(&pin mut self) {} + } +} + +mod empty { + def!(Foo: !Unpin); + def!(Bar: ?Unpin); + def!(Baz: Unpin); + + impl Drop for Foo {} //~ ERROR not all trait items implemented, missing one of: `drop`, `pin_drop` [E0046] + impl Drop for Bar {} //~ ERROR not all trait items implemented, missing one of: `drop`, `pin_drop` [E0046] + impl Drop for Baz {} //~ ERROR not all trait items implemented, missing one of: `drop`, `pin_drop` [E0046] +} + +mod irrelevant { + def!(Foo: !Unpin); + def!(Bar: ?Unpin); + def!(Baz: Unpin); + + impl Drop for Foo { + //~^ ERROR not all trait items implemented, missing one of: `drop`, `pin_drop` + type Type = (); //~ ERROR type `Type` is not a member of trait `Drop` [E0437] + const N: usize = 0; //~ ERROR const `N` is not a member of trait `Drop` + fn foo() {} //~ ERROR method `foo` is not a member of trait `Drop` + } + impl Drop for Bar { + //~^ ERROR not all trait items implemented, missing one of: `drop`, `pin_drop` + type Type = (); //~ ERROR type `Type` is not a member of trait `Drop` [E0437] + const N: usize = 0; //~ ERROR const `N` is not a member of trait `Drop` + fn foo() {} //~ ERROR method `foo` is not a member of trait `Drop` + } + impl Drop for Baz { + //~^ ERROR not all trait items implemented, missing one of: `drop`, `pin_drop` + type Type = (); //~ ERROR type `Type` is not a member of trait `Drop` [E0437] + const N: usize = 0; //~ ERROR const `N` is not a member of trait `Drop` + fn foo() {} //~ ERROR method `foo` is not a member of trait `Drop` + } +} + +mod explicit_call_pin_drop { + def!(Foo: !Unpin); + def!(Bar: ?Unpin); + def!(Baz: Unpin); + + impl_drop!(Foo: fn drop(&mut self) { Drop::pin_drop(todo!()) }); //~ ERROR explicit use of destructor method [E0040] + //~^ ERROR could not impl `Drop::drop(&mut self)` for a type that implements `!Unpin` + impl_drop!(Bar: fn drop(&mut self) { Drop::pin_drop(todo!()) }); //~ ERROR explicit use of destructor method [E0040] + impl_drop!(Baz: fn drop(&mut self) { Drop::pin_drop(todo!()) }); //~ ERROR explicit use of destructor method [E0040] +} + +mod explicit_call_drop { + def!(Foo: !Unpin); + def!(Bar: ?Unpin); + def!(Baz: Unpin); + + impl_drop!(Foo: fn pin_drop(&pin mut self) { Drop::drop(todo!()) }); //~ ERROR explicit use of destructor method [E0040] + impl_drop!(Bar: fn pin_drop(&pin mut self) { Drop::drop(todo!()) }); //~ ERROR explicit use of destructor method [E0040] + //~^ ERROR implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + impl_drop!(Baz: fn pin_drop(&pin mut self) { Drop::drop(todo!()) }); //~ ERROR explicit use of destructor method [E0040] + //~^ ERROR implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/pinned-drop.stderr b/tests/ui/pin-ergonomics/pinned-drop.stderr new file mode 100644 index 0000000000000..1ccf3b4c2384f --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop.stderr @@ -0,0 +1,512 @@ +error[E0437]: type `Type` is not a member of trait `Drop` + --> $DIR/pinned-drop.rs:140:9 + | +LL | type Type = (); + | ^^^^^^^^^^^^^^^ not a member of trait `Drop` + +error[E0438]: const `N` is not a member of trait `Drop` + --> $DIR/pinned-drop.rs:141:9 + | +LL | const N: usize = 0; + | ^^^^^^^^^^^^^^^^^^^ not a member of trait `Drop` + +error[E0407]: method `foo` is not a member of trait `Drop` + --> $DIR/pinned-drop.rs:142:9 + | +LL | fn foo() {} + | ^^^^^^^^^^^ not a member of trait `Drop` + +error[E0437]: type `Type` is not a member of trait `Drop` + --> $DIR/pinned-drop.rs:146:9 + | +LL | type Type = (); + | ^^^^^^^^^^^^^^^ not a member of trait `Drop` + +error[E0438]: const `N` is not a member of trait `Drop` + --> $DIR/pinned-drop.rs:147:9 + | +LL | const N: usize = 0; + | ^^^^^^^^^^^^^^^^^^^ not a member of trait `Drop` + +error[E0407]: method `foo` is not a member of trait `Drop` + --> $DIR/pinned-drop.rs:148:9 + | +LL | fn foo() {} + | ^^^^^^^^^^^ not a member of trait `Drop` + +error[E0437]: type `Type` is not a member of trait `Drop` + --> $DIR/pinned-drop.rs:152:9 + | +LL | type Type = (); + | ^^^^^^^^^^^^^^^ not a member of trait `Drop` + +error[E0438]: const `N` is not a member of trait `Drop` + --> $DIR/pinned-drop.rs:153:9 + | +LL | const N: usize = 0; + | ^^^^^^^^^^^^^^^^^^^ not a member of trait `Drop` + +error[E0407]: method `foo` is not a member of trait `Drop` + --> $DIR/pinned-drop.rs:154:9 + | +LL | fn foo() {} + | ^^^^^^^^^^^ not a member of trait `Drop` + +error: could not impl `Drop::drop(&mut self)` for a type that implements `!Unpin` + --> $DIR/pinned-drop.rs:35:25 + | +LL | impl_drop!(Foo: fn drop(&mut self) {}); + | ^^^^^^^^^^^^^^^^^^ help: consider implement `Drop::pin_drop(&pin mut self)` instead + | + = help: `impl !Unpin` is intended for pinned projections, which requires the value pinned until it's deallocated +note: `Unpin` implemented for `drop::mut_self::Foo` + --> $DIR/pinned-drop.rs:8:9 + | +LL | impl !Unpin for $name {} + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | def!(Foo: !Unpin); + | ----------------- in this macro invocation + = note: this error originates in the macro `def` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: could not impl `Drop::drop(&mut self)` for a type that implements `!Unpin` + --> $DIR/pinned-drop.rs:47:25 + | +LL | impl_drop!(Foo: fn drop(self: Pin<&mut Self>) {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider implement `Drop::pin_drop(&pin mut self)` instead + | + = help: `impl !Unpin` is intended for pinned projections, which requires the value pinned until it's deallocated +note: `Unpin` implemented for `drop::pin_mut_self::Foo` + --> $DIR/pinned-drop.rs:8:9 + | +LL | impl !Unpin for $name {} + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | def!(Foo: !Unpin); + | ----------------- in this macro invocation + = note: this error originates in the macro `def` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop.rs:47:39 + | +LL | impl_drop!(Foo: fn drop(self: Pin<&mut Self>) {}); + | ^^^^^^^^^^^^^^ expected `&mut drop::pin_mut_self::Foo`, found `Pin<&mut drop::pin_mut_self::Foo>` + | + = note: expected signature `fn(&mut drop::pin_mut_self::Foo)` + found signature `fn(Pin<&mut drop::pin_mut_self::Foo>)` +help: change the self-receiver type to match the trait + | +LL - impl_drop!(Foo: fn drop(self: Pin<&mut Self>) {}); +LL + impl_drop!(Foo: fn drop(&mut self) {}); + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop.rs:49:39 + | +LL | impl_drop!(Bar: fn drop(self: Pin<&mut Self>) {}); + | ^^^^^^^^^^^^^^ expected `&mut drop::pin_mut_self::Bar`, found `Pin<&mut drop::pin_mut_self::Bar>` + | + = note: expected signature `fn(&mut drop::pin_mut_self::Bar)` + found signature `fn(Pin<&mut drop::pin_mut_self::Bar>)` +help: change the self-receiver type to match the trait + | +LL - impl_drop!(Bar: fn drop(self: Pin<&mut Self>) {}); +LL + impl_drop!(Bar: fn drop(&mut self) {}); + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop.rs:50:39 + | +LL | impl_drop!(Baz: fn drop(self: Pin<&mut Self>) {}); + | ^^^^^^^^^^^^^^ expected `&mut drop::pin_mut_self::Baz`, found `Pin<&mut drop::pin_mut_self::Baz>` + | + = note: expected signature `fn(&mut drop::pin_mut_self::Baz)` + found signature `fn(Pin<&mut drop::pin_mut_self::Baz>)` +help: change the self-receiver type to match the trait + | +LL - impl_drop!(Baz: fn drop(self: Pin<&mut Self>) {}); +LL + impl_drop!(Baz: fn drop(&mut self) {}); + | + +error: could not impl `Drop::drop(&mut self)` for a type that implements `!Unpin` + --> $DIR/pinned-drop.rs:58:25 + | +LL | impl_drop!(Foo: fn drop(&pin mut self) {}); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider implement `Drop::pin_drop(&pin mut self)` instead + | + = help: `impl !Unpin` is intended for pinned projections, which requires the value pinned until it's deallocated +note: `Unpin` implemented for `drop::pin_mut_self_sugar::Foo` + --> $DIR/pinned-drop.rs:8:9 + | +LL | impl !Unpin for $name {} + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | def!(Foo: !Unpin); + | ----------------- in this macro invocation + = note: this error originates in the macro `def` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop.rs:58:33 + | +LL | impl_drop!(Foo: fn drop(&pin mut self) {}); + | ^^^^^^^^^^^^^ expected `&mut drop::pin_mut_self_sugar::Foo`, found `Pin<&mut drop::pin_mut_self_sugar::Foo>` + | + = note: expected signature `fn(&mut drop::pin_mut_self_sugar::Foo)` + found signature `fn(Pin<&mut drop::pin_mut_self_sugar::Foo>)` +help: change the self-receiver type to match the trait + | +LL - impl_drop!(Foo: fn drop(&pin mut self) {}); +LL + impl_drop!(Foo: fn drop(&mut self) {}); + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop.rs:60:33 + | +LL | impl_drop!(Bar: fn drop(&pin mut self) {}); + | ^^^^^^^^^^^^^ expected `&mut drop::pin_mut_self_sugar::Bar`, found `Pin<&mut drop::pin_mut_self_sugar::Bar>` + | + = note: expected signature `fn(&mut drop::pin_mut_self_sugar::Bar)` + found signature `fn(Pin<&mut drop::pin_mut_self_sugar::Bar>)` +help: change the self-receiver type to match the trait + | +LL - impl_drop!(Bar: fn drop(&pin mut self) {}); +LL + impl_drop!(Bar: fn drop(&mut self) {}); + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop.rs:61:33 + | +LL | impl_drop!(Baz: fn drop(&pin mut self) {}); + | ^^^^^^^^^^^^^ expected `&mut drop::pin_mut_self_sugar::Baz`, found `Pin<&mut drop::pin_mut_self_sugar::Baz>` + | + = note: expected signature `fn(&mut drop::pin_mut_self_sugar::Baz)` + found signature `fn(Pin<&mut drop::pin_mut_self_sugar::Baz>)` +help: change the self-receiver type to match the trait + | +LL - impl_drop!(Baz: fn drop(&pin mut self) {}); +LL + impl_drop!(Baz: fn drop(&mut self) {}); + | + +error: implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + --> $DIR/pinned-drop.rs:72:25 + | +LL | impl_drop!(Bar: fn pin_drop(&mut self) {}); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: impl `Drop::drop(&mut self)` instead + | +LL - impl_drop!(Bar: fn pin_drop(&mut self) {}); +LL + impl_drop!(Bar: fn drop(&mut self) {}); + | +help: or impl `!Unpin` for `pin_drop::mut_self::Bar` instead + | +LL + impl !Unpin for pin_drop::mut_self::Bar` + | + +error: implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + --> $DIR/pinned-drop.rs:74:25 + | +LL | impl_drop!(Baz: fn pin_drop(&mut self) {}); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: impl `Drop::drop(&mut self)` instead + | +LL - impl_drop!(Baz: fn pin_drop(&mut self) {}); +LL + impl_drop!(Baz: fn drop(&mut self) {}); + | +help: or impl `!Unpin` for `pin_drop::mut_self::Baz` instead + | +LL + impl !Unpin for pin_drop::mut_self::Baz` + | + +error[E0053]: method `pin_drop` has an incompatible type for trait + --> $DIR/pinned-drop.rs:71:37 + | +LL | impl_drop!(Foo: fn pin_drop(&mut self) {}); + | ^^^^^^^^^ expected `Pin<&mut pin_drop::mut_self::Foo>`, found `&mut pin_drop::mut_self::Foo` + | + = note: expected signature `fn(Pin<&mut pin_drop::mut_self::Foo>)` + found signature `fn(&mut pin_drop::mut_self::Foo)` +help: change the self-receiver type to match the trait + | +LL - impl_drop!(Foo: fn pin_drop(&mut self) {}); +LL + impl_drop!(Foo: fn pin_drop(self: Pin<&mut pin_drop::mut_self::Foo>) {}); + | + +error[E0053]: method `pin_drop` has an incompatible type for trait + --> $DIR/pinned-drop.rs:72:37 + | +LL | impl_drop!(Bar: fn pin_drop(&mut self) {}); + | ^^^^^^^^^ expected `Pin<&mut pin_drop::mut_self::Bar>`, found `&mut pin_drop::mut_self::Bar` + | + = note: expected signature `fn(Pin<&mut pin_drop::mut_self::Bar>)` + found signature `fn(&mut pin_drop::mut_self::Bar)` +help: change the self-receiver type to match the trait + | +LL - impl_drop!(Bar: fn pin_drop(&mut self) {}); +LL + impl_drop!(Bar: fn pin_drop(self: Pin<&mut pin_drop::mut_self::Bar>) {}); + | + +error[E0053]: method `pin_drop` has an incompatible type for trait + --> $DIR/pinned-drop.rs:74:37 + | +LL | impl_drop!(Baz: fn pin_drop(&mut self) {}); + | ^^^^^^^^^ expected `Pin<&mut pin_drop::mut_self::Baz>`, found `&mut pin_drop::mut_self::Baz` + | + = note: expected signature `fn(Pin<&mut pin_drop::mut_self::Baz>)` + found signature `fn(&mut pin_drop::mut_self::Baz)` +help: change the self-receiver type to match the trait + | +LL - impl_drop!(Baz: fn pin_drop(&mut self) {}); +LL + impl_drop!(Baz: fn pin_drop(self: Pin<&mut pin_drop::mut_self::Baz>) {}); + | + +error: implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + --> $DIR/pinned-drop.rs:86:25 + | +LL | ... impl_drop!(Bar: fn pin_drop(self: Pin<&mut Self>) {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: impl `Drop::drop(&mut self)` instead + | +LL - impl_drop!(Bar: fn pin_drop(self: Pin<&mut Self>) {}); +LL + impl_drop!(Bar: fn drop(&mut self) {}); + | +help: or impl `!Unpin` for `pin_drop::pin_mut_self::Bar` instead + | +LL + impl !Unpin for pin_drop::pin_mut_self::Bar` + | + +error: implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + --> $DIR/pinned-drop.rs:87:25 + | +LL | ... impl_drop!(Baz: fn pin_drop(self: Pin<&mut Self>) {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: impl `Drop::drop(&mut self)` instead + | +LL - impl_drop!(Baz: fn pin_drop(self: Pin<&mut Self>) {}); +LL + impl_drop!(Baz: fn drop(&mut self) {}); + | +help: or impl `!Unpin` for `pin_drop::pin_mut_self::Baz` instead + | +LL + impl !Unpin for pin_drop::pin_mut_self::Baz` + | + +error: implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + --> $DIR/pinned-drop.rs:96:25 + | +LL | impl_drop!(Bar: fn pin_drop(&pin mut self) {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: impl `Drop::drop(&mut self)` instead + | +LL - impl_drop!(Bar: fn pin_drop(&pin mut self) {}); +LL + impl_drop!(Bar: fn drop(&mut self) {}); + | +help: or impl `!Unpin` for `pin_drop::pin_mut_self_sugar::Bar` instead + | +LL + impl !Unpin for pin_drop::pin_mut_self_sugar::Bar` + | + +error: implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + --> $DIR/pinned-drop.rs:97:25 + | +LL | impl_drop!(Baz: fn pin_drop(&pin mut self) {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: impl `Drop::drop(&mut self)` instead + | +LL - impl_drop!(Baz: fn pin_drop(&pin mut self) {}); +LL + impl_drop!(Baz: fn drop(&mut self) {}); + | +help: or impl `!Unpin` for `pin_drop::pin_mut_self_sugar::Baz` instead + | +LL + impl !Unpin for pin_drop::pin_mut_self_sugar::Baz` + | + +error: conflict implementation of `Drop::drop` and `Drop::pin_drop` + --> $DIR/pinned-drop.rs:106:5 + | +LL | impl Drop for Foo { + | ^^^^^^^^^^^^^^^^^ +LL | +LL | fn drop(&mut self) {} + | --------------------- + | | + | `drop(&mut self)` implemented here + | help: remove this implementation +LL | fn pin_drop(&pin mut self) {} + | -------------------------- `pin_drop(&pin mut self)` implemented here + +error: conflict implementation of `Drop::drop` and `Drop::pin_drop` + --> $DIR/pinned-drop.rs:111:5 + | +LL | impl Drop for Bar { + | ^^^^^^^^^^^^^^^^^ +LL | +LL | fn drop(&mut self) {} + | ------------------ `drop(&mut self)` implemented here +LL | fn pin_drop(&pin mut self) {} + | ----------------------------- + | | + | `pin_drop(&pin mut self)` implemented here + | help: remove this implementation + +error: conflict implementation of `Drop::drop` and `Drop::pin_drop` + --> $DIR/pinned-drop.rs:116:5 + | +LL | impl Drop for Baz { + | ^^^^^^^^^^^^^^^^^ +LL | +LL | fn drop(&mut self) {} + | ------------------ `drop(&mut self)` implemented here +LL | fn pin_drop(&pin mut self) {} + | ----------------------------- + | | + | `pin_drop(&pin mut self)` implemented here + | help: remove this implementation + +error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop` + --> $DIR/pinned-drop.rs:128:5 + | +LL | impl Drop for Foo {} + | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation + +error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop` + --> $DIR/pinned-drop.rs:129:5 + | +LL | impl Drop for Bar {} + | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation + +error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop` + --> $DIR/pinned-drop.rs:130:5 + | +LL | impl Drop for Baz {} + | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation + +error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop` + --> $DIR/pinned-drop.rs:138:5 + | +LL | impl Drop for Foo { + | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation + +error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop` + --> $DIR/pinned-drop.rs:144:5 + | +LL | impl Drop for Bar { + | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation + +error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop` + --> $DIR/pinned-drop.rs:150:5 + | +LL | impl Drop for Baz { + | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation + +error: could not impl `Drop::drop(&mut self)` for a type that implements `!Unpin` + --> $DIR/pinned-drop.rs:163:21 + | +LL | impl_drop!(Foo: fn drop(&mut self) { Drop::pin_drop(todo!()) }); + | ^^^^^^^^^^^^^^^^^^ help: consider implement `Drop::pin_drop(&pin mut self)` instead + | + = help: `impl !Unpin` is intended for pinned projections, which requires the value pinned until it's deallocated +note: `Unpin` implemented for `explicit_call_pin_drop::Foo` + --> $DIR/pinned-drop.rs:8:9 + | +LL | impl !Unpin for $name {} + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | def!(Foo: !Unpin); + | ----------------- in this macro invocation + = note: this error originates in the macro `def` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + --> $DIR/pinned-drop.rs:175:21 + | +LL | impl_drop!(Bar: fn pin_drop(&pin mut self) { Drop::drop(todo!()) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: impl `Drop::drop(&mut self)` instead + | +LL - impl_drop!(Bar: fn pin_drop(&pin mut self) { Drop::drop(todo!()) }); +LL + impl_drop!(Bar: fn drop(&mut self) { Drop::drop(todo!()) }); + | +help: or impl `!Unpin` for `explicit_call_drop::Bar` instead + | +LL + impl !Unpin for explicit_call_drop::Bar` + | + +error: implementing `Drop::pin_drop(&pin mut self)` requires `Self: !Unpin` + --> $DIR/pinned-drop.rs:177:21 + | +LL | impl_drop!(Baz: fn pin_drop(&pin mut self) { Drop::drop(todo!()) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: impl `Drop::drop(&mut self)` instead + | +LL - impl_drop!(Baz: fn pin_drop(&pin mut self) { Drop::drop(todo!()) }); +LL + impl_drop!(Baz: fn drop(&mut self) { Drop::drop(todo!()) }); + | +help: or impl `!Unpin` for `explicit_call_drop::Baz` instead + | +LL + impl !Unpin for explicit_call_drop::Baz` + | + +error[E0040]: explicit use of destructor method + --> $DIR/pinned-drop.rs:163:42 + | +LL | impl_drop!(Foo: fn drop(&mut self) { Drop::pin_drop(todo!()) }); + | ^^^^^^^^^^^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop` + +error[E0040]: explicit use of destructor method + --> $DIR/pinned-drop.rs:165:42 + | +LL | impl_drop!(Bar: fn drop(&mut self) { Drop::pin_drop(todo!()) }); + | ^^^^^^^^^^^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop` + +error[E0040]: explicit use of destructor method + --> $DIR/pinned-drop.rs:166:42 + | +LL | impl_drop!(Baz: fn drop(&mut self) { Drop::pin_drop(todo!()) }); + | ^^^^^^^^^^^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop` + +error[E0040]: explicit use of destructor method + --> $DIR/pinned-drop.rs:174:50 + | +LL | impl_drop!(Foo: fn pin_drop(&pin mut self) { Drop::drop(todo!()) }); + | ^^^^^^^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop` + +error[E0040]: explicit use of destructor method + --> $DIR/pinned-drop.rs:175:50 + | +LL | impl_drop!(Bar: fn pin_drop(&pin mut self) { Drop::drop(todo!()) }); + | ^^^^^^^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop` + +error[E0040]: explicit use of destructor method + --> $DIR/pinned-drop.rs:177:50 + | +LL | impl_drop!(Baz: fn pin_drop(&pin mut self) { Drop::drop(todo!()) }); + | ^^^^^^^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop` + +error: aborting due to 45 previous errors + +Some errors have detailed explanations: E0040, E0046, E0053, E0407, E0437, E0438. +For more information about an error, try `rustc --explain E0040`.