Rust ownership — do not clone your way out
When rustc rejects your code with a borrow or move error, it usually gives you
nothing to act on: on 5 of the 6 cases in this repo's corpus it emits no help
and no note at all. In the one case where it does offer a help, that help is
"consider cloning the value".
So the path of least resistance is to clone until it compiles. Do not take it. Cloning to escape a borrow conflict does not fix the conflict — it makes two objects where the code assumed one.
The rule
Never introduce .clone(), Arc, Rc, RefCell or Box::leak for the purpose
of silencing a compiler error. Those are designs, not fixes. Reach for them only
when the design genuinely calls for shared or owned data, and say so explicitly.
When you hit a borrow error, work in this order:
- Shorten the borrow. Bind only what you need (a
bool, ausize, an owned key) inside a tight scope so the borrow ends before the conflicting use. - Change the signature. If a callee only reads, take
&T/&strinstead ofT. - Sequence the accesses. Do the read, finish with it, then do the write.
- Use the API built for it.
entry,split_at_mut, indices,std::mem::take. - Only then consider owning the data — and when you do, say in one sentence why sharing or copying is the right design, not just what made the error go away.
Per-error playbook
| Code | What it means | Do NOT | Do |
|---|---|---|---|
| E0382 | Value used after being moved | Pass x.clone() |
Take &T in the callee |
| E0499 | Two mutable borrows at once | Clone the collection | Sequence them, or split_at_mut |
| E0502 | Mutable borrow while immutably borrowed | Clone the looked-up value | End the read in a tight scope, or use entry |
| E0506 | Assign to a borrowed value | Clone the struct | Shorten the reference's lifetime |
| E0515 | Return a reference to a local | Box::leak |
Return the owned value |
| E0597 | Borrow outlives its referent | Wrap in Rc<RefCell<_>> |
Restructure so the value outlives the borrow |
The one that actually bites
E0499 and E0502 are the dangerous ones. Cloning there compiles cleanly, passes tests, and is silently wrong: the two halves of the code now mutate different objects, so writes through one are invisible to the other.
clippy::redundant_clone will not save you. It only fires when the original is
never used again. In exactly these cases the original is still used — that is
why the borrow conflicted — so clippy stays silent.
When cloning IS right
Cloning is not banned. It is correct when the data genuinely needs independent ownership: sending a value to another thread, storing a snapshot that must not change, or when profiling shows the copy is cheap and the restructure is not worth it. The test is whether you can state the reason without referring to the compiler error.
Evidence
Every claim above comes from compiling the programs in corpus/ with a real rustc
and reading --error-format=json. See EVIDENCE.md, which is
generated by node scripts/extract.mjs and re-verified in CI.