Skip to content

hir-ty: walk container exprs for unused_must_use#22405

Open
MavenRain wants to merge 1 commit into
rust-lang:masterfrom
MavenRain:feat-must-use-container-exprs
Open

hir-ty: walk container exprs for unused_must_use#22405
MavenRain wants to merge 1 commit into
rust-lang:masterfrom
MavenRain:feat-must-use-container-exprs

Conversation

@MavenRain

Copy link
Copy Markdown
Contributor

ExprValidator::check_unused_must_use previously matched only Expr::Call and Expr::MethodCall directly on the expression of a Statement::Expr with semicolon. This left several stmt-with-semi cases unwarned: blocks whose tail is a #[must_use] call ({ produces() };), unsafe-blocks (unsafe { produces() };), if/else arms, match arms, and const blocks.

Refactors check_unused_must_use into a recursive collector that walks into Expr::Block { tail, .. }, Expr::Unsafe { tail, .. }, Expr::If { then_branch, else_branch, .. }, Expr::Match { arms, .. }, and Expr::Const(inner) before applying the existing leaf check (callee or method #[must_use] attribute, or #[must_use] ADT return type). The diagnostic stays at the leaf call so the span points to the actual must_use producer rather than the wrapping block.

Adds ide-diagnostics tests covering each new container case (block tail, unsafe block tail, nested blocks, if/else branches, match arms, const block, #[must_use] ADT through a block) and lock-in tests confirming that the existing RustcLint plumbing already honors #[allow(unused_must_use)], #[allow(unused)], and #[deny(unused_must_use)] attribute resolution.

Follow-up to #22239.

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 19, 2026
Comment thread crates/hir-ty/src/diagnostics/expr.rs Outdated
fn collect_unused_must_use(
&self,
expr: ExprId,
diags: &mut Vec<BodyValidationDiagnostic<'db>>,

@ChayimFriedman2 ChayimFriedman2 May 19, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You can just push to self.diagnostics.

View changes since the review

Comment thread crates/hir-ty/src/diagnostics/expr.rs Outdated
// Walk through container expressions so that the value-producing leaf is
// checked even when wrapped in a block, `unsafe { .. }`, `if`/`match`, or
// a `const { .. }` block.
match &self.body[expr] {

@ChayimFriedman2 ChayimFriedman2 May 19, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Or better, there is no need for a recursion here, given a block has up to one tail expression. Instead loop until you reach it.

View changes since the review

MavenRain added a commit to MavenRain/rust-analyzer that referenced this pull request May 20, 2026
  Address ChayimFriedman2 review feedback on rust-lang#22405:

  * Push directly to self.diagnostics rather than threading a
    &mut Vec parameter through the recursion.  Drops the
    check_unused_must_use / collect_unused_must_use split and the
    allocation in the thin wrapper.

  * Replace the recursive single-tail-chain walk (Block/Unsafe/Const)
    with a loop that reassigns expr until reaching a non-chain leaf.
    Branching containers (If/Match) still recurse since they have
    multiple arms.

  The borrow checker required hoisting the Statement::Expr pass
  out of the main loop in validate_block, since MatchCheckCtx
  holds &self.infcx and the must_use pass now needs &mut self.
  The two passes are independent (must_use on expression
  statements, non_exhaustive_let on let statements) so order is
  free.

  19 unused_must_use tests + 981 hir-ty tests + 693
  ide-diagnostics tests pass.

Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>
@rustbot

This comment has been minimized.

MavenRain added a commit to MavenRain/rust-analyzer that referenced this pull request May 21, 2026
    Address ChayimFriedman2 review feedback on rust-lang#22405:

    * Push directly to self.diagnostics rather than threading a
      &mut Vec parameter through the recursion.  Drops the
      check_unused_must_use / collect_unused_must_use split and the
      allocation in the thin wrapper.

    * Replace the recursive single-tail-chain walk (Block/Unsafe/Const)
      with a loop that reassigns expr until reaching a non-chain leaf.
      Branching containers (If/Match) still recurse since they have
      multiple arms.

    The borrow checker required hoisting the Statement::Expr pass
    out of the main loop in validate_block, since MatchCheckCtx
    holds &self.infcx and the must_use pass now needs &mut self.
    The two passes are independent (must_use on expression
    statements, non_exhaustive_let on let statements) so order is
    free.

    19 unused_must_use tests + 981 hir-ty tests + 693
    ide-diagnostics tests pass.

Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>
@MavenRain MavenRain force-pushed the feat-must-use-container-exprs branch from 2db699b to ffe5641 Compare May 21, 2026 09:42
@MavenRain MavenRain requested a review from ChayimFriedman2 May 21, 2026 09:45
Comment thread crates/hir-ty/src/diagnostics/expr.rs Outdated
let (Expr::Block { statements, .. } | Expr::Unsafe { statements, .. }) = expr else {
return;
};
if self.validate_lints {

@ChayimFriedman2 ChayimFriedman2 May 25, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why did you separate to a new loop? And why this if?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch . . . the split was a workaround: making check_unused_must_use take &mut self so it could push to self.diagnostics directly meant it could no longer run in the same loop as the MatchCheckCtx (which borrows &self.infcx). I've reverted it to &self with a small accumulator the caller drains, so both checks share the single loop again and validate_lints is back on the match arm.

@MavenRain MavenRain requested a review from ChayimFriedman2 May 30, 2026 09:52
}

#[test]
fn allow_attribute_on_fn_silences_lint() {

@ChayimFriedman2 ChayimFriedman2 May 30, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We already have tests for lint attributes, we don't need to test them for every lint. Please remove those tests.

View changes since the review

@MavenRain MavenRain requested a review from ChayimFriedman2 June 4, 2026 14:56
@MavenRain

Copy link
Copy Markdown
Contributor Author

Done: removed the four allow_/deny_ lock-in tests; kept only the container-expression behavior tests. Agreed the generic lint-attribute handling is already covered and doesn't need re-testing per lint.

@ChayimFriedman2 ChayimFriedman2 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ExprValidator::check_unused_must_use previously matched only Expr::Call and Expr::MethodCall directly on the expression of a Statement::Expr with semicolon. This left several stmt-with-semi cases unwarned: blocks whose tail is a #[must_use] call, unsafe-blocks, if/else arms, match arms, and const blocks.

Refactors check_unused_must_use to walk into Expr::Block { tail }, Expr::Unsafe { tail }, Expr::If { then_branch, else_branch }, Expr::Match { arms }, and Expr::Const(inner) before applying the existing leaf check (callee or method #[must_use] attribute, or #[must_use] ADT return type). The diagnostic stays at the leaf call so the span points to the actual must_use producer rather than the wrapping block.

Adds ide-diagnostics tests covering each new container case.

Follow-up to rust-lang#22239.

Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>
@MavenRain MavenRain force-pushed the feat-must-use-container-exprs branch from 2632230 to c859808 Compare June 7, 2026 05:19
@MavenRain

Copy link
Copy Markdown
Contributor Author

@ChayimFriedman2 CI is red solely from the cancelled powerpc + wasm32); all 13 real jobs are green; could you re-run the cross job or merge past it (contributors can't re-trigger upstream CI)?

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

Labels

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.

3 participants