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

Tracking issue for ManuallyDrop::take #55422

Closed
5 tasks done
CAD97 opened this issue Oct 27, 2018 · 27 comments · Fixed by #68066
Closed
5 tasks done

Tracking issue for ManuallyDrop::take #55422

CAD97 opened this issue Oct 27, 2018 · 27 comments · Fixed by #68066
Labels
B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. 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. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@CAD97
Copy link
Contributor

CAD97 commented Oct 27, 2018

This is a tracking issue for the function ManuallyDrop::take, gated on the feature manually_drop_take.

Steps:

Unresolved questions:

@frewsxcv frewsxcv added the C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. label Oct 27, 2018
@kennytm kennytm added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Oct 28, 2018
kennytm added a commit to kennytm/rust that referenced this issue Oct 28, 2018
Add ManuallyDrop::take

Tracking issue: rust-lang#55422

Proposed in this form in https://internals.rust-lang.org/t/mini-rfc-manuallydrop-take/8679,
see that thread for some history.

A small convenience wrapper for `ManuallyDrop` that makes a pattern (taking ownership of the contained data in drop) more obvious.
@RalfJung
Copy link
Member

I am a bit worried about the name of this method being too innocent-looking. We have take as a safe method in other places, like Option and Iterator. This leaves the fact that the method is unsafe as the only safeguard -- which is a problem e.g. when this gets (accidentally) used inside an unsafe fn or in a large unsafe block.

I'd prefer a name that already indicates this to be a dangerous operation. Strawman: take_unchecked because it doesn't check you are taking twice?

@CAD97
Copy link
Contributor Author

CAD97 commented Oct 29, 2018

Note that it has to be written as ManuallyDrop::take, which eliminates some of the risk of using a familiar name, as it's attached to ManuallyDrop, which is known to have interesting semantics, and thus is hard to use accidentally.

(Procedural note: I'll update OP with useful information soon.)

@SimonSapin
Copy link
Contributor

@RalfJung I’m sympathetic to this argument, but we also have ManuallyDrop::drop which is (almost) as innocent-looking, and also doesn’t check if we are dropping twice.

(I also notice that ManuallyDrop::into_inner is safe, even though it would be unsound to call after drop or take.)

So I’m inclined to FCP to stabilize as-is. Or do you feel strongly we should rename?

@RalfJung
Copy link
Member

RalfJung commented Feb 1, 2019

No, not very strongly. And not being able to say foo.take() helps a lot.

@ghost
Copy link

ghost commented Feb 28, 2019

Anything blocking stabilization? I've wanted this method from time to time.

@ghost
Copy link

ghost commented Feb 28, 2019

The naming issue might be related to MaybeUninit::into_initialized() vs MaybeUninit::read_initialized(). Would it make sense to name the method here ManuallyDrop::read()?

@scottmcm
Copy link
Member

scottmcm commented Jun 27, 2019

Anything that needs to be resolved for this to stabilize, libs?

I just ended up here because someone on discord was just using mem::replace(x, mem::uninitialized()) (😭) where hopefully they would have just used this if it were stable.

@RalfJung
Copy link
Member

The corresponding (unstable) method on MaybeUninit is (currently) called "read", because the safety concerns are a lot like the ones of ptr::read. Would the same make sense here as well?

@SimonSapin
Copy link
Contributor

This sounds reasonable. In fact both methods are implemented based on ptr::read. We can repeat it again in the docs:

Like std::ptr::read, this function semantically moves […]

@rust-lang/libs, what do you think?

@CAD97
Copy link
Contributor Author

CAD97 commented Jun 28, 2019

Documentation is updated and rename is done in #62198. I've also finally updated the OP with the proper details. I can roll stabilization into #62198 if desired, or it can be done separately of course.

@HyeonuPark
Copy link

I think this method is only reasonable only if we don't have MaybeUninit in stable. Practically we use ManuallyDrop when we need untagged Option, because we don't have any other way to prevent accidentally dropping invalid data. But now we have MaybeUninit in stable which exactly is for this purpose.

Is there some use case that can't be reasonably expressed using MaybeUninit?

@CAD97
Copy link
Contributor Author

CAD97 commented Jul 9, 2019

@HyeonuPark ManuallyDrop is for a place that is valid (semantically) 99.99% of the time, or just needs its drop glue to be skipped. To this end, it derefs to its target so you can use &ManuallyDrop<T> as &T. Of important note is that while ManuallyDrop is allowed to be in a logically invalid state (i.e. a dropped value that needs to not be reused), it is not allowed to be in a physically invalid bit pattern, therefore preserving the niche of the underlying type.

Note also that MaybeUninit::read is also still unstable, so the functionality offered by this function is (implementable in userland but) not available in std.

@HyeonuPark
Copy link

@CAD97 I agree ManuallyDrop is useful, but not sure about ManuallyDrop::read(). Isn't this thread for stabilizing this method? Is there some use case that can't be reasonably expressed using MaybeUninit?

@CAD97
Copy link
Contributor Author

CAD97 commented Jul 10, 2019

@HyeonuPark The main use case is for in Drop::drop(&mut self) and you want to consume one of your members by value, usually because of a strict API that you're wrapping.

@RalfJung
Copy link
Member

RalfJung commented Jul 13, 2019

ManuallyDrop is for a place that is valid 99.99% of the time

No, ManuallyDrop must be valid (in the sense of the validity invariant) 100% of the time. A ManuallyDrop<bool> of value 8 is insta-UB. The thing is, dropping leaves the validity invariant intact (it has to, drop glue would go terribly wrong otherwise).

@alexcrichton
Copy link
Member

I'm going to de-nominate this because stabilization happens outside of triage meetings and happens when a libs team member feels confident enough to propose stabilization.

@RalfJung
Copy link
Member

Re: the parallel with MaybeUninit; my thinking is actually that read should probably be renamed to read_init or read_assume_init or so, something that indicates that this may only be done after initialization is complete.

@jonas-schievink jonas-schievink added the B-unstable Blocker: Implemented in the nightly compiler and unstable. label Nov 26, 2019
@petertodd
Copy link
Contributor

Should this function take &Self or &mut Self?

I think &mut Self is the better API, as it's consistent with the general case that take() transfers ownership and thus should only be called once; in the rare case where you really need to take() more than once you can always use ptr::read() instead.

Having said that, there is a difference in variance between the two, though I think it's a 100% pedantic difference. The &Self version is covariant over T, while the &mut Self version is invariant over T. This means that the following won't compile:

unsafe fn foo<'a>(src: &mut ManuallyDrop<&'static ()>) -> &'a () {
    ManuallyDrop::<&'a ()>::take(src)
}

