Skip to content

Rewrite redundant_else as a late pass.#17329

Merged
samueltardieu merged 5 commits into
rust-lang:masterfrom
Jarcho:redundant_else
Jul 6, 2026
Merged

Rewrite redundant_else as a late pass.#17329
samueltardieu merged 5 commits into
rust-lang:masterfrom
Jarcho:redundant_else

Conversation

@Jarcho

@Jarcho Jarcho commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

The main behaviour changes are:

  • Lint on blocks returning !. This greatly increases the number of cases this lints on.
  • Don't lint inside a macro when the divergence comes from a different macro.
  • Suggest adding a semicolon when syntactically needed.

The old test file was a bit of a mess so it was rewritten. This was done as the final commit and the new code passes both the old and the new tests.

changelog: [redundant_else]: Take into account divergent function calls.

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Jul 1, 2026
@rustbot

rustbot commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

r? @dswij

rustbot has assigned @dswij.
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: 8 candidates
  • 8 candidates expanded to 8 candidates
  • Random selection from dswij, llogiq, samueltardieu

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

Lintcheck changes for 322f4dc

Lint Added Removed Changed
clippy::redundant_else 8 1 7

This comment will be updated if you push new changes

@Jarcho
Jarcho force-pushed the redundant_else branch 5 times, most recently from a0652e8 to 0866f3b Compare July 1, 2026 01:43
@Jarcho

Jarcho commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Really thinking this should ignore loops as the final expression. They're the biggest source of something which doesn't obviously diverge. On the other hand large if/match expressions have the same issue and they already linted.

@dswij

dswij commented Jul 3, 2026

Copy link
Copy Markdown
Member

r? clippy

@rustbot rustbot assigned flip1995 and unassigned dswij Jul 3, 2026
Comment on lines +51 to 60
fn check_block_post(&mut self, cx: &LateContext<'tcx>, b: &'tcx Block<'_>) {
if let Some(e) = b.expr {
check(cx, b.span.ctxt(), false, e);
}
}

let mut app = Applicability::MachineApplicable;
if let ExprKind::Block(block, _) = &els.kind {
for stmt in &block.stmts {
// If the `else` block contains a local binding or a macro invocation, Clippy shouldn't auto-fix it
if matches!(&stmt.kind, StmtKind::Let(_) | StmtKind::MacCall(_)) {
app = Applicability::Unspecified;
break;
}
}
fn check_stmt(&mut self, cx: &LateContext<'tcx>, s: &'tcx Stmt<'_>) {
if let StmtKind::Expr(e) | StmtKind::Semi(e) = s.kind {
check(cx, s.span.ctxt(), matches!(s.kind, StmtKind::Expr(_)), e);
}

@samueltardieu samueltardieu Jul 5, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: I think that using check_block() would best reflect the intention (forget about GitHub borked way of showing a diff on a diff) and is one line shorter:

Suggested change
fn check_block_post(&mut self, cx: &LateContext<'tcx>, b: &'tcx Block<'_>) {
if let Some(e) = b.expr {
check(cx, b.span.ctxt(), false, e);
}
}
let mut app = Applicability::MachineApplicable;
if let ExprKind::Block(block, _) = &els.kind {
for stmt in &block.stmts {
// If the `else` block contains a local binding or a macro invocation, Clippy shouldn't auto-fix it
if matches!(&stmt.kind, StmtKind::Let(_) | StmtKind::MacCall(_)) {
app = Applicability::Unspecified;
break;
}
}
fn check_stmt(&mut self, cx: &LateContext<'tcx>, s: &'tcx Stmt<'_>) {
if let StmtKind::Expr(e) | StmtKind::Semi(e) = s.kind {
check(cx, s.span.ctxt(), matches!(s.kind, StmtKind::Expr(_)), e);
}
fn check_block(&mut self, cx: &LateContext<'tcx>, b: &'tcx Block<'_>) {
for s in b.stmts {
if let StmtKind::Expr(e) | StmtKind::Semi(e) = s.kind {
check(cx, s.span.ctxt(), matches!(s.kind, StmtKind::Expr(_)), e);
}
}
if let Some(e) = b.expr {
check(cx, b.span.ctxt(), false, e);
}
}

Moreover, in any case, you should use span_lint_hir_and_then to post the lint on e.hir_id, otherwise this would fail as the lint would be posted on the block (because of check_block() or check_block_post()) instead of the last expression of the block:

            {
                #[expect(clippy::redundant_else)]
                if black_box(true) {
                    return
                } else {
                    $({ black_box(()) })
                }
            }

(nevermind the content, I just wanted a lintable expression as the last expr of a block)

Right now, it fails, but will succeed if #[expect] is applied to the block itself, which should not be necessary.

View changes since the review

@Jarcho Jarcho Jul 5, 2026

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.

check_block will be worse for perf due to the cache use. Or it would be if we fix other lints to not use check_block when check_stmt would be a better starting point; it might be neutral right now.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status) and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties labels Jul 5, 2026
@rustbot

rustbot commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

Comment thread clippy_lints/src/redundant_else.rs Outdated
&& let Some(indent) = indent_of(cx, e.span)
{
let sp = else_.span.with_lo(then.span.hi());
span_lint_and_then(cx, REDUNDANT_ELSE, sp, "redundant else block", |diag| {

@samueltardieu samueltardieu Jul 5, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
span_lint_and_then(cx, REDUNDANT_ELSE, sp, "redundant else block", |diag| {
span_lint_hir_and_then(cx, REDUNDANT_ELSE, e.hir_id, sp, "redundant else block", |diag| {

View changes since the review

@samueltardieu
samueltardieu added this pull request to the merge queue Jul 6, 2026
Merged via the queue into rust-lang:master with commit 39df31c Jul 6, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-author Status: This is awaiting some action from the author. (Use `@rustbot ready` to update this status)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants