Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
44 changes: 41 additions & 3 deletions compiler/rustc_borrowck/src/diagnostics/move_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
match error {
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
self.add_borrow_suggestions(err, span);
self.add_borrow_suggestions(err, span, !binds_to.is_empty());
if binds_to.is_empty() {
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
let place_desc = match self.describe_place(move_from.as_ref()) {
Expand Down Expand Up @@ -787,29 +787,67 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}

fn add_borrow_suggestions(&self, err: &mut Diag<'_>, span: Span) {
fn add_borrow_suggestions(
&self,
err: &mut Diag<'_>,
span: Span,
is_destructuring_pattern_move: bool,
) {
match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
Ok(snippet) if snippet.starts_with('*') => {
let sp = span.with_lo(span.lo() + BytePos(1));
let inner = self.find_expr(sp);
let mut is_raw_ptr = false;
let mut is_ref = false;
let mut is_destructuring_assignment = false;
let mut is_nested_deref = false;
if let Some(inner) = inner {
is_nested_deref =
matches!(inner.kind, hir::ExprKind::Unary(hir::UnOp::Deref, _));
let typck_result = self.infcx.tcx.typeck(self.mir_def_id());
if let Some(inner_type) = typck_result.node_type_opt(inner.hir_id) {
if matches!(inner_type.kind(), ty::RawPtr(..)) {
is_raw_ptr = true;
} else if matches!(inner_type.kind(), ty::Ref(..)) {
is_ref = true;
}
}
is_destructuring_assignment =
self.infcx.tcx.hir_parent_iter(inner.hir_id).any(|(_, node)| {
matches!(
node,
hir::Node::LetStmt(&hir::LetStmt {
source: hir::LocalSource::AssignDesugar,
..
})
)
});
}
// If the `inner` is a raw pointer, do not suggest removing the "*", see #126863
// FIXME: need to check whether the assigned object can be a raw pointer, see `tests/ui/borrowck/issue-20801.rs`.
if !is_raw_ptr {
if is_raw_ptr {
return;
}

if !is_destructuring_pattern_move || is_ref {
err.span_suggestion_verbose(
span.with_hi(span.lo() + BytePos(1)),
"consider removing the dereference here",
String::new(),
Applicability::MaybeIncorrect,
);
} else if !is_destructuring_assignment && !is_nested_deref {
err.span_suggestion_verbose(
span.shrink_to_lo(),
"consider borrowing here",
'&',
Applicability::MaybeIncorrect,
);
} else {
err.span_help(
span,
"destructuring assignment cannot borrow from this expression; consider using a `let` binding instead",
);
}
}
_ => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Regression test for #154826.

use std::rc::Rc;

struct NonCopy;

fn main() {
let b: NonCopy;
(b,) = *Rc::new((NonCopy,));
//~^ ERROR cannot move out of an `Rc`
//~| HELP destructuring assignment cannot borrow from this expression; consider using a `let` binding instead
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
error[E0507]: cannot move out of an `Rc`
--> $DIR/borrow-from-overloaded-deref-assign-issue-154826.rs:9:12
|
LL | (b,) = *Rc::new((NonCopy,));
| - ^^^^^^^^^^^^^^^^^^^^
| |
| data moved here because the place has type `NonCopy`, which does not implement the `Copy` trait
|
help: destructuring assignment cannot borrow from this expression; consider using a `let` binding instead
--> $DIR/borrow-from-overloaded-deref-assign-issue-154826.rs:9:12
|
LL | (b,) = *Rc::new((NonCopy,));
| ^^^^^^^^^^^^^^^^^^^^
note: if `NonCopy` implemented `Clone`, you could clone the value
--> $DIR/borrow-from-overloaded-deref-assign-issue-154826.rs:5:1
|
LL | struct NonCopy;
| ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
...
LL | (b,) = *Rc::new((NonCopy,));
| - you could clone this value

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0507`.
12 changes: 12 additions & 0 deletions tests/ui/suggestions/borrow-from-overloaded-deref-issue-154826.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Regression test for #154826.

use std::sync::LazyLock;

static V: LazyLock<(Vec<u8>,)> = LazyLock::new(|| (vec![],));

fn main() {
let (v,) = *V;
//~^ ERROR cannot move out of dereference of `LazyLock<(Vec<u8>,)>`
//~| HELP consider borrowing here
let _: &Vec<_> = &v;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error[E0507]: cannot move out of dereference of `LazyLock<(Vec<u8>,)>`
--> $DIR/borrow-from-overloaded-deref-issue-154826.rs:8:16
|
LL | let (v,) = *V;
| - ^^
| |
| data moved here because `v` has type `Vec<u8>`, which does not implement the `Copy` trait
|
help: consider borrowing here
|
LL | let (v,) = &*V;
| +

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0507`.
10 changes: 5 additions & 5 deletions tests/ui/suggestions/issue-102892.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ LL | let (a, b) = **arc; // suggests putting `&**arc` here; with that, fixed
| | ...and here
| data moved here
|
= note: move occurs because these variables have types that don't implement the `Copy` trait
help: consider removing the dereference here
|
LL - let (a, b) = **arc; // suggests putting `&**arc` here; with that, fixed!
LL + let (a, b) = *arc; // suggests putting `&**arc` here; with that, fixed!
help: destructuring assignment cannot borrow from this expression; consider using a `let` binding instead
--> $DIR/issue-102892.rs:11:18
|
LL | let (a, b) = **arc; // suggests putting `&**arc` here; with that, fixed!
| ^^^^^
= note: move occurs because these variables have types that don't implement the `Copy` trait

error: aborting due to 4 previous errors

Expand Down
Loading