Skip to content

Add block_scrutinee lint#16855

Open
shivendra02467 wants to merge 1 commit intorust-lang:masterfrom
shivendra02467:block-scrutinee-lint
Open

Add block_scrutinee lint#16855
shivendra02467 wants to merge 1 commit intorust-lang:masterfrom
shivendra02467:block-scrutinee-lint

Conversation

@shivendra02467
Copy link
Copy Markdown

@shivendra02467 shivendra02467 commented Apr 15, 2026

This PR introduces a new late pass lint to catch scrutinees unnecessarily wrapped in blocks on older editions, preventing unintended behavior regarding temporary lifetimes.

Fixes #16827

changelog: new lint: [block_scrutinee] to warn on scrutinees wrapped in blocks in older editions

@rustbot rustbot added needs-fcp PRs that add, remove, or rename lints and need an FCP S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Apr 15, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 15, 2026

r? @llogiq

rustbot has assigned @llogiq.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: 7 candidates
  • 7 candidates expanded to 7 candidates
  • Random selection from Jarcho, dswij, llogiq, samueltardieu

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 15, 2026

Lintcheck changes for 89131a5

Lint Added Removed Changed
clippy::block_scrutinee 140 0 0

This comment will be updated if you push new changes

@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

@rustbot rustbot added has-merge-commits PR has merge commits, merge with caution. S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) labels Apr 15, 2026
@rustbot rustbot removed S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) has-merge-commits PR has merge commits, merge with caution. labels Apr 15, 2026
@rustbot

This comment has been minimized.

@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 24, 2026

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@llogiq
Copy link
Copy Markdown
Contributor

llogiq commented Apr 25, 2026

What is the behavior in the current edition? Would it make sense to check whether the block survives a lifetime check if the edition was updated?

@shivendra02467
Copy link
Copy Markdown
Author

Hi @llogiq, thanks for taking a look!
To answer your questions:

  1. Behavior in the 2024 edition:As of the 2024 edition, temporaries created in the tail expression of a block are dropped "before" the body executes (at the end of the block). Prior to 2024, they were not dropped until the end of the entire match/if let statement. This can cause a real bug like someone tried to fix a deadlock by doing if let Some(x) = { lock().foo() } { ... }. They assumed the lock would drop before the body. That works in 2024, but silently deadlocks in 2021.

  2. Regarding a lifetime check:
    @Darksonn explicitly addressed this in the original issue (Warn on old editions when scrutinee is wrapped in a block #16827) and determined that an advanced lifetime check isn't necessary because removing the block (when it only contains a tail expression) "never" changes behavior prior to the 2024 edition:
    If the user meant to drop the temporaries (like the deadlock fix attempt), the block doesn't actually work in the 2021 edition anyway. The code is broken and they must rewrite it (eg. extracting the value to a separate let statement).
    If the user didnt mean to drop temporaries, the block is just unnecessary visual noise, and removing it makes the code less confusing without changing the drop semantics.

because of this, we should warn unconditionally on older editions to catch these false assumptions without needing deeper type/lifetime checking. Let me know if you think we should still try to narrow the lint down!


declare_clippy_lint! {
/// ### What it does
/// Warns when a match, if let, or while let scrutinee is wrapped in a block.
Copy link
Copy Markdown
Member

@Darksonn Darksonn Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should clarify that it only triggers on 2021 edition.

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

Comment on lines +13 to +15
/// ### Why is this bad?
/// Prior to the 2024 edition, wrapping the scrutinee in a block did not drop
/// temporaries before the body executes.
Copy link
Copy Markdown
Member

@Darksonn Darksonn Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// ### Why is this bad?
/// Prior to the 2024 edition, wrapping the scrutinee in a block did not drop
/// temporaries before the body executes.
/// ### Why is this bad?
/// It is unusual to write `{ expr }` when you could just have written
/// `expr`, and it is unlikely that anyone would write that for any reason
/// other than wanting temporaries in `expr` to be dropped before executing
/// the body of the `match`/`if let`/`while` statement. However, prior to
/// the 2024 edition, wrapping the scrutinee in a block did not drop
/// temporaries before the body executes.

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated!

Comment thread clippy_lints/src/block_scrutinee.rs Outdated
cx,
BLOCK_SCRUTINEE,
scrutinee.span,
"scrutinee is wrapped in a block which will not drop temporaries until the end of the statement in this edition",
Copy link
Copy Markdown
Member

@Darksonn Darksonn Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"scrutinee is wrapped in a block which will not drop temporaries until the end of the statement in this edition",
"scrutinee is wrapped in a block which will not drop temporaries until the end of the statement on this edition",

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed this error message to the new improved one

Copy link
Copy Markdown
Member

@Darksonn Darksonn Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this error message would look better if changed along these lines.

error: temporary values in this block-wrapped scrutinee will not be dropped until the end of the `if let` statement
  --> tests/ui/block_scrutinee.rs:10:22
   |
LL |     if let Some(x) = { my_function() } {
   |                      ^^^^^^^^^^^^^^^^^
   |
   = note: this behavior is specific to Rust editions prior to 2024
   = note: in Rust 2024, temporaries in a block scrutinee drop immediately before the match arm or block body
   = note: `-D clippy::block-scrutinee` implied by `-D warnings`
help: remove the block to yield the same behavior but with cleaner code
   |
LL |     if let Some(x) = my_function() {
   |                      ~~~~~~~~~~~~~
help: if you intended to drop temporaries early, move the expression to a separate local binding
   |
LL |     if let Some(x) = { let res = my_function(); res } {
   |                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View changes since the review

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated! Thank you

@Darksonn
Copy link
Copy Markdown
Member

Please include a test that verifies that this does not trigger on the 2024 edition.

@Darksonn
Copy link
Copy Markdown
Member

Darksonn commented Apr 25, 2026

What is the behavior in the current edition?

The behavior of { expr } in the current edition is what you would expect. Temporaries in the expression are dropped right away when the block returns, and not after the end of the parent expression's scope.

Would it make sense to check whether the block survives a lifetime check if the edition was updated?

I don't think so. Nobody is going to write { expr } when they could have written expr without a good reason, and on older editions, the behavior is exactly identical, so there is no good reason to do it on older editions. Anyone writing { expr } did so with the intent of getting the 2024 edition behavior. If they don't get that behavior, we should tell them.

@shivendra02467
Copy link
Copy Markdown
Author

@Darksonn Thanks for suggesting the improvements, I will update the PR to include them.

@llogiq
Copy link
Copy Markdown
Contributor

llogiq commented Apr 25, 2026

Ok. I think the lint should suggest updating the edition in case the user actually wants the early drop – or moving the block into its own let stmt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-fcp PRs that add, remove, or rename lints and need an FCP S-waiting-on-review Status: Awaiting review from the assignee but also interested parties

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Warn on old editions when scrutinee is wrapped in a block

4 participants