From 00cee6c9f0b2467316defef96603c8c55774a1bd Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 7 Dec 2024 12:21:48 -0600 Subject: [PATCH 1/4] first draft of the must_use_false RFC --- text/0000-must_use-false.md | 99 +++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 text/0000-must_use-false.md diff --git a/text/0000-must_use-false.md b/text/0000-must_use-false.md new file mode 100644 index 00000000000..441fe86f6cb --- /dev/null +++ b/text/0000-must_use-false.md @@ -0,0 +1,99 @@ +- Feature Name: `must_use_false` +- Start Date: 2024-12-07 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +# Summary +[summary]: #summary + +Allow annotating functions with `#[must_use = false]` to suppress any warning generated due to its return type being marked as `#[must_use]`. + +# Motivation +[motivation]: #motivation + +The primary motivation is that there are some situations where a function is technically fallible, but it is almost always correct to not check its result. + +example: +```rust +/// Try to open a file before it is required. +/// +/// This result can be safely ignored, +/// as the file will be automatically opened again +/// when it is actually needed. +#[must_use = false] +pub fn hint_premptive_open(&mut self) -> io::Result<()> { + /* ... */ +} +``` + +Another example is closing files and similar operations, where the only possible error recovery is to just ignoring the error. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +The `#[must_use]` attribute can also take a boolean value instead of a string value. + +When a function is annotated with `#[must_use = false]`, its result can be ignored without triggering the `unused_must_use` lint, even if its return type is marked as `must_use`. + +`#[must_use = true]` is equivelent to `#[must_use]`. + +When used on a type, `#[must_use = false]` is equivelent to not having any `#[must_use]` attribute. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +The `must_use` attribute is used to control when the `unused_must_use` lint is emitted. + +It has three forms: +1. the plain `#[must_use]` form, equivelent to `#[must_use = true]`. +2. the boolean form, `#[must_use = BOOLEAN]`, where `BOOLEAN` is either `true` or `false`. +3. the string form, `#[must_use = "MESSAGE"]`, where `MESSAGE` is a help message to emmitted alongside the `unused_must_use` lint. + +For the purposes of calculating whether to emit `unused_must_use` for an expression, every function and type item is in one of the following `must_use` states: +1. a positive state, corrosponding to any `must_use` attribute besides `must_use = false`. +2. a neutral state, corrosponding to no `must_use` attribute +3. a negative state, corrosponding to `must_use = false`. + +For each +[expression statement](https://doc.rust-lang.org/reference/statements.html#expression-statements), +the following process is used to calculate a positive (emit the lint) or negative (do not emit the lint) result: +1. if the expression of the expression statement is a function call, check the `must_use` state of that function, otherwise skip to step 3 +2. if the function has a neutral state, continue to step 3, otherwise the result is positive/negative according the the state +3. if the type of the expression has a positive `must_use` state, the result is positive, otherwise, the result is negative. + + +# Drawbacks +[drawbacks]: #drawbacks + +Yet another "opt-in/opt-out" dance, similar to `#[non_exhaustive]`. + +The usecase is fairly niche. + +Implementation complexity. + +Passing the result of a `#[must_use = false]` function through an identity function will cause the lint to trigger. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +An `=` style attribute is used since this is already used for `must_use`, and it intuativly evokes the idea of "overwriting" a variable. + +`#[must_use = true]` is provided for symmetry. + +# Prior art +[prior-art]: #prior-art + +* [Pre-RFC on IRLO](https://internals.rust-lang.org/t/pre-rfc-must-use-false/21861) +* Scala's `@CanIgnoreResult` annotation + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +- Is this the best way we can handle this, or is there a more elegant/general solution that doesn't involve marking every single function? + +# Future possibilities +[future-possibilities]: #future-possibilities + +* A future edition making `#[must_use]` the default for functions that return something other than `()`. +* Allow annotating a module/crate with `#[must_use]` to make all its functions and methods default to `must_use`. + From 7cfab2ce20ae457ce7cc9444b352bc6080f0661a Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 7 Dec 2024 12:24:36 -0600 Subject: [PATCH 2/4] assign RFC number --- text/{0000-must_use-false.md => 3737-must_use-false.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename text/{0000-must_use-false.md => 3737-must_use-false.md} (98%) diff --git a/text/0000-must_use-false.md b/text/3737-must_use-false.md similarity index 98% rename from text/0000-must_use-false.md rename to text/3737-must_use-false.md index 441fe86f6cb..2a434a53563 100644 --- a/text/0000-must_use-false.md +++ b/text/3737-must_use-false.md @@ -1,6 +1,6 @@ - Feature Name: `must_use_false` - Start Date: 2024-12-07 -- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- RFC PR: [rust-lang/rfcs#3737](https://github.com/rust-lang/rfcs/pull/3737) - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) # Summary From a4c6a76ba9f42e016d353260365850c42fe11ea2 Mon Sep 17 00:00:00 2001 From: lolbinarycat Date: Sat, 7 Dec 2024 20:29:23 -0600 Subject: [PATCH 3/4] fix typo Co-authored-by: Josh Triplett --- text/3737-must_use-false.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/text/3737-must_use-false.md b/text/3737-must_use-false.md index 2a434a53563..afbb3f5f9df 100644 --- a/text/3737-must_use-false.md +++ b/text/3737-must_use-false.md @@ -50,9 +50,9 @@ It has three forms: 3. the string form, `#[must_use = "MESSAGE"]`, where `MESSAGE` is a help message to emmitted alongside the `unused_must_use` lint. For the purposes of calculating whether to emit `unused_must_use` for an expression, every function and type item is in one of the following `must_use` states: -1. a positive state, corrosponding to any `must_use` attribute besides `must_use = false`. -2. a neutral state, corrosponding to no `must_use` attribute -3. a negative state, corrosponding to `must_use = false`. +1. a positive state, corresponding to any `must_use` attribute besides `must_use = false`. +2. a neutral state, corresponding to no `must_use` attribute +3. a negative state, corresponding to `must_use = false`. For each [expression statement](https://doc.rust-lang.org/reference/statements.html#expression-statements), From f4a625329c1e2a50c51e7c89f73326c7bb8dc87a Mon Sep 17 00:00:00 2001 From: lolbinarycat Date: Sat, 7 Dec 2024 20:29:39 -0600 Subject: [PATCH 4/4] Update text/3737-must_use-false.md Co-authored-by: Josh Triplett --- text/3737-must_use-false.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3737-must_use-false.md b/text/3737-must_use-false.md index afbb3f5f9df..6526b19c9de 100644 --- a/text/3737-must_use-false.md +++ b/text/3737-must_use-false.md @@ -45,7 +45,7 @@ When used on a type, `#[must_use = false]` is equivelent to not having any `#[mu The `must_use` attribute is used to control when the `unused_must_use` lint is emitted. It has three forms: -1. the plain `#[must_use]` form, equivelent to `#[must_use = true]`. +1. the plain `#[must_use]` form, equivalent to `#[must_use = true]`. 2. the boolean form, `#[must_use = BOOLEAN]`, where `BOOLEAN` is either `true` or `false`. 3. the string form, `#[must_use = "MESSAGE"]`, where `MESSAGE` is a help message to emmitted alongside the `unused_must_use` lint.