-
Notifications
You must be signed in to change notification settings - Fork 13k
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
It is too easy to lose #[must_use]
annotations when using impl Trait, leading to footguns
#51560
Comments
Since Rust 1.27 stabilizes |
I think it would make sense for @rust-lang/lang to quickly review and agree on how we should handle this. A lint seems plausible. Inside the same module, where we know the concrete underlying type, it would definitely make sense to pass through the |
Why is the |
I agree with @eddyb that |
In that case, is it fine that returning an Maybe we should suggest to the author of the function to add the attribute to the function if the real type is |
@oli-obk Right, there's nothing meaningfully tying such a function to |
The new thing being stabilized in 1.27 is specifically |
We may need to add an arm for rust/src/librustc_lint/unused.rs Lines 61 to 72 in 5205ae8
|
So, I'd absolutely support adding However, I also think we ought to handle this case somehow, preferably in a way that doesn't require the user to manually propagate #[must_use]
struct S { ... }
impl Trait for S { ... }
fn foo() -> impl Trait {
} |
@joshtriplett I don't think we should. The type, including its must-use'dness, is not a part of the public API in that context. If you want the function return to be treated as must-use, the solution in that case is to tag the function as must-use. |
@withoutboats Then in that case, would it make sense to have a lint suggesting propagation of |
@joshtriplett I don't think so. The point of returning impl Trait is to hide the return type and the facts of its API, the fact that the type is must-use seems no different from other facts about the return type. |
As alluded to above, I argue that this is a bug in the must-use lint due to its antedating impl-Trait; I don't see sufficient cause here to complicate the language with another lint or feature. A pull request is forthcoming. |
Hm, perhaps this was too confidently worded: see description of the new pull request #51571. |
So let me summarize to see if I understand correctly what you're planning for must_use for traits: #[must_use]
struct Foo {}
#[must_use]
trait MustUseTrait {}
impl MustUseTrait for Foo {}
trait CanUseTrait {}
impl CanUseTrait for Foo {}
fn get_foo() -> Foo { Foo {} }
fn get_must_use_trait() -> impl MustUseTrait { Foo {} }
fn get_can_use_trait() -> impl CanUseTrait { Foo {} }
fn main() {
get_foo(); // Warning (because of must_use on Foo and MustUseTrait)
get_must_use_trait(); // Warning (because of must_use on MustUseTrait)
get_can_use_trait(); // No warning (must_use on Foo does not matter because the type is anonymous)
} |
I think expanding the applicability of must_use should probably be introduced using an RFC. It seems to me that there are two different approaches proposed and an RFC could clarify why we chose a certain approach:
|
Can you provide an example of a case where it is the correct thing to return a concrete type that is tagged as My original premise is that this is an unintentional mistake in 95-99% of the cases, which feels like the ideal case for a lint. In the (rare) case where the author of the I don't know exactly which "other facts" you mean, but I can think of two primary things:
I think that the I know the auto trait aspect was much discussed, so I don't wish to re-litigate it. My point here is that we made the decision to automatically pass them for ergonomics:
I think there's a case to be made that |
As a concrete side note, I opened this because I did it myself: I wrote some code that returned For me, it's right up there with #36375 in that my "normal" flow of programming that I've established since ~Rust 0.12 doesn't quite work the same with |
@shepmaster IMO the more conservative approach would be to not leak must_use on the concrete type. If that turns out to be the wrong call, it can always be added later. I think defining must_use on traits (e.g. on The big advantage of defining must_use on the trait is that this system can also work for unnameable types like the return type of an async function. Additionally it also avoids all the boilerplate code that defines each concrete iterator or future type as much_use. |
@shepmaster I think the current approach of "stick |
To be clear, I'm totally happy with implementing I really just don't want to see this particular feature held up by a months (years?) long discussion of the ideal Platonic implementation of
Isn't that what the current implementation does? Am I missing something?
I believe that's what I'm proposing... 😕
Yes, I 💯 believe that that's a better option, and I'll add one more: presumably it will also work for trait objects. I just don't want to lose what existing ergonomics we have until someone implements These don't even have to be mutually exclusive options! The lint can catch cases that a The lint could even be removed once the better solution is created, if we felt it didn't carry its weight anymore. |
I also want to suggest a more aggressive approach: existential |
😮 I wonder how hard it would be to turn such a thing on to see the impact. 😨 |
@shepmaster Thanks for the compelling argument! I agree with what I think is the implication of your post: this question boils down to "Is @oli-obk What is the distinction with |
Allow #[must_use] on traits Addresses #55506, but we'll probably want to add it to some library traits like `Iterator` before the issue is considered fixed. Fixes #51560. `#[must_use]` is already permitted on traits, with no effect, so this seems like a bug fix, but I might be overlooking something. This currently warns for `impl Trait` or `dyn Trait` when the `Trait` is `#[must_use]` (although I don't think the latter is currently possible, so it's simply future-proofed).
If I return a direct type that is
must_use
, I get a helpful compiler warning:The equivalent (and I believe preferred) code using
impl Trait
gives no such useful feedback:Amusingly, this isn't a new problem, as returning a boxed trait object also has the same problem. It's arguably worse there because you've performed an allocation for no good reason, but it's also less likely because people are more reluctant to introduce unneeded allocations.
The text was updated successfully, but these errors were encountered: