mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 15:01:51 +00:00
6eaa7fb576
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. |
||
---|---|---|
.. | ||
auxiliary | ||
issue-18652.rs | ||
issue-18661.rs | ||
issue-30906.rs | ||
issue-30906.stderr | ||
issue-53448.rs | ||
non-tupled-arg-mismatch.rs | ||
non-tupled-arg-mismatch.stderr | ||
non-tupled-call.rs | ||
non-tupled-call.stderr | ||
type-id-higher-rank.rs | ||
unboxed-closure-feature-gate.rs | ||
unboxed-closure-feature-gate.stderr | ||
unboxed-closure-illegal-move.rs | ||
unboxed-closure-illegal-move.stderr | ||
unboxed-closure-immutable-capture.rs | ||
unboxed-closure-immutable-capture.stderr | ||
unboxed-closure-no-cyclic-sig.rs | ||
unboxed-closure-no-cyclic-sig.stderr | ||
unboxed-closure-region.rs | ||
unboxed-closure-region.stderr | ||
unboxed-closure-sugar-default.rs | ||
unboxed-closure-sugar-default.stderr | ||
unboxed-closure-sugar-equiv.rs | ||
unboxed-closure-sugar-equiv.stderr | ||
unboxed-closure-sugar-lifetime-elision.rs | ||
unboxed-closure-sugar-lifetime-elision.stderr | ||
unboxed-closure-sugar-not-used-on-fn.rs | ||
unboxed-closure-sugar-not-used-on-fn.stderr | ||
unboxed-closure-sugar-region.rs | ||
unboxed-closure-sugar-region.stderr | ||
unboxed-closure-sugar-used-on-struct-1.rs | ||
unboxed-closure-sugar-used-on-struct-1.stderr | ||
unboxed-closure-sugar-used-on-struct-3.rs | ||
unboxed-closure-sugar-used-on-struct-3.stderr | ||
unboxed-closure-sugar-used-on-struct.rs | ||
unboxed-closure-sugar-used-on-struct.stderr | ||
unboxed-closure-sugar-wrong-number-number-type-parameters-1.rs | ||
unboxed-closure-sugar-wrong-number-number-type-parameters-1.stderr | ||
unboxed-closure-sugar-wrong-number-number-type-parameters-3.rs | ||
unboxed-closure-sugar-wrong-number-number-type-parameters-3.stderr | ||
unboxed-closure-sugar-wrong-number-number-type-parameters.rs | ||
unboxed-closure-sugar-wrong-number-number-type-parameters.stderr | ||
unboxed-closure-sugar-wrong-trait.rs | ||
unboxed-closure-sugar-wrong-trait.stderr | ||
unboxed-closures-all-traits.rs | ||
unboxed-closures-blanket-fn-mut.rs | ||
unboxed-closures-blanket-fn.rs | ||
unboxed-closures-borrow-conflict.rs | ||
unboxed-closures-borrow-conflict.stderr | ||
unboxed-closures-boxed.rs | ||
unboxed-closures-by-ref.rs | ||
unboxed-closures-call-fn-autoderef.rs | ||
unboxed-closures-call-sugar-autoderef.rs | ||
unboxed-closures-call-sugar-object-autoderef.rs | ||
unboxed-closures-call-sugar-object.rs | ||
unboxed-closures-counter-not-moved.rs | ||
unboxed-closures-counter-not-moved.stderr | ||
unboxed-closures-cross-crate.rs | ||
unboxed-closures-direct-sugary-call.rs | ||
unboxed-closures-drop.rs | ||
unboxed-closures-extern-fn-hr.rs | ||
unboxed-closures-extern-fn.rs | ||
unboxed-closures-failed-recursive-fn-1.rs | ||
unboxed-closures-failed-recursive-fn-1.stderr | ||
unboxed-closures-failed-recursive-fn-2.rs | ||
unboxed-closures-failed-recursive-fn-2.stderr | ||
unboxed-closures-fn-as-fnmut-and-fnonce.rs | ||
unboxed-closures-fnmut-as-fn.rs | ||
unboxed-closures-fnmut-as-fn.stderr | ||
unboxed-closures-fnmut-as-fnonce.rs | ||
unboxed-closures-generic.rs | ||
unboxed-closures-infer-arg-types-from-expected-bound.rs | ||
unboxed-closures-infer-arg-types-from-expected-object-type.rs | ||
unboxed-closures-infer-arg-types-w-bound-regs-from-expected-bound.rs | ||
unboxed-closures-infer-argument-types-two-region-pointers.rs | ||
unboxed-closures-infer-argument-types-two-region-pointers.stderr | ||
unboxed-closures-infer-explicit-call-early.rs | ||
unboxed-closures-infer-fn-once-move-from-projection.rs | ||
unboxed-closures-infer-fn-once-move-from-projection.stderr | ||
unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs | ||
unboxed-closures-infer-fnmut-calling-fnmut-no-mut.stderr | ||
unboxed-closures-infer-fnmut-calling-fnmut.rs | ||
unboxed-closures-infer-fnmut-missing-mut.rs | ||
unboxed-closures-infer-fnmut-missing-mut.stderr | ||
unboxed-closures-infer-fnmut-move-missing-mut.rs | ||
unboxed-closures-infer-fnmut-move-missing-mut.stderr | ||
unboxed-closures-infer-fnmut-move.rs | ||
unboxed-closures-infer-fnmut.rs | ||
unboxed-closures-infer-fnonce-call-twice.rs | ||
unboxed-closures-infer-fnonce-call-twice.stderr | ||
unboxed-closures-infer-fnonce-move-call-twice.rs | ||
unboxed-closures-infer-fnonce-move-call-twice.stderr | ||
unboxed-closures-infer-fnonce-move.rs | ||
unboxed-closures-infer-fnonce.rs | ||
unboxed-closures-infer-kind.rs | ||
unboxed-closures-infer-recursive-fn.rs | ||
unboxed-closures-infer-upvar.rs | ||
unboxed-closures-manual-impl.rs | ||
unboxed-closures-monomorphization.rs | ||
unboxed-closures-move-from-projection-issue-30046.rs | ||
unboxed-closures-move-mutable.rs | ||
unboxed-closures-move-mutable.stderr | ||
unboxed-closures-move-some-upvars-in-by-ref-closure.rs | ||
unboxed-closures-mutate-upvar.rs | ||
unboxed-closures-mutate-upvar.stderr | ||
unboxed-closures-mutated-upvar-from-fn-closure.rs | ||
unboxed-closures-mutated-upvar-from-fn-closure.stderr | ||
unboxed-closures-prelude.rs | ||
unboxed-closures-recursive-fn-using-fn-mut.rs | ||
unboxed-closures-recursive-fn-using-fn-mut.stderr | ||
unboxed-closures-simple.rs | ||
unboxed-closures-single-word-env.rs | ||
unboxed-closures-static-call-fn-once.rs | ||
unboxed-closures-static-call-wrong-trait.rs | ||
unboxed-closures-static-call-wrong-trait.stderr | ||
unboxed-closures-sugar-object.rs | ||
unboxed-closures-type-mismatch-closure-from-another-scope.rs | ||
unboxed-closures-type-mismatch-closure-from-another-scope.stderr | ||
unboxed-closures-type-mismatch.rs | ||
unboxed-closures-type-mismatch.stderr | ||
unboxed-closures-unique-type-id.rs | ||
unboxed-closures-unsafe-extern-fn.rs | ||
unboxed-closures-unsafe-extern-fn.stderr | ||
unboxed-closures-wrong-abi.rs | ||
unboxed-closures-wrong-abi.stderr | ||
unboxed-closures-wrong-arg-type-extern-fn.rs | ||
unboxed-closures-wrong-arg-type-extern-fn.stderr | ||
unboxed-closures-zero-args.rs |