Skip to content

manual_unwrap_or_default suggested when ref keyword is used #14716

@mrclmh

Description

@mrclmh

Summary

The lint manual_unwrap_or_default is only suggested in the version where the ref keyword is used.

Lint Name

manual_unwrap_or_default

Reproducer

I tried this code:

struct Project {
    name: Option<String>,
}

fn func(project: &Project) {
    // this version triggers the lint
    let _name = match project.name {
        Some(ref x) => x,
        None => "",
    };

    // counter-example: this version does not trigger the lint
    let _name2 = match &project.name {
        Some(x) => x,
        None => "",
    };
}

I saw this happen:

error: match can be simplified with `.unwrap_or_default()`
   --> src/main.rs:156:17
    |
156 |       let _name = match project.name {
    |  _________________^
157 | |         Some(ref x) => x,
158 | |         None => "",
159 | |     };
    | |_____^ help: replace it with: `project.name.unwrap_or_default()`
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or_default
    = note: `-D clippy::manual-unwrap-or-default` implied by `-D clippy::all`
    = help: to override `-D clippy::all` add `#[allow(clippy::manual_unwrap_or_default)]`

Applying the suggestion results in an error:

error[E0507]: cannot move out of `project.name` which is behind a shared reference
    --> src/main.rs:156:22
     |
156  |     let _incorrect = project.name.unwrap_or_default();
     |                      ^^^^^^^^^^^^ ------------------- `project.name` moved due to this method call
     |                      |
     |                      help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
     |                      move occurs because `project.name` has type `std::option::Option<std::string::String>`, which does not implement the `Copy` trait
     |
note: `std::option::Option::<T>::unwrap_or_default` takes ownership of the receiver `self`, which moves `project.name`
    --> /Users/mrclmh/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:1048:30
     |
1048 |     pub fn unwrap_or_default(self) -> T
     |                              ^^^^
help: you can `clone` the value and consume it, but this might not be your desired behavior
     |
156  |     let _incorrect = <std::option::Option<std::string::String> as Clone>::clone(&project.name).unwrap_or_default();
     |                      ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++            +
help: consider cloning the value if the performance cost is acceptable
     |
156  |     let _incorrect = project.name.clone().unwrap_or_default();
     |                                  ++++++++

I expected to see this happen:
The code should not trigger the lint, because the suggested code is not valid.

Version

rustc 1.85.0 (4d91de4e4 2025-02-17)
binary: rustc
commit-hash: 4d91de4e48198da2e33413efdcd9cd2cc0c46688
commit-date: 2025-02-17
host: aarch64-apple-darwin
release: 1.85.0
LLVM version: 19.1.7

Additional Labels

No response

Metadata

Metadata

Assignees

Labels

C-bugCategory: Clippy is not doing the correct thingI-false-positiveIssue: The lint was triggered on code it shouldn't haveI-suggestion-causes-errorIssue: The suggestions provided by this Lint cause an ICE/error when applied

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions