Skip to content

Commit f9b9467

Browse files
Rollup merge of #76640 - fusion-engineering-forks:synconcecell-drop, r=matklad
Simplify SyncOnceCell's `take` and `drop`. Prevents copies by using `assume_init_read` and `assume_init_drop`.
2 parents 148b24f + aa68aaa commit f9b9467

File tree

2 files changed

+14
-26
lines changed

2 files changed

+14
-26
lines changed

library/std/src/lazy.rs

+13-26
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
cell::{Cell, UnsafeCell},
88
fmt,
99
marker::PhantomData,
10-
mem::{self, MaybeUninit},
10+
mem::MaybeUninit,
1111
ops::{Deref, Drop},
1212
panic::{RefUnwindSafe, UnwindSafe},
1313
sync::Once,
@@ -316,13 +316,7 @@ impl<T> SyncOnceCell<T> {
316316
/// ```
317317
#[unstable(feature = "once_cell", issue = "74465")]
318318
pub fn into_inner(mut self) -> Option<T> {
319-
// SAFETY: Safe because we immediately free `self` without dropping
320-
let inner = unsafe { self.take_inner() };
321-
322-
// Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set
323-
// the state to uninitialized.
324-
mem::forget(self);
325-
inner
319+
self.take()
326320
}
327321

328322
/// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state.
@@ -348,22 +342,12 @@ impl<T> SyncOnceCell<T> {
348342
/// ```
349343
#[unstable(feature = "once_cell", issue = "74465")]
350344
pub fn take(&mut self) -> Option<T> {
351-
mem::take(self).into_inner()
352-
}
353-
354-
/// Takes the wrapped value out of a `SyncOnceCell`.
355-
/// Afterwards the cell is no longer initialized.
356-
///
357-
/// Safety: The cell must now be free'd WITHOUT dropping. No other usages of the cell
358-
/// are valid. Only used by `into_inner` and `drop`.
359-
unsafe fn take_inner(&mut self) -> Option<T> {
360-
// The mutable reference guarantees there are no other threads that can observe us
361-
// taking out the wrapped value.
362-
// Right after this function `self` is supposed to be freed, so it makes little sense
363-
// to atomically set the state to uninitialized.
364345
if self.is_initialized() {
365-
let value = mem::replace(&mut self.value, UnsafeCell::new(MaybeUninit::uninit()));
366-
Some(value.into_inner().assume_init())
346+
self.once = Once::new();
347+
// SAFETY: `self.value` is initialized and contains a valid `T`.
348+
// `self.once` is reset, so `is_initialized()` will be false again
349+
// which prevents the value from being read twice.
350+
unsafe { Some((&mut *self.value.get()).assume_init_read()) }
367351
} else {
368352
None
369353
}
@@ -416,9 +400,12 @@ impl<T> SyncOnceCell<T> {
416400

417401
unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> {
418402
fn drop(&mut self) {
419-
// SAFETY: The cell is being dropped, so it can't be accessed again.
420-
// We also don't touch the `T`, which validates our usage of #[may_dangle].
421-
unsafe { self.take_inner() };
403+
if self.is_initialized() {
404+
// Safety: The cell is initialized and being dropped, so it can't
405+
// be accessed again. We also don't touch the `T` other than
406+
// dropping it, which validates our usage of #[may_dangle].
407+
unsafe { (&mut *self.value.get()).assume_init_drop() };
408+
}
422409
}
423410
}
424411

library/std/src/sync/once.rs

+1
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ struct WaiterQueue<'a> {
191191

192192
impl Once {
193193
/// Creates a new `Once` value.
194+
#[inline]
194195
#[stable(feature = "once_new", since = "1.2.0")]
195196
#[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
196197
pub const fn new() -> Once {

0 commit comments

Comments
 (0)