diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index ba111d394ec26..a2fb4306ca415 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -235,11 +235,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } } - FnSelfUseKind::Normal { - self_arg, - implicit_into_iter, - is_option_or_result, - } => { + FnSelfUseKind::Normal { self_arg, implicit_into_iter, self_name } => { if implicit_into_iter { err.span_label( fn_call_span, @@ -287,14 +283,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ), ); } - if is_option_or_result && maybe_reinitialized_locations.is_empty() { - err.span_suggestion_verbose( - fn_call_span.shrink_to_lo(), - "consider calling `.as_ref()` to borrow the type's contents", - "as_ref().".to_string(), - Applicability::MachineApplicable, - ); + + let borrow_method = match self_name { + Some(sym::Option | sym::Result) => Some("as_ref"), + Some(sym::Pin) => Some("as_mut"), + _ => None, + }; + + if let Some(borrow_method) = borrow_method { + if maybe_reinitialized_locations.is_empty() { + err.span_suggestion_verbose( + fn_call_span.shrink_to_lo(), + &format!( + "consider calling `.{}()` to borrow the type's contents", + borrow_method, + ), + format!("{}().", borrow_method), + Applicability::MachineApplicable, + ); + } } + // Avoid pointing to the same function in multiple different // error messages. if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 84acfbf941d05..9cc017609ebfe 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -13,7 +13,11 @@ use rustc_middle::mir::{ use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt}; use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; -use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span}; +use rustc_span::{ + hygiene::DesugaringKind, + symbol::{sym, Symbol}, + Span, +}; use rustc_target::abi::VariantIdx; use super::borrow_set::BorrowData; @@ -577,9 +581,8 @@ pub(super) enum FnSelfUseKind<'tcx> { Normal { self_arg: Ident, implicit_into_iter: bool, - /// Whether the self type of the method call has an `.as_ref()` method. /// Used for better diagnostics. - is_option_or_result: bool, + self_name: Option, }, /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)` FnOnceCall, @@ -948,18 +951,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let kind = kind.unwrap_or_else(|| { // This isn't a 'special' use of `self` debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span); + let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn() && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop); - let parent_self_ty = parent - .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl) - .and_then(|did| match tcx.type_of(did).kind() { - ty::Adt(def, ..) => Some(def.did), - _ => None, - }); - let is_option_or_result = parent_self_ty.map_or(false, |def_id| { - matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result)) - }); - FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result } + + let self_name = self.body.local_decls[target_temp] + .ty + .ty_adt_def() + .and_then(|def| tcx.get_diagnostic_name(def.did)); + + FnSelfUseKind::Normal { self_arg, implicit_into_iter, self_name } }); return FnSelfUse { diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 09fc6df542975..3a222d00588bc 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -402,6 +402,7 @@ use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver}; // See for more details. #[stable(feature = "pin", since = "1.33.0")] #[lang = "pin"] +#[rustc_diagnostic_item = "Pin"] #[fundamental] #[repr(transparent)] #[derive(Copy, Clone)] diff --git a/src/test/ui/suggestions/pin-content-move.rs b/src/test/ui/suggestions/pin-content-move.rs new file mode 100644 index 0000000000000..326bae3cffb1e --- /dev/null +++ b/src/test/ui/suggestions/pin-content-move.rs @@ -0,0 +1,23 @@ +use std::pin::Pin; + +struct Foo; + +impl Foo { + fn foo(self: Pin<&mut Self>) {} +} + +fn main() { + let mut foo = Foo; + let foo = Pin::new(&mut foo); + foo.foo(); + //~^ HELP consider calling `.as_mut()` to borrow the type's contents + foo.foo(); + //~^ ERROR use of moved value + + let mut x = 1; + let mut x = Pin::new(&mut x); + x.get_mut(); + //~^ HELP consider calling `.as_mut()` to borrow the type's contents + x.get_mut(); + //~^ ERROR use of moved value +} diff --git a/src/test/ui/suggestions/pin-content-move.stderr b/src/test/ui/suggestions/pin-content-move.stderr new file mode 100644 index 0000000000000..4696caa8551e7 --- /dev/null +++ b/src/test/ui/suggestions/pin-content-move.stderr @@ -0,0 +1,45 @@ +error[E0382]: use of moved value: `foo` + --> $DIR/pin-content-move.rs:14:5 + | +LL | let foo = Pin::new(&mut foo); + | --- move occurs because `foo` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait +LL | foo.foo(); + | ----- `foo` moved due to this method call +LL | +LL | foo.foo(); + | ^^^ value used here after move + | +note: this function takes ownership of the receiver `self`, which moves `foo` + --> $DIR/pin-content-move.rs:6:12 + | +LL | fn foo(self: Pin<&mut Self>) {} + | ^^^^ +help: consider calling `.as_mut()` to borrow the type's contents + | +LL | foo.as_mut().foo(); + | +++++++++ + +error[E0382]: use of moved value: `x` + --> $DIR/pin-content-move.rs:21:5 + | +LL | let mut x = Pin::new(&mut x); + | ----- move occurs because `x` has type `Pin<&mut i32>`, which does not implement the `Copy` trait +LL | x.get_mut(); + | --------- `x` moved due to this method call +LL | +LL | x.get_mut(); + | ^ value used here after move + | +note: this function takes ownership of the receiver `self`, which moves `x` + --> $SRC_DIR/core/src/pin.rs:LL:COL + | +LL | pub const fn get_mut(self) -> &'a mut T + | ^^^^ +help: consider calling `.as_mut()` to borrow the type's contents + | +LL | x.as_mut().get_mut(); + | +++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`.