Skip to content

Conversation

GuillaumeGomez
Copy link
Member

@GuillaumeGomez GuillaumeGomez commented May 23, 2025

The function_casts_as_integer lint detects cases where users cast a function pointer into an integer.

warn-by-default

Example

fn foo() {} let x = foo as usize;
warning: casting a function into an integer implicitly --> $DIR/function_casts_as_integer.rs:9:17 | LL | let x = foo as usize; | ^^^^^^^^ | help: add `fn() as usize` | LL | let x = foo as fn() as usize; | +++++++ 

Explanation

You should never cast a function directly into an integer but go through a cast as fn first to make it obvious what's going on. It also allows to prevent confusion with (associated) constants.

Related to #81686 and https://stackoverflow.com/questions/68701177/whats-the-meaning-of-casting-a-rust-enum-variant-to-a-numeric-data-type

r? @Urgau

@rustbot rustbot added O-unix Operating system: Unix-like S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 23, 2025
@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez force-pushed the function_casts_as_integer branch 2 times, most recently from 07f2c3c to 4978962 Compare May 23, 2025 20:54
@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez force-pushed the function_casts_as_integer branch 2 times, most recently from 3db3153 to d8b1955 Compare May 24, 2025 10:10
@rust-log-analyzer

This comment has been minimized.

@Urgau Urgau added T-lang Relevant to the language team and removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 24, 2025
@GuillaumeGomez GuillaumeGomez force-pushed the function_casts_as_integer branch from d8b1955 to 45984df Compare May 24, 2025 18:45
@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez force-pushed the function_casts_as_integer branch from 45984df to a6107b4 Compare May 24, 2025 19:09
@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez force-pushed the function_casts_as_integer branch from a6107b4 to 24d757e Compare May 24, 2025 22:47
@rustbot
Copy link
Collaborator

rustbot commented May 24, 2025

Some changes occurred in src/tools/clippy

cc @rust-lang/clippy

@rust-log-analyzer

This comment has been minimized.

@Urgau Urgau added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 26, 2025
@GuillaumeGomez GuillaumeGomez force-pushed the function_casts_as_integer branch from 24d757e to 3529162 Compare May 27, 2025 14:12
@rustbot
Copy link
Collaborator

rustbot commented May 27, 2025

The Miri subtree was changed

cc @rust-lang/miri

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

/// a cast as `fn` first to make it obvious what's going on. It also allows
/// to prevent confusion with (associated) constants.
pub FUNCTION_CASTS_AS_INTEGER,
Warn,
Copy link
Member

Choose a reason for hiding this comment

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

Clippy has a few lints for fn to integer casts. But they are all restriction or style lints in Clippy. Adding a warn-by-default lint about this to rustc might be a bit aggressive 🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

I know, I implemented one myself. 😉 I think it highlights the fact that this is a big issue and that the compiler should warn about it and eventually even forbid this fn to integer cast (you need to cast to an fn pointer first).

But in any case, it's up to the lang team.

Copy link
Member

Choose a reason for hiding this comment

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

Agreed 👍 Just want to add this information as "prior art" for the lang team to make this decision. Even though it might've sounded like it, I'm not against adding this lint to rustc.

Clippy question: Do you think if this lint gets added to rustc, we can (partially) deprecate Clippy lints?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hard to say. For example confusing_method_to_numeric_cast provides extra information about what (likely) went wrong. But with the current lint, they likely would already have seen the problem and fixed it. So by default I'd say yes. But we could eventually uplift part of them to add the extra context clippy has that this lint doesn't provide. Would make it much more interesting and even more useful.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, a partial uplift might be good then, should this be accepted.

@rust-log-analyzer

This comment has been minimized.

@traviscross
Copy link
Contributor

The last time we discussed this on lang, one part of the outcome is what @joshtriplett said in #141470 (comment):

If that API ends up taking longer than expected, we'd also approve an interim lint catching specific cases like the integer max/min functions.

To what degree might that be helpful?

In prior discussion, one place where the PR in its current form raised questions is that it seems that we'd be asking people to write out full function signatures in order to make these casts (including, then, having to import or otherwise name function argument and return types that may otherwise not be needed there), and there was a feeling that this may seem too onerous.

