Skip to content

Disable cast_lossless when casting to u128 from any (u)int type #12496

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 20, 2024

Conversation

Jacherr
Copy link
Contributor

@Jacherr Jacherr commented Mar 15, 2024

Fixes #12492

Disables cast_lossless when casting to u128 from any int or uint type. The lint states that when casting to any int type, there can potentially be lossy behaviour if the source type ever exceeds the size of the destination type in the future, which is impossible with a destination of u128.

It's possible this is a bit of a niche edge case which is better addressed by just disabling the lint in code, but I personally couldn't think of any good reason to still lint in this specific case - maybe except if the source is a bool, for readability reasons :).

changelog: FP: cast_lossless: disable lint when casting to u128 from any (u)int type

@rustbot
Copy link
Collaborator

rustbot commented Mar 15, 2024

r? @blyxyas

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

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Mar 15, 2024
@Alexendoo
Copy link
Member

I think the lint still applies here, the message could be updated but replacing a lossless cast with from is still a good suggestion

The type of the RHS could be changed in the future for example to a lossy cast

Copy link
Member

@blyxyas blyxyas left a comment

Choose a reason for hiding this comment

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

Meow meow meow =^w^=

// If source is bool, still lint due to the lint message differing (refers to style)
if in_constant(cx, expr.hir_id)
|| (!cast_from.is_bool()
&& (matches!(cast_to.kind(), ty::Int(IntTy::I128)) || matches!(cast_to.kind(), ty::Uint(UintTy::U128))))
Copy link
Member

Choose a reason for hiding this comment

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

Casting from a u128 to a i128 could be dangerous. u128 is the only data type that we can be sure that they won't cause an error.

Suggested change
&& (matches!(cast_to.kind(), ty::Int(IntTy::I128)) || matches!(cast_to.kind(), ty::Uint(UintTy::U128))))
&& matches!(cast_to.kind(), ty::Uint(UintTy::U128))

Copy link
Member

@blyxyas blyxyas left a comment

Choose a reason for hiding this comment

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

Sorry for the delay, I actually viewed this change the day you committed it but forgot to approve it 😅

LGTM, thanks! ❤️ Could you squash the commits into one?

@Jacherr Jacherr changed the title Disable cast_lossless when casting to u128/i128 from any (u)int type Disable cast_lossless when casting to u128 from any (u)int type Mar 20, 2024
@blyxyas
Copy link
Member

blyxyas commented Mar 20, 2024

@bors r+

@bors
Copy link
Contributor

bors commented Mar 20, 2024

📌 Commit 477108d has been approved by blyxyas

It is now in the queue for this repository.

@bors
Copy link
Contributor

bors commented Mar 20, 2024

⌛ Testing commit 477108d with merge 34766a6...

@bors
Copy link
Contributor

bors commented Mar 20, 2024

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: blyxyas
Pushing 34766a6 to master...

@bors bors merged commit 34766a6 into rust-lang:master Mar 20, 2024
@Jacherr Jacherr deleted the issue-12492 branch May 30, 2024 16:49
@TomFryersMidsummer
Copy link

I'm not sure this should have been turned off. To expand on what @Alexendoo wrote:

This lint guards against two possible changes which would make the cast lossless.

  1. Changing the source type to a larger one.
  2. Changing the destination type to a smaller one.

While u128 is indeed immune to the first problem, it's (particularly) susceptible to the second.

For instance, take this code.

type Id = u128;

fn from_database_id(x: u64) -> Id {
    x as Id
}

If Id were to be made a u32, from_database_id would no longer be injective, which could cause a bug. Using Id::from would prevent this.

@smoelius
Copy link
Contributor

If Id were to be made a u32, from_database_id would no longer be injective, which could cause a bug.

Your concern is valid, but I think cast_possible_truncation would fire in that case (playground).

(I should have mentioned this in #12492.)

@Alexendoo
Copy link
Member

If anything that triggers cast_lossless becomes lossy it would trigger one of the other cast_ lints (unless we're missing a case)

@smoelius
Copy link
Contributor

If anything that triggers cast_lossless becomes lossy it would trigger one of the other cast_ lints (unless we're missing a case)

I am willing to believe that, but is that an argument for keeping things the way they were? Could you explain?

@Alexendoo
Copy link
Member

It was to say that it's consistent with the other cast_lossless cases and isn't a reason to remove as u128

My view of it is the lint suggests replacing n as T with T::from(n) where possible to prevent future changes to n or T from causing unexpected behaviour. It also benefits the reader as they no longer have to consider if there is truncation/wrapping/etc happening

There are lints to catch these potentially unexpected casts, but they're all in pedantic and often #[allow]d anyway because e.g. T::try_from(n).unwrap() is a bit ugly

For the suggestion of replacing n as u128 with u128::from(n) specifically it's true that no change to n can cause truncation to occur but that's not the only thing it protects against. As mentioned a change to the destination type (potentially through an alias) may cause issues

But also changes to the type of n can cause issues, if it becomes a signed integer type the from version will become a compile error and have you consider how you want to handle negatives. The as cast could be the answer to that, but you don't always want sign extension or the 2's complement form

@smoelius
Copy link
Contributor

Thank you very much for explaining. I think this is the main point where we disagree:

As mentioned a change to the destination type (potentially through an alias) may cause issues

I agree this could happen, but it feels remote. To me, a change the type of the expression seems far more likely, and flagging such possibilities is where the lint really provides value.

Having said that, this is not a hill I'd want to die on. So thank you again for taking the time to write #12496 (comment).

@Alexendoo
Copy link
Member

Thanks, there's a while until the next meeting so let's just go with a poll since it's split:

https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy/topic/Should.20.60as.20u128.60.20trigger.20cast_lossless

@smoelius
Copy link
Contributor

@Alexendoo Thank you for opening the poll.

@blyxyas Thank you for reviewing this PR.

@Jacherr Thank you jumping on my issue and resolving it. I'm sorry that your contribution will likely be reverted.

bors added a commit that referenced this pull request Jul 24, 2024
Lint casts to `u128` in `cast_lossless`

Reverts #12496 per https://rust-lang.zulipchat.com/#narrow/stream/257328-clippy/topic/Should.20.60as.20u128.60.20trigger.20cast_lossless

Also changes the lint messages and refactors the suggestion production - Fixes #12695

changelog: [`cast_lossless`]: lint casts to `u128`
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.

cast_lossless should not warn about casts to u128
7 participants