Skip to content

Commit 0e54c26

Browse files
Rollup merge of #154843 - nataliakokoromyti:fix-154826-deref-help, r=mati865
Fix conflicting deref move suggestion for LazyLock patterns fixes #154826. Rust was suggesting *V -> V for let (v,) = *V, which then triggered a follow-up error suggesting the opposite. This patch makes that case suggest borrowing (&*V) instead. Also handles destructuring assignment separately so we don’t emit a misleading &*... fix-it there.
2 parents d12af20 + 7d68017 commit 0e54c26

6 files changed

Lines changed: 111 additions & 8 deletions

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

Lines changed: 41 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,67 @@ 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;
803+
let mut is_nested_deref = false;
796804
if let Some(inner) = inner {
805+
is_nested_deref =
806+
matches!(inner.kind, hir::ExprKind::Unary(hir::UnOp::Deref, _));
797807
let typck_result = self.infcx.tcx.typeck(self.mir_def_id());
798808
if let Some(inner_type) = typck_result.node_type_opt(inner.hir_id) {
799809
if matches!(inner_type.kind(), ty::RawPtr(..)) {
800810
is_raw_ptr = true;
811+
} else if matches!(inner_type.kind(), ty::Ref(..)) {
812+
is_ref = true;
801813
}
802814
}
815+
is_destructuring_assignment =
816+
self.infcx.tcx.hir_parent_iter(inner.hir_id).any(|(_, node)| {
817+
matches!(
818+
node,
819+
hir::Node::LetStmt(&hir::LetStmt {
820+
source: hir::LocalSource::AssignDesugar,
821+
..
822+
})
823+
)
824+
});
803825
}
804826
// If the `inner` is a raw pointer, do not suggest removing the "*", see #126863
805827
// 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 {
828+
if is_raw_ptr {
829+
return;
830+
}
831+
832+
if !is_destructuring_pattern_move || is_ref {
807833
err.span_suggestion_verbose(
808834
span.with_hi(span.lo() + BytePos(1)),
809835
"consider removing the dereference here",
810836
String::new(),
811837
Applicability::MaybeIncorrect,
812838
);
839+
} else if !is_destructuring_assignment && !is_nested_deref {
840+
err.span_suggestion_verbose(
841+
span.shrink_to_lo(),
842+
"consider borrowing here",
843+
'&',
844+
Applicability::MaybeIncorrect,
845+
);
846+
} else {
847+
err.span_help(
848+
span,
849+
"destructuring assignment cannot borrow from this expression; consider using a `let` binding instead",
850+
);
813851
}
814852
}
815853
_ => {
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`.

tests/ui/suggestions/issue-102892.stderr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ LL | let (a, b) = **arc; // suggests putting `&**arc` here; with that, fixed
6161
| | ...and here
6262
| data moved here
6363
|
64-
= note: move occurs because these variables have types that don't implement the `Copy` trait
65-
help: consider removing the dereference here
66-
|
67-
LL - let (a, b) = **arc; // suggests putting `&**arc` here; with that, fixed!
68-
LL + let (a, b) = *arc; // suggests putting `&**arc` here; with that, fixed!
64+
help: destructuring assignment cannot borrow from this expression; consider using a `let` binding instead
65+
--> $DIR/issue-102892.rs:11:18
6966
|
67+
LL | let (a, b) = **arc; // suggests putting `&**arc` here; with that, fixed!
68+
| ^^^^^
69+
= note: move occurs because these variables have types that don't implement the `Copy` trait
7070

7171
error: aborting due to 4 previous errors
7272

0 commit comments

Comments
 (0)