@@ -249,6 +249,8 @@ use std::boxed::Box;
249249use  core:: any:: Any ; 
250250use  core:: borrow; 
251251use  core:: cell:: Cell ; 
252+ #[ cfg( not( no_global_oom_handling) ) ]  
253+ use  core:: clone:: CloneToUninit ; 
252254use  core:: cmp:: Ordering ; 
253255use  core:: fmt; 
254256use  core:: hash:: { Hash ,  Hasher } ; 
@@ -268,8 +270,6 @@ use core::slice::from_raw_parts_mut;
268270
269271#[ cfg( not( no_global_oom_handling) ) ]  
270272use  crate :: alloc:: handle_alloc_error; 
271- #[ cfg( not( no_global_oom_handling) ) ]  
272- use  crate :: alloc:: WriteCloneIntoRaw ; 
273273use  crate :: alloc:: { AllocError ,  Allocator ,  Global ,  Layout } ; 
274274use  crate :: borrow:: { Cow ,  ToOwned } ; 
275275#[ cfg( not( no_global_oom_handling) ) ]  
@@ -1749,7 +1749,8 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
17491749    } 
17501750} 
17511751
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 >  { 
17531754    /// Makes a mutable reference into the given `Rc`. 
17541755/// 
17551756/// 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> {
18001801/// assert!(76 == *data); 
18011802/// assert!(weak.upgrade().is_none()); 
18021803/// ``` 
1803- #[ cfg( not( no_global_oom_handling) ) ]  
18041804#[ inline]  
18051805    #[ stable( feature = "rc_unique" ,  since = "1.4.0" ) ]  
18061806    pub  fn  make_mut ( this :  & mut  Self )  -> & mut  T  { 
1807+         let  size_of_val = size_of_val :: < T > ( & * * this) ; 
1808+ 
18071809        if  Rc :: strong_count ( this)  != 1  { 
18081810            // 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; 
18161827        }  else  if  Rc :: weak_count ( this)  != 0  { 
18171828            // 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 ( ) ) ; 
18191834            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+                 ) ; 
18221843
18231844                this. inner ( ) . dec_strong ( ) ; 
18241845                // Remove implicit strong-weak ref (no need to craft a fake 
18251846                // Weak here -- we know other Weaks can clean up for us) 
18261847                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 ( ) ) ; 
18281850            } 
18291851        } 
18301852        // 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> {
36863708        } 
36873709    } 
36883710} 
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