| Age | Commit message (Collapse) | Author | Lines |
|
|
|
|
|
Detect borrow checker errors where `.clone()` would be an appropriate user action
When a value is moved twice, suggest cloning the earlier move:
```
error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
--> $DIR/union-move.rs:49:18
|
LL | move_out(x.f1_nocopy);
| ^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `x.f1_nocopy` has type `ManuallyDrop<RefCell<i32>>`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL | move_out(x.f1_nocopy.clone());
| ++++++++
```
When a value is borrowed by an `fn` call, consider if cloning the result of the call would be reasonable, and suggest cloning that, instead of the argument:
```
error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/variance-issue-20533.rs:53:14
|
LL | let a = AffineU32(1);
| - binding `a` declared here
LL | let x = bat(&a);
| -- borrow of `a` occurs here
LL | drop(a);
| ^ move out of `a` occurs here
LL | drop(x);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let x = bat(&a).clone();
| ++++++++
```
otherwise, suggest cloning the argument:
```
error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/variance-issue-20533.rs:59:14
|
LL | let a = ClonableAffineU32(1);
| - binding `a` declared here
LL | let x = foo(&a);
| -- borrow of `a` occurs here
LL | drop(a);
| ^ move out of `a` occurs here
LL | drop(x);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL - let x = foo(&a);
LL + let x = foo(a.clone());
|
```
This suggestion doesn't attempt to square out the types between what's cloned and what the `fn` expects, to allow the user to make a determination on whether to change the `fn` call or `fn` definition themselves.
Special case move errors caused by `FnOnce`:
```
error[E0382]: use of moved value: `blk`
--> $DIR/once-cant-call-twice-on-heap.rs:8:5
|
LL | fn foo<F:FnOnce()>(blk: F) {
| --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
LL | blk();
| ----- `blk` moved due to this call
LL | blk();
| ^^^ value used here after move
|
note: `FnOnce` closures can only be called once
--> $DIR/once-cant-call-twice-on-heap.rs:6:10
|
LL | fn foo<F:FnOnce()>(blk: F) {
| ^^^^^^^^ `F` is made to be an `FnOnce` closure here
LL | blk();
| ----- this value implements `FnOnce`, which causes it to be moved when called
```
Account for redundant `.clone()` calls in resulting suggestions:
```
error[E0507]: cannot move out of dereference of `S`
--> $DIR/needs-clone-through-deref.rs:15:18
|
LL | for _ in self.clone().into_iter() {}
| ^^^^^^^^^^^^ ----------- value moved due to this method call
| |
| move occurs because value has type `Vec<usize>`, which does not implement the `Copy` trait
|
note: `into_iter` takes ownership of the receiver `self`, which moves value
--> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
help: you can `clone` the value and consume it, but this might not be your desired behavior
|
LL | for _ in <Vec<usize> as Clone>::clone(&self).into_iter() {}
| ++++++++++++++++++++++++++++++ ~
```
We use the presence of `&mut` values in a move error as a proxy for the user caring about side effects, so we don't emit a clone suggestion in that case:
```
error[E0505]: cannot move out of `s` because it is borrowed
--> $DIR/borrowck-overloaded-index-move-index.rs:53:7
|
LL | let mut s = "hello".to_string();
| ----- binding `s` declared here
LL | let rs = &mut s;
| ------ borrow of `s` occurs here
...
LL | f[s] = 10;
| ^ move out of `s` occurs here
...
LL | use_mut(rs);
| -- borrow later used here
```
We properly account for `foo += foo;` errors where we *don't* suggest `foo.clone() += foo;`, instead suggesting `foo += foo.clone();`.
---
Each commit can be reviewed in isolation. There are some "cleanup" commits, but kept them separate in order to show *why* specific changes were being made, and their effect on tests' output.
Fix #49693, CC #64167.
|
|
Added comments and reworded messages
|
|
|
|
|
|
remove some things that do not need to be
|
|
Account for trait/impl difference when suggesting changing argument from ref to mut ref
Do not ICE when encountering a lifetime error involving an argument with an immutable reference of a method that differs from the trait definition.
Fix #123414.
|
|
|
|
|
|
We attempt to suggest an appropriate clone for move errors on expressions
like `S { ..s }` where a field isn't `Copy`. If we can't suggest, we still don't
emit the incorrect suggestion of `S { ..s }.clone()`.
```
error[E0509]: cannot move out of type `S<K>`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:28:19
|
LL | let _s2 = S { a: 2, ..s0 };
| ^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.c` has type `K`, which does not implement the `Copy` trait
|
help: clone the value from the field instead of using the spread operator syntax
|
LL | let _s2 = S { a: 2, c: s0.c.clone(), ..s0 };
| +++++++++++++++++
```
```
error[E0509]: cannot move out of type `S<()>`, which implements the `Drop` trait
--> $DIR/borrowck-struct-update-with-dtor.rs:20:19
|
LL | let _s2 = S { a: 2, ..s0 };
| ^^^^^^^^^^^^^^^^
| |
| cannot move out of here
| move occurs because `s0.b` has type `B`, which does not implement the `Copy` trait
|
note: `B` doesn't implement `Copy` or `Clone`
--> $DIR/borrowck-struct-update-with-dtor.rs:4:1
|
LL | struct B;
| ^^^^^^^^
help: if `B` implemented `Clone`, you could clone the value from the field instead of using the spread operator syntax
|
LL | let _s2 = S { a: 2, b: s0.b.clone(), ..s0 };
| +++++++++++++++++
```
|
|
```
error[E0382]: use of moved value: `blk`
--> $DIR/once-cant-call-twice-on-heap.rs:8:5
|
LL | fn foo<F:FnOnce()>(blk: F) {
| --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
LL | blk();
| ----- `blk` moved due to this call
LL | blk();
| ^^^ value used here after move
|
note: `FnOnce` closures can only be called once
--> $DIR/once-cant-call-twice-on-heap.rs:6:10
|
LL | fn foo<F:FnOnce()>(blk: F) {
| ^^^^^^^^ `F` is made to be an `FnOnce` closure here
LL | blk();
| ----- this value implements `FnOnce`, which causes it to be moved when called
```
|
|
Explicitly look for `expr += other_expr;` and avoid suggesting
`expr.clone() += other_expr;`, instead suggesting `expr += other_expr.clone();`.
|
|
```
error[E0505]: cannot move out of `a` because it is borrowed
--> $DIR/variance-issue-20533.rs:28:14
|
LL | let a = AffineU32(1);
| - binding `a` declared here
LL | let x = foo(&a);
| -- borrow of `a` occurs here
LL | drop(a);
| ^ move out of `a` occurs here
LL | drop(x);
| - borrow later used here
|
help: consider cloning the value if the performance cost is acceptable
|
LL | let x = foo(&a).clone();
| ++++++++
```
|
|
|
|
|
|
|
|
|
|
```
error[E0507]: cannot move out of `val`, a captured variable in an `FnMut` closure
--> $DIR/issue-87456-point-to-closure.rs:10:28
|
LL | let val = String::new();
| --- captured outer variable
LL |
LL | take_mut(|| {
| -- captured by this `FnMut` closure
LL |
LL | let _foo: String = val;
| ^^^ move occurs because `val` has type `String`, which does not implement the `Copy` trait
|
help: consider borrowing here
|
LL | let _foo: String = &val;
| +
help: consider cloning the value if the performance cost is acceptable
|
LL | let _foo: String = val.clone();
| ++++++++
```
|
|
```
error[E0507]: cannot move out of `*x` which is behind a shared reference
--> $DIR/borrowck-fn-in-const-a.rs:6:16
|
LL | return *x
| ^^ move occurs because `*x` has type `String`, which does not implement the `Copy` trait
|
help: consider cloning the value if the performance cost is acceptable
|
LL - return *x
LL + return x.clone()
|
```
|
|
|
|
|
|
|
|
Tweak value suggestions in `borrowck` and `hir_analysis`
Unify the output of `suggest_assign_value` and `ty_kind_suggestion`.
Ideally we'd make these a single function, but doing so would likely require modify the crate dependency tree.
|
|
Add handling for `String`, `Box`, `Option` and `Result`.
|
|
|
|
|
|
Unify the output of `suggest_assign_value` and `ty_kind_suggestion`.
Ideally we'd make these a single function, but doing so would likely require modify the crate dependency tree.
|
|
to mut ref
Do not ICE when encountering a lifetime error involving an argument with
an immutable reference of a method that differs from the trait definition.
Fix #123414.
|
|
When encoutnering a case like
```rust
//@ run-rustfix
use std::collections::HashMap;
fn main() {
let vs = vec![0, 0, 1, 1, 3, 4, 5, 6, 3, 3, 3];
let mut counts = HashMap::new();
for num in vs {
let count = counts.entry(num).or_insert(0);
*count += 1;
}
let _ = counts.iter().max_by_key(|(_, v)| v);
```
produce the following suggestion
```
error: lifetime may not live long enough
--> $DIR/return-value-lifetime-error.rs:13:47
|
LL | let _ = counts.iter().max_by_key(|(_, v)| v);
| ------- ^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure is &'2 &i32
| has type `&'1 (&i32, &i32)`
|
help: dereference the return value
|
LL | let _ = counts.iter().max_by_key(|(_, v)| **v);
| ++
```
Fix #50195.
|
|
|
|
compiler: fix few unused_peekable and needless_pass_by_ref_mut clippy lints
This fixes few instances of `unused_peekable` and `needless_pass_by_ref_mut`. While i expected to fix more warnings, `needless_pass_by_ref_mut` produced too much for one PR, so i stopped here.
Better reviewed commit by commit, as fixes splitted by chunks.
|
|
maybe bug here?
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_borrowck\src\diagnostics\conflict_errors.rs:3857:35
|
3857 | pub(crate) fn emit(&self, cx: &mut MirBorrowckCtxt<'_, 'tcx>, diag: &mut Diag<'_>) -> String {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&MirBorrowckCtxt<'_, 'tcx>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
warning: this argument is a mutable reference, but not used mutably
--> compiler\rustc_borrowck\src\type_check\liveness\trace.rs:601:17
|
601 | typeck: &mut TypeChecker<'_, 'tcx>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&TypeChecker<'_, 'tcx>`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut
|
|
|
|
Fix diagnostics for async block cloning
Closes #121547
r? diagnostics
|
|
Rather than `.into_iter().rev().find_position(...)`, this case can
simply call `.iter().rposition(...)`.
|
|
|
|
|
|
Rename `hir::Local` into `hir::LetStmt`
Follow-up of #122776.
As discussed on [zulip](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Improve.20naming.20of.20.60ExprKind.3A.3ALet.60.3F).
I made this change into a separate PR because I'm less sure about this change as is. For example, we have `visit_local` and `LocalSource` items. Is it fine to keep these two as is (I supposed it is but I prefer to ask) or not? Having `Node::Local(LetStmt)` makes things more explicit but is it going too far?
r? ```@oli-obk```
|
|
|
|
|
|
|
|
|
|
|
|
For ref pattern in func param, the mutability suggestion has to apply to the binding.
For example: `fn foo(&x: &i32)` -> `fn foo(&(mut x): &i32)`
fixes #122415
|
|
|
|
|
|
Sometimes move errors are because of a misplaced `continue`, but we didn't
surface that anywhere. Now when there are more than one set of nested loops
we show them out and point at the `continue` and `break` expressions within
that might need to go elsewhere.
```
error[E0382]: use of moved value: `foo`
--> $DIR/nested-loop-moved-value-wrong-continue.rs:46:18
|
LL | for foo in foos {
| ---
| |
| this reinitialization might get skipped
| move occurs because `foo` has type `String`, which does not implement the `Copy` trait
...
LL | for bar in &bars {
| ---------------- inside of this loop
...
LL | baz.push(foo);
| --- value moved here, in previous iteration of loop
...
LL | qux.push(foo);
| ^^^ value used here after move
|
note: verify that your loop breaking logic is correct
--> $DIR/nested-loop-moved-value-wrong-continue.rs:41:17
|
LL | for foo in foos {
| ---------------
...
LL | for bar in &bars {
| ----------------
...
LL | continue;
| ^^^^^^^^ this `continue` advances the loop at line 33
help: consider moving the expression out of the loop so it is only moved once
|
LL ~ let mut value = baz.push(foo);
LL ~ for bar in &bars {
LL |
...
LL | if foo == *bar {
LL ~ value;
|
help: consider cloning the value if the performance cost is acceptable
|
LL | baz.push(foo.clone());
| ++++++++
```
Fix #92531.
|
|
be cloned
When encountering a move error on a value within a loop of any kind,
identify if the moved value belongs to a call expression that should not
be cloned and avoid the semantically incorrect suggestion. Also try to
suggest moving the call expression outside of the loop instead.
```
error[E0382]: use of moved value: `vec`
--> $DIR/recreating-value-in-loop-condition.rs:6:33
|
LL | let vec = vec!["one", "two", "three"];
| --- move occurs because `vec` has type `Vec<&str>`, which does not implement the `Copy` trait
LL | while let Some(item) = iter(vec).next() {
| ----------------------------^^^--------
| | |
| | value moved here, in previous iteration of loop
| inside of this loop
|
note: consider changing this parameter type in function `iter` to borrow instead if owning the value isn't necessary
--> $DIR/recreating-value-in-loop-condition.rs:1:17
|
LL | fn iter<T>(vec: Vec<T>) -> impl Iterator<Item = T> {
| ---- ^^^^^^ this parameter takes ownership of the value
| |
| in this function
help: consider moving the expression out of the loop so it is only moved once
|
LL ~ let mut value = iter(vec);
LL ~ while let Some(item) = value.next() {
|
```
We use the presence of a `break` in the loop that would be affected by
the moved value as a heuristic for "shouldn't be cloned".
Fix #121466.
|
|
Detect calls to .clone() on T: !Clone types on borrowck errors
When encountering a lifetime error on a type that *holds* a type that doesn't implement `Clone`, explore the item's body for potential calls to `.clone()` that are only cloning the reference `&T` instead of `T` because `T: !Clone`. If we find this, suggest `T: Clone`.
```
error[E0502]: cannot borrow `*list` as mutable because it is also borrowed as immutable
--> $DIR/clone-on-ref.rs:7:5
|
LL | for v in list.iter() {
| ---- immutable borrow occurs here
LL | cloned_items.push(v.clone())
| ------- this call doesn't do anything, the result is still `&T` because `T` doesn't implement `Clone`
LL | }
LL | list.push(T::default());
| ^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL |
LL | drop(cloned_items);
| ------------ immutable borrow later used here
|
help: consider further restricting this bound
|
LL | fn foo<T: Default + Clone>(list: &mut Vec<T>) {
| +++++++
```
```
error[E0505]: cannot move out of `x` because it is borrowed
--> $DIR/clone-on-ref.rs:23:10
|
LL | fn qux(x: A) {
| - binding `x` declared here
LL | let a = &x;
| -- borrow of `x` occurs here
LL | let b = a.clone();
| ------- this call doesn't do anything, the result is still `&A` because `A` doesn't implement `Clone`
LL | drop(x);
| ^ move out of `x` occurs here
LL |
LL | println!("{b:?}");
| ----- borrow later used here
|
help: consider annotating `A` with `#[derive(Clone)]`
|
LL + #[derive(Clone)]
LL | struct A;
|
```
Fix #48677.
|