about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMara Bos <m-ou.se@m-ou.se>2020-09-12 13:40:50 +0200
committerMara Bos <m-ou.se@m-ou.se>2020-09-12 14:00:38 +0200
commit8a261a2b342d85d11c67a8d4dd3408778bd0f5b7 (patch)
tree4736708ca29c5fa7ceddbc73b6a6501707b1684c
parent2d6cbd21b2c5819c7fa42eb5a3713667b67e4f03 (diff)
downloadrust-8a261a2b342d85d11c67a8d4dd3408778bd0f5b7.tar.gz
rust-8a261a2b342d85d11c67a8d4dd3408778bd0f5b7.zip
Simplify SyncOnceCell's `take` and `drop`.
-rw-r--r--library/std/src/lazy.rs39
1 files changed, 13 insertions, 26 deletions
diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs
index 091e2091fb0..e0095e64faf 100644
--- a/library/std/src/lazy.rs
+++ b/library/std/src/lazy.rs
@@ -7,7 +7,7 @@ use crate::{
     cell::{Cell, UnsafeCell},
     fmt,
     marker::PhantomData,
-    mem::{self, MaybeUninit},
+    mem::MaybeUninit,
     ops::{Deref, Drop},
     panic::{RefUnwindSafe, UnwindSafe},
     sync::Once,
@@ -316,13 +316,7 @@ impl<T> SyncOnceCell<T> {
     /// ```
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn into_inner(mut self) -> Option<T> {
-        // SAFETY: Safe because we immediately free `self` without dropping
-        let inner = unsafe { self.take_inner() };
-
-        // Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set
-        // the state to uninitialized.
-        mem::forget(self);
-        inner
+        self.take()
     }
 
     /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state.
@@ -348,22 +342,12 @@ impl<T> SyncOnceCell<T> {
     /// ```
     #[unstable(feature = "once_cell", issue = "74465")]
     pub fn take(&mut self) -> Option<T> {
-        mem::take(self).into_inner()
-    }
-
-    /// Takes the wrapped value out of a `SyncOnceCell`.
-    /// Afterwards the cell is no longer initialized.
-    ///
-    /// Safety: The cell must now be free'd WITHOUT dropping. No other usages of the cell
-    /// are valid. Only used by `into_inner` and `drop`.
-    unsafe fn take_inner(&mut self) -> Option<T> {
-        // The mutable reference guarantees there are no other threads that can observe us
-        // taking out the wrapped value.
-        // Right after this function `self` is supposed to be freed, so it makes little sense
-        // to atomically set the state to uninitialized.
         if self.is_initialized() {
-            let value = mem::replace(&mut self.value, UnsafeCell::new(MaybeUninit::uninit()));
-            Some(value.into_inner().assume_init())
+            self.once = Once::new();
+            // SAFETY: `self.value` is initialized and contains a valid `T`.
+            // `self.once` is reset, so `is_initialized()` will be false again
+            // which prevents the value from being read twice.
+            unsafe { Some((&mut *self.value.get()).assume_init_read()) }
         } else {
             None
         }
@@ -416,9 +400,12 @@ impl<T> SyncOnceCell<T> {
 
 unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> {
     fn drop(&mut self) {
-        // SAFETY: The cell is being dropped, so it can't be accessed again.
-        // We also don't touch the `T`, which validates our usage of #[may_dangle].
-        unsafe { self.take_inner() };
+        if self.is_initialized() {
+            // Safety: The cell is initialized and being dropped, so it can't
+            // be accessed again. We also don't touch the `T` other than
+            // dropping it, which validates our usage of #[may_dangle].
+            unsafe { (&mut *self.value.get()).assume_init_drop() };
+        }
     }
 }