What options might we have to ameliorate that?

@traviscross traviscross added the P-lang-drag-2 Lang team prioritization drag level 2.https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang. label Oct 11, 2025
@Amanieu
Copy link
Member

Amanieu commented Oct 13, 2025

I can realistically see the following options:

  1. Keep this lint as implemented.
  2. Change this lint to use _ placeholders instead of type names in the function signature. This will usually be shorter than the original signature, which helps a bit.
  3. Add a method on functions to extract the address as a usize. Unfortunately this runs into the question of whether function pointers have provenance since if this is the case then we will want separate expose_provenance and addr methods. This lint would then suggest expose_provenance since this matches the current semantics of pointer to integer casts.

While option 3 seems superior, it is likely to take a long time to settle the provenance question and stabilize the API. What I am suggesting is that we could implement option 1 or 2 in the meantime.

@GuillaumeGomez
Copy link
Member Author

As the main goal of this lint is to make people realize they're likely doing a function pointer cast (and not an integer cast), I think the current approach is the best.

@GuillaumeGomez GuillaumeGomez force-pushed the function_casts_as_integer branch from 3777126 to 6325073 Compare October 14, 2025 13:16
@rustbot

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez force-pushed the function_casts_as_integer branch 2 times, most recently from e813cba to a47e09f Compare October 14, 2025 13:58
@rustbot rustbot added the A-run-make Area: port run-make Makefiles to rmake.rs label Oct 14, 2025
@rustbot

This comment has been minimized.

@GuillaumeGomez GuillaumeGomez force-pushed the function_casts_as_integer branch from a47e09f to e813cba Compare October 14, 2025 14:03
@rustbot
Copy link
Collaborator

rustbot commented Oct 14, 2025

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.

@traviscross
Copy link
Contributor

The last time we discussed this on lang, we discussed how special-casing the functions where this is a known problem, e.g. min, max, size_of, etc., might be one option. To what degree do you think that would or would not be helpful?

@GuillaumeGomez
Copy link
Member Author

It's what we initially did in clippy before realizing there were cases like minimum/maximum too. The list just grew too big to be maintainable. Hence why I opened the current PR.

In short: if you didn't mean to cast a function, then thanks to this lint you will realize right away. If did you mean to cast a function, then either you allow the lint or you apply the suggestion. In the long term, it seems that we want to forbid casting functions to integers directly, so this lint would be a first step into this direction while fixing a very big already existing unnoticed source of bugs.

@bors
Copy link
Collaborator

bors commented Oct 17, 2025

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

@bors bors added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Oct 17, 2025
@traviscross
Copy link
Contributor

What do you think about suggesting that people do this cast via a pointer to unit? I.e., f as *const () as usize? If the person is expecting max to be a number rather than a function, there's no reason to be casting through a pointer, so perhaps this would achieve the same effect, in terms of prevent error, while not having to elaborate the function signatures.

@GuillaumeGomez
Copy link
Member Author

But then the readability of the suggested code is pretty bad since you have no tip of why you need this intermediate cast.

@traviscross
Copy link
Contributor

traviscross commented Oct 17, 2025

I don't know. I'm not sure that passing it through fn(..) -> .. provides any more of a tip about why the intermediate cast is needed. If anything, the elaborated function signature is going to raise more questions for me as the reader about whether there's maybe something else non-obvious going on. If I see a cast through a void pointer to an integer, though, I'll think, "OK, that makes sense, whatever".

@GuillaumeGomez
Copy link
Member Author

Well, if you think "OK, that makes sense, whatever", then that's an issue. The whole point is to force you to realize what's going on by reading it. Then either it's the intended purpose and you leave things as is (and eventually add a code comment 😄), or it's not and then you clean up.

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

Labels

A-run-make Area: port run-make Makefiles to rmake.rs I-lang-nominated Nominated for discussion during a lang team meeting. I-lang-radar Items that are on lang's radar and will need eventual work or consideration. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. O-unix Operating system: Unix-like O-windows Operating system: Windows P-lang-drag-2 Lang team prioritization drag level 2.https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. S-waiting-on-t-lang Status: Awaiting decision from T-lang T-clippy Relevant to the Clippy team. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team