Skip to content

Conversation

@dhardy
Copy link
Contributor

@dhardy dhardy commented Jan 7, 2026

Let Option and Box derive #[must_use] from their generic parameter T.

Rendered

@ehuss ehuss added T-lang Relevant to the language team, which will review and decide on the RFC. T-libs-api Relevant to the library API team, which will review and decide on the RFC. labels Jan 7, 2026
@burdges
Copy link

burdges commented Jan 8, 2026

Is there some reason #[must_use] should not be a marker trait?

@Lokathor
Copy link
Contributor

Lokathor commented Jan 8, 2026

I would say that actually must_use is more a property of a particular function, not really of types, and sticking it on types is a shorthanded way to put it on a lot of functions "for free" cognitively. I'd say it's best if we, as an ecosystem, stick to having must_use on functions/methods rather than types.

@dlight
Copy link

dlight commented Jan 9, 2026

I would say that actually must_use is more a property of a particular function, not really of types, and sticking it on types is a shorthanded way to put it on a lot of functions "for free" cognitively. I'd say it's best if we, as an ecosystem, stick to having must_use on functions/methods rather than types.

So #[must_use] could be a marker trait on the function's type where it is applied (each function has a unique type) and on each type it is applied. Then you add a blanked impl on functions whenever their output type impls the trait.

(it could be two traits, one for types you apply #[must_use] and another for functions, so that returning the function doesn't trigger it)

@dhardy
Copy link
Contributor Author

dhardy commented Jan 9, 2026

I would say that actually must_use is more a property of a particular function, not really of types

Yes, but #[must_use] on types already has stable support (since 1.0 I think).

So #[must_use] could be a marker trait

Perhaps, but that would be quite a significant revision. Definitely out-of-scope for this RFC.

@dlight
Copy link

dlight commented Jan 9, 2026

Agreed! For this RFC a trait is not necessary. If extending this feature to custom types is desired, a trait would be useful

@kennytm
Copy link
Member

kennytm commented Jan 10, 2026

Note that it is already possible to mark a trait as #[must_use] (which is how rustc can warn about unused Future). It does not help this RFC though.

# Guide-level explanation
[guide-level-explanation]: #guide-level-explanation

The `Option` and `Box` types will "magically" have the `#[must_use]` attribute if and only if their generic parameter `T` does.
Copy link

Choose a reason for hiding this comment

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

why "magically"?

why not permit #[must_use] on the parameters themselves, e.g.

pub struct Option<#[must_use] T> {
    Some(T),
    None,
}

"desugars"1 to

impl<T: MustUse> MustUse for Option<T> {}

Footnotes

  1. There will not necessarily be an actual MustUse trait in the implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

impl<T: MustUse> MustUse for Option {}

#[must_use] is not currently a trait. If you want to make an RFC for that, please go ahead. It may be a good idea, but it is an idea for another RFC, not this one.

Since #[must_use] is not currently a trait, we lack the language to describe derive behaviour, hence use of "magically" here.

Option<#[must_use] T>

Use of #[must_use] on parameters is novel syntax that I don't particularly like.

Copy link

Choose a reason for hiding this comment

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

sorry, i thought i was clear in the original comment that "the MustUse trait" was mentioned purely as an analogy, and not as a normative suggestion, but perhaps not. fwiw i think a MustUse trait would be bad since

  1. trait solver is slow and heavy compared to just looking at some simple hard-coded rules based on named types/traits.
  2. it gives perhaps too much flexibility to the user. do we really want people to be able to write impl<T: Copy> MustUse for Thing<T>, for instance.

i think users should have access to more fine-grained #[must_use] annotations, but that doesn't per-se have to be part of this change since Option and Box alone would be clear usability improvements in my book.

i don't want to overlitigate, but i still reckon this RFC doesn't really justify the "magic" design as written: it's clearly conceptually easier to special case these two generic types, but i don't see it as better from a maintenance perspective if we do want to rip it out for something holistic. for instance is_ty_must_use is already more complicated than ideally it should be (sidebar: and, seemingly, incomplete; see this playground). should we keep adding additional branches ad infinitum?

Copy link
Member

Choose a reason for hiding this comment

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

Use of #[must_use] on parameters is novel syntax that I don't particularly like.

Attribute on type parameter is already in use since #3621 (ref), it is no longer a novel syntax.

#[derive(CoercePointee)]
#[repr(transparent)]
struct MySmartPointer<#[pointee] T: ?Sized, U> {
    ptr: Box<T>,
    _phantom: PhantomData<U>,
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Option<#[must_use] T>

Something like this would be clearer (though I do find derive's "magic" handling of generic parameters unfortunate relative to making this explicit, as with autoimpl):

#[derive(must_use)]
enum Option<T> { /* ... */ }

That may be besides the point though if this RFC adds more complexity than value. (I had no idea that Result<T, Infallible> would not trigger a "must use" warning.)

@dhardy
Copy link
Contributor Author

dhardy commented Jan 15, 2026

Since there have been a number of suggestions about how to generalise this RFC, let me be clear: this RFC is extremely specific on purpose:

  • This RFC affects only two std types in a way which should be compatible with any more general "must_use derive" mechanism
  • It addresses what I see as the largest short-comings of #[must_use] without the complexity of a general "attribute derive mechanism" or turning #[must_use] into a trait

@tmccombs
Copy link

tmccombs commented Jan 17, 2026

It seems strange to me for it to magically apply to these two types, without a more general mechanism.

And why not Result? Or Pin?

@burdges
Copy link

burdges commented Jan 18, 2026

Appears #[must_use] could be a trait based upon the above comments. I think here the reason is just simplicity:

Result is #[must_use] now. The issue here is Option<Result<..>> and Box<Result<..>> are not #[must_use] now, so you must manually put a #[must_use] on fns returning them.

Afaik, no pointer types are #[must_use] so Pin does not come up, but sure Pin<Box<Result<..>>> becomes a question if Box<Result<..>> becomes #[must_use].

Comment on lines +1 to +9
- Feature Name: Let `Option` derive `#[must_use]`
- Start Date: 2026-01-07
- RFC PR: [rust-lang/rfcs#3906](https://github.com/rust-lang/rfcs/pull/3906)
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)

# Summary
[summary]: #summary

Let `Option` and `Box` derive `#[must_use]` from their generic parameter `T`.
Copy link
Contributor

Choose a reason for hiding this comment

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

2cents: I think "inherit" may be a better term ot use than "derive". For me at least, in reading this RFC title I expected something like #[derive(MustUse)] to be involved.

Choose a reason for hiding this comment

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

derive may cause confusion with derive macro.

but inherit may also cause confusion with that in OOP sense.

I think propagate is a better word.

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

Labels

T-lang Relevant to the language team, which will review and decide on the RFC. T-libs-api Relevant to the library API team, which will review and decide on the RFC.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants