diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index a313b91ef9bda..36bcb1f369a93 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 = conflicting implementations 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..cc5d302dc6ec4 100644 --- a/compiler/rustc_hir_analysis/src/check/always_applicable.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -12,6 +12,7 @@ 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 +71,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 +296,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 mut drop_span = None; + let mut pin_drop_span = None; + for item in tcx.associated_items(drop_impl_did).in_definition_order() { + match item.kind { + ty::AssocKind::Fn { name: sym::drop, .. } => { + drop_span = Some(tcx.def_span(item.def_id)) + } + ty::AssocKind::Fn { name: sym::pin_drop, .. } => { + pin_drop_span = Some(tcx.def_span(item.def_id)) + } + _ => {} + } + } + + 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 e124dfeb72840..383f09d83be7b 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; @@ -1278,6 +1279,15 @@ fn check_impl_items_against_trait<'tcx>( if !is_implemented_here { let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_id)); match tcx.eval_default_body_stability(trait_item_id, full_impl_span) { + // When the feature `pin_ergonomics` is disabled, we report `Drop::drop` is missing, + // instead of `Drop::drop` is unstable that might be confusing. + EvalResult::Deny { .. } + if !tcx.features().pin_ergonomics() + && tcx.is_lang_item(trait_ref.def_id, hir::LangItem::Drop) + && tcx.item_name(trait_item_id) == sym::drop => + { + missing_items.push(tcx.associated_item(trait_item_id)); + } EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable( tcx, full_impl_span, 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 209b0156de323..2fa52600e07af 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1708,3 +1708,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..f2629aa3a2168 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -37,9 +37,12 @@ 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` + && !tcx.is_lang_item(tcx.parent(body_id), 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_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 4a741169443dd..654fdca089fed 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -26,6 +26,9 @@ mir_build_borrow_of_moved_value = borrow of moved value .value_borrowed_label = value borrowed here after move .suggestion = borrow this binding in the pattern to avoid moving the value +mir_build_call_drop_explicitly_requires_unsafe = + call `{$function}` explicitly is unsafe and requires unsafe block + mir_build_call_to_deprecated_safe_fn_requires_unsafe = call to deprecated safe function `{$function}` is unsafe and requires unsafe block .note = consult the function's documentation for information on how to avoid undefined behavior diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index a06c030b103b2..4d9d34d387a7c 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -542,6 +542,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { CallToFunctionWith { function: func_did, missing, build_enabled }, ); } + if let Some(trait_did) = self.tcx.trait_of_assoc(func_did) + && self.tcx.is_lang_item(trait_did, hir::LangItem::Drop) + { + self.requires_unsafe(expr.span, CallDropExplicitly(func_did)); + } } } ExprKind::RawBorrow { arg, .. } => { @@ -770,6 +775,8 @@ enum UnsafeOpKind { build_enabled: Vec, }, UnsafeBinderCast, + /// Calling `Drop::drop` or `Drop::pin_drop` explicitly. + CallDropExplicitly(DefId), } use UnsafeOpKind::*; @@ -947,6 +954,9 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), + CallDropExplicitly(_) => { + span_bug!(span, "`Drop::drop` or `Drop::pin_drop` should not be called explicitly") + } } } @@ -1164,6 +1174,13 @@ impl UnsafeOpKind { UnsafeBinderCast => { dcx.emit_err(UnsafeBinderCastRequiresUnsafe { span, unsafe_not_inherited_note }); } + CallDropExplicitly(did) => { + dcx.emit_err(CallDropExplicitlyRequiresUnsafe { + span, + unsafe_not_inherited_note, + function: tcx.def_path_str(*did), + }); + } } } } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 3d9753d72da58..79ea22ff92b96 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -532,6 +532,16 @@ pub(crate) struct UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed { pub(crate) unsafe_not_inherited_note: Option, } +#[derive(Diagnostic)] +#[diag(mir_build_call_drop_explicitly_requires_unsafe, code = E0133)] +pub(crate) struct CallDropExplicitlyRequiresUnsafe { + #[primary_span] + pub(crate) span: Span, + pub(crate) function: String, + #[subdiagnostic] + pub(crate) unsafe_not_inherited_note: Option, +} + #[derive(Subdiagnostic)] #[label(mir_build_unsafe_not_inherited)] pub(crate) struct UnsafeNotInheritedNote { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index eca4259efa7d1..ab9ee61000954 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1688,6 +1688,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..138460d54cf99 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. + unsafe { Drop::pin_drop(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 f78ab89d7545a..41bd79d4b5d41 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit f78ab89d7545ac17780e6a367055cc089f4cd2ec +Subproject commit 41bd79d4b5d41a541879b384580a3a558a27ee96 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/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs index 7f669d0b93e5d..173b22eb737cf 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()); @@ -71,6 +77,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 b721654a506f0..e1919666adbda 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:51:6 + --> $DIR/feature-gate-pin_ergonomics.rs:57:6 | LL | &pin mut x: &pin mut i32, | ^^^ @@ -89,7 +99,7 @@ LL | &pin mut x: &pin mut i32, = 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:51:18 + --> $DIR/feature-gate-pin_ergonomics.rs:57:18 | LL | &pin mut x: &pin mut i32, | ^^^ @@ -99,7 +109,7 @@ LL | &pin mut x: &pin mut i32, = 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:54:6 + --> $DIR/feature-gate-pin_ergonomics.rs:60:6 | LL | &pin const y: &'a pin const i32, | ^^^ @@ -109,7 +119,7 @@ LL | &pin const y: &'a pin const i32, = 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:54:23 + --> $DIR/feature-gate-pin_ergonomics.rs:60:23 | LL | &pin const y: &'a pin const i32, | ^^^ @@ -119,7 +129,7 @@ LL | &pin const y: &'a pin const i32, = 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:57:9 + --> $DIR/feature-gate-pin_ergonomics.rs:63:9 | LL | ref pin mut z: i32, | ^^^ @@ -129,7 +139,7 @@ LL | ref pin mut z: i32, = 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:58:9 + --> $DIR/feature-gate-pin_ergonomics.rs:64:9 | LL | ref pin const w: i32, | ^^^ @@ -139,7 +149,7 @@ LL | ref pin const w: i32, = 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:70:23 + --> $DIR/feature-gate-pin_ergonomics.rs:76:23 | LL | fn foo_sugar(&pin mut self) {} | ^^^ @@ -149,7 +159,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:71:29 + --> $DIR/feature-gate-pin_ergonomics.rs:77:29 | LL | fn foo_sugar_const(&pin const self) {} | ^^^ @@ -159,7 +169,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:77:18 + --> $DIR/feature-gate-pin_ergonomics.rs:81: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:87:18 | LL | let _y: &pin mut Foo = x; | ^^^ @@ -169,7 +189,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:80:22 + --> $DIR/feature-gate-pin_ergonomics.rs:90:22 | LL | fn foo_sugar(_: &pin mut Foo) {} | ^^^ @@ -179,7 +199,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:92:22 + --> $DIR/feature-gate-pin_ergonomics.rs:102:22 | LL | fn baz_sugar(_: &pin const Foo) {} | ^^^ @@ -189,7 +209,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:95:35 + --> $DIR/feature-gate-pin_ergonomics.rs:105:35 | LL | let mut x: Pin<&mut _> = &pin mut Foo; | ^^^ @@ -199,7 +219,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:100:27 + --> $DIR/feature-gate-pin_ergonomics.rs:110:27 | LL | let x: Pin<&_> = &pin const Foo; | ^^^ @@ -209,7 +229,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:107:10 + --> $DIR/feature-gate-pin_ergonomics.rs:117:10 | LL | &pin mut x: &pin mut i32, | ^^^ @@ -219,7 +239,7 @@ LL | &pin mut x: &pin mut i32, = 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:107:22 + --> $DIR/feature-gate-pin_ergonomics.rs:117:22 | LL | &pin mut x: &pin mut i32, | ^^^ @@ -229,7 +249,7 @@ LL | &pin mut x: &pin mut i32, = 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:110:10 + --> $DIR/feature-gate-pin_ergonomics.rs:120:10 | LL | &pin const y: &'a pin const i32, | ^^^ @@ -239,7 +259,7 @@ LL | &pin const y: &'a pin const i32, = 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:110:27 + --> $DIR/feature-gate-pin_ergonomics.rs:120:27 | LL | &pin const y: &'a pin const i32, | ^^^ @@ -249,7 +269,7 @@ LL | &pin const y: &'a pin const i32, = 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:113:13 + --> $DIR/feature-gate-pin_ergonomics.rs:123:13 | LL | ref pin mut z: i32, | ^^^ @@ -259,7 +279,7 @@ LL | ref pin mut z: i32, = 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:114:13 + --> $DIR/feature-gate-pin_ergonomics.rs:124:13 | LL | ref pin const w: i32, | ^^^ @@ -278,8 +298,26 @@ 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 { + | ^^^^^^^^^^^^^^^^^ missing `drop` in implementation + | + = help: implement the missing item: `fn drop(&mut self) { todo!() }` + 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 @@ -289,7 +327,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 @@ -297,7 +335,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 @@ -316,7 +354,7 @@ help: consider reborrowing the `Pin` instead of moving it LL | x.as_mut().foo(); | +++++++++ -error: aborting due to 30 previous errors +error: aborting due to 34 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..a8005b94dbba2 --- /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 conflicting implementations of `Drop::drop` and `Drop::pin_drop` + fn drop(&mut self) {} + fn pin_drop(&pin mut self) {} + } + + impl Drop for Bar { + //~^ ERROR conflicting implementations 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..61a5136c7a800 --- /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: conflicting implementations 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: conflicting implementations 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-unsafety-check.rs b/tests/ui/pin-ergonomics/pinned-drop-unsafety-check.rs new file mode 100644 index 0000000000000..59dc378b6a4e4 --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-unsafety-check.rs @@ -0,0 +1,88 @@ +#![no_std] +#![no_core] +#![feature(no_core, pin_ergonomics, lang_items)] +#![allow(incomplete_features)] + +// This checks that calling `Drop::pin_drop` and `Drop::drop` explicitly is unsafe +// and requires unsafe block. +// Note that this tiny-`core` library ignores `Unpin` related stuffs as we don't care about that, +// and thus the `Pin` type is just simply a wrapper around a pointer. + +#[lang = "drop"] +trait Drop { + fn drop(&mut self) { + Self::pin_drop(Pin { pointer: self }); + //~^ ERROR call `Drop::pin_drop` explicitly is unsafe and requires unsafe block + unsafe { Self::pin_drop(Pin { pointer: self }) }; // ok + } + + fn pin_drop(self: Pin<&mut Self>) { + Self::drop(self.pointer); + //~^ ERROR call `Drop::drop` explicitly is unsafe and requires unsafe block + unsafe { Self::drop(self.pointer) }; // ok + } +} + +#[lang = "pin"] +// This is a dummy `Pin` type that is just simply a wrapper around a pointer. +struct Pin { + pointer: T, +} + +#[lang = "deref"] +trait Deref: PointeeSized { + #[lang = "deref_target"] + type Target: PointeeSized; + + fn deref(&self) -> &Self::Target; +} + +#[lang = "deref_mut"] +trait DerefMut: Deref + PointeeSized { + fn deref_mut(&mut self) -> &mut Self::Target; +} + +impl Deref for Pin { + type Target = Ptr::Target; + + fn deref(&self) -> &Self::Target { + &*self.pointer + } +} + +// skip the `Unpin` check, as this test doesn't care about that. +impl DerefMut for Pin { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.pointer + } +} + +impl Deref for &mut T { + type Target = T; + + fn deref(&self) -> &Self::Target { + self + } +} + + +#[lang = "copy"] +trait Copy {} + +#[lang = "sized"] +trait Sized: MetaSized {} + +#[lang = "meta_sized"] +trait MetaSized: PointeeSized {} + +#[lang = "pointee_sized"] +trait PointeeSized {} + +#[lang = "legacy_receiver"] +trait LegacyReceiver: PointeeSized {} + +impl LegacyReceiver for &T {} +impl LegacyReceiver for &mut T {} +impl LegacyReceiver for Pin {} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/pinned-drop-unsafety-check.stderr b/tests/ui/pin-ergonomics/pinned-drop-unsafety-check.stderr new file mode 100644 index 0000000000000..282ae4388315d --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-unsafety-check.stderr @@ -0,0 +1,15 @@ +error[E0133]: call `Drop::pin_drop` explicitly is unsafe and requires unsafe block + --> $DIR/pinned-drop-unsafety-check.rs:14:9 + | +LL | Self::pin_drop(Pin { pointer: self }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0133]: call `Drop::drop` explicitly is unsafe and requires unsafe block + --> $DIR/pinned-drop-unsafety-check.rs:20:9 + | +LL | Self::drop(self.pointer); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. 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)); +}