Skip to content

Conversation

@joshtriplett
Copy link
Member

@joshtriplett joshtriplett commented Oct 5, 2025

This suppresses warnings on things like Result<(), !>, which helps simplify code using the common pattern of having an Error associated type: code will only have to check the error if there is a possibility of error.

This will, for instance, help with future refactorings of write! in the standard library.

As this is a user-visible change to lint behavior, it'll require a lang FCP.


My proposal, here, is that we handle this simple case to make common patterns more usable. This does not rule out the possibility of adding more cases in the future, including general trait-based cases. However, I don't think we should make this common case wait on the more general cases. In particular, this solution does not close any doors on replacing this special case with a general case.

This would unblock some planned work in the standard library to make write! more usable for infallible cases (e.g. writing into a Vec or String).

This simplifies the initial conditional, and will allow reusing the
variable in subsequent checks.
@rustbot rustbot added 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. labels Oct 5, 2025
@rustbot
Copy link
Collaborator

rustbot commented Oct 5, 2025

r? @fmease

rustbot has assigned @fmease.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@joshtriplett joshtriplett added T-lang Relevant to the language team I-lang-nominated Nominated for discussion during a lang team meeting. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. relnotes Marks issues that should be documented in the release notes of the next release. labels Oct 5, 2025
@fmease fmease added S-waiting-on-team DEPRECATED: Use the team-based variants `S-waiting-on-t-lang`, `S-waiting-on-t-compiler`, ... and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 5, 2025
@fmease
Copy link
Member

fmease commented Oct 5, 2025

I'll be waiting for the outcome of T-lang's triage meeting before reviewing this since the proposed rules might very well change drastically (e.g., trait-driven vs. not trait-driven; cc Zulip discussion).

@joshtriplett
Copy link
Member Author

Summarizing the Zulip discussion:

  • What this PR does: We could do this by looking for any uninhabited type. This takes into account types that are not publicly known to be uninhabited, and types that are marked as #[non_exhaustive] (so they may not always be uninhabited).
  • We could do this by hardcoding types like ! or Infallible.
  • We could do this by identifying the types in some other way, such as a dedicated attribute, or a trait.
  • We could require people to use Result::into_ok() (once stabilized). This would be less readable, though.
  • Some discussion about cases like enums with variants that are sometimes configured out.

@joshtriplett
Copy link
Member Author

joshtriplett commented Oct 5, 2025

My proposal, here, is that we handle this simple case to make common patterns more usable. This does not rule out the possibility of adding more cases in the future, including general trait-based cases. However, I don't think we should make this common case wait on the more general cases. In particular, this solution does not close any doors on replacing this special case with a general case.

This would unblock some planned work in the standard library to make write! more usable for infallible cases (e.g. writing into a Vec or String).

@Amanieu
Copy link
Member

Amanieu commented Oct 5, 2025

As a general rule I think this should follow the same rules what let Ok(()) = foo would accept.

@joshtriplett joshtriplett force-pushed the unused-must-use-ignore-result-unit-uninhabited branch from d9d6c49 to 23a0751 Compare October 6, 2025 05:10
@joshtriplett
Copy link
Member Author

I've updated this to follow the same pattern as other inhabitedness checking, of only caring about non_exhaustive from external crates.

I've also updated it to handle ControlFlow.

@joshtriplett joshtriplett changed the title unused_must_use: Don't warn on Result<(), Uninhabited> unused_must_use: Don't warn on Result<(), Uninhabited> or ControlFlow<Uninhabited, ()> Oct 6, 2025
@niacdoial
Copy link
Contributor

huh...
github doesn't let me choose your branch as a PR destination.
er... anyway, I would like to contribute a test (making sure unresolved type aliases behave like inhabited types), if you'll let me:
https://github.com/niacdoial/rust-contrib-fork/tree/must_use_uninhab

@joshtriplett
Copy link
Member Author

huh... github doesn't let me choose your branch as a PR destination. er... anyway, I would like to contribute a test (making sure unresolved type aliases behave like inhabited types), if you'll let me: https://github.com/niacdoial/rust-contrib-fork/tree/must_use_uninhab

Added, thanks!

@Urgau Urgau added S-waiting-on-t-lang Status: Awaiting decision from T-lang and removed S-waiting-on-team DEPRECATED: Use the team-based variants `S-waiting-on-t-lang`, `S-waiting-on-t-compiler`, ... labels Oct 6, 2025
@traviscross traviscross added the P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang label Oct 8, 2025
@scottmcm
Copy link
Member

scottmcm commented Oct 8, 2025

Is this the same as "don't must_use warn on things that are ZSTs"?

Thus it could be phrased as "change the ()-specific rule to any ZST, not just the unit ZST".

@joshtriplett
Copy link
Member Author

@scottmcm I don't want to generalize that here yet, because someone might e.g. have some #[must_use] ZST that represents "capture this token and pass it to some other function to prove you got an Ok", and I wouldn't want to override that. Some more general design could argue for that, but () is the case that I'm confident any more general solution will encompass.

@traviscross traviscross removed the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Oct 8, 2025
@traviscross
Copy link
Contributor

This makes sense to me, in particular how this helps with write!, etc., and the test cases seem right.

@rfcbot fcp merge

