Auto merge of #116113 - kpreid:arcmut, r=dtolnay · model-checking/verify-rust-std@e1edea8 (original) (raw)
`@@ -249,6 +249,8 @@ use std::boxed::Box;
`
249
249
`use core::any::Any;
`
250
250
`use core::borrow;
`
251
251
`use core::cell::Cell;
`
``
252
`+
#[cfg(not(no_global_oom_handling))]
`
``
253
`+
use core::clone::CloneToUninit;
`
252
254
`use core::cmp::Ordering;
`
253
255
`use core::fmt;
`
254
256
`use core::hash::{Hash, Hasher};
`
`@@ -268,8 +270,6 @@ use core::slice::from_raw_parts_mut;
`
268
270
``
269
271
`#[cfg(not(no_global_oom_handling))]
`
270
272
`use crate::alloc::handle_alloc_error;
`
271
``
`-
#[cfg(not(no_global_oom_handling))]
`
272
``
`-
use crate::alloc::WriteCloneIntoRaw;
`
273
273
`use crate::alloc::{AllocError, Allocator, Global, Layout};
`
274
274
`use crate::borrow::{Cow, ToOwned};
`
275
275
`#[cfg(not(no_global_oom_handling))]
`
`@@ -1749,7 +1749,8 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
`
1749
1749
`}
`
1750
1750
`}
`
1751
1751
``
1752
``
`-
impl<T: Clone, A: Allocator + Clone> Rc<T, A> {
`
``
1752
`+
#[cfg(not(no_global_oom_handling))]
`
``
1753
`+
impl<T: ?Sized + CloneToUninit, A: Allocator + Clone> Rc<T, A> {
`
1753
1754
`` /// Makes a mutable reference into the given Rc
.
``
1754
1755
`///
`
1755
1756
`` /// If there are other Rc
pointers to the same allocation, then make_mut
will
``
`@@ -1800,31 +1801,52 @@ impl<T: Clone, A: Allocator + Clone> Rc<T, A> {
`
1800
1801
`/// assert!(76 == *data);
`
1801
1802
`/// assert!(weak.upgrade().is_none());
`
1802
1803
```` /// ```
````
1803
``
`-
#[cfg(not(no_global_oom_handling))]
`
1804
1804
`#[inline]
`
1805
1805
`#[stable(feature = "rc_unique", since = "1.4.0")]
`
1806
1806
`pub fn make_mut(this: &mut Self) -> &mut T {
`
``
1807
`+
let size_of_val = size_of_val::(&**this);
`
``
1808
+
1807
1809
`if Rc::strong_count(this) != 1 {
`
1808
1810
`// Gotta clone the data, there are other Rcs.
`
1809
``
`-
// Pre-allocate memory to allow writing the cloned value directly.
`
1810
``
`-
let mut rc = Self::new_uninit_in(this.alloc.clone());
`
1811
``
`-
unsafe {
`
1812
``
`-
let data = Rc::get_mut_unchecked(&mut rc);
`
1813
``
`-
(**this).write_clone_into_raw(data.as_mut_ptr());
`
1814
``
`-
*this = rc.assume_init();
`
1815
``
`-
}
`
``
1811
+
``
1812
`+
let this_data_ref: &T = &**this;
`
``
1813
`` +
// in_progress
drops the allocation if we panic before finishing initializing it.
``
``
1814
`+
let mut in_progress: UniqueRcUninit<T, A> =
`
``
1815
`+
UniqueRcUninit::new(this_data_ref, this.alloc.clone());
`
``
1816
+
``
1817
`+
// Initialize with clone of this.
`
``
1818
`+
let initialized_clone = unsafe {
`
``
1819
`` +
// Clone. If the clone panics, in_progress
will be dropped and clean up.
``
``
1820
`+
this_data_ref.clone_to_uninit(in_progress.data_ptr());
`
``
1821
`+
// Cast type of pointer, now that it is initialized.
`
``
1822
`+
in_progress.into_rc()
`
``
1823
`+
};
`
``
1824
+
``
1825
`` +
// Replace this
with newly constructed Rc.
``
``
1826
`+
*this = initialized_clone;
`
1816
1827
`} else if Rc::weak_count(this) != 0 {
`
1817
1828
`// Can just steal the data, all that's left is Weaks
`
1818
``
`-
let mut rc = Self::new_uninit_in(this.alloc.clone());
`
``
1829
+
``
1830
`+
// We don't need panic-protection like the above branch does, but we might as well
`
``
1831
`+
// use the same mechanism.
`
``
1832
`+
let mut in_progress: UniqueRcUninit<T, A> =
`
``
1833
`+
UniqueRcUninit::new(&**this, this.alloc.clone());
`
1819
1834
`unsafe {
`
1820
``
`-
let data = Rc::get_mut_unchecked(&mut rc);
`
1821
``
`-
data.as_mut_ptr().copy_from_nonoverlapping(&**this, 1);
`
``
1835
`` +
// Initialize in_progress
with move of **this.
``
``
1836
`` +
// We have to express this in terms of bytes because T: ?Sized
; there is no
``
``
1837
`` +
// operation that just copies a value based on its size_of_val()
.
``
``
1838
`+
ptr::copy_nonoverlapping(
`
``
1839
`+
ptr::from_ref(&**this).cast::(),
`
``
1840
`+
in_progress.data_ptr().cast::(),
`
``
1841
`+
size_of_val,
`
``
1842
`+
);
`
1822
1843
``
1823
1844
` this.inner().dec_strong();
`
1824
1845
`// Remove implicit strong-weak ref (no need to craft a fake
`
1825
1846
`// Weak here -- we know other Weaks can clean up for us)
`
1826
1847
` this.inner().dec_weak();
`
1827
``
`-
ptr::write(this, rc.assume_init());
`
``
1848
`` +
// Replace this
with newly constructed Rc that has the moved data.
``
``
1849
`+
ptr::write(this, in_progress.into_rc());
`
1828
1850
`}
`
1829
1851
`}
`
1830
1852
`// This unsafety is ok because we're guaranteed that the pointer
`
`@@ -3686,3 +3708,67 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for UniqueRc<T, A> {
`
3686
3708
`}
`
3687
3709
`}
`
3688
3710
`}
`
``
3711
+
``
3712
`` +
/// A unique owning pointer to a [RcBox
] that does not imply the contents are initialized,
``
``
3713
`+
/// but will deallocate it (without dropping the value) when dropped.
`
``
3714
`+
///
`
``
3715
`` +
/// This is a helper for [Rc::make_mut()
] to ensure correct cleanup on panic.
``
``
3716
`` +
/// It is nearly a duplicate of UniqueRc<MaybeUninit<T>, A>
except that it allows T: !Sized
,
``
``
3717
`` +
/// which MaybeUninit
does not.
``
``
3718
`+
#[cfg(not(no_global_oom_handling))]
`
``
3719
`+
struct UniqueRcUninit<T: ?Sized, A: Allocator> {
`
``
3720
`+
ptr: NonNull<RcBox>,
`
``
3721
`+
layout_for_value: Layout,
`
``
3722
`+
alloc: Option,
`
``
3723
`+
}
`
``
3724
+
``
3725
`+
#[cfg(not(no_global_oom_handling))]
`
``
3726
`+
impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> {
`
``
3727
`` +
/// Allocate a RcBox with layout suitable to contain for_value
or a clone of it.
``
``
3728
`+
fn new(for_value: &T, alloc: A) -> UniqueRcUninit<T, A> {
`
``
3729
`+
let layout = Layout::for_value(for_value);
`
``
3730
`+
let ptr = unsafe {
`
``
3731
`+
Rc::allocate_for_layout(
`
``
3732
`+
layout,
`
``
3733
`+
|layout_for_rcbox| alloc.allocate(layout_for_rcbox),
`
``
3734
`+
|mem| mem.with_metadata_of(ptr::from_ref(for_value) as *const RcBox),
`
``
3735
`+
)
`
``
3736
`+
};
`
``
3737
`+
Self { ptr: NonNull::new(ptr).unwrap(), layout_for_value: layout, alloc: Some(alloc) }
`
``
3738
`+
}
`
``
3739
+
``
3740
`` +
/// Returns the pointer to be written into to initialize the [Rc
].
``
``
3741
`+
fn data_ptr(&mut self) -> *mut T {
`
``
3742
`+
let offset = data_offset_align(self.layout_for_value.align());
`
``
3743
`+
unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T }
`
``
3744
`+
}
`
``
3745
+
``
3746
`` +
/// Upgrade this into a normal [Rc
].
``
``
3747
`+
///
`
``
3748
`+
/// # Safety
`
``
3749
`+
///
`
``
3750
`` +
/// The data must have been initialized (by writing to [Self::data_ptr()
]).
``
``
3751
`+
unsafe fn into_rc(mut self) -> Rc<T, A> {
`
``
3752
`+
let ptr = self.ptr;
`
``
3753
`+
let alloc = self.alloc.take().unwrap();
`
``
3754
`+
mem::forget(self);
`
``
3755
`` +
// SAFETY: The pointer is valid as per UniqueRcUninit::new
, and the caller is responsible
``
``
3756
`+
// for having initialized the data.
`
``
3757
`+
unsafe { Rc::from_ptr_in(ptr.as_ptr(), alloc) }
`
``
3758
`+
}
`
``
3759
`+
}
`
``
3760
+
``
3761
`+
#[cfg(not(no_global_oom_handling))]
`
``
3762
`+
impl<T: ?Sized, A: Allocator> Drop for UniqueRcUninit<T, A> {
`
``
3763
`+
fn drop(&mut self) {
`
``
3764
`+
// SAFETY:
`
``
3765
`+
// * new() produced a pointer safe to deallocate.
`
``
3766
`+
// * We own the pointer unless into_rc() was called, which forgets us.
`
``
3767
`+
unsafe {
`
``
3768
`+
self.alloc
`
``
3769
`+
.take()
`
``
3770
`+
.unwrap()
`
``
3771
`+
.deallocate(self.ptr.cast(), rcbox_layout_for_value_layout(self.layout_for_value));
`
``
3772
`+
}
`
``
3773
`+
}
`
``
3774
`+
}
`