diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index a313b91ef9bda..e36302124f63f 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -116,6 +116,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` @@ -441,6 +446,13 @@ hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a t hir_analysis_parenthesized_fn_trait_expansion = parenthesized trait syntax expands to `{$expanded_type}` +hir_analysis_pin_v2_without_pin_drop = + `{$adt_name}` must implement `pin_drop` + .note = `{$adt_name}` is marked `#[pin_v2]` here + .help = structurally pinned types must keep `Pin`'s safety contract + .pin_drop_sugg = implement `pin_drop` instead + .remove_pin_v2_sugg = remove the `#[pin_v2]` attribute if it is not intended for structurally pinning + hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind} .label = not allowed in type signatures diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index f39d1b7af345a..d3a93e6e4cd97 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::sym; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -70,7 +72,11 @@ pub(crate) fn check_drop_impl( drop_impl_did, adt_def.did(), adt_to_impl_args, - ) + )?; + + check_drop_xor_pin_drop(tcx, adt_def.did(), drop_impl_did)?; + + Ok(()) } _ => { span_bug!(tcx.def_span(drop_impl_did), "incoherent impl of Drop"); @@ -291,3 +297,68 @@ fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>( Ok(()) } + +/// This function checks at least and at most one of `Drop::drop` and `Drop::pin_drop` is implemented. +/// It also checks that `Drop::pin_drop` must be implemented if `#[pin_v2]` is present on the type. +fn check_drop_xor_pin_drop<'tcx>( + tcx: TyCtxt<'tcx>, + adt_def_id: DefId, + drop_impl_did: LocalDefId, +) -> Result<(), ErrorGuaranteed> { + let item_impl = tcx.hir_expect_item(drop_impl_did).expect_impl(); + let mut drop_span = None; + let mut pin_drop_span = 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_span = Some(fn_sig.span), + sym::pin_drop => pin_drop_span = Some(fn_sig.span), + _ => {} + } + } + } + + match (drop_span, pin_drop_span) { + (None, None) => { + if tcx.features().pin_ergonomics() { + return Err(tcx.dcx().emit_err(crate::errors::MissingOneOfTraitItem { + span: tcx.def_span(drop_impl_did), + note: None, + missing_items_msg: "drop`, `pin_drop".to_string(), + })); + } else { + return Err(tcx + .dcx() + .span_delayed_bug(tcx.def_span(drop_impl_did), "missing `Drop::drop`")); + } + } + (Some(span), None) => { + if tcx.adt_def(adt_def_id).is_pin_project() { + let pin_v2_span = tcx.get_attr(adt_def_id, sym::pin_v2).map(|attr| attr.span()); + let adt_name = tcx.item_name(adt_def_id); + return Err(tcx.dcx().emit_err(crate::errors::PinV2WithoutPinDrop { + span, + pin_v2_span, + adt_name, + })); + } + } + (None, Some(span)) => { + if !tcx.features().pin_ergonomics() { + return Err(tcx.dcx().span_delayed_bug( + span, + "`Drop::pin_drop` should be guarded by the library feature gate", + )); + } + } + (Some(drop_span), Some(pin_drop_span)) => { + return Err(tcx.dcx().emit_err(crate::errors::ConflictImplDropAndPinDrop { + span: tcx.def_span(drop_impl_did), + drop_span, + pin_drop_span, + })); + } + } + Ok(()) +} diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 1e12adbbfc6e0..4738c655b638e 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -24,6 +24,7 @@ use rustc_middle::ty::{ TypeVisitable, TypeVisitableExt, fold_regions, }; use rustc_session::lint::builtin::UNINHABITED_STATIC; +use rustc_span::sym; use rustc_target::spec::{AbiMap, AbiMapping}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index f1c84a14de306..861fb4cb34c20 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -92,7 +92,7 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _; use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index dbad98fd79528..619e55ecedb84 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1718,3 +1718,31 @@ pub(crate) struct AsyncDropWithoutSyncDrop { #[primary_span] pub span: Span, } + +#[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, +} + +#[derive(Diagnostic)] +#[diag(hir_analysis_pin_v2_without_pin_drop)] +#[help] +pub(crate) struct PinV2WithoutPinDrop { + #[primary_span] + #[suggestion( + hir_analysis_pin_drop_sugg, + code = "fn pin_drop(&pin mut self)", + applicability = "maybe-incorrect" + )] + pub span: Span, + #[note] + #[suggestion(hir_analysis_remove_pin_v2_sugg, code = "", applicability = "maybe-incorrect")] + pub pin_v2_span: Option, + pub adt_name: Symbol, +} diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index f59fcab46661f..5d01ebb04961e 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -37,9 +37,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 38718bad9e57e..7c5082393c03c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1682,6 +1682,7 @@ symbols! { pic, pie, pin, + pin_drop, pin_ergonomics, pin_macro, pin_v2, diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index 7125bf54701bb..22eb404036d82 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. @@ -237,5 +239,30 @@ pub const 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); + #[rustc_default_body_unstable(feature = "pin_ergonomics", issue = "130494")] + 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. + /// + /// For types that support pin-projection (i.e., marked with `#[pin_v2]`), this method must be used. + /// + /// For any type, at least and at most one of [`Drop::drop`] and [`Drop::pin_drop`] should be + /// implemented. + /// + /// See also [`Drop::drop`] for more details. + /// + /// [`Drop::drop`]: crate::ops::Drop::drop + /// [`Drop::pin_drop`]: crate::ops::Drop::pin_drop + /// [`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/src/doc/book b/src/doc/book index f660f341887c8..61b49a3b68bb8 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit f660f341887c8bbcd6c24fbfdf5d2a262f523965 +Subproject commit 61b49a3b68bb8df752289b2b286025743f7b98a6 diff --git a/tests/codegen-units/item-collection/drop-glue-eager.rs b/tests/codegen-units/item-collection/drop-glue-eager.rs index cc0ea701e66f3..9c768692bb8f6 100644 --- a/tests/codegen-units/item-collection/drop-glue-eager.rs +++ b/tests/codegen-units/item-collection/drop-glue-eager.rs @@ -10,6 +10,7 @@ struct StructWithDrop { impl Drop for StructWithDrop { //~ MONO_ITEM fn ::drop + //~ MONO_ITEM fn ::pin_drop fn drop(&mut self) {} } @@ -24,6 +25,7 @@ enum EnumWithDrop { impl Drop for EnumWithDrop { //~ MONO_ITEM fn ::drop + //~ MONO_ITEM fn ::pin_drop fn drop(&mut self) {} } @@ -34,6 +36,7 @@ enum EnumNoDrop { // We should be able to monomorphize drops for struct with lifetimes. impl<'a> Drop for StructWithDropAndLt<'a> { //~ MONO_ITEM fn as std::ops::Drop>::drop + //~ MONO_ITEM fn as std::ops::Drop>::pin_drop fn drop(&mut self) {} } @@ -52,5 +55,6 @@ struct StructWithLtAndPredicate<'a: 'a> { // We should be able to monomorphize drops for struct with lifetimes. impl<'a> Drop for StructWithLtAndPredicate<'a> { //~ MONO_ITEM fn as std::ops::Drop>::drop + //~ MONO_ITEM fn as std::ops::Drop>::pin_drop fn drop(&mut self) {} } diff --git a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs index ef8f916539395..00fe4c3413a29 100644 --- a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs +++ b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs @@ -9,6 +9,7 @@ struct StructWithDtor(u32); impl Drop for StructWithDtor { //~ MONO_ITEM fn ::drop + //~ MONO_ITEM fn ::pin_drop fn drop(&mut self) {} } diff --git a/tests/codegen-units/item-collection/generic-drop-glue.rs b/tests/codegen-units/item-collection/generic-drop-glue.rs index b4c6c231e3d62..7b7d536938f2d 100644 --- a/tests/codegen-units/item-collection/generic-drop-glue.rs +++ b/tests/codegen-units/item-collection/generic-drop-glue.rs @@ -39,6 +39,7 @@ struct NonGenericWithDrop(#[allow(dead_code)] i32); impl Drop for NonGenericWithDrop { //~ MONO_ITEM fn ::drop + //~ MONO_ITEM fn ::pin_drop fn drop(&mut self) {} } diff --git a/tests/codegen-units/item-collection/non-generic-closures.rs b/tests/codegen-units/item-collection/non-generic-closures.rs index 2d9c461e6fd2d..cba53e6905882 100644 --- a/tests/codegen-units/item-collection/non-generic-closures.rs +++ b/tests/codegen-units/item-collection/non-generic-closures.rs @@ -74,5 +74,6 @@ struct PresentDrop; impl Drop for PresentDrop { //~ MONO_ITEM fn ::drop @@ non_generic_closures-cgu.0[External] + //~ MONO_ITEM fn ::pin_drop @@ non_generic_closures-cgu.0[External] fn drop(&mut self) {} } diff --git a/tests/codegen-units/item-collection/non-generic-drop-glue.rs b/tests/codegen-units/item-collection/non-generic-drop-glue.rs index d83336f4d78d9..4722374fcad4c 100644 --- a/tests/codegen-units/item-collection/non-generic-drop-glue.rs +++ b/tests/codegen-units/item-collection/non-generic-drop-glue.rs @@ -11,6 +11,7 @@ struct StructWithDrop { impl Drop for StructWithDrop { //~ MONO_ITEM fn ::drop + //~ MONO_ITEM fn ::pin_drop fn drop(&mut self) {} } @@ -25,6 +26,7 @@ enum EnumWithDrop { impl Drop for EnumWithDrop { //~ MONO_ITEM fn ::drop + //~ MONO_ITEM fn ::pin_drop fn drop(&mut self) {} } diff --git a/tests/codegen-units/item-collection/transitive-drop-glue.rs b/tests/codegen-units/item-collection/transitive-drop-glue.rs index 844d74526f413..914a47348a7d0 100644 --- a/tests/codegen-units/item-collection/transitive-drop-glue.rs +++ b/tests/codegen-units/item-collection/transitive-drop-glue.rs @@ -13,6 +13,7 @@ struct Leaf; impl Drop for Leaf { //~ MONO_ITEM fn ::drop + //~ MONO_ITEM fn ::pin_drop fn drop(&mut self) {} } diff --git a/tests/codegen-units/item-collection/tuple-drop-glue.rs b/tests/codegen-units/item-collection/tuple-drop-glue.rs index 4380735597a4e..8482b997d8355 100644 --- a/tests/codegen-units/item-collection/tuple-drop-glue.rs +++ b/tests/codegen-units/item-collection/tuple-drop-glue.rs @@ -9,6 +9,7 @@ struct Dropped; impl Drop for Dropped { //~ MONO_ITEM fn ::drop + //~ MONO_ITEM fn ::pin_drop fn drop(&mut self) {} } diff --git a/tests/ui/async-await/async-drop/unexpected-sort.stderr b/tests/ui/async-await/async-drop/unexpected-sort.stderr index a6e4f9fd57307..9cf2f016f977f 100644 --- a/tests/ui/async-await/async-drop/unexpected-sort.stderr +++ b/tests/ui/async-await/async-drop/unexpected-sort.stderr @@ -13,10 +13,16 @@ LL | type c = (); error[E0046]: not all trait items implemented, missing: `drop` --> $DIR/unexpected-sort.rs:9:1 | -LL | impl Drop for a { - | ^^^^^^^^^^^^^^^ missing `drop` in implementation +LL | / impl Drop for a { +LL | | fn b() {} +LL | | } + | |_^ | - = help: implement the missing item: `fn drop(&mut self) { todo!() }` + = note: default implementation of `drop` is unstable + = note: use of unstable library feature `pin_ergonomics` + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0046]: not all trait items implemented, missing: `drop` --> $DIR/unexpected-sort.rs:12:1 diff --git a/tests/ui/drop/missing-drop-method.stderr b/tests/ui/drop/missing-drop-method.stderr index 1128f33e627b3..64d06ac289266 100644 --- a/tests/ui/drop/missing-drop-method.stderr +++ b/tests/ui/drop/missing-drop-method.stderr @@ -2,9 +2,13 @@ error[E0046]: not all trait items implemented, missing: `drop` --> $DIR/missing-drop-method.rs:2:1 | LL | impl Drop for DropNoMethod {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: implement the missing item: `fn drop(&mut self) { todo!() }` + = note: default implementation of `drop` is unstable + = note: use of unstable library feature `pin_ergonomics` + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 1 previous error diff --git a/tests/ui/drop/nonsense-drop-impl-issue-139278.stderr b/tests/ui/drop/nonsense-drop-impl-issue-139278.stderr index 825e883fa6d8a..eeecc3e854805 100644 --- a/tests/ui/drop/nonsense-drop-impl-issue-139278.stderr +++ b/tests/ui/drop/nonsense-drop-impl-issue-139278.stderr @@ -7,10 +7,16 @@ LL | const SPLOK: u32 = 0; error[E0046]: not all trait items implemented, missing: `drop` --> $DIR/nonsense-drop-impl-issue-139278.rs:4:1 | -LL | impl Drop for Foo { - | ^^^^^^^^^^^^^^^^^ missing `drop` in implementation +LL | / impl Drop for Foo { +LL | | const SPLOK: u32 = 0; +LL | | } + | |_^ | - = help: implement the missing item: `fn drop(&mut self) { todo!() }` + = note: default implementation of `drop` is unstable + = note: use of unstable library feature `pin_ergonomics` + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 2 previous errors diff --git a/tests/ui/dropck/unconstrained_const_param_on_drop.stderr b/tests/ui/dropck/unconstrained_const_param_on_drop.stderr index 515637dd47fc3..ebdebb344549d 100644 --- a/tests/ui/dropck/unconstrained_const_param_on_drop.stderr +++ b/tests/ui/dropck/unconstrained_const_param_on_drop.stderr @@ -14,9 +14,13 @@ error[E0046]: not all trait items implemented, missing: `drop` --> $DIR/unconstrained_const_param_on_drop.rs:3:1 | LL | impl Drop for Foo {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `drop` in implementation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: implement the missing item: `fn drop(&mut self) { todo!() }` + = note: default implementation of `drop` is unstable + = note: use of unstable library feature `pin_ergonomics` + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0207]: the const parameter `UNUSED` is not constrained by the impl trait, self type, or predicates --> $DIR/unconstrained_const_param_on_drop.rs:3:6 diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs index 07aba0d1d2815..90d3b6bd1a776 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -11,6 +11,12 @@ impl Foo { fn foo_sugar_const(&pin const self) {} //~ ERROR pinned reference syntax is experimental } +impl Drop for Foo { + //~^ ERROR not all trait items implemented, missing: `drop` + fn pin_drop(&pin mut self) {} //~ ERROR pinned reference syntax is experimental + //~^ ERROR use of unstable library feature `pin_ergonomics` [E0658] +} + fn foo(mut x: Pin<&mut Foo>) { Foo::foo_sugar(x.as_mut()); Foo::foo_sugar_const(x.as_ref()); @@ -60,6 +66,10 @@ mod not_compiled { fn foo_sugar_const(&pin const self) {} //~ ERROR pinned reference syntax is experimental } + impl Drop for Foo { + fn pin_drop(&pin mut self) {} //~ ERROR pinned reference syntax is experimental + } + fn foo(mut x: Pin<&mut Foo>) { Foo::foo_sugar(x.as_mut()); Foo::foo_sugar_const(x.as_ref()); diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr index cff564c01fc6b..a01f1b72b6215 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr @@ -19,7 +19,17 @@ LL | fn foo_sugar_const(&pin const self) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:17:14 + --> $DIR/feature-gate-pin_ergonomics.rs:16:18 + | +LL | fn pin_drop(&pin mut self) {} + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:23:14 | LL | let _y: &pin mut Foo = x; | ^^^ @@ -29,7 +39,7 @@ LL | let _y: &pin mut Foo = x; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:21:14 + --> $DIR/feature-gate-pin_ergonomics.rs:27:14 | LL | let _y: &pin const Foo = x; | ^^^ @@ -39,7 +49,7 @@ LL | let _y: &pin const Foo = x; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:24:18 + --> $DIR/feature-gate-pin_ergonomics.rs:30:18 | LL | fn foo_sugar(_: &pin mut Foo) {} | ^^^ @@ -49,7 +59,7 @@ LL | fn foo_sugar(_: &pin mut Foo) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:36:18 + --> $DIR/feature-gate-pin_ergonomics.rs:42:18 | LL | fn baz_sugar(_: &pin const Foo) {} | ^^^ @@ -59,7 +69,7 @@ LL | fn baz_sugar(_: &pin const Foo) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:39:31 + --> $DIR/feature-gate-pin_ergonomics.rs:45:31 | LL | let mut x: Pin<&mut _> = &pin mut Foo; | ^^^ @@ -69,7 +79,7 @@ LL | let mut x: Pin<&mut _> = &pin mut Foo; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:44:23 + --> $DIR/feature-gate-pin_ergonomics.rs:50:23 | LL | let x: Pin<&_> = &pin const Foo; | ^^^ @@ -79,7 +89,7 @@ LL | let x: Pin<&_> = &pin const Foo; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:59:23 + --> $DIR/feature-gate-pin_ergonomics.rs:65:23 | LL | fn foo_sugar(&pin mut self) {} | ^^^ @@ -89,7 +99,7 @@ LL | fn foo_sugar(&pin mut self) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:60:29 + --> $DIR/feature-gate-pin_ergonomics.rs:66:29 | LL | fn foo_sugar_const(&pin const self) {} | ^^^ @@ -99,7 +109,17 @@ LL | fn foo_sugar_const(&pin const self) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:66:18 + --> $DIR/feature-gate-pin_ergonomics.rs:70:22 + | +LL | fn pin_drop(&pin mut self) {} + | ^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:76:18 | LL | let _y: &pin mut Foo = x; | ^^^ @@ -109,7 +129,7 @@ LL | let _y: &pin mut Foo = x; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:69:22 + --> $DIR/feature-gate-pin_ergonomics.rs:79:22 | LL | fn foo_sugar(_: &pin mut Foo) {} | ^^^ @@ -119,7 +139,7 @@ LL | fn foo_sugar(_: &pin mut Foo) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:81:22 + --> $DIR/feature-gate-pin_ergonomics.rs:91:22 | LL | fn baz_sugar(_: &pin const Foo) {} | ^^^ @@ -129,7 +149,7 @@ LL | fn baz_sugar(_: &pin const Foo) {} = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:84:35 + --> $DIR/feature-gate-pin_ergonomics.rs:94:35 | LL | let mut x: Pin<&mut _> = &pin mut Foo; | ^^^ @@ -139,7 +159,7 @@ LL | let mut x: Pin<&mut _> = &pin mut Foo; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: pinned reference syntax is experimental - --> $DIR/feature-gate-pin_ergonomics.rs:89:27 + --> $DIR/feature-gate-pin_ergonomics.rs:99:27 | LL | let x: Pin<&_> = &pin const Foo; | ^^^ @@ -158,8 +178,34 @@ LL | #[pin_v2] = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: use of unstable library feature `pin_ergonomics` + --> $DIR/feature-gate-pin_ergonomics.rs:16:5 + | +LL | fn pin_drop(&pin mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0046]: not all trait items implemented, missing: `drop` + --> $DIR/feature-gate-pin_ergonomics.rs:14:1 + | +LL | / impl Drop for Foo { +LL | | +LL | | fn pin_drop(&pin mut self) {} +LL | | +LL | | } + | |_^ + | + = note: default implementation of `drop` is unstable + = note: use of unstable library feature `pin_ergonomics` + = note: see issue #130494 for more information + = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + error[E0382]: use of moved value: `x` - --> $DIR/feature-gate-pin_ergonomics.rs:28:9 + --> $DIR/feature-gate-pin_ergonomics.rs:34:9 | LL | fn bar(x: Pin<&mut Foo>) { | - move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait @@ -169,7 +215,7 @@ LL | foo(x); | ^ value used here after move | note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary - --> $DIR/feature-gate-pin_ergonomics.rs:14:15 + --> $DIR/feature-gate-pin_ergonomics.rs:20:15 | LL | fn foo(mut x: Pin<&mut Foo>) { | --- ^^^^^^^^^^^^^ this parameter takes ownership of the value @@ -177,7 +223,7 @@ LL | fn foo(mut x: Pin<&mut Foo>) { | in this function error[E0382]: use of moved value: `x` - --> $DIR/feature-gate-pin_ergonomics.rs:33:5 + --> $DIR/feature-gate-pin_ergonomics.rs:39:5 | LL | fn baz(mut x: Pin<&mut Foo>) { | ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait @@ -196,7 +242,7 @@ help: consider reborrowing the `Pin` instead of moving it LL | x.as_mut().foo(); | +++++++++ -error: aborting due to 18 previous errors +error: aborting due to 22 previous errors -Some errors have detailed explanations: E0382, E0658. -For more information about an error, try `rustc --explain E0382`. +Some errors have detailed explanations: E0046, E0382, E0658. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/pin-ergonomics/pinned-drop-check.rs b/tests/ui/pin-ergonomics/pinned-drop-check.rs new file mode 100644 index 0000000000000..d7ca489ad56ff --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-check.rs @@ -0,0 +1,127 @@ +//@ edition:2024 +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +// This test ensures that at least and at most one of `drop` and `pin_drop` +// are implemented for types that implement `Drop`. + +mod drop_only { + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn drop(&mut self) {} // ok, only `drop` is implemented + } + + impl Drop for Bar { + fn drop(&mut self) {} //~ ERROR `Bar` must implement `pin_drop` + } +} + +mod pin_drop_only { + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn pin_drop(&pin mut self) {} // ok, only `pin_drop` is implemented + } + + impl Drop for Bar { + fn pin_drop(&pin mut self) {} // ok, non-`#[pin_v2]` can also implement `pin_drop` + } +} + +mod both { + struct Foo; + #[pin_v2] + struct Bar; + + 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) {} + } +} + +mod neither { + struct Foo; + #[pin_v2] + struct Bar; + + 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] +} + +mod drop_wrong_type { + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn drop(&pin mut self) {} //~ ERROR method `drop` has an incompatible type for trait [E0053] + } + impl Drop for Bar { + fn drop(&pin mut self) {} + //~^ ERROR method `drop` has an incompatible type for trait [E0053] + //~| ERROR `Bar` must implement `pin_drop` + } +} + +mod pin_drop_wrong_type { + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn pin_drop(&mut self) {} //~ ERROR method `pin_drop` has an incompatible type for trait [E0053] + } + + impl Drop for Bar { + fn pin_drop(&mut self) {} //~ ERROR method `pin_drop` has an incompatible type for trait [E0053] + } +} + +mod explicit_call_pin_drop { + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn drop(&mut self) { + Drop::pin_drop(todo!()); //~ ERROR explicit use of destructor method [E0040] + } + } + impl Drop for Bar { + fn drop(&mut self) { + //~^ ERROR `Bar` must implement `pin_drop` + Drop::pin_drop(todo!()); //~ ERROR explicit use of destructor method [E0040] + } + } +} + +mod explicit_call_drop { + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn pin_drop(&pin mut self) { + Drop::drop(todo!()); //~ ERROR explicit use of destructor method [E0040] + } + } + impl Drop for Bar { + fn pin_drop(&pin mut self) { + Drop::drop(todo!()); //~ ERROR explicit use of destructor method [E0040] + } + } +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/pinned-drop-check.stderr b/tests/ui/pin-ergonomics/pinned-drop-check.stderr new file mode 100644 index 0000000000000..20a042bca0ff5 --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-check.stderr @@ -0,0 +1,154 @@ +error: `Bar` must implement `pin_drop` + --> $DIR/pinned-drop-check.rs:18:9 + | +LL | fn drop(&mut self) {} + | ^^^^^^^^^^^^^^^^^^ help: implement `pin_drop` instead: `fn pin_drop(&pin mut self)` + | + = help: structurally pinned types must keep `Pin`'s safety contract + +error: conflict implementation of `Drop::drop` and `Drop::pin_drop` + --> $DIR/pinned-drop-check.rs:41:5 + | +LL | impl Drop for Foo { + | ^^^^^^^^^^^^^^^^^ +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 + +error: conflict implementation of `Drop::drop` and `Drop::pin_drop` + --> $DIR/pinned-drop-check.rs:47: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 + +error[E0046]: not all trait items implemented, missing one of: `drop`, `pin_drop` + --> $DIR/pinned-drop-check.rs:59: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-check.rs:60:5 + | +LL | impl Drop for Bar {} + | ^^^^^^^^^^^^^^^^^ missing one of `drop`, `pin_drop` in implementation + +error: `Bar` must implement `pin_drop` + --> $DIR/pinned-drop-check.rs:72:9 + | +LL | fn drop(&pin mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^ help: implement `pin_drop` instead: `fn pin_drop(&pin mut self)` + | + = help: structurally pinned types must keep `Pin`'s safety contract + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:69:17 + | +LL | fn drop(&pin mut self) {} + | ^^^^^^^^^^^^^ expected `&mut drop_wrong_type::Foo`, found `Pin<&mut drop_wrong_type::Foo>` + | + = note: expected signature `fn(&mut drop_wrong_type::Foo)` + found signature `fn(Pin<&mut drop_wrong_type::Foo>)` +help: change the self-receiver type to match the trait + | +LL - fn drop(&pin mut self) {} +LL + fn drop(&mut self) {} + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:72:17 + | +LL | fn drop(&pin mut self) {} + | ^^^^^^^^^^^^^ expected `&mut drop_wrong_type::Bar`, found `Pin<&mut drop_wrong_type::Bar>` + | + = note: expected signature `fn(&mut drop_wrong_type::Bar)` + found signature `fn(Pin<&mut drop_wrong_type::Bar>)` +help: change the self-receiver type to match the trait + | +LL - fn drop(&pin mut self) {} +LL + fn drop(&mut self) {} + | + +error[E0053]: method `pin_drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:84:21 + | +LL | fn pin_drop(&mut self) {} + | ^^^^^^^^^ expected `Pin<&mut pin_drop_wrong_type::Foo>`, found `&mut pin_drop_wrong_type::Foo` + | + = note: expected signature `fn(Pin<&mut pin_drop_wrong_type::Foo>)` + found signature `fn(&mut pin_drop_wrong_type::Foo)` +help: change the self-receiver type to match the trait + | +LL - fn pin_drop(&mut self) {} +LL + fn pin_drop(self: Pin<&mut pin_drop_wrong_type::Foo>) {} + | + +error[E0053]: method `pin_drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:88:21 + | +LL | fn pin_drop(&mut self) {} + | ^^^^^^^^^ expected `Pin<&mut pin_drop_wrong_type::Bar>`, found `&mut pin_drop_wrong_type::Bar` + | + = note: expected signature `fn(Pin<&mut pin_drop_wrong_type::Bar>)` + found signature `fn(&mut pin_drop_wrong_type::Bar)` +help: change the self-receiver type to match the trait + | +LL - fn pin_drop(&mut self) {} +LL + fn pin_drop(self: Pin<&mut pin_drop_wrong_type::Bar>) {} + | + +error: `Bar` must implement `pin_drop` + --> $DIR/pinned-drop-check.rs:103:9 + | +LL | fn drop(&mut self) { + | ^^^^^^^^^^^^^^^^^^ help: implement `pin_drop` instead: `fn pin_drop(&pin mut self)` + | + = help: structurally pinned types must keep `Pin`'s safety contract + +error[E0040]: explicit use of destructor method + --> $DIR/pinned-drop-check.rs:99:13 + | +LL | 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-check.rs:105:13 + | +LL | 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-check.rs:117:13 + | +LL | Drop::drop(todo!()); + | ^^^^^^^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop` + +error[E0040]: explicit use of destructor method + --> $DIR/pinned-drop-check.rs:122:13 + | +LL | Drop::drop(todo!()); + | ^^^^^^^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop` + +error: aborting due to 15 previous errors + +Some errors have detailed explanations: E0040, E0046, E0053. +For more information about an error, try `rustc --explain E0040`. diff --git a/tests/ui/pin-ergonomics/pinned-drop.rs b/tests/ui/pin-ergonomics/pinned-drop.rs new file mode 100644 index 0000000000000..482cf22cdc1b2 --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop.rs @@ -0,0 +1,52 @@ +//@ run-pass +//@ edition:2024 +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +use std::pin::Pin; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::task::{Context, Poll, Waker}; + +#[pin_v2] +struct Foo { + dropped: Arc, +} + +impl Foo { + fn new(dropped: Arc) -> Self { + Self { dropped } + } +} + +impl Drop for Foo { + fn pin_drop(self: Pin<&mut Self>) { + self.dropped.store(true, Ordering::Relaxed); + } +} + +impl Future for Foo { + type Output = (); + + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + Poll::Ready(()) + } +} + +fn block_on>(mut f: F) -> T { + let waker = Waker::noop(); + let mut cx = Context::from_waker(waker); + + let f = &pin mut f; + loop { + if let Poll::Ready(ret) = f.poll(&mut cx) { + break ret; + } + } +} + +fn main() { + let dropped = Arc::new(AtomicBool::new(false)); + block_on(Foo::new(dropped.clone())); + assert!(dropped.load(Ordering::Relaxed)); +}