Skip to content

Clippy fix for "contains_key followed by insert" produces "borrow of moved value" error #9925

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
fishrockz opened this issue Nov 20, 2022 · 2 comments · Fixed by #14314
Closed
Labels
C-bug Category: Clippy is not doing the correct thing

Comments

@fishrockz
Copy link

fishrockz commented Nov 20, 2022

When running cargo clippy --fix

[will@localhost girderstream]$ cargo clippy --fix
   Compiling girderstream v0.1.0 (/home/will/projects/rust/buildsystems/girderstream)
warning: failed to automatically apply fixes suggested by rustc to crate `girderstream`

after fixes were automatically applied the compiler reported errors within these files:

  * src/project/project.rs

This likely indicates a bug in either rustc or cargo itself,
and we would appreciate a bug report! You're likely to see 
a number of compiler warnings after this message which cargo
attempted to fix but failed. If you could open an issue at
https://github.com/rust-lang/rust/issues
quoting the full output of this command we'd be very appreciative!
Note that you may be able to make some more progress in the near-term
fixing code with the `--broken-code` flag

The following errors were reported:
error[E0382]: borrow of moved value: `junctioned_provider`
   --> src/project/project.rs:185:54
    |
163 |         for (junctioned_provider, junctioned_element) in junctioned_project.provides {
    |              ------------------- move occurs because `junctioned_provider` has type `std::string::String`, which does not implement the `Copy` trait
...
182 |             if let std::collections::hash_map::Entry::Vacant(e) = self.provides.entry(junctioned_provider) {
    |                                                                                       ------------------- value moved here
...
185 |                 panic!("Cant have two elements with {junctioned_provider} even through a junction");
    |                                                      ^^^^^^^^^^^^^^^^^^^ value borrowed here after move
    |
    = note: this error originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

For more information about this error, try `rustc --explain E0382`.
Original diagnostics will follow.

warning: usage of `contains_key` followed by `insert` on a `HashMap`
   --> src/project/project.rs:182:13
    |
182 | /             if self.provides.contains_key(&junctioned_provider) {
183 | |                 panic!("Cant have two elements with {junctioned_provider} even through a junction");
184 | |             } else {
185 | |                 self.provides
186 | |                     .insert(junctioned_provider, junctioned_element);
187 | |             }
    | |_____________^
    |
    = note: `#[warn(clippy::map_entry)]` on by default
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
help: try this
    |
182 ~             if let std::collections::hash_map::Entry::Vacant(e) = self.provides.entry(junctioned_provider) {
183 +                 e.insert(junctioned_element);
184 +             } else {
185 +                 panic!("Cant have two elements with {junctioned_provider} even through a junction");
186 +             }
    |

warning: `girderstream` (lib test) generated 1 warning
warning: `girderstream` (lib) generated 1 warning (1 duplicate)
    Finished dev [unoptimized + debuginfo] target(s) in 21.37s

The code fails because I use the thing I test for in the hash map in the else. This seems fairly sensible so I am surprised this wasn't picked up already. Maybe I'm missing something silly.

Ether way the output suggested creating a issue so I have done

Meta

rustc --version --verbose:

rustc 1.64.0 (a55dd71d5 2022-09-19)
binary: rustc
commit-hash: a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52
commit-date: 2022-09-19
host: x86_64-unknown-linux-gnu
release: 1.64.0
LLVM version: 14.0.6

To reproduce clone https://gitlab.com/girderstream/girderstream/-/commit/edc55aa923ad4fdb51e4494998c4b681b6fcb260 and run cargo clippy --fix

This is the diff clippy suggests with cargo clippy --fix --broken-code https://gitlab.com/girderstream/girderstream/-/commit/f7cbc3b097d859805d1f27b56b0973fb3004e963

which can be fixed with https://gitlab.com/girderstream/girderstream/-/commit/83422f677efb4eba8eb7a54da5cecc6022992d38 but is not always a good idea to add a clone.

Its a shame you cant pass in a borrow to HashMap.entry()

@fishrockz fishrockz added the C-bug Category: Clippy is not doing the correct thing label Nov 20, 2022
@matthiaskrgr matthiaskrgr transferred this issue from rust-lang/rust Nov 21, 2022
@claraphyll
Copy link

This issue still exists. Maybe map_entry should only be applied when the key type is Copy.

@jmquigs
Copy link
Contributor

jmquigs commented Jun 8, 2024

The following simple program reproduces this in rustc 1.80.0-nightly (804421dff 2024-06-07)

use std::collections::HashMap;

fn main() {
    let mut hm:HashMap<String,bool> = HashMap::new();
    let key = "hello".to_string();
    if hm.contains_key(&key) {
        let bval = hm.get_mut(&key).unwrap();
        *bval = false;
    } else {
        hm.insert(key, true);
    }
}

causing this error after fix:

error[E0382]: borrow of moved value: `key`
 --> src/main.rs:9:31
  |
5 |     let key = "hello".to_string();
  |         --- move occurs because `key` has type `std::string::String`, which does not implement the `Copy` trait      
6 |     if let std::collections::hash_map::Entry::Vacant(e) = hm.entry(key) {
  |                                                                    --- value moved here
...
9 |         let bval = hm.get_mut(&key).unwrap();
  |                               ^^^^ value borrowed here after move

error: aborting due to 1 previous error

As @maxi0604 suggested, perhaps if the key is not Copy the lint could simply warn about this but not attempt a fix. An autofix does not seem simple because the get_mut line is now invalid - the key would need to have been cloned in the call to entry for that to work.

github-merge-queue bot pushed a commit that referenced this issue Mar 2, 2025
Closes #13306
Closes #9925
Closes #9470
Closes #9305

Clippy gives wrong suggestions when the key is not `Copy`. As suggested
in #9925, in such cases Clippy will simply warn but no fix.

changelog: [`map_entry`]: fix wrong suggestions when key is not `Copy`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: Clippy is not doing the correct thing
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants