Skip to content

Add unnecessary_intermediate_cast lint#16501

Open
Rua wants to merge 1 commit intorust-lang:masterfrom
Rua:unnecessary_intermediate_cast
Open

Add unnecessary_intermediate_cast lint#16501
Rua wants to merge 1 commit intorust-lang:masterfrom
Rua:unnecessary_intermediate_cast

Conversation

@Rua
Copy link
Copy Markdown
Contributor

@Rua Rua commented Feb 3, 2026

This adds a lint to check for two casts in a row. It lints if the first cast is redundant, and the same effect could be achieved by casting straight to the final type. It's probably not so likely to find this in human-written code, but can be useful for cleaning up automatically generated code before further human consumption, like for example in transpiling software.

This is my first lint PR, so please let me know if I missed anything. In particular, I'm not entirely sure if it will interfere with other casting lints (like unnecessary_cast), nor how to remedy it in case it does.

changelog: new lint: [unnecessary_intermediate_cast]

@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 Feb 3, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Feb 3, 2026

r? @Jarcho

rustbot has assigned @Jarcho.
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

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 3, 2026

Lintcheck changes for e1c830d

Lint Added Removed Changed
clippy::unnecessary_intermediate_cast 90 0 0

This comment will be updated if you push new changes

@Rua Rua force-pushed the unnecessary_intermediate_cast branch from 4a7f2b8 to bf11f00 Compare February 3, 2026 16:12
@rustbot

This comment has been minimized.

@Rua Rua force-pushed the unnecessary_intermediate_cast branch from bf11f00 to e1c830d Compare February 23, 2026 10:51
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Feb 23, 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.

@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Mar 5, 2026

☔ The latest upstream changes (possibly #15979) made this pull request unmergeable. Please resolve the merge conflicts.

@Rua
Copy link
Copy Markdown
Contributor Author

Rua commented Mar 23, 2026

Do I need to do anything more here (other than rebasing/resolving conflicts)? Not sure if it got missed or whatever.

@Jarcho
Copy link
Copy Markdown
Contributor

Jarcho commented Mar 27, 2026

You have problems with how you're handling pointers and integers. The is_cast_allowed filter also doesn't really simplify or speed anything up. The approach I would take is to handle all non-integer casts first followed by splitting the integer types into their components and then handling those. Something like:

match (a, b, c) {
    (RawPtr(..), RawPtr(..), RawPtr(..)) => {}
    (RawPtr(a, _), RawPtr(..), _) if !a.is_sized(cx.tcx, cx.typing_env()) => return,
    (RawPtr(..), RawPtr(..), _) => {},
    (Bool, Int(_) | Uint(_), Int(_) | Uint(_)) => {},
    (Float(a), Float(b), _) if a < b => {},
    (Float(a), Float(b), Float(c)) if a > b && b > c => {},
    (a, b, c) if let Some((sign1, (_, max1))) = int_parts(a)
        && let Some((sign2, (min2, max2))) = int_parts(b)
        && let Some((_, (min3, _))) = int_parts(c)
        && !matches!(c, Char)
        => match (sign1, sign2) {
            (Unsigned, _) if max1 < max2 => {},
            (Unsigned, Unsigned) if max1 == max2 => {},
            (Signed, Signed) if max1 <= max2 => {},
            _ if min2 >= min3 => {}
            _ => return,
        }
    _ => return,
}

enum Signedness { Signed, Unsigned }
#[derive(PartialEq, PartialOrd)]
enum Size { _8, _16, _32, _64, _128 }

fn int_parts(ty: Ty<'_>) -> Option<(Signedness, (Size, Size))> {
    match ty.kind {
        Int(ty) => (Signed, int_bounds(ty)),
        Uint(ty) => (Unsigned, int_bounds(ty)),
        RawPtr(..) => (Unsigned, (_16, _64)),
        Char => (Unsigned, (_32, _32)),
        _ => None,
    }
}

fn int_bounds(ty: IntTy) -> (Size, Size) {
    match ty {
        I8 => (_8, _8),
        I16 => (_16, _16),
        I32 => (_32, _32),
        I64 => (_64, _64),
        I128 => (_128, _128),
        Isize => (_16, _64),
    }
}

@Jarcho
Copy link
Copy Markdown
Contributor

Jarcho commented Mar 27, 2026

@rustbot label lint-nominated

@rustbot rustbot added the lint-nominated Create an FCP-thread on Zulip for this PR label Mar 27, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Mar 27, 2026

This lint has been nominated for inclusion.

A FCP topic has been created on Zulip.

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

Labels

lint-nominated Create an FCP-thread on Zulip for this PR 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.

Lint for unnecessary double casts

3 participants