@joshtriplett joshtriplett force-pushed the unused-must-use-ignore-result-unit-uninhabited branch from f4ca5fb to 7aa7ecc Compare October 10, 2025 20:14
@traviscross traviscross added I-lang-radar Items that are on lang's radar and will need eventual work or consideration. and removed I-lang-nominated Nominated for discussion during a lang team meeting. P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang labels Oct 15, 2025
@rust-rfcbot rust-rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. to-announce Announce this issue on triage meeting and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Oct 18, 2025
@rust-rfcbot
Copy link
Collaborator

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

This will be merged soon.

// Suppress warnings on `Result<(), Uninhabited>` (e.g. `Result<(), !>`).
ty::Adt(def, args)
if cx.tcx.is_diagnostic_item(sym::Result, def.did())
&& args.type_at(0).is_unit()
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason why this checks for T = ()? Result<T, !> is basically T, so I'd expect this to not check for (). In #147854, which I opened because I haven't seen this PR, I just return is_ty_must_use(cx, args.type_at(0), expr, span) here.

Copy link
Member Author

Choose a reason for hiding this comment

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

@WaffleLapkin I can see the argument for that, but it'd be less clear-cut. Result<(), !> has only one possible value, so there's zero value in checking it at all, and it seems safe to unconditionally make it ignore must_use. Something like Result<u32, !>, on the other hand, would currently be flagged by the must_use on Result, and it would be a potential surprise to people to stop doing that; people might be expecting to have to capture the return value with let Ok(value) = ..., for instance.

If we were going to potentially suppress warnings on Result<T, !>, I think that'd need a separate FCP. We might also want to let people know that they may want to mark the function #[must_use] if they were previously counting on the Result to do that.

Separately from that, if we're checking for T being #[must_use], it'd be nice to have a design where a function returning Result<T, E> produces an unused_must_use warning if you apply a ? and then ignore the T. But that doesn't have to happen right away, and I'm all for incremental results.

One way or another, though, I think that would be an additional change requiring an additional FCP.

@fmease fmease removed the S-waiting-on-fcp Status: PR is in FCP and is awaiting for FCP to complete. label Oct 20, 2025
@joshtriplett
Copy link
Member Author

I'm going to go ahead and merge given the FCP and @fmease's r=me, to get the incremental improvement that's already been approved. But we can always evaluate further enhancements to this further in the future.

@bors r=fmease rollup

@bors
Copy link
Collaborator

bors commented Oct 20, 2025

📌 Commit 7aa7ecc has been approved by fmease

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 20, 2025
Zalathar added a commit to Zalathar/rust that referenced this pull request Oct 20, 2025
…e-result-unit-uninhabited, r=fmease

unused_must_use: Don't warn on `Result<(), Uninhabited>` or `ControlFlow<Uninhabited, ()>`

This suppresses warnings on things like `Result<(), !>`, which helps simplify code using the common pattern of having an `Error` associated type: code will only have to check the error if there is a possibility of error.

This will, for instance, help with future refactorings of `write!` in the standard library.

As this is a user-visible change to lint behavior, it'll require a lang FCP.

---

My proposal, here, is that we handle this simple case to make common patterns more usable. This does not rule out the possibility of adding more cases in the future, including general trait-based cases. However, I don't think we should make this common case wait on the more general cases. In particular, this solution does not close any doors on replacing this special case with a general case.

This would unblock some planned work in the standard library to make `write!` more usable for infallible cases (e.g. writing into a `Vec` or `String`).
bors added a commit that referenced this pull request Oct 20, 2025
Rollup of 2 pull requests

Successful merges:

 - #146167 (Deny-by-default never type lints)
 - #147382 (unused_must_use: Don't warn on `Result<(), Uninhabited>` or `ControlFlow<Uninhabited, ()>`)

r? `@ghost`
`@rustbot` modify labels: rollup
bors added a commit that referenced this pull request Oct 20, 2025
Rollup of 3 pull requests

Successful merges:

 - #146167 (Deny-by-default never type lints)
 - #147382 (unused_must_use: Don't warn on `Result<(), Uninhabited>` or `ControlFlow<Uninhabited, ()>`)
 - #147821 (Do not GC the current active incremental session directory)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 061f854 into rust-lang:master Oct 20, 2025
10 checks passed
@rustbot rustbot added this to the 1.92.0 milestone Oct 20, 2025
rust-timer added a commit that referenced this pull request Oct 20, 2025
Rollup merge of #147382 - joshtriplett:unused-must-use-ignore-result-unit-uninhabited, r=fmease

unused_must_use: Don't warn on `Result<(), Uninhabited>` or `ControlFlow<Uninhabited, ()>`

This suppresses warnings on things like `Result<(), !>`, which helps simplify code using the common pattern of having an `Error` associated type: code will only have to check the error if there is a possibility of error.

This will, for instance, help with future refactorings of `write!` in the standard library.

As this is a user-visible change to lint behavior, it'll require a lang FCP.

---

My proposal, here, is that we handle this simple case to make common patterns more usable. This does not rule out the possibility of adding more cases in the future, including general trait-based cases. However, I don't think we should make this common case wait on the more general cases. In particular, this solution does not close any doors on replacing this special case with a general case.

This would unblock some planned work in the standard library to make `write!` more usable for infallible cases (e.g. writing into a `Vec` or `String`).
@joshtriplett joshtriplett deleted the unused-must-use-ignore-result-unit-uninhabited branch October 22, 2025 02:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. 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. relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-lang Relevant to the language team to-announce Announce this issue on triage meeting

Projects

None yet

Development

Successfully merging this pull request may close these issues.