Skip to content

Commit 2bddfca

Browse files
borrowck: suggest borrowing for destructuring moves from overloaded deref
1 parent c92036b commit 2bddfca

5 files changed

Lines changed: 99 additions & 3 deletions

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
678678
fn add_move_hints(&self, error: GroupedMoveError<'tcx>, err: &mut Diag<'_>, span: Span) {
679679
match error {
680680
GroupedMoveError::MovesFromPlace { mut binds_to, move_from, .. } => {
681-
self.add_borrow_suggestions(err, span);
681+
self.add_borrow_suggestions(err, span, !binds_to.is_empty());
682682
if binds_to.is_empty() {
683683
let place_ty = move_from.ty(self.body, self.infcx.tcx).ty;
684684
let place_desc = match self.describe_place(move_from.as_ref()) {
@@ -787,29 +787,60 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
787787
}
788788
}
789789

790-
fn add_borrow_suggestions(&self, err: &mut Diag<'_>, span: Span) {
790+
fn add_borrow_suggestions(
791+
&self,
792+
err: &mut Diag<'_>,
793+
span: Span,
794+
is_destructuring_pattern_move: bool,
795+
) {
791796
match self.infcx.tcx.sess.source_map().span_to_snippet(span) {
792797
Ok(snippet) if snippet.starts_with('*') => {
793798
let sp = span.with_lo(span.lo() + BytePos(1));
794799
let inner = self.find_expr(sp);
795800
let mut is_raw_ptr = false;
801+
let mut is_ref = false;
802+
let mut is_destructuring_assignment = false;
796803
if let Some(inner) = inner {
797804
let typck_result = self.infcx.tcx.typeck(self.mir_def_id());
798805
if let Some(inner_type) = typck_result.node_type_opt(inner.hir_id) {
799806
if matches!(inner_type.kind(), ty::RawPtr(..)) {
800807
is_raw_ptr = true;
808+
} else if matches!(inner_type.kind(), ty::Ref(..)) {
809+
is_ref = true;
801810
}
802811
}
812+
is_destructuring_assignment =
813+
self.infcx.tcx.hir_parent_iter(inner.hir_id).any(|(_, node)| {
814+
matches!(
815+
node,
816+
hir::Node::LetStmt(&hir::LetStmt {
817+
source: hir::LocalSource::AssignDesugar,
818+
..
819+
})
820+
)
821+
});
803822
}
804823
// If the `inner` is a raw pointer, do not suggest removing the "*", see #126863
805824
// FIXME: need to check whether the assigned object can be a raw pointer, see `tests/ui/borrowck/issue-20801.rs`.
806-
if !is_raw_ptr {
825+
if !is_raw_ptr && (!is_destructuring_pattern_move || is_ref) {
807826
err.span_suggestion_verbose(
808827
span.with_hi(span.lo() + BytePos(1)),
809828
"consider removing the dereference here",
810829
String::new(),
811830
Applicability::MaybeIncorrect,
812831
);
832+
} else if !is_raw_ptr && !is_destructuring_assignment {
833+
err.span_suggestion_verbose(
834+
span.shrink_to_lo(),
835+
"consider borrowing here",
836+
'&',
837+
Applicability::MaybeIncorrect,
838+
);
839+
} else if !is_raw_ptr {
840+
err.span_help(
841+
span,
842+
"destructuring assignment cannot borrow from this expression; consider using a `let` binding instead",
843+
);
813844
}
814845
}
815846
_ => {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Regression test for #154826.
2+
3+
use std::rc::Rc;
4+
5+
struct NonCopy;
6+
7+
fn main() {
8+
let b: NonCopy;
9+
(b,) = *Rc::new((NonCopy,));
10+
//~^ ERROR cannot move out of an `Rc`
11+
//~| HELP destructuring assignment cannot borrow from this expression; consider using a `let` binding instead
12+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0507]: cannot move out of an `Rc`
2+
--> $DIR/borrow-from-overloaded-deref-assign-issue-154826.rs:9:12
3+
|
4+
LL | (b,) = *Rc::new((NonCopy,));
5+
| - ^^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| data moved here because the place has type `NonCopy`, which does not implement the `Copy` trait
8+
|
9+
help: destructuring assignment cannot borrow from this expression; consider using a `let` binding instead
10+
--> $DIR/borrow-from-overloaded-deref-assign-issue-154826.rs:9:12
11+
|
12+
LL | (b,) = *Rc::new((NonCopy,));
13+
| ^^^^^^^^^^^^^^^^^^^^
14+
note: if `NonCopy` implemented `Clone`, you could clone the value
15+
--> $DIR/borrow-from-overloaded-deref-assign-issue-154826.rs:5:1
16+
|
17+
LL | struct NonCopy;
18+
| ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
19+
...
20+
LL | (b,) = *Rc::new((NonCopy,));
21+
| - you could clone this value
22+
23+
error: aborting due to 1 previous error
24+
25+
For more information about this error, try `rustc --explain E0507`.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Regression test for #154826.
2+
3+
use std::sync::LazyLock;
4+
5+
static V: LazyLock<(Vec<u8>,)> = LazyLock::new(|| (vec![],));
6+
7+
fn main() {
8+
let (v,) = *V;
9+
//~^ ERROR cannot move out of dereference of `LazyLock<(Vec<u8>,)>`
10+
//~| HELP consider borrowing here
11+
let _: &Vec<_> = &v;
12+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0507]: cannot move out of dereference of `LazyLock<(Vec<u8>,)>`
2+
--> $DIR/borrow-from-overloaded-deref-issue-154826.rs:8:16
3+
|
4+
LL | let (v,) = *V;
5+
| - ^^
6+
| |
7+
| data moved here because `v` has type `Vec<u8>`, which does not implement the `Copy` trait
8+
|
9+
help: consider borrowing here
10+
|
11+
LL | let (v,) = &*V;
12+
| +
13+
14+
error: aborting due to 1 previous error
15+
16+
For more information about this error, try `rustc --explain E0507`.

0 commit comments

Comments
 (0)