Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 19 additions & 26 deletions library/core/src/mem/drop_guard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ pub struct DropGuard<T, F>
where
F: FnOnce(T),
{
inner: ManuallyDrop<T>,
f: ManuallyDrop<F>,
inner: ManuallyDrop<DropGuardInner<T, F>>,
}

struct DropGuardInner<T, F> {
value: T,
f: F,
}

impl<T, F> DropGuard<T, F>
Expand All @@ -57,8 +61,8 @@ where
/// ```
#[unstable(feature = "drop_guard", issue = "144426")]
#[must_use]
pub const fn new(inner: T, f: F) -> Self {
Self { inner: ManuallyDrop::new(inner), f: ManuallyDrop::new(f) }
pub const fn new(value: T, f: F) -> Self {
DropGuard { inner: ManuallyDrop::new(DropGuardInner { value, f }) }
}

/// Consumes the `DropGuard`, returning the wrapped value.
Expand Down Expand Up @@ -86,21 +90,14 @@ where
#[unstable(feature = "drop_guard", issue = "144426")]
#[inline]
pub fn into_inner(guard: Self) -> T {
// First we ensure that dropping the guard will not trigger
// its destructor
Comment on lines -89 to -90
Copy link
Member

Choose a reason for hiding this comment

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

This comment seems valuable, I wouldn't remove it.

let mut guard = ManuallyDrop::new(guard);

// Next we manually read the stored value from the guard.
//
// SAFETY: this is safe because we've taken ownership of the guard.
let value = unsafe { ManuallyDrop::take(&mut guard.inner) };

// Finally we drop the stored closure. We do this *after* having read
// the value, so that even if the closure's `drop` function panics,
// unwinding still tries to drop the value.
//
// SAFETY: this is safe because we've taken ownership of the guard.
unsafe { ManuallyDrop::drop(&mut guard.f) };
// SAFETY: This ManuallyDrop is owned by another ManuallyDrop which is
// dropped at the end of this function.
let DropGuardInner { value, f } = unsafe { ManuallyDrop::take(&mut guard.inner) };
// FIXME(#47949): `value` should drop if dropping `f` panics.
// If #47949 is fixed, this can be removed.
// This is tested in mem::drop_guard_always_drops_value_if_closure_drop_unwinds.
drop(f);
value
}
}
Expand All @@ -113,7 +110,7 @@ where
type Target = T;

fn deref(&self) -> &T {
&*self.inner
&self.inner.value
}
}

Expand All @@ -123,7 +120,7 @@ where
F: FnOnce(T),
{
fn deref_mut(&mut self) -> &mut T {
&mut *self.inner
&mut self.inner.value
}
}

Expand All @@ -134,12 +131,8 @@ where
{
fn drop(&mut self) {
// SAFETY: `DropGuard` is in the process of being dropped.
let inner = unsafe { ManuallyDrop::take(&mut self.inner) };

// SAFETY: `DropGuard` is in the process of being dropped.
let f = unsafe { ManuallyDrop::take(&mut self.f) };

f(inner);
let DropGuardInner { value, f } = unsafe { ManuallyDrop::take(&mut self.inner) };
f(value);
}
}

Expand Down
Loading