Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3447,6 +3447,7 @@ dependencies = [
"rustc_errors",
"rustc_graphviz",
"rustc_hir",
"rustc_hir_analysis",
"rustc_index",
"rustc_infer",
"rustc_lexer",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_borrowck/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_graphviz = { path = "../rustc_graphviz" }
rustc_hir = { path = "../rustc_hir" }
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_lexer = { path = "../rustc_lexer" }
Expand Down
50 changes: 43 additions & 7 deletions compiler/rustc_borrowck/src/diagnostics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::GeneratorKind;
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
Expand Down Expand Up @@ -1066,18 +1067,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
CallKind::Normal { self_arg, desugaring, method_did } => {
let self_arg = self_arg.unwrap();
let tcx = self.infcx.tcx;
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
let ty = moved_place.ty(self.body, tcx).ty;
let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
Some(def_id) => {
let infcx = self.infcx.tcx.infer_ctxt().build();
type_known_to_meet_bound_modulo_regions(
&infcx,
self.param_env,
infcx.tcx.mk_imm_ref(
infcx.tcx.lifetimes.re_erased,
infcx.tcx.erase_regions(ty),
),
tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)),
def_id,
DUMMY_SP,
)
Expand Down Expand Up @@ -1133,8 +1132,45 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
place_name, partially_str, loop_message
),
);
let ty = moved_place.ty(self.body, self.infcx.tcx).ty;
if let ty::Adt(def, ..) = ty.kind()
&& Some(def.did()) == self.infcx.tcx.lang_items().pin_type()
{
err.span_suggestion_verbose(
fn_call_span.shrink_to_lo(),
"consider reborrowing the `Pin` instead of moving it",
"as_mut().".to_string(),
Applicability::MaybeIncorrect,
);
}
if let Some(clone_trait) = tcx.lang_items().clone_trait() {
// We can't use `predicate_may_hold` or `can_eq` without ICEs in
// borrowck because of the inference context, so we do a poor-man's
// version here.
for impl_def_id in tcx.all_impls(clone_trait) {
if let Some(def_id) = impl_def_id.as_local()
&& let hir_id = tcx.hir().local_def_id_to_hir_id(def_id)
&& let hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl {
self_ty,
..
}),
..
}) = tcx.hir().get(hir_id)
{
if ty == hir_ty_to_ty(tcx, self_ty) {
err.span_suggestion_verbose(
fn_call_span.shrink_to_lo(),
"you can `clone` the value and consume it, but this \
might not be your desired behavior",
"clone().".to_string(),
Applicability::MaybeIncorrect,
);
}
}
}
}
}
let tcx = self.infcx.tcx;
// Avoid pointing to the same function in multiple different
// error messages.
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
Expand Down
4 changes: 4 additions & 0 deletions src/test/ui/moves/move-fn-self-receiver.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ note: `Foo::use_pin_box_self` takes ownership of the receiver `self`, which move
|
LL | fn use_pin_box_self(self: Pin<Box<Self>>) {}
| ^^^^
help: consider reborrowing the `Pin` instead of moving it
|
LL | pin_box_foo.as_mut().use_pin_box_self();
| +++++++++

error[E0505]: cannot move out of `mut_foo` because it is borrowed
--> $DIR/move-fn-self-receiver.rs:50:5
Expand Down
15 changes: 15 additions & 0 deletions src/test/ui/moves/pin-mut-reborrow.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// run-rustfix
use std::pin::Pin;

struct Foo;

impl Foo {
fn foo(self: Pin<&mut Self>) {}
}

fn main() {
let mut foo = Foo;
let mut foo = Pin::new(&mut foo);
foo.as_mut().foo();
foo.foo(); //~ ERROR use of moved value
}
15 changes: 15 additions & 0 deletions src/test/ui/moves/pin-mut-reborrow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// run-rustfix
use std::pin::Pin;

struct Foo;

impl Foo {
fn foo(self: Pin<&mut Self>) {}
}

fn main() {
let mut foo = Foo;
let mut foo = Pin::new(&mut foo);
foo.foo();
foo.foo(); //~ ERROR use of moved value
}
23 changes: 23 additions & 0 deletions src/test/ui/moves/pin-mut-reborrow.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error[E0382]: use of moved value: `foo`
--> $DIR/pin-mut-reborrow.rs:14:5
|
LL | let mut 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 | foo.foo();
| ^^^ value used here after move
|
note: `Foo::foo` takes ownership of the receiver `self`, which moves `foo`
--> $DIR/pin-mut-reborrow.rs:7:12
|
LL | fn foo(self: Pin<&mut Self>) {}
| ^^^^
help: consider reborrowing the `Pin` instead of moving it
|
LL | foo.as_mut().foo();
| +++++++++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0382`.
11 changes: 11 additions & 0 deletions src/test/ui/moves/suggest-clone.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// run-rustfix

#[derive(Clone)]
struct Foo;
impl Foo {
fn foo(self) {}
}
fn main() {
let foo = &Foo;
foo.clone().foo(); //~ ERROR cannot move out
}
11 changes: 11 additions & 0 deletions src/test/ui/moves/suggest-clone.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// run-rustfix

#[derive(Clone)]
struct Foo;
impl Foo {
fn foo(self) {}
}
fn main() {
let foo = &Foo;
foo.foo(); //~ ERROR cannot move out
}
22 changes: 22 additions & 0 deletions src/test/ui/moves/suggest-clone.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
error[E0507]: cannot move out of `*foo` which is behind a shared reference
--> $DIR/suggest-clone.rs:10:5
|
LL | foo.foo();
| ^^^^-----
| | |
| | `*foo` moved due to this method call
| move occurs because `*foo` has type `Foo`, which does not implement the `Copy` trait
|
note: `Foo::foo` takes ownership of the receiver `self`, which moves `*foo`
--> $DIR/suggest-clone.rs:6:12
|
LL | fn foo(self) {}
| ^^^^
help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | foo.clone().foo();
| ++++++++

error: aborting due to previous error

For more information about this error, try `rustc --explain E0507`.