diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b105a97cdf98d..565f3a863bb75 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2982,6 +2982,12 @@ impl Param { None } + /// Returns `true` if parameter is exactly `&pin mut self`. + pub fn is_pinned_mut_self_receiver(&self) -> bool { + self.to_self() + .is_some_and(|eself| matches!(eself.node, SelfKind::Pinned(None, Mutability::Mut))) + } + /// Returns `true` if parameter is `self`. pub fn is_self(&self) -> bool { if let PatKind::Ident(_, ident, _) = self.pat.kind { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 3e0bc072a8d04..4b0133f516b64 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1215,7 +1215,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Target::from_assoc_item_kind(&i.kind, AssocCtxt::Impl { of_trait: is_in_trait_impl }), ); - let (ident, (generics, kind)) = match &i.kind { + let (mut ident, (generics, kind)) = match &i.kind { AssocItemKind::Const(box ConstItem { ident, generics, @@ -1323,6 +1323,25 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let span = self.lower_span(i.span); + let trait_item_def_id = if is_in_trait_impl { + Some( + self.get_partial_res(i.id) + .and_then(|r| r.expect_full_res().opt_def_id()) + .ok_or_else(|| { + self.dcx().span_delayed_bug( + span, + "could not resolve trait item being implemented", + ) + }), + ) + } else { + None + }; + + if self.resolver.pin_drop_sugar_impl_items.contains(&i.id) { + ident = Ident::new(sym::pin_drop, ident.span); + } + let item = hir::ImplItem { owner_id: hir_id.expect_owner(), ident: self.lower_ident(ident), @@ -1330,15 +1349,7 @@ impl<'hir> LoweringContext<'_, 'hir> { impl_kind: if is_in_trait_impl { ImplItemImplKind::Trait { defaultness, - trait_item_def_id: self - .get_partial_res(i.id) - .and_then(|r| r.expect_full_res().opt_def_id()) - .ok_or_else(|| { - self.dcx().span_delayed_bug( - span, - "could not resolve trait item being implemented", - ) - }), + trait_item_def_id: trait_item_def_id.unwrap(), } } else { ImplItemImplKind::Inherent { vis_span: self.lower_span(i.vis.span) } diff --git a/compiler/rustc_attr_parsing/src/attributes/pin_v2.rs b/compiler/rustc_attr_parsing/src/attributes/pin_v2.rs index c7e78e1c0df54..06e4bc7374e08 100644 --- a/compiler/rustc_attr_parsing/src/attributes/pin_v2.rs +++ b/compiler/rustc_attr_parsing/src/attributes/pin_v2.rs @@ -15,5 +15,5 @@ impl NoArgsAttributeParser for PinV2Parser { Allow(Target::Struct), Allow(Target::Union), ]); - const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PinV2; + const CREATE: fn(Span) -> AttributeKind = AttributeKind::PinV2; } diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 2cdcf75d00be7..4ff56a640c19e 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1212,7 +1212,7 @@ pub enum AttributeKind { }, /// Represents `#[pin_v2]` - PinV2, + PinV2(Span), /// Represents `#[prelude_import]` PreludeImport, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index f2b528d1dcdc2..7169fa433ffd8 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -86,7 +86,7 @@ impl AttributeKind { PatchableFunctionEntry { .. } => Yes, Path(..) => No, PatternComplexityLimit { .. } => No, - PinV2 => Yes, + PinV2(..) => Yes, PreludeImport => No, ProcMacro => No, ProcMacroAttribute => No, diff --git a/compiler/rustc_hir_analysis/src/check/always_applicable.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs index 689911000ea8c..dd32389cc32d3 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, TypeVisitableExt, TypingMode}; +use rustc_span::sym; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -72,7 +73,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"); @@ -363,3 +368,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 = rustc_hir::find_attr!(tcx, adt_def_id, PinV2(attr) => *attr); + 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 26c87f14cd737..54e4991b210fc 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, Unnormalized, 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::traits; @@ -1347,6 +1348,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 3225e00b24b26..30d3e109a0080 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -94,7 +94,7 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_session::errors::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 1bb54f27dcbdd..2fa9b05821644 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1968,3 +1968,35 @@ pub(crate) struct EiiDefkindMismatchStaticSafety { pub span: Span, pub eii_name: Symbol, } + +#[derive(Diagnostic)] +#[diag("conflicting implementations of `Drop::drop` and `Drop::pin_drop`")] +pub(crate) struct ConflictImplDropAndPinDrop { + #[primary_span] + pub span: Span, + #[label("`drop(&mut self)` implemented here")] + pub drop_span: Span, + #[label("`pin_drop(&pin mut self)` implemented here")] + pub pin_drop_span: Span, +} + +#[derive(Diagnostic)] +#[diag("`{$adt_name}` must implement `pin_drop`")] +#[help("structurally pinned types must keep `Pin`'s safety contract")] +pub(crate) struct PinV2WithoutPinDrop { + #[primary_span] + #[suggestion( + "implement `pin_drop` instead", + code = "fn pin_drop(&pin mut self)", + applicability = "maybe-incorrect" + )] + pub span: Span, + #[note("`{$adt_name}` is marked `#[pin_v2]` here")] + #[suggestion( + "remove the `#[pin_v2]` attribute if it is not intended for structurally pinning", + 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 fc504116101c9..2d46eb8292eff 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_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 6381a5c49835d..1b26d0a269943 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -349,7 +349,7 @@ impl AdtDefData { debug!("found non-exhaustive variant list for {:?}", did); flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE; } - if find_attr!(tcx, did, PinV2) { + if find_attr!(tcx, did, PinV2(..)) { debug!("found pin-project type {:?}", did); flags |= AdtFlags::IS_PIN_PROJECT; } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 93da73e1e4505..4ef599c9c203e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -29,7 +29,7 @@ use rustc_abi::{ }; use rustc_ast as ast; use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree}; -use rustc_ast::node_id::NodeMap; +use rustc_ast::node_id::{NodeMap, NodeSet}; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; @@ -204,6 +204,8 @@ pub struct ResolverGlobalCtxt { pub struct ResolverAstLowering<'tcx> { /// Resolutions for nodes that have a single resolution. pub partial_res_map: NodeMap, + /// Impl items accepted by resolver as `fn drop(&pin mut self)` sugar for `Drop::pin_drop`. + pub pin_drop_sugar_impl_items: NodeSet, /// Resolutions for import nodes, which have multiple resolutions in different namespaces. pub import_res_map: NodeMap>>>, /// Resolutions for labels (node IDs of their corresponding blocks or loops). diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index aceddcc54de95..d169419c54226 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -461,6 +461,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, .. } => { @@ -661,6 +666,8 @@ enum UnsafeOpKind { build_enabled: Vec, }, UnsafeBinderCast, + /// Calling `Drop::drop` or `Drop::pin_drop` explicitly. + CallDropExplicitly(DefId), } use UnsafeOpKind::*; @@ -829,6 +836,9 @@ impl UnsafeOpKind { unsafe_not_inherited_note, }, ), + CallDropExplicitly(_) => { + span_bug!(span, "`Drop::drop` or `Drop::pin_drop` should not be called explicitly") + } } } @@ -1034,6 +1044,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 dbdb51d56e8c1..c55275962e085 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -562,6 +562,16 @@ pub(crate) struct UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed { pub(crate) unsafe_not_inherited_note: Option, } +#[derive(Diagnostic)] +#[diag("call `{$function}` explicitly is unsafe and requires unsafe block", 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("items do not inherit unsafety from separate enclosing items")] pub(crate) struct UnsafeNotInheritedNote { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a978138e3e1ff..13eaddbc9e7bf 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -259,7 +259,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::PatchableFunctionEntry { .. } | AttributeKind::Path(..) | AttributeKind::PatternComplexityLimit { .. } - | AttributeKind::PinV2 + | AttributeKind::PinV2(..) | AttributeKind::PreludeImport | AttributeKind::ProfilerRuntime | AttributeKind::RecursionLimit { .. } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 014a472c2c1bb..0a062a6b3b645 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -27,7 +27,7 @@ use rustc_errors::{ use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId}; -use rustc_hir::{MissingLifetimeKind, PrimTy, TraitCandidate}; +use rustc_hir::{LangItem, MissingLifetimeKind, PrimTy, TraitCandidate}; use rustc_middle::middle::resolve_bound_vars::Set1; use rustc_middle::ty::{AssocTag, DelegationInfo, Visibility}; use rustc_middle::{bug, span_bug}; @@ -1473,6 +1473,20 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc } impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { + fn is_lang_drop_trait_for_resolve(&self, trait_id: DefId) -> bool { + if let Some(local_def_id) = trait_id.as_local() { + return self.r.local_lang_drop_traits.contains(&local_def_id); + } + + // Resolver output is an input to the all-crates lang-items query, so use + // raw local AST collection plus external crate metadata instead. + self.r + .tcx + .defined_lang_items(trait_id.krate) + .iter() + .any(|&(def_id, lang_item)| def_id == trait_id && lang_item == LangItem::Drop) + } + fn new(resolver: &'a mut Resolver<'ra, 'tcx>) -> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // During late resolution we only track the module component of the parent scope, // although it may be useful to track other components as well for diagnostics. @@ -3538,6 +3552,25 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); } + fn is_drop_impl_item_pin_drop_sugar( + &self, + trait_id: Option, + ident: Ident, + kind: &AssocItemKind, + ) -> bool { + if !trait_id.is_some_and(|trait_id| self.is_lang_drop_trait_for_resolve(trait_id)) + || ident.name != sym::drop + { + return false; + } + + let AssocItemKind::Fn(box Fn { sig, .. }) = kind else { + return false; + }; + + sig.decl.inputs.first().is_some_and(Param::is_pinned_mut_self_receiver) + } + fn resolve_impl_item( &mut self, item: &'ast AssocItem, @@ -3641,11 +3674,18 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { LifetimeBinderKind::Function, generics.span, |this| { + let is_pin_drop_sugar = + this.is_drop_impl_item_pin_drop_sugar(trait_id, *ident, &item.kind); + let effective_ident = if is_pin_drop_sugar { + Ident::new(sym::pin_drop, ident.span) + } else { + *ident + }; // If this is a trait impl, ensure the method // exists in trait this.check_trait_item( item.id, - *ident, + effective_ident, &item.kind, ValueNS, item.span, @@ -3653,6 +3693,14 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |i, s, c| MethodNotMemberOfTrait(i, s, c), ); + if is_pin_drop_sugar + && this.r.partial_res_map.get(&item.id).is_some_and(|res| { + matches!(res.full_res(), Some(Res::Def(DefKind::AssocFn, _))) + }) + { + this.r.pin_drop_sugar_impl_items.insert(item.id); + } + visit::walk_assoc_item(this, item, AssocCtxt::Impl { of_trait: true }) }, ); @@ -5590,6 +5638,15 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { } let def_id = self.r.local_def_id(item.id); + if matches!(&item.kind, ItemKind::Trait(..)) + && item + .attrs + .iter() + .any(|attr| attr.has_name(sym::lang) && attr.value_str() == Some(sym::drop)) + { + self.r.local_lang_drop_traits.insert(def_id); + } + let count = generics .params .iter() diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b15e4b1b72774..7da0a2d22ea78 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -37,7 +37,7 @@ use late::{ }; use macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef}; use rustc_arena::{DroplessArena, TypedArena}; -use rustc_ast::node_id::NodeMap; +use rustc_ast::node_id::{NodeMap, NodeSet}; use rustc_ast::{ self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs, Generics, NodeId, Path, attr, @@ -56,7 +56,9 @@ use rustc_hir::def::{ self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, MacroKinds, NonMacroAttrKind, PartialRes, PerNS, }; -use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; +use rustc_hir::def_id::{ + CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap, LocalDefIdSet, +}; use rustc_hir::definitions::{PerParentDisambiguatorState, PerParentDisambiguatorsMap}; use rustc_hir::{PrimTy, TraitCandidate, find_attr}; use rustc_index::bit_set::DenseBitSet; @@ -1315,6 +1317,10 @@ pub struct Resolver<'ra, 'tcx> { /// Resolutions for nodes that have a single resolution. partial_res_map: NodeMap = Default::default(), + /// Local traits with a raw `#[lang = "drop"]` AST attribute. + local_lang_drop_traits: LocalDefIdSet = Default::default(), + /// Impl items accepted as `fn drop(&pin mut self)` sugar for `Drop::pin_drop`. + pin_drop_sugar_impl_items: NodeSet = Default::default(), /// Resolutions for import nodes, which have multiple resolutions in different namespaces. import_res_map: NodeMap>> = Default::default(), /// An import will be inserted into this map if it has been used. @@ -1820,6 +1826,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { multi_segment_macro_resolutions: Default::default(), lint_buffer: LintBuffer::default(), node_id_to_def_id, + local_lang_drop_traits: Default::default(), + pin_drop_sugar_impl_items: Default::default(), invocation_parents, trait_impls: Default::default(), confused_type_with_std_module: Default::default(), @@ -1957,6 +1965,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let ast_lowering = ty::ResolverAstLowering { partial_res_map: self.partial_res_map, + pin_drop_sugar_impl_items: self.pin_drop_sugar_impl_items, import_res_map: self.import_res_map, label_res_map: self.label_res_map, lifetimes_res_map: self.lifetimes_res_map, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 695103a249b49..dcd6e6f2fc7d5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1516,6 +1516,7 @@ symbols! { pic, pie, pin, + pin_drop, pin_ergonomics, pin_v2, platform_intrinsics, 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/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 6cb4492c37544..e69797c0aa063 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -11,6 +11,20 @@ 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] +} + +struct Sugar; + +impl Drop for Sugar { + //~^ ERROR not all trait items implemented, missing: `drop` + fn 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 +85,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..c4db06d499450 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr @@ -19,7 +19,27 @@ 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:24:14 + | +LL | fn 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:31:14 | LL | let _y: &pin mut Foo = x; | ^^^ @@ -29,7 +49,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:35:14 | LL | let _y: &pin const Foo = x; | ^^^ @@ -39,7 +59,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:38:18 | LL | fn foo_sugar(_: &pin mut Foo) {} | ^^^ @@ -49,7 +69,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:50:18 | LL | fn baz_sugar(_: &pin const Foo) {} | ^^^ @@ -59,7 +79,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:53:31 | LL | let mut x: Pin<&mut _> = &pin mut Foo; | ^^^ @@ -69,7 +89,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:58:23 | LL | let x: Pin<&_> = &pin const Foo; | ^^^ @@ -79,7 +99,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:65:6 | LL | &pin mut x: &pin mut i32, | ^^^ @@ -89,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:51:18 + --> $DIR/feature-gate-pin_ergonomics.rs:65:18 | LL | &pin mut x: &pin mut i32, | ^^^ @@ -99,7 +119,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:68:6 | LL | &pin const y: &'a pin const i32, | ^^^ @@ -109,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:54:23 + --> $DIR/feature-gate-pin_ergonomics.rs:68:23 | LL | &pin const y: &'a pin const i32, | ^^^ @@ -119,7 +139,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:71:9 | LL | ref pin mut z: i32, | ^^^ @@ -129,7 +149,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:72:9 | LL | ref pin const w: i32, | ^^^ @@ -139,7 +159,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:84:23 | LL | fn foo_sugar(&pin mut self) {} | ^^^ @@ -149,7 +169,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:85:29 | LL | fn foo_sugar_const(&pin const self) {} | ^^^ @@ -159,7 +179,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:89: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:95:18 | LL | let _y: &pin mut Foo = x; | ^^^ @@ -169,7 +199,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:98:22 | LL | fn foo_sugar(_: &pin mut Foo) {} | ^^^ @@ -179,7 +209,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:110:22 | LL | fn baz_sugar(_: &pin const Foo) {} | ^^^ @@ -189,7 +219,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:113:35 | LL | let mut x: Pin<&mut _> = &pin mut Foo; | ^^^ @@ -199,7 +229,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:118:27 | LL | let x: Pin<&_> = &pin const Foo; | ^^^ @@ -209,7 +239,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:125:10 | LL | &pin mut x: &pin mut i32, | ^^^ @@ -219,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:107:22 + --> $DIR/feature-gate-pin_ergonomics.rs:125:22 | LL | &pin mut x: &pin mut i32, | ^^^ @@ -229,7 +259,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:128:10 | LL | &pin const y: &'a pin const i32, | ^^^ @@ -239,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:110:27 + --> $DIR/feature-gate-pin_ergonomics.rs:128:27 | LL | &pin const y: &'a pin const i32, | ^^^ @@ -249,7 +279,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:131:13 | LL | ref pin mut z: i32, | ^^^ @@ -259,7 +289,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:132:13 | LL | ref pin const w: i32, | ^^^ @@ -278,8 +308,44 @@ 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[E0658]: use of unstable library feature `pin_ergonomics` + --> $DIR/feature-gate-pin_ergonomics.rs:24:5 + | +LL | fn 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[E0046]: not all trait items implemented, missing: `drop` + --> $DIR/feature-gate-pin_ergonomics.rs:22:1 + | +LL | impl Drop for Sugar { + | ^^^^^^^^^^^^^^^^^^^ 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:42: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 +355,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:28:15 | LL | fn foo(mut x: Pin<&mut Foo>) { | --- ^^^^^^^^^^^^^ this parameter takes ownership of the value @@ -297,7 +363,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:47: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 +382,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 37 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..bd8d096fec547 --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-check.rs @@ -0,0 +1,205 @@ +//@ 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, non-`#[pin_v2]` can also implement `pin_drop` + } + + impl Drop for Bar { + fn pin_drop(&pin mut self) {} // ok, `#[pin_v2]` implements `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_sugar { + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn drop(&pin mut self) {} // ok, sugar for `pin_drop` + } + + impl Drop for Bar { + fn drop(&pin mut self) {} // ok, sugar for `pin_drop` + } +} + +mod drop_pin_const_wrong_type { + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn drop(&pin const self) {} //~ ERROR method `drop` has an incompatible type for trait [E0053] + } + + impl Drop for Bar { + fn drop(&pin const self) {} + //~^ ERROR method `drop` has an incompatible type for trait [E0053] + //~| ERROR `Bar` must implement `pin_drop` + } +} + +mod drop_with_lifetime_wrong_type { + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn drop<'a>(&'a pin mut self) {} + //~^ ERROR method `drop` has an incompatible type for trait [E0053] + } + + impl Drop for Bar { + fn drop<'a>(&'a pin mut self) {} + //~^ ERROR method `drop` has an incompatible type for trait [E0053] + //~| ERROR `Bar` must implement `pin_drop` + } +} + +mod drop_explicit_pin_wrong_type { + use std::pin::Pin; + + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn drop(self: Pin<&mut Self>) {} + //~^ ERROR method `drop` has an incompatible type for trait [E0053] + } + + impl Drop for Bar { + fn drop(self: 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] + } + } +} + +mod explicit_call_drop_sugar { + struct Foo; + + impl Drop for Foo { + fn drop(&pin mut self) { + Drop::drop(todo!()); //~ ERROR explicit use of destructor method [E0040] + Drop::pin_drop(todo!()); //~ ERROR explicit use of destructor method [E0040] + } + } +} + +mod sugar_and_pin_drop { + struct Foo; + #[pin_v2] + struct Bar; + + impl Drop for Foo { + fn drop(&pin mut self) {} + fn pin_drop(&pin mut self) {} //~ ERROR duplicate definitions with name `pin_drop` + } + + impl Drop for Bar { + fn drop(&pin mut self) {} + fn pin_drop(&pin mut self) {} //~ ERROR duplicate definitions with name `pin_drop` + } +} + +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..5e3821f371911 --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-check.stderr @@ -0,0 +1,338 @@ +error[E0201]: duplicate definitions with name `pin_drop`: + --> $DIR/pinned-drop-check.rs:196:9 + | +LL | fn drop(&pin mut self) {} + | ------------------------- previous definition here +LL | fn pin_drop(&pin mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition + | + --> $SRC_DIR/core/src/ops/drop.rs:LL:COL + | + = note: item in trait + +error[E0201]: duplicate definitions with name `pin_drop`: + --> $DIR/pinned-drop-check.rs:201:9 + | +LL | fn drop(&pin mut self) {} + | ------------------------- previous definition here +LL | fn pin_drop(&pin mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definition + | + --> $SRC_DIR/core/src/ops/drop.rs:LL:COL + | + = note: item in trait + +error: `Bar` must implement `pin_drop` + --> $DIR/pinned-drop-check.rs:18:9 + | +LL | fn drop(&mut self) {} + | ^^^^^^^^^^^^^^^^^^ + | + = help: structurally pinned types must keep `Pin`'s safety contract +note: `Bar` is marked `#[pin_v2]` here + --> $DIR/pinned-drop-check.rs:10:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ +help: implement `pin_drop` instead + | +LL - fn drop(&mut self) {} +LL + fn pin_drop(&pin mut self) {} + | +help: remove the `#[pin_v2]` attribute if it is not intended for structurally pinning + | +LL - #[pin_v2] + | + +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:87:9 + | +LL | fn drop(&pin const self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: structurally pinned types must keep `Pin`'s safety contract +note: `Bar` is marked `#[pin_v2]` here + --> $DIR/pinned-drop-check.rs:79:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ +help: implement `pin_drop` instead + | +LL - fn drop(&pin const self) {} +LL + fn pin_drop(&pin mut self) {} + | +help: remove the `#[pin_v2]` attribute if it is not intended for structurally pinning + | +LL - #[pin_v2] + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:83:17 + | +LL | fn drop(&pin const self) {} + | ^^^^^^^^^^^^^^^ expected `&mut drop_pin_const_wrong_type::Foo`, found `Pin<&drop_pin_const_wrong_type::Foo>` + | + = note: expected signature `fn(&mut drop_pin_const_wrong_type::Foo)` + found signature `fn(Pin<&drop_pin_const_wrong_type::Foo>)` +help: change the self-receiver type to match the trait + | +LL - fn drop(&pin const self) {} +LL + fn drop(&mut self) {} + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:87:17 + | +LL | fn drop(&pin const self) {} + | ^^^^^^^^^^^^^^^ expected `&mut drop_pin_const_wrong_type::Bar`, found `Pin<&drop_pin_const_wrong_type::Bar>` + | + = note: expected signature `fn(&mut drop_pin_const_wrong_type::Bar)` + found signature `fn(Pin<&drop_pin_const_wrong_type::Bar>)` +help: change the self-receiver type to match the trait + | +LL - fn drop(&pin const self) {} +LL + fn drop(&mut self) {} + | + +error: `Bar` must implement `pin_drop` + --> $DIR/pinned-drop-check.rs:104:9 + | +LL | fn drop<'a>(&'a pin mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: structurally pinned types must keep `Pin`'s safety contract +note: `Bar` is marked `#[pin_v2]` here + --> $DIR/pinned-drop-check.rs:95:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ +help: implement `pin_drop` instead + | +LL - fn drop<'a>(&'a pin mut self) {} +LL + fn pin_drop(&pin mut self) {} + | +help: remove the `#[pin_v2]` attribute if it is not intended for structurally pinning + | +LL - #[pin_v2] + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:99:21 + | +LL | fn drop<'a>(&'a pin mut self) {} + | ^^^^^^^^^^^^^^^^ expected `&mut drop_with_lifetime_wrong_type::Foo`, found `Pin<&mut Foo>` + | + = note: expected signature `fn(&mut drop_with_lifetime_wrong_type::Foo)` + found signature `fn(Pin<&mut drop_with_lifetime_wrong_type::Foo>)` +help: change the self-receiver type to match the trait + | +LL - fn drop<'a>(&'a pin mut self) {} +LL + fn drop<'a>(&mut self) {} + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:104:21 + | +LL | fn drop<'a>(&'a pin mut self) {} + | ^^^^^^^^^^^^^^^^ expected `&mut drop_with_lifetime_wrong_type::Bar`, found `Pin<&mut Bar>` + | + = note: expected signature `fn(&mut drop_with_lifetime_wrong_type::Bar)` + found signature `fn(Pin<&mut drop_with_lifetime_wrong_type::Bar>)` +help: change the self-receiver type to match the trait + | +LL - fn drop<'a>(&'a pin mut self) {} +LL + fn drop<'a>(&mut self) {} + | + +error: `Bar` must implement `pin_drop` + --> $DIR/pinned-drop-check.rs:123:9 + | +LL | fn drop(self: Pin<&mut Self>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: structurally pinned types must keep `Pin`'s safety contract +note: `Bar` is marked `#[pin_v2]` here + --> $DIR/pinned-drop-check.rs:114:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ +help: implement `pin_drop` instead + | +LL - fn drop(self: Pin<&mut Self>) {} +LL + fn pin_drop(&pin mut self) {} + | +help: remove the `#[pin_v2]` attribute if it is not intended for structurally pinning + | +LL - #[pin_v2] + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:118:23 + | +LL | fn drop(self: Pin<&mut Self>) {} + | ^^^^^^^^^^^^^^ expected `&mut drop_explicit_pin_wrong_type::Foo`, found `Pin<&mut Foo>` + | + = note: expected signature `fn(&mut drop_explicit_pin_wrong_type::Foo)` + found signature `fn(Pin<&mut drop_explicit_pin_wrong_type::Foo>)` +help: change the self-receiver type to match the trait + | +LL - fn drop(self: Pin<&mut Self>) {} +LL + fn drop(&mut self) {} + | + +error[E0053]: method `drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:123:23 + | +LL | fn drop(self: Pin<&mut Self>) {} + | ^^^^^^^^^^^^^^ expected `&mut drop_explicit_pin_wrong_type::Bar`, found `Pin<&mut Bar>` + | + = note: expected signature `fn(&mut drop_explicit_pin_wrong_type::Bar)` + found signature `fn(Pin<&mut drop_explicit_pin_wrong_type::Bar>)` +help: change the self-receiver type to match the trait + | +LL - fn drop(self: Pin<&mut Self>) {} +LL + fn drop(&mut self) {} + | + +error[E0053]: method `pin_drop` has an incompatible type for trait + --> $DIR/pinned-drop-check.rs:135: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:139: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:154:9 + | +LL | fn drop(&mut self) { + | ^^^^^^^^^^^^^^^^^^ + | + = help: structurally pinned types must keep `Pin`'s safety contract +note: `Bar` is marked `#[pin_v2]` here + --> $DIR/pinned-drop-check.rs:145:5 + | +LL | #[pin_v2] + | ^^^^^^^^^ +help: implement `pin_drop` instead + | +LL - fn drop(&mut self) { +LL + fn pin_drop(&pin mut self) { + | +help: remove the `#[pin_v2]` attribute if it is not intended for structurally pinning + | +LL - #[pin_v2] + | + +error[E0040]: explicit use of destructor method + --> $DIR/pinned-drop-check.rs:150: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:156: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:168: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:173: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:183: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:184:13 + | +LL | Drop::pin_drop(todo!()); + | ^^^^^^^^^^^^^^ + | | + | explicit destructor calls not allowed + | help: consider using `drop` function: `drop` + +error: aborting due to 25 previous errors + +Some errors have detailed explanations: E0040, E0046, E0053, E0201. +For more information about an error, try `rustc --explain E0040`. diff --git a/tests/ui/pin-ergonomics/pinned-drop-sugar-no-core.rs b/tests/ui/pin-ergonomics/pinned-drop-sugar-no-core.rs new file mode 100644 index 0000000000000..daf7dfb8bfe65 --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-sugar-no-core.rs @@ -0,0 +1,78 @@ +//@ check-pass + +#![no_std] +#![no_core] +#![no_main] +#![feature(no_core, pin_ergonomics, lang_items)] +#![allow(incomplete_features)] + +#[lang = "pointee_sized"] +trait PointeeSized {} + +#[lang = "meta_sized"] +trait MetaSized: PointeeSized {} + +#[lang = "sized"] +trait Sized: MetaSized {} + +#[lang = "copy"] +trait Copy {} + +#[lang = "legacy_receiver"] +trait LegacyReceiver: PointeeSized {} + +#[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; +} + +#[lang = "pin"] +struct Pin { + pointer: T, +} + +impl LegacyReceiver for &T {} +impl LegacyReceiver for &mut T {} +impl LegacyReceiver for Pin {} + +impl Deref for Pin { + type Target = Ptr::Target; + + fn deref(&self) -> &Self::Target { + &*self.pointer + } +} + +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 = "drop"] +trait Drop { + fn drop(&mut self) {} + fn pin_drop(self: Pin<&mut Self>) {} +} + +struct LocalDrop; + +impl Drop for LocalDrop { + fn drop(&pin mut self) {} +} diff --git a/tests/ui/pin-ergonomics/pinned-drop-sugar-not-other-traits.rs b/tests/ui/pin-ergonomics/pinned-drop-sugar-not-other-traits.rs new file mode 100644 index 0000000000000..704f42da5c4b4 --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-sugar-not-other-traits.rs @@ -0,0 +1,58 @@ +//@ edition:2024 + +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +use std::pin::Pin; + +struct S; + +trait NeedsPinDrop { + fn pin_drop(self: Pin<&mut Self>); +} + +impl NeedsPinDrop for S { + //~^ ERROR not all trait items implemented, missing: `pin_drop` [E0046] + fn drop(&pin mut self) {} + //~^ ERROR method `drop` is not a member of trait `NeedsPinDrop` +} + +trait HasDrop { + fn drop(self: Pin<&mut Self>); +} + +impl HasDrop for S { + fn drop(&pin mut self) {} +} + +trait HasPinnedDropReceiver { + fn drop(self: &pin mut Self); +} + +impl HasPinnedDropReceiver for S { + fn drop(&pin mut self) {} +} + +struct Inherent; + +impl Inherent { + fn drop(&pin mut self) {} +} + +mod local_drop_trait { + use std::pin::Pin; + + struct S; + + trait Drop { + fn pin_drop(self: Pin<&mut Self>); + } + + impl Drop for S { + //~^ ERROR not all trait items implemented, missing: `pin_drop` [E0046] + fn drop(&pin mut self) {} + //~^ ERROR method `drop` is not a member of trait `Drop` + } +} + +fn main() {} diff --git a/tests/ui/pin-ergonomics/pinned-drop-sugar-not-other-traits.stderr b/tests/ui/pin-ergonomics/pinned-drop-sugar-not-other-traits.stderr new file mode 100644 index 0000000000000..76ac873da37a7 --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-sugar-not-other-traits.stderr @@ -0,0 +1,34 @@ +error[E0407]: method `drop` is not a member of trait `NeedsPinDrop` + --> $DIR/pinned-drop-sugar-not-other-traits.rs:16:5 + | +LL | fn drop(&pin mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `NeedsPinDrop` + +error[E0407]: method `drop` is not a member of trait `Drop` + --> $DIR/pinned-drop-sugar-not-other-traits.rs:53:9 + | +LL | fn drop(&pin mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `Drop` + +error[E0046]: not all trait items implemented, missing: `pin_drop` + --> $DIR/pinned-drop-sugar-not-other-traits.rs:14:1 + | +LL | fn pin_drop(self: Pin<&mut Self>); + | ---------------------------------- `pin_drop` from trait +... +LL | impl NeedsPinDrop for S { + | ^^^^^^^^^^^^^^^^^^^^^^^ missing `pin_drop` in implementation + +error[E0046]: not all trait items implemented, missing: `pin_drop` + --> $DIR/pinned-drop-sugar-not-other-traits.rs:51:5 + | +LL | fn pin_drop(self: Pin<&mut Self>); + | ---------------------------------- `pin_drop` from trait +... +LL | impl Drop for S { + | ^^^^^^^^^^^^^^^ missing `pin_drop` in implementation + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0046, E0407. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/pin-ergonomics/pinned-drop-sugar.rs b/tests/ui/pin-ergonomics/pinned-drop-sugar.rs new file mode 100644 index 0000000000000..11c940d2e2dff --- /dev/null +++ b/tests/ui/pin-ergonomics/pinned-drop-sugar.rs @@ -0,0 +1,31 @@ +//@ check-pass +//@ edition:2024 + +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +struct Unpinned; + +#[pin_v2] +struct Pinned; + +struct Qualified; +struct CoreQualified; + +impl Drop for Unpinned { + fn drop(&pin mut self) {} +} + +impl Drop for Pinned { + fn drop(&pin mut self) {} +} + +impl std::ops::Drop for Qualified { + fn drop(&pin mut self) {} +} + +impl core::ops::Drop for CoreQualified { + fn drop(&pin mut self) {} +} + +fn main() {} 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)); +}