@@ -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 :: < T > ( & * * 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 :: < u8 > ( ) ,
1840
+ in_progress. data_ptr ( ) . cast :: < u8 > ( ) ,
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 < T > > ,
3721
+ layout_for_value : Layout ,
3722
+ alloc : Option < A > ,
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 < T > ) ,
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
+ }
0 commit comments