Skip to content

needless_borrow suggestion changes a reference to a move which breaks surrounding code #8391

Closed
@wfraser

Description

@wfraser

Summary

Consider std::io::Read, which has methods that take self, but the trait is also explicitly implemented for &mut R where R: Read.

Consider the following code:

use std::io::{Cursor, Read};
let mut r = Cursor::new("hello world");
let a = (&mut r).take(3);
// do stuff, drop a
let b = r.take(3);

a lets you still use r afterward, but b does not, because it moves r into the wrapper.

Lint Name

needless_borrow

Reproducer

I ran into this problem with code that uses a reader in a loop, using take to read it in chunks, similar to this:

use std::io::{self, Cursor, Read, Write};

fn main() {
    let mut data = Cursor::new("line 1\n\
        line 2\n\
        line 3\n\
        line 4\n");
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    loop {
        let mut chunk = (&mut data).take(2); // `(&mut data)` can't be replaced by `data`!
        let n = io::copy(&mut chunk, &mut stdout).unwrap();
        if n == 0 {
            break;
        }
        stdout.write_all(b".").unwrap();
    }
}

Clippy says:

warning: this expression borrows a value the compiler would automatically borrow
  [--> src/main.rs:11:25
](https://play.rust-lang.org/#)   |
11 |         let mut chunk = (&mut data).take(2); // `(&mut data)` can't be replaced by `data`!
   |                         ^^^^^^^^^^^ help: change this to: `data`
   |
   = note: `#[warn(clippy::needless_borrow)]` on by default
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

But that won't compile:

error[[E0382]](https://doc.rust-lang.org/stable/error-index.html#E0382): use of moved value: `data`
   [--> src/main.rs:12:25
](https://play.rust-lang.org/#)    |
4   |     let mut data = Cursor::new("line 1\n\
    |         -------- move occurs because `data` has type `std::io::Cursor<&str>`, which does not implement the `Copy` trait
...
12  |         let mut chunk = data.take(2);
    |                         ^^^^ ------- `data` moved due to this method call, in previous iteration of loop
    |
note: this function takes ownership of the receiver `self`, which moves `data`

Version

rustc 1.60.0-nightly (27f5d830e 2022-02-02)          
binary: rustc                                        
commit-hash: 27f5d830eb11cd7bdc834d6f0d78120976f75443
commit-date: 2022-02-02                              
host: x86_64-unknown-linux-gnu                       
release: 1.60.0-nightly                              
LLVM version: 13.0.0

Additional Labels

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: Clippy is not doing the correct thingI-false-positiveIssue: The lint was triggered on code it shouldn't have

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions