diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index b89b03683baef..7a795a73065d6 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -306,6 +306,7 @@ struct RcBox { #[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] +#[repr(transparent)] pub struct Rc { ptr: NonNull>, phantom: PhantomData>, @@ -933,6 +934,41 @@ impl Rc { Weak { ptr: this.ptr } } + /// Convert a reference to an [`Rc`] into a reference to a [`Weak`] of the same type. + /// + /// This is a type-only operation; it doesn't modify the inner reference counts. + /// Therefore if you call [`Weak::weak_count()`] on the returned `&Weak`, + /// it is possible to get a result of `0`, which is otherwise only possible + /// when there are no remaining strong references and the value has been dropped. + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_as_weak)] + /// + /// use std::rc::{Rc, Weak}; + /// + /// let five: &Rc = &Rc::new(5); + /// + /// let weak_five: &Weak = Rc::as_weak(five); + /// ``` + #[inline] + #[unstable(feature = "rc_as_weak", issue = "100472")] + #[must_use] + pub const fn as_weak(this: &Self) -> &Weak { + // SAFETY: `Rc` and `Weak` are guaranteed to have the same representation + // because both are `#[repr(transparent)]` with their only (non-ZST) field being + // being a `NonNull>`. The static guarantees carried by a `Weak` (that + // the pointer will point to a live `RcBox` allocation _unless_ it is the sentinel + // value of `usize::MAX`) are strictly weaker than those carried by an `Rc` (that + // the pointer will always point to a live `RcBox` allocation containing a live `T`). + // The different drop in their drop behaviour is not relevant because this function + // is only concerned with shared references, not owned values. Therefore no safety + // invariants are violated by interpreting an `&Rc` as a `&Weak`. + let weak = this as *const Self as *const Weak; + unsafe { &*weak } + } + /// Gets the number of [`Weak`] pointers to this allocation. /// /// # Examples @@ -2143,6 +2179,7 @@ impl> ToRcSlice for I { /// /// [`upgrade`]: Weak::upgrade #[stable(feature = "rc_weak", since = "1.4.0")] +#[repr(transparent)] pub struct Weak { // This is a `NonNull` to allow optimizing the size of this type in enums, // but it is not necessarily a valid pointer. diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index 32433cfbdcff6..dbec1b3d30f8a 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -103,6 +103,10 @@ fn test_weak_count() { let w = Rc::downgrade(&a); assert!(Rc::strong_count(&a) == 1); assert!(Rc::weak_count(&a) == 1); + let r: &Weak = Rc::as_weak(&a); + assert!(Rc::strong_count(&a) == 1); + assert!(Rc::weak_count(&a) == 1); + assert!(r.as_ptr() == Rc::as_ptr(&a)); drop(w); assert!(Rc::strong_count(&a) == 1); assert!(Rc::weak_count(&a) == 0); diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 4c03cc3ed158a..40e80417e9954 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -232,6 +232,7 @@ macro_rules! acquire { /// [rc_examples]: crate::rc#examples #[cfg_attr(not(test), rustc_diagnostic_item = "Arc")] #[stable(feature = "rust1", since = "1.0.0")] +#[repr(transparent)] pub struct Arc { ptr: NonNull>, phantom: PhantomData>, @@ -282,6 +283,7 @@ impl Arc { /// /// [`upgrade`]: Weak::upgrade #[stable(feature = "arc_weak", since = "1.4.0")] +#[repr(transparent)] pub struct Weak { // This is a `NonNull` to allow optimizing the size of this type in enums, // but it is not necessarily a valid pointer. @@ -959,6 +961,41 @@ impl Arc { } } + /// Convert a reference to an [`Arc`] into a reference to a [`Weak`] of the same type. + /// + /// This is a type-only operation; it doesn't modify the inner reference counts. + /// Therefore if you call [`Weak::weak_count()`] on the returned `&Weak`, + /// it is possible to get a result of `0`, which is otherwise only possible + /// when there are no remaining strong references and the value has been dropped. + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_as_weak)] + /// + /// use std::sync::{Arc, Weak}; + /// + /// let five: &Arc = &Arc::new(5); + /// + /// let weak_five: &Weak = Arc::as_weak(five); + /// ``` + #[inline] + #[unstable(feature = "rc_as_weak", issue = "100472")] + #[must_use] + pub const fn as_weak(this: &Self) -> &Weak { + // SAFETY: `Arc` and `Weak` are guaranteed to have the same representation + // because both are `#[repr(transparent)]` with their only (non-ZST) field being + // being a `NonNull>`. The static guarantees carried by a `Weak` (that + // the pointer will point to a live `ArcInner` allocation _unless_ it is the sentinel + // value of `usize::MAX`) are strictly weaker than those carried by an `Arc` (that + // the pointer will always point to a live `ArcInner` allocation containing a live `T`). + // The different drop in their drop behaviour is not relevant because this function + // is only concerned with shared references, not owned values. Therefore no safety + // invariants are violated by interpreting an `&Arc` as a `&Weak`. + let weak = this as *const Self as *const Weak; + unsafe { &*weak } + } + /// Gets the number of [`Weak`] pointers to this allocation. /// /// # Safety diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index 202d0e7f02057..4eca3bb9f15ee 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -314,6 +314,10 @@ fn test_weak_count() { let w = Arc::downgrade(&a); assert!(Arc::strong_count(&a) == 1); assert!(Arc::weak_count(&a) == 1); + let r: &Weak = Arc::as_weak(&a); + assert!(Arc::strong_count(&a) == 1); + assert!(Arc::weak_count(&a) == 1); + assert!(r.as_ptr() == Arc::as_ptr(&a)); let x = w.clone(); assert!(Arc::weak_count(&a) == 2); drop(w);