-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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 the #[manually_drop]
attribute.
#101586
Conversation
Some changes occurred in src/tools/clippy cc @rust-lang/clippy |
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @compiler-errors (or someone else) soon. Please see the contribution instructions for more information. |
afaict |
Yes indeed, I'm exaggerating slightly in the PR description. Added a "morally" to fix. |
Sorry for taking so long to get to this, but I don't have the capacity to review this change right now. r? compiler |
☔ The latest upstream changes (presumably #102306) made this pull request unmergeable. Please resolve the merge conflicts. |
I'm going through the code, but isn't this something that shouldn't be insta-stable? CC @rust-lang/lang |
Uh, definitely the intent was to gate this behind a feature flag. See e.g. I guess I should be clearer about this in the PR description. I'll edit that in now. |
Shouldn't the feature flag be defined in |
// FIXME: This is not correct for `#[manually_drop]` in general, only when the struct is | ||
// a smart pointer whose pointee is at the same address, and whose pointee implements `Drop`. | ||
// Instead of checking for `#[manually_drop]`, this should likely be a more restricted check | ||
// for such types, or else union really should special-case and only permit `ManuallyDrop`, and | ||
// not `#[manually_drop]` types in general. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be addressed before landing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before stabilization, but I would argue it's safe to publish an initial version (marked experimental and unstable) without making a choice here. The current behavior is "merely" overly conservative, and does not prevent (safe) experimentation with the feature.
The current behavior could even be acceptable in the final version, it's just not completely ideal.
@@ -134,6 +134,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { | |||
} | |||
|
|||
if let ty::Adt(def, _) = arg_ty.kind() { | |||
// FIXME: This is not correct with `#[manually_drop]`, as that is just like any other type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this instead be changed to check against the lang_item DefId then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could do that, but then we're committing to ManuallyDrop remaining special, right? (And this e.g. prohibits removing the lang item)
The code changes seem reasonable (but incomplete, given the FIXMEs?). Apologies for the delay. Rerolling for a final reviewer as I'm a bit overwhelmed. r? compiler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you remove the manually_drop
lang item in this PR as well/change it to #[cfg(bootstrap)]
?
@@ -2141,6 +2153,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { | |||
sym::rustc_main, | |||
sym::unix_sigpipe, | |||
sym::derive, | |||
sym::manually_drop, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't think this should be necessary 🤔
what happens if you don't add it here and use manually_drop
as a crate attr?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right! That's simple enough. It's already checked by the other changes to this file, so removing it from this list makes the error messages less redundant.
Other way around, I think -- see the dev guide, which says |
I've done this in the version I'm going to upload, but it seems very fragile. ...
#[cfg_attr(bootstrap, lang = "manually_drop")]
#[cfg_attr(not(bootstrap), manually_drop)]
...
pub struct ManuallyDrop<T: ?Sized> { ... } The way it's done here, updating the bootstrap version past the version that deletes the lang item version is a breaking change that requires updating this code. But if we support the lang item and the attribute both at the same time, we can delete the lang item later at our leisure, once the bootstrap rustc supports the attribute. |
Hey! It looks like you've submitted a new PR for the library teams! If this PR contains changes to any Examples of
|
When updating the bootstrap compiler, the person doing that goes through all |
Ah, okay, that's good then! I was worried I'd be adding responsibilities onto someone who didn't already do this kind of thing. LMK if I implemented it incorrectly. :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good enough to land as unstable 👍
r=me after the test changes
OK, addressed those last two comments and also did a Thank you for the reviews! |
Add the `#[manually_drop]` attribute. This attribute is equivalent to `#[lang = "manually_drop"]`, and the behavior of both are extended to allow the type to define `Drop`, in which case, that will still be run. Only the field drop glue is suppressed. This PR should essentially fully implement rust-lang#100344, and is gated behind the feature flag `manually_drop_attr`. Some additional notes: ### The meaning of `#[manually_drop]` `#[manually_drop]` means "do not destroy the fields automatically during destruction". `ManuallyDrop`, could "just", morally speaking, be `#[manually_drop] struct ManuallyDrop<T>(T);`. The intent is, per the MCP, to allow customization of the drop order, without making the interface for initializing or accessing the fields of the struct clumsier than a normal Rust type. It also -- and people did seem excited about this part -- lifts `ManuallyDrop` from being a special language supported feature to just another user of `#[manually_drop]`. ### Insignificant Drop There is the question of how this interacts with "insignificant" drop. I had trouble understanding the comments, but insignificant drop appears to just be a static analysis tool, and not something that changes behavior. (For example, it's used to detect if a language change will reorder drops in a meaningful way -- meaning, reorder the significant drops, not the insignificant ones.) Since it's unlikely to be used for `#[manually_drop]` types, I don't think it matters a whole lot. And where a destructor is defined, it would seem to make sense for `#[manually_drop]` types to match exactly the behavior of `union`, since they both have the shared property that field drop glue is suppressed. ### Users that expect `adt.is_manually_drop()` <-> "is `std::mem::ManuallyDrop`" I looked for all locations that queried for `is_manually_drop` in any form, and found two difficult cases which are hardcoded for `ManuallyDrop` in particular. The first is a clippy lint for redundant clones. I don't understand why it special-cases `ManuallyDrop`, and it's almost certainly wrong for it to special-case `#[manually_drop]` types in general. However, without understanding the original rationale, I have trouble figuring the right fix. Perhaps it should simply be deleted altogether. The second is unions -- specifically, the logic for disabling `DerefMut`. `my_union.x.y = z` will automatically dereference `my_union.x` if it implements `DerefMut`, unless it is `ManuallyDrop`, in which case it will not. This is because `ManuallyDrop` is a pointer back to its content, and so this will automatically call `drop` on a probably uninitialized field, and is unsafe. This is true of `ManuallyDrop`, but not necessarily any other `#[manually_drop]` type. I believe the correct fix would, instead, be a way to mark and detect types which are a smart pointer whose pointee is within `self`. See, for example, this playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=76fb22a6214ce453538fc18ec35a839d But that needs to wait for a separate RFC. For now, we apply exactly the same restriction for `ManuallyDrop` and for any other `#[manually_drop]` type, even though it may be confusing. ## To-do in future PRs 1. Delete `#[lang = "manually_drop"]`. I'm not sure if anything special needs to be done here other than replacing it with `#[manually_drop]` -- is there a compatibility guarantee that must be upheld? 2. (Optional) Fix the redundant clone check to correctly handle `#[manually_drop]` structs that aren't `ManuallyDrop`. 3. When there is more experience with the feature (e.g. in Crubit) create a full RFC based on the MCP, and go through the remainder of the stabilization process. (Also, do things like generalize the union error messages to not specifically mention `ManuallyDrop`, but also mention `#[manually_drop]`. For as long as the feature is unstable, the error messages would be confusing if they referenced it...)
Sorry about that, I really had thought I'd run tests. Fix committed and pushed. |
This comment has been minimized.
This comment has been minimized.
Is there anything I need to do here? |
To deal with the currently broken tests, you can use: git fetch <rust-lang-branch>
git rebase <rust-lang-branch>/master
./x.py test src/test/ui --bless |
@@ -113,6 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { | |||
} | |||
|
|||
if let ty::Adt(def, _) = arg_ty.kind() { | |||
// FIXME: This is not correct with `#[manually_drop]`, as that is just like any other type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this should get merged like this, could you open up a Clippy issue describing the possible extension that could be done here, please?
@ssbr any updates on this? |
This attribute is equivalent to `#[lang = "manually_drop"]`, and the behavior of both are extended to allow the type to define `Drop`, in which case, that will still be run. Only the field drop glue is suppressed. This PR should essentially fully implement rust-lang#100344. Some additional notes: `#[manually_drop]` means "do not destroy the fields automatically during destruction". `ManuallyDrop`, is (or could be) "just" `#[manually_drop] struct ManuallyDrop<T>(T);`. The intent is, per the MCP, to allow customization of the drop order, without making the interface for initializing or accessing the fields of the struct clumsier than a normal Rust type. It also -- and people did seem excited about this part -- lifts `ManuallyDrop` from being a special language supported feature to just another user of `#[manually_drop]`. There is the question of how this interacts with "insignificant" drop. I had trouble understanding the comments, but insignificant drop appears to just be a static analysis tool, and not something that changes behavior. (For example, it's used to detect if a language change will reorder drops in a meaningful way -- meaning, reorder the significant drops, not the insignificant ones.) Since it's unlikely to be used for `#[manually_drop]` types, I don't think it matters a whole lot. And where a destructor is defined, it would seem to make sense for `#[manually_drop]` types to match exactly the behavior of `union`, since they both have the shared property that field drop glue is suppressed. I looked for all locations that queried for `is_manually_drop` in any form, and found two difficult cases which are hardcoded for `ManuallyDrop` in particular. The first is a clippy lint for redundant clones. I don't understand why it special-cases `ManuallyDrop`, and it's almost certainly wrong for it to special-case `#[manually_drop]` types in general. However, without understanding the original rationale, I have trouble figuring the right fix. Perhaps it should simply be deleted altogether. The second is unions -- specifically, the logic for disabling `DerefMut`. `my_union.x.y = z` will automatically dereference `my_union.x` if it implements `DerefMut`, unless it is `ManuallyDrop`, in which case it will not. This is because `ManuallyDrop` is a pointer back to its content, and so this will automatically call `drop` on a probably uninitialized field, and is unsafe. This is true of `ManuallyDrop`, but not necessarily any other `#[manually_drop]` type. I believe the correct fix would, instead, be a way to mark and detect types which are a smart pointer whose pointee is within `self`. See, for example, this playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=76fb22a6214ce453538fc18ec35a839d But that needs to wait for a separate RFC. For now, we apply exactly the same restriction for `ManuallyDrop` and for any other `#[manually_drop]` type, even though it may be confusing. 1. Delete `#[lang = "manually_drop"]`. I'm not sure if anything special needs to be done here other than replacing it with `#[manually_drop]` -- is there a compatibility guarantee that must be upheld? 2. (Optional) Fix the redundant clone check to correctly handle `#[manually_drop]` structs that aren't `ManuallyDrop`. 3. When there is more experience with the feature (e.g. in Crubit) create a full RFC based on the MCP, and go through the remainder of the stabilization process. (Also, do things like generalize the union error messages to not specifically mention `ManuallyDrop`, but also mention `#[manually_drop]`. For as long as the feature is unstable, the error messages would be confusing if they referenced it...)
Co-authored-by: lcnr <[email protected]>
Sorry, I was really confused about the AI because the tests continue to all pass on my side, and then I let it drop from my radar. Let me take a look at how to reproduce, so that I can |
This comment has been minimized.
This comment has been minimized.
The job Click to see the possible cause of the failure (guessed by this bot)
|
I figured out why tests continue to pass locally but fail remotely. The failure message says:
... however, there is no
... so I'm going to wait until next week, and hopefully the ICE is fixed by then. |
☔ The latest upstream changes (presumably #108464) made this pull request unmergeable. Please resolve the merge conflicts. |
@ssbr FYI: when a PR is ready for review, send a message containing |
Ping from triage: I'm closing this due to inactivity, Please reopen when you are ready to continue with this. @rustbot label: +S-inactive |
This attribute is equivalent to
#[lang = "manually_drop"]
, and the behavior of both are extended to allow the type to defineDrop
, in which case, that will still be run. Only the field drop glue is suppressed.This PR should essentially fully implement #100344, and is gated behind the feature flag
manually_drop_attr
.Some additional notes:
The meaning of
#[manually_drop]
#[manually_drop]
means "do not destroy the fields automatically during destruction".ManuallyDrop
, could "just", morally speaking, be#[manually_drop] struct ManuallyDrop<T>(T);
.The intent is, per the MCP, to allow customization of the drop order, without making the interface for initializing or accessing the fields of the struct clumsier than a normal Rust type. It also -- and people did seem excited about this part -- lifts
ManuallyDrop
from being a special language supported feature to just another user of#[manually_drop]
.Insignificant Drop
There is the question of how this interacts with "insignificant" drop. I had trouble understanding the comments, but insignificant drop appears to just be a static analysis tool, and not something that changes behavior. (For example, it's used to detect if a language change will reorder drops in a meaningful way -- meaning, reorder the significant drops, not the insignificant ones.) Since it's unlikely to be used for
#[manually_drop]
types, I don't think it matters a whole lot. And where a destructor is defined, it would seem to make sense for#[manually_drop]
types to match exactly the behavior ofunion
, since they both have the shared property that field drop glue is suppressed.Users that expect
adt.is_manually_drop()
<-> "isstd::mem::ManuallyDrop
"I looked for all locations that queried for
is_manually_drop
in any form, and found two difficult cases which are hardcoded forManuallyDrop
in particular.The first is a clippy lint for redundant clones. I don't understand why it special-cases
ManuallyDrop
, and it's almost certainly wrong for it to special-case#[manually_drop]
types in general. However, without understanding the original rationale, I have trouble figuring the right fix. Perhaps it should simply be deleted altogether.The second is unions -- specifically, the logic for disabling
DerefMut
.my_union.x.y = z
will automatically dereferencemy_union.x
if it implementsDerefMut
, unless it isManuallyDrop
, in which case it will not. This is becauseManuallyDrop
is a pointer back to its content, and so this will automatically calldrop
on a probably uninitialized field, and is unsafe.This is true of
ManuallyDrop
, but not necessarily any other#[manually_drop]
type. I believe the correct fix would, instead, be a way to mark and detect types which are a smart pointer whose pointee is withinself
. See, for example, this playground link:https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=76fb22a6214ce453538fc18ec35a839d
But that needs to wait for a separate RFC. For now, we apply exactly the same restriction for
ManuallyDrop
and for any other#[manually_drop]
type, even though it may be confusing.To-do in future PRs
#[manually_drop]
structs that aren'tManuallyDrop
.ManuallyDrop
, but also mention#[manually_drop]
. For as long as the feature is unstable, the error messages would be confusing if they referenced it...)