Skip to content
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

Add #[must_bind] attribute and lint #78715

Closed
wants to merge 1 commit into from
Closed

Conversation

vi
Copy link
Contributor

@vi vi commented Nov 3, 2020

Prototype implementation of https://internals.rust-lang.org/t/pre-rfc-must-bind/12658

Like #[must_use], but also catches let _ =.

Intended to be used on semaphore guards and similar things where RAII guard is detached from the protected resource.
Beginner users often think that _ is just a funny variable name and the guard will be dropped at the end of block instead of immediately. This may introduce silent logic error into the code.

TODO:

  • Require #[feature] instead of insta-stable
  • Proper test
  • Add section to reference
  • Probably refactor the code
  • Decide on a specific lint text and attribute name
  • Detecting #[must_bind] without #[must_use] as error.
  • Automatically suggest an edit for cargo fix

Is this idea worth pursuing further or it's unlikely to go through even with the TODOs resolved?

@rust-highfive
Copy link
Collaborator

r? @davidtwco

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Nov 3, 2020
/// [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_bind-attribute
pub UNUSED_MUST_BIND,
Warn,
"Bogus `_` binding of a type flagged as `#[must_bind]`. Use something like `_guard`.",
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
"Bogus `_` binding of a type flagged as `#[must_bind]`. Use something like `_guard`.",
"types marked as `#[must_bind]` should be assigned to a variable, not dropped immediately",

@ghost
Copy link

ghost commented Nov 6, 2020

Did not know _ and _guard are different things. 💡
Would be nice to warn the user if they used the wrong variant.

I general (not necessarily with #[must_bind]) I think people should be made aware of this difference. Is this even mentioned in the book?

@Mark-Simulacrum Mark-Simulacrum added I-nominated T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Nov 6, 2020
@Mark-Simulacrum
Copy link
Member

I'm going to nominate for lang team because while I tend to think this is not the right fix (it's too similar to must_use, IMO), I think it may be worth trying to get a brief discussion at least on the _ vs _guard difference; I think I frequently see users (including myself) forgetting that these two are different.

@vi
Copy link
Contributor Author

vi commented Nov 6, 2020

I think people should be made aware of this difference.

#[must_bind] attribute allows telling it to users at the moment where they need it the most, i.e. when dealing with content-less drop-only RAII guards (which some may consider an anti-pattern per se).

Copy link
Member

@davidtwco davidtwco left a comment

Choose a reason for hiding this comment

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

As Mark as noted, needs lang team involvement but w/r/t implementation:

In addition to the changes you've noted in the MR description, I've added some nitpicks below - but the implementation looks broadly correct to me.

descr_post_path
),
WhatAttrToCheck::MustBind => format!(
"Bogus `let _ =` binding of {}`{}`{}. Use something like `let _guard =`.",
Copy link
Member

Choose a reason for hiding this comment

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

This should be changed to the same message suggested by this comment.

let (expr, attr_to_check) = match s.kind {
hir::StmtKind::Semi(ref expr) => (&**expr, WhatAttrToCheck::MustUse),
hir::StmtKind::Local(ref local) => {
match local.pat.kind {
Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer a guard in the match arm: if !matches!(local.pat.kind, hir::PatKind::Wild)

});
op_warned = true;
}
match attr_to_check {
Copy link
Member

Choose a reason for hiding this comment

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

if matches!(attr_to_check, WhatAttrToCheck::MustUse) would be preferable

});
true
}
ty::Closure(..) => match attr_to_check {
Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer a guard in the match arm: if matches!(attr_to_check, WhatAttrToCheck::MustUse)

}
_ => false,
},
ty::Generator(..) => match attr_to_check {
Copy link
Member

Choose a reason for hiding this comment

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

Likewise, guard in match arm.

let expr = match s.kind {
hir::StmtKind::Semi(ref expr) => &**expr,
#[derive(Clone, Copy)]
enum WhatAttrToCheck {
Copy link
Member

Choose a reason for hiding this comment

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

I'd rename this to something like UnusedResultsAttr (bikeshedding welcome) and I prefer it declared outside of the function and impl.

@vi
Copy link
Contributor Author

vi commented Nov 12, 2020

Note: #[must_not_await] implementation may also touch this code.
Shall this pull request somehow prepare for addition of the third checking mode?

@jyn514
Copy link
Member

jyn514 commented Nov 12, 2020

@vi I think this change is small enough you don't have to worry about it, the author of must_not_await can take care of conflicts when they open their PR.

@Mark-Simulacrum
Copy link
Member

We discussed this change in the last language team meeting. I think the general feeling is that we agree that this is a problem worth solving, but this does not quite feel like the right solution, or at least a broader exploration of the design space would be warranted first.

The next step here is likely to close this PR in favor of a future project group, which would explore the solution space a bit more before proposing a concrete solution. If you'd be interested in driving this project group, please start a thread in #t-lang on Zulip and we can coordinate on who will liaison the group and the charter drafting. The project group scope can be adjusted for how much time interested parties have to invest, but likely at least a solution space of fixing confusion around _ makes sense; an extension might be to look at temporary lifetime rules in general.

I'm leaving this PR open and nominated as an informed "Final comment period" on the suggested path above, and unless there's further discussion taking us in a different path the lang team will likely close this during next triage.

Thanks @vi!

@Mark-Simulacrum
Copy link
Member

Thanks! We've discussed a bit more over Zulip since then, and the current consensus remains that we would like to see an exploration of the design space some more perhaps targeted at solving the underlying problems rather than patching over it. Going to go ahead and close this PR for the time being, though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants