-
Notifications
You must be signed in to change notification settings - Fork 13.3k
lint: allow specific functions to be tagged #[must_use]
#22348
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
Conversation
A function marked with `#[must_use]` behaves as if it returns a `#[must_use]` type, not matter what the actual return type is, e.g. #[must_use} fn foo() -> i32 { 1 } foo(); // error: unused result which must be used The #[must_use] lint is currently restricted to types; types that should *usually* not be ignored can be tagged with it to warn the user. This serves most purposes well, but it doesn't always work, since a function/method may be just acting as a go-between for a must-use type and a more general/flexible one, without doing anything significant (i.e. not really counting as a "use" of the must-use type). In this case, the function can be marked `#[must_use]` to ensure that its own result can be used, and avoid accidental ignoring of must-use types.
These functions are just adapters for `Result`, and something like `returns_result().ok()` is likely to be accidentally not handling the possibility of error as intended: `ok` does not *require* that the variant is `Ok`, and so errors are just silently ignord. Something like `returns_result().ok().unwrap()` is more likely to be what was desired. Similarly for `err`. Users who do wish to just ignore the result can use `let _ = returns_result();` or `drop(returns_result());` instead of calling one of these (effectively) no-op methods.
r? @Aatch (rust_highfive has picked a reviewer for you, use r? to override) |
cc @larsbergstrom @Manishearth I think I saw you mentioning this problem with This appears prudent to me. Wondering what others think about the expanded scope of |
@brson I'm a huge fan of this, as it would prevent creating 'dummy' types just to |
Looks good to me. I don't think it needs an RFC, however this is technically a breaking change (breaks |
@larsbergstrom FWIW we'll probably end up doing most of the session types stuff in tree anyway. If they want to have a discussion on the (practical) capabilities of the plugin system so that they can formulate their research in that way, I don't mind scheduling one :) |
I think @alexcrichton implemented |
This seems like a fine extension to I feel like adding |
I'm not sure if this has any use for our case specifically (session types), but it would definitely add a lot of granularity to the |
.ok() is currently the way to explicitly ignore the return value. This breaks stable functions so its clearly not just "slightly" RFC worthy. |
It doesn't break anything since this is a warning (though I did mention that putting it on deny would make it a slightly breaking change) |
You claim that it doesn't break anything and then mention a case where it breaks something? |
I mean it doesn't break other stable functions as you said |
#![deny(unused_must_use)]
fn f() -> Result<(), ()> {
Ok(())
}
fn main() {
f().ok();
} A program using only stable features that this breaks. |
"stable functions". I agree with that. |
Says who? The most I can say is that it was a way to do this. |
There is exactly two obvious uses of
|
|
From what I recall, the original reason not to use let _ had something to do with questionable drop semantics. Either way, I believe the need for an RFC has been demonstrated. |
Additionally, we're still in alpha, so breaking-in-edge-cases changes like this are fine. |
Breaking #[stable] functions in the prelude is now fine because ...? Just because you don't use it doesn't mean that it's an "edge-case", whatever that means. |
It isn't "now fine", it was always fine. In alpha, breaking changes will happen even to stable things and things not behind a feature gate. In beta, there should be very few, and in release, none unless there is some major unavoidable bug. FWIW Servo does use |
Conversely, something can still be an edge case even if someone personally uses it a lot. In this case, it's not just me that doesn't use it. And yes, there's been a regular stream of breaking changes for prelude functionality in the alpha. (@Manishearth for the current HEAD 4ab928728e3d65ac4c6ca72cd6c8aa0c75fde33b, there are 4 and 55 instances of |
Ah, nice. They got reduced :) |
|
The context of that is that you're adding something to the prelude. Major changes of functionality, or introduction/removal of things from the prelude require an RfC. Something that might break a function used in the prelude if used in a certain way ... eh, not really. Besides, IIRC lints are informally considered unstable for now until we figure out a stability story for them (there's a bug on this somewhere) |
How convenient for you. |
(Closing in favour of the RFC, rust-lang/rfcs#886; to keep the queue nice.) |
A function marked with
#[must_use]
behaves as if it returns a#[must_use]
type, no matter what the actual return type is, e.g.The #[must_use] lint is currently restricted to types; types that should
usually not be ignored can be tagged with it to warn the user. This
serves most purposes well, but it doesn't always work, since a
function/method may be just acting as a go-between for a must-use type
and a more general/flexible one, without doing anything
significant (i.e. not really counting as a "use" of the must-use type).
In this case, the function can be marked
#[must_use]
to ensure thatits own result can be used, and avoid accidental ignoring of must-use
types.
The second commit marks
Result::{ok, err}
#[must_use]
since they're "pure"Result
adaptors.