@@ -5,7 +5,7 @@ use crate::primitive::sync::atomic::{self, AtomicBool};
55use core:: cell:: UnsafeCell ;
66use core:: cmp;
77use core:: fmt;
8- use core:: mem:: { self , MaybeUninit } ;
8+ use core:: mem:: { self , ManuallyDrop , MaybeUninit } ;
99use core:: sync:: atomic:: Ordering ;
1010
1111use core:: ptr;
@@ -39,6 +39,10 @@ pub struct AtomicCell<T> {
3939 ///
4040 /// Using MaybeUninit to prevent code outside the cell from observing partially initialized state:
4141 /// <https://github.com/crossbeam-rs/crossbeam/issues/833>
42+ ///
43+ /// Note:
44+ /// - we'll never store uninitialized `T` due to our API only using initialized `T`.
45+ /// - this `MaybeUninit` does *not* fix <https://github.com/crossbeam-rs/crossbeam/issues/315>.
4246 value : UnsafeCell < MaybeUninit < T > > ,
4347}
4448
@@ -68,6 +72,9 @@ impl<T> AtomicCell<T> {
6872
6973 /// Consumes the atomic and returns the contained value.
7074 ///
75+ /// This is safe because passing `self` by value guarantees that no other threads are
76+ /// concurrently accessing the atomic data.
77+ ///
7178 /// # Examples
7279 ///
7380 /// ```
@@ -79,8 +86,13 @@ impl<T> AtomicCell<T> {
7986 /// assert_eq!(v, 7);
8087 /// ```
8188 pub fn into_inner ( self ) -> T {
82- // SAFETY: we'll never store uninitialized `T`
83- unsafe { self . value . into_inner ( ) . assume_init ( ) }
89+ let this = ManuallyDrop :: new ( self ) ;
90+ // SAFETY:
91+ // - passing `self` by value guarantees that no other threads are concurrently
92+ // accessing the atomic data
93+ // - the raw pointer passed in is valid because we got it from an owned value.
94+ // - `ManuallyDrop` prevents double dropping `T`
95+ unsafe { this. as_ptr ( ) . read ( ) }
8496 }
8597
8698 /// Returns `true` if operations on values of this type are lock-free.
@@ -294,6 +306,22 @@ impl<T: Copy + Eq> AtomicCell<T> {
294306 }
295307}
296308
309+ // `MaybeUninit` prevents `T` from being dropped, we need to implement `Drop`
310+ // for `AtomicCell` to avoid leaks of non-`Copy` types.
311+ impl < T > Drop for AtomicCell < T > {
312+ fn drop ( & mut self ) {
313+ if mem:: needs_drop :: < T > ( ) {
314+ // SAFETY:
315+ // - the mutable reference guarantees that no other threads are concurrently accessing the atomic data
316+ // - the raw pointer passed in is valid because we got it from a reference
317+ // - `MaybeUninit` prevents double dropping `T`
318+ unsafe {
319+ drop ( self . as_ptr ( ) . read ( ) ) ;
320+ }
321+ }
322+ }
323+ }
324+
297325macro_rules! impl_arithmetic {
298326 ( $t: ty, fallback, $example: tt) => {
299327 impl AtomicCell <$t> {
0 commit comments