@@ -258,8 +258,7 @@ use core::intrinsics::abort;
258
258
use core:: iter;
259
259
use core:: marker:: { PhantomData , Unsize } ;
260
260
#[ cfg( not( no_global_oom_handling) ) ]
261
- use core:: mem:: size_of_val;
262
- use core:: mem:: { self , align_of_val_raw, forget, ManuallyDrop } ;
261
+ use core:: mem:: { self , align_of_val_raw, forget, size_of_val, ManuallyDrop } ;
263
262
use core:: ops:: { CoerceUnsized , Deref , DerefMut , DispatchFromDyn , Receiver } ;
264
263
use core:: panic:: { RefUnwindSafe , UnwindSafe } ;
265
264
#[ cfg( not( no_global_oom_handling) ) ]
@@ -1651,7 +1650,7 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
1651
1650
}
1652
1651
}
1653
1652
1654
- impl < T : Clone , A : Allocator + Clone > Rc < T , A > {
1653
+ impl < T : ? Sized + CloneToUninit , A : Allocator + Clone > Rc < T , A > {
1655
1654
/// Makes a mutable reference into the given `Rc`.
1656
1655
///
1657
1656
/// If there are other `Rc` pointers to the same allocation, then `make_mut` will
@@ -1706,27 +1705,47 @@ impl<T: Clone, A: Allocator + Clone> Rc<T, A> {
1706
1705
#[ inline]
1707
1706
#[ stable( feature = "rc_unique" , since = "1.4.0" ) ]
1708
1707
pub fn make_mut ( this : & mut Self ) -> & mut T {
1708
+ let size_of_val = mem:: size_of_val :: < T > ( & * * this) ;
1709
+
1709
1710
if Rc :: strong_count ( this) != 1 {
1710
1711
// Gotta clone the data, there are other Rcs.
1711
- // Pre-allocate memory to allow writing the cloned value directly.
1712
- let mut rc = Self :: new_uninit_in ( this. alloc . clone ( ) ) ;
1713
- unsafe {
1714
- let data = Rc :: get_mut_unchecked ( & mut rc) ;
1715
- ( * * this) . clone_to_uninit ( data. as_mut_ptr ( ) ) ;
1716
- * this = rc. assume_init ( ) ;
1717
- }
1712
+
1713
+ let this_data_ref: & T = & * * this;
1714
+ // `in_progress` drops the allocation if we panic before finishing initializing it.
1715
+ let mut in_progress: RcUninit < T , A > = RcUninit :: new ( this_data_ref, this. alloc . clone ( ) ) ;
1716
+
1717
+ // Initialize with clone of this.
1718
+ let initialized_clone = unsafe {
1719
+ // Clone. If the clone panics, `in_progress` will be dropped and clean up.
1720
+ this_data_ref. clone_to_uninit ( in_progress. data_ptr ( ) ) ;
1721
+ // Cast type of pointer, now that it is initialized.
1722
+ in_progress. into_rc ( )
1723
+ } ;
1724
+
1725
+ // Replace `this` with newly constructed Rc.
1726
+ * this = initialized_clone;
1718
1727
} else if Rc :: weak_count ( this) != 0 {
1719
1728
// Can just steal the data, all that's left is Weaks
1720
- let mut rc = Self :: new_uninit_in ( this. alloc . clone ( ) ) ;
1729
+
1730
+ // We don't need panic-protection like the above branch does, but we might as well
1731
+ // use the same mechanism.
1732
+ let mut in_progress: RcUninit < T , A > = RcUninit :: new ( & * * this, this. alloc . clone ( ) ) ;
1721
1733
unsafe {
1722
- let data = Rc :: get_mut_unchecked ( & mut rc) ;
1723
- data. as_mut_ptr ( ) . copy_from_nonoverlapping ( & * * this, 1 ) ;
1734
+ // Initialize `in_progress` with move of **this.
1735
+ // We have to express this in terms of bytes because `T: ?Sized`; there is no
1736
+ // operation that just copies a value based on its `size_of_val()`.
1737
+ ptr:: copy_nonoverlapping (
1738
+ ptr:: from_ref ( & * * this) . cast :: < u8 > ( ) ,
1739
+ in_progress. data_ptr ( ) . cast :: < u8 > ( ) ,
1740
+ size_of_val,
1741
+ ) ;
1724
1742
1725
1743
this. inner ( ) . dec_strong ( ) ;
1726
1744
// Remove implicit strong-weak ref (no need to craft a fake
1727
1745
// Weak here -- we know other Weaks can clean up for us)
1728
1746
this. inner ( ) . dec_weak ( ) ;
1729
- ptr:: write ( this, rc. assume_init ( ) ) ;
1747
+ // Replace `this` with newly constructed Rc that has the moved data.
1748
+ ptr:: write ( this, in_progress. into_rc ( ) ) ;
1730
1749
}
1731
1750
}
1732
1751
// This unsafety is ok because we're guaranteed that the pointer
@@ -1736,7 +1755,9 @@ impl<T: Clone, A: Allocator + Clone> Rc<T, A> {
1736
1755
// reference to the allocation.
1737
1756
unsafe { & mut this. ptr . as_mut ( ) . value }
1738
1757
}
1758
+ }
1739
1759
1760
+ impl < T : Clone , A : Allocator + Clone > Rc < T , A > {
1740
1761
/// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the
1741
1762
/// clone.
1742
1763
///
@@ -3360,6 +3381,66 @@ fn data_offset_align(align: usize) -> usize {
3360
3381
layout. size ( ) + layout. padding_needed_for ( align)
3361
3382
}
3362
3383
3384
+ /// A unique owning pointer to a [`RcBox`] **that does not imply the contents are initialized,**
3385
+ /// but will deallocate it (without dropping the value) when dropped.
3386
+ ///
3387
+ /// This is a helper for [`Rc::make_mut()`] to ensure correct cleanup on panic.
3388
+ struct RcUninit < T : ?Sized , A : Allocator > {
3389
+ ptr : NonNull < RcBox < T > > ,
3390
+ layout_for_value : Layout ,
3391
+ alloc : Option < A > ,
3392
+ }
3393
+
3394
+ impl < T : ?Sized , A : Allocator > RcUninit < T , A > {
3395
+ /// Allocate a RcBox with layout suitable to contain `for_value` or a clone of it.
3396
+ #[ cfg( not( no_global_oom_handling) ) ]
3397
+ fn new ( for_value : & T , alloc : A ) -> RcUninit < T , A > {
3398
+ let layout = Layout :: for_value ( for_value) ;
3399
+ let ptr = unsafe {
3400
+ Rc :: allocate_for_layout (
3401
+ layout,
3402
+ |layout_for_rcbox| alloc. allocate ( layout_for_rcbox) ,
3403
+ |mem| mem. with_metadata_of ( ptr:: from_ref ( for_value) as * const RcBox < T > ) ,
3404
+ )
3405
+ } ;
3406
+ Self { ptr : NonNull :: new ( ptr) . unwrap ( ) , layout_for_value : layout, alloc : Some ( alloc) }
3407
+ }
3408
+
3409
+ /// Returns the pointer to be written into to initialize the [`Rc`].
3410
+ fn data_ptr ( & mut self ) -> * mut T {
3411
+ let offset = data_offset_align ( self . layout_for_value . align ( ) ) ;
3412
+ unsafe { self . ptr . as_ptr ( ) . byte_add ( offset) as * mut T }
3413
+ }
3414
+
3415
+ /// Upgrade this into a normal [`Rc`].
3416
+ ///
3417
+ /// # Safety
3418
+ ///
3419
+ /// The data must have been initialized (by writing to [`Self::data_ptr()`]).
3420
+ unsafe fn into_rc ( mut self ) -> Rc < T , A > {
3421
+ let ptr = self . ptr ;
3422
+ let alloc = self . alloc . take ( ) . unwrap ( ) ;
3423
+ mem:: forget ( self ) ;
3424
+ // SAFETY: The pointer is valid as per `RcUninit::new`, and the caller is responsible
3425
+ // for having initialized the data.
3426
+ unsafe { Rc :: from_ptr_in ( ptr. as_ptr ( ) , alloc) }
3427
+ }
3428
+ }
3429
+
3430
+ impl < T : ?Sized , A : Allocator > Drop for RcUninit < T , A > {
3431
+ fn drop ( & mut self ) {
3432
+ // SAFETY:
3433
+ // * new() produced a pointer safe to deallocate.
3434
+ // * We own the pointer unless into_rc() was called, which forgets us.
3435
+ unsafe {
3436
+ self . alloc
3437
+ . take ( )
3438
+ . unwrap ( )
3439
+ . deallocate ( self . ptr . cast ( ) , rcbox_layout_for_value_layout ( self . layout_for_value ) ) ;
3440
+ }
3441
+ }
3442
+ }
3443
+
3363
3444
/// A uniquely owned `Rc`
3364
3445
///
3365
3446
/// This represents an `Rc` that is known to be uniquely owned -- that is, have exactly one strong
0 commit comments