A &mut ManuallyDrop<T> used this way is kind of like owning a T; the analogous Box<T> version does compile:

fn foo<'a>(src: Box<&'static ()>) -> &'a () {
    *src
}

But as I said above, I'm pretty sure this is a very pedantic objection, as you have to go out of your way to see this difference in action. The following compiles just fine, with Rust coercing the lifetime after the take() call:

unsafe fn foo<'a>(src: &mut ManuallyDrop<&'static ()>) -> &'a () {
    ManuallyDrop::take(src)
}

But I'm relatively new to thinking hard about variance, so if anyone thinks I missed something in the above I'd love to hear. :)

@petertodd
Copy link
Contributor

Naming

take_unchecked() would be a logical analogy to the safe Option::take() - the latter checks if you call it twice, while the former doesn't. However we already have the unsafe, unchecked, ManuallyDrop::drop(), so I'd vote for sticking to the existing take() name. After all, it has to be called with ManuallyDrop::take(src), so it should be clear to the reader that you aren't doing a standard, safe, take().

@RalfJung
Copy link
Member

Or alternatively we could deprecate ManuallyDrop::drop and rename it to ManuallyDrop::drop_unchecked.

@petertodd
Copy link
Contributor

@RalfJung So counter-argument to my "it should be clear" argument: How many people who are unfamiliar with ManuallyDrop read it and think "ah, drop flags!"?

@jyn514
Copy link
Member

jyn514 commented Jan 8, 2020

IMO, anyone who sees ManuallyDrop and unsafe already knows there's something fishy going on, I don't think it needs to be reinforced by _unchecked.

@Amanieu
Copy link
Member

Amanieu commented Jan 9, 2020

I would like to stabilize this function as it is. For reference, here is the signature:

impl<T> ManuallyDrop<T> {
    pub unsafe fn take(slot: &mut ManuallyDrop<T>) -> T;
}

@rfcbot fcp merge

@rfcbot
Copy link

rfcbot commented Jan 9, 2020

Team member @Amanieu has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Jan 9, 2020
@CAD97
Copy link
Contributor Author

CAD97 commented Jan 9, 2020

I went ahead and filed the stabilization PR at #68066 along with reclaimed doc improvements from the closed rename PR.

@rfcbot
Copy link

rfcbot commented Jan 10, 2020

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Jan 10, 2020
@rfcbot rfcbot added the finished-final-comment-period The final comment period is finished for this PR / Issue. label Jan 20, 2020
@rfcbot
Copy link

rfcbot commented Jan 20, 2020

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.

The RFC will be merged soon.

@rfcbot rfcbot removed the final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. label Jan 20, 2020
@bors bors closed this as completed in b5a3341 Jan 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. 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. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.