rust-lang / rust-lang/rust-clippy

clippy::let_and_return incorrectly applies when a temporary is needed to resolve borrows

Open
#11,308 4 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

I tried this code:

    let result = stmt_select_note
        .query_and_then(
            named_params![
               ":txid": txid.as_ref(),
               ":output_index": index,
            ],
            to_spendable_note,
        )?
        .next()
        .transpose();

    result

And ran:

cargo clippy --all-features --tests --fix

I expected to see this happen:

The Clippy let_and_return lint should detect that the result temporary is necessary in order for the enclosing method to compile.

Instead, this happened:

Checking zcash_client_sqlite v0.7.1 (/home/nuttycom/work/librustzcash/work/zcash_client_sqlite)
warning: failed to automatically apply fixes suggested by rustc to crate `zcash_client_sqlite`

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

  * zcash_client_sqlite/src/wallet/sapling.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[E0597]: `stmt_select_note` does not live long enough
   --> zcash_client_sqlite/src/wallet/sapling.rs:149:5
    |
149 |        stmt_select_note
    |   _____^
    |  |_____|
    | ||
150 | ||         .query_and_then(
151 | ||             named_params![
152 | ||                ":txid": txid.as_ref(),
...   ||
155 | ||             to_spendable_note,
156 | ||         )?
    | ||_________^- a temporary with access to the borrow is created here ...
    |  |_________|
    |            borrowed value does not live long enough
...
159 |    }
    |    -
    |    |
    |    `stmt_select_note` dropped here while still borrowed
    |    ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::ops::ControlFlow<std::result::Result<std::convert::Infallible, rusqlite::Error>, rusqlite::AndThenRows<'_, for<'r, 's> fn(&'r rusqlite::Row<'s>) -> std::result::Result<zcash_client_backend::wallet::ReceivedSaplingNote<ReceivedNoteId>, error::SqliteClientError> {wallet::sapling::to_spendable_note}>>`
    |
    = note: the temporary is part of an expression at the end of a block;
            consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
    |
149 ~     let x = stmt_select_note
150 |         .query_and_then(
  ...
157 |         .next()
158 ~         .transpose(); x
    |

error: aborting due to previous error

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

warning: returning the result of a `let` binding from a block
   --> zcash_client_sqlite/src/wallet/sapling.rs:158:5
    |
147 | /     let result = stmt_select_note
148 | |         .query_and_then(
149 | |             named_params![
150 | |                ":txid": txid.as_ref(),
...   |
155 | |         .next()
156 | |         .transpose();
    | |_____________________- unnecessary `let` binding
157 |
158 |       result
    |       ^^^^^^
    |
    = note: `#[warn(clippy::let_and_return)]` on by default
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return
help: return the expression directly
    |
147 ~
148 |
149 ~     stmt_select_note
150 +         .query_and_then(
151 +             named_params![
152 +                ":txid": txid.as_ref(),
153 +                ":output_index": index,
154 +             ],
155 +             to_spendable_note,
156 +         )?
157 +         .next()
158 +         .transpose()
    |

warning: `zcash_client_sqlite` (lib test) generated 1 warning
    Finished dev [unoptimized + debuginfo] target(s) in 16.79s
Meta

rustc --version --verbose:

rustc 1.65.0 (897e37553 2022-11-02)
binary: rustc
commit-hash: 897e37553bba8b42751c67658967889d11ecd120
commit-date: 2022-11-02
host: x86_64-unknown-linux-gnu
release: 1.65.0
LLVM version: 15.0.0

I also attempted to run this as cargo +nightly clippy --all-features --tests --fix and encountered the same error.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the report with cargo clippy --all-features --tests --fix against zcash_client_sqlite/src/wallet/sapling.rs, using the shown let_and_return example. Start by tracing the let_and_return lint and its suggested fix; done means the lint no longer suggests removing a temporary when that change causes the borrow-checking error.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.