From 5adc0312b8fce7a5f68139cdccda87f7d758faa2 Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Mon, 23 Feb 2026 21:54:17 -0800 Subject: [PATCH 1/9] core::sync: Rename Exclusive to SyncView --- library/core/src/sync/mod.rs | 4 +- .../src/sync/{exclusive.rs => sync_view.rs} | 105 +++++++++--------- library/std/src/sync/mod.rs | 2 +- 3 files changed, 56 insertions(+), 55 deletions(-) rename library/core/src/sync/{exclusive.rs => sync_view.rs} (71%) diff --git a/library/core/src/sync/mod.rs b/library/core/src/sync/mod.rs index 4365e4cb250ca..6c2660263a705 100644 --- a/library/core/src/sync/mod.rs +++ b/library/core/src/sync/mod.rs @@ -3,6 +3,6 @@ #![stable(feature = "rust1", since = "1.0.0")] pub mod atomic; -mod exclusive; +mod sync_view; #[unstable(feature = "exclusive_wrapper", issue = "98407")] -pub use exclusive::Exclusive; +pub use sync_view::SyncView; diff --git a/library/core/src/sync/exclusive.rs b/library/core/src/sync/sync_view.rs similarity index 71% rename from library/core/src/sync/exclusive.rs rename to library/core/src/sync/sync_view.rs index 35b8120995187..35abe17a94738 100644 --- a/library/core/src/sync/exclusive.rs +++ b/library/core/src/sync/sync_view.rs @@ -1,4 +1,4 @@ -//! Defines [`Exclusive`]. +//! Defines [`SyncView`]. use core::clone::TrivialClone; use core::cmp::Ordering; @@ -10,18 +10,18 @@ use core::ops::{Coroutine, CoroutineState}; use core::pin::Pin; use core::task::{Context, Poll}; -/// `Exclusive` provides _mutable_ access, also referred to as _exclusive_ +/// `SyncView` provides _mutable_ access, also referred to as _exclusive_ /// access to the underlying value. However, it only permits _immutable_, or _shared_ /// access to the underlying value when that value is [`Sync`]. /// -/// While this may seem not very useful, it allows `Exclusive` to _unconditionally_ -/// implement `Sync`. Indeed, the safety requirements of `Sync` state that for `Exclusive` +/// While this may seem not very useful, it allows `SyncView` to _unconditionally_ +/// implement `Sync`. Indeed, the safety requirements of `Sync` state that for `SyncView` /// to be `Sync`, it must be sound to _share_ across threads, that is, it must be sound -/// for `&Exclusive` to cross thread boundaries. By design, a `&Exclusive` for non-`Sync` T +/// for `&SyncView` to cross thread boundaries. By design, a `&SyncView` for non-`Sync` T /// has no API whatsoever, making it useless, thus harmless, thus memory safe. /// /// Certain constructs like [`Future`]s can only be used with _exclusive_ access, -/// and are often `Send` but not `Sync`, so `Exclusive` can be used as hint to the +/// and are often `Send` but not `Sync`, so `SyncView` can be used as hint to the /// Rust compiler that something is `Sync` in practice. /// /// ## Examples @@ -47,22 +47,22 @@ use core::task::{Context, Poll}; /// }); /// ``` /// -/// `Exclusive` ensures the struct is `Sync` without stripping the future of its +/// `SyncView` ensures the struct is `Sync` without stripping the future of its /// functionality: /// /// ``` /// #![feature(exclusive_wrapper)] /// use core::cell::Cell; -/// use core::sync::Exclusive; +/// use core::sync::SyncView; /// /// async fn other() {} /// fn assert_sync(t: T) {} /// struct State { -/// future: Exclusive +/// future: SyncView /// } /// /// assert_sync(State { -/// future: Exclusive::new(async { +/// future: SyncView::new(async { /// let cell = Cell::new(1); /// let cell_ref = &cell; /// other().await; @@ -73,7 +73,7 @@ use core::task::{Context, Poll}; /// /// ## Parallels with a mutex /// -/// In some sense, `Exclusive` can be thought of as a _compile-time_ version of +/// In some sense, `SyncView` can be thought of as a _compile-time_ version of /// a mutex, as the borrow-checker guarantees that only one `&mut` can exist /// for any value. This is a parallel with the fact that /// `&` and `&mut` references together can be thought of as a _compile-time_ @@ -82,28 +82,29 @@ use core::task::{Context, Poll}; #[doc(alias = "SyncWrapper")] #[doc(alias = "SyncCell")] #[doc(alias = "Unique")] -// `Exclusive` can't have derived `PartialOrd`, `Clone`, etc. impls as they would +#[doc(alias = "Exclusive")] +// `SyncView` can't have derived `PartialOrd`, `Clone`, etc. impls as they would // use `&` access to the inner value, violating the `Sync` impl's safety // requirements. #[derive(Default)] #[repr(transparent)] -pub struct Exclusive { +pub struct SyncView { inner: T, } -// See `Exclusive`'s docs for justification. +// See `SyncView`'s docs for justification. #[unstable(feature = "exclusive_wrapper", issue = "98407")] -unsafe impl Sync for Exclusive {} +unsafe impl Sync for SyncView {} #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl fmt::Debug for Exclusive { +impl fmt::Debug for SyncView { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.debug_struct("Exclusive").finish_non_exhaustive() + f.debug_struct("SyncView").finish_non_exhaustive() } } -impl Exclusive { - /// Wrap a value in an `Exclusive` +impl SyncView { + /// Wrap a value in an `SyncView` #[unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] @@ -111,7 +112,7 @@ impl Exclusive { Self { inner: t } } - /// Unwrap the value contained in the `Exclusive` + /// Unwrap the value contained in the `SyncView` #[unstable(feature = "exclusive_wrapper", issue = "98407")] #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] @@ -121,7 +122,7 @@ impl Exclusive { } } -impl Exclusive { +impl SyncView { /// Gets exclusive access to the underlying value. #[unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] @@ -132,38 +133,38 @@ impl Exclusive { /// Gets pinned exclusive access to the underlying value. /// - /// `Exclusive` is considered to _structurally pin_ the underlying - /// value, which means _unpinned_ `Exclusive`s can produce _unpinned_ - /// access to the underlying value, but _pinned_ `Exclusive`s only + /// `SyncView` is considered to _structurally pin_ the underlying + /// value, which means _unpinned_ `SyncView`s can produce _unpinned_ + /// access to the underlying value, but _pinned_ `SyncView`s only /// produce _pinned_ access to the underlying value. #[unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { - // SAFETY: `Exclusive` can only produce `&mut T` if itself is unpinned + // SAFETY: `SyncView` can only produce `&mut T` if itself is unpinned // `Pin::map_unchecked_mut` is not const, so we do this conversion manually unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } } - /// Build a _mutable_ reference to an `Exclusive` from + /// Build a _mutable_ reference to an `SyncView` from /// a _mutable_ reference to a `T`. This allows you to skip - /// building an `Exclusive` with [`Exclusive::new`]. + /// building an `SyncView` with [`SyncView::new`]. #[unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] - pub const fn from_mut(r: &'_ mut T) -> &'_ mut Exclusive { - // SAFETY: repr is ≥ C, so refs have the same layout; and `Exclusive` properties are `&mut`-agnostic - unsafe { &mut *(r as *mut T as *mut Exclusive) } + pub const fn from_mut(r: &'_ mut T) -> &'_ mut SyncView { + // SAFETY: repr is ≥ C, so refs have the same layout; and `SyncView` properties are `&mut`-agnostic + unsafe { &mut *(r as *mut T as *mut SyncView) } } - /// Build a _pinned mutable_ reference to an `Exclusive` from + /// Build a _pinned mutable_ reference to an `SyncView` from /// a _pinned mutable_ reference to a `T`. This allows you to skip - /// building an `Exclusive` with [`Exclusive::new`]. + /// building an `SyncView` with [`SyncView::new`]. #[unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] - pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive> { - // SAFETY: `Exclusive` can only produce `&mut T` if itself is unpinned + pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut SyncView> { + // SAFETY: `SyncView` can only produce `&mut T` if itself is unpinned // `Pin::map_unchecked_mut` is not const, so we do this conversion manually unsafe { Pin::new_unchecked(Self::from_mut(r.get_unchecked_mut())) } } @@ -171,7 +172,7 @@ impl Exclusive { #[unstable(feature = "exclusive_wrapper", issue = "98407")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] -impl const From for Exclusive { +impl const From for SyncView { #[inline] fn from(t: T) -> Self { Self::new(t) @@ -179,7 +180,7 @@ impl const From for Exclusive { } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl FnOnce for Exclusive +impl FnOnce for SyncView where F: FnOnce, Args: Tuple, @@ -192,7 +193,7 @@ where } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl FnMut for Exclusive +impl FnMut for SyncView where F: FnMut, Args: Tuple, @@ -203,7 +204,7 @@ where } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl Fn for Exclusive +impl Fn for SyncView where F: Sync + Fn, Args: Tuple, @@ -214,7 +215,7 @@ where } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl Future for Exclusive +impl Future for SyncView where T: Future + ?Sized, { @@ -227,7 +228,7 @@ where } #[unstable(feature = "coroutine_trait", issue = "43122")] // also #98407 -impl Coroutine for Exclusive +impl Coroutine for SyncView where G: Coroutine + ?Sized, { @@ -241,7 +242,7 @@ where } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl AsRef for Exclusive +impl AsRef for SyncView where T: Sync + ?Sized, { @@ -252,7 +253,7 @@ where } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl Clone for Exclusive +impl Clone for SyncView where T: Sync + Clone, { @@ -264,31 +265,31 @@ where #[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] -unsafe impl TrivialClone for Exclusive where T: Sync + TrivialClone {} +unsafe impl TrivialClone for SyncView where T: Sync + TrivialClone {} #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl Copy for Exclusive where T: Sync + Copy {} +impl Copy for SyncView where T: Sync + Copy {} #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl PartialEq> for Exclusive +impl PartialEq> for SyncView where T: Sync + PartialEq + ?Sized, U: Sync + ?Sized, { #[inline] - fn eq(&self, other: &Exclusive) -> bool { + fn eq(&self, other: &SyncView) -> bool { self.inner == other.inner } } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl StructuralPartialEq for Exclusive where T: Sync + StructuralPartialEq + ?Sized {} +impl StructuralPartialEq for SyncView where T: Sync + StructuralPartialEq + ?Sized {} #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl Eq for Exclusive where T: Sync + Eq + ?Sized {} +impl Eq for SyncView where T: Sync + Eq + ?Sized {} #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl Hash for Exclusive +impl Hash for SyncView where T: Sync + Hash + ?Sized, { @@ -299,19 +300,19 @@ where } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl PartialOrd> for Exclusive +impl PartialOrd> for SyncView where T: Sync + PartialOrd + ?Sized, U: Sync + ?Sized, { #[inline] - fn partial_cmp(&self, other: &Exclusive) -> Option { + fn partial_cmp(&self, other: &SyncView) -> Option { self.inner.partial_cmp(&other.inner) } } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl Ord for Exclusive +impl Ord for SyncView where T: Sync + Ord + ?Sized, { diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 5da50480c7232..439b5b09a5ac0 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -172,7 +172,7 @@ // These come from `core` & `alloc` and only in one flavor: no poisoning. #[unstable(feature = "exclusive_wrapper", issue = "98407")] -pub use core::sync::Exclusive; +pub use core::sync::SyncView; #[stable(feature = "rust1", since = "1.0.0")] pub use core::sync::atomic; From 4a3dbe364247ab06d0041faaec84fca7bfd902b3 Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Mon, 23 Feb 2026 22:10:38 -0800 Subject: [PATCH 2/9] core::sync::SyncView: make use of AsMut This moves the inherent `get_mut` method to be `AsMut::as_mut`, and renames `get_pin_mut` to `as_pin_mut` accordingly. It also constifies the `AsRef` (and `AsMut`) implementations, preserving the `const` status of the original `get_mut`, albeit only unstably. --- library/core/src/sync/sync_view.rs | 33 ++++++++++++++++++------------ 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/library/core/src/sync/sync_view.rs b/library/core/src/sync/sync_view.rs index 35abe17a94738..407da1e92ea84 100644 --- a/library/core/src/sync/sync_view.rs +++ b/library/core/src/sync/sync_view.rs @@ -123,14 +123,6 @@ impl SyncView { } impl SyncView { - /// Gets exclusive access to the underlying value. - #[unstable(feature = "exclusive_wrapper", issue = "98407")] - #[must_use] - #[inline] - pub const fn get_mut(&mut self) -> &mut T { - &mut self.inner - } - /// Gets pinned exclusive access to the underlying value. /// /// `SyncView` is considered to _structurally pin_ the underlying @@ -140,7 +132,7 @@ impl SyncView { #[unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] - pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { + pub const fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { // SAFETY: `SyncView` can only produce `&mut T` if itself is unpinned // `Pin::map_unchecked_mut` is not const, so we do this conversion manually unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } @@ -199,7 +191,7 @@ where Args: Tuple, { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output { - self.get_mut().call_mut(args) + self.as_mut().call_mut(args) } } @@ -223,7 +215,7 @@ where #[inline] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - self.get_pin_mut().poll(cx) + self.as_pin_mut().poll(cx) } } @@ -237,21 +229,36 @@ where #[inline] fn resume(self: Pin<&mut Self>, arg: R) -> CoroutineState { - G::resume(self.get_pin_mut(), arg) + G::resume(self.as_pin_mut(), arg) } } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl AsRef for SyncView +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef for SyncView where T: Sync + ?Sized, { + /// Gets shared access to the underlying value. #[inline] fn as_ref(&self) -> &T { &self.inner } } +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsMut for SyncView +where + T: ?Sized, +{ + /// Gets exclusive access to the underlying value. + #[inline] + fn as_mut(&mut self) -> &mut T { + &mut self.inner + } +} + #[unstable(feature = "exclusive_wrapper", issue = "98407")] impl Clone for SyncView where From b36062071eff06c12fd3cc120fdf7a0cf568e25b Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Mon, 23 Feb 2026 22:30:41 -0800 Subject: [PATCH 3/9] core::sync::SyncView: constify all the impls --- library/core/src/sync/sync_view.rs | 58 +++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/library/core/src/sync/sync_view.rs b/library/core/src/sync/sync_view.rs index 407da1e92ea84..df459469f48dc 100644 --- a/library/core/src/sync/sync_view.rs +++ b/library/core/src/sync/sync_view.rs @@ -86,7 +86,6 @@ use core::task::{Context, Poll}; // `SyncView` can't have derived `PartialOrd`, `Clone`, etc. impls as they would // use `&` access to the inner value, violating the `Sync` impl's safety // requirements. -#[derive(Default)] #[repr(transparent)] pub struct SyncView { inner: T, @@ -96,6 +95,18 @@ pub struct SyncView { #[unstable(feature = "exclusive_wrapper", issue = "98407")] unsafe impl Sync for SyncView {} +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for SyncView +where + T: [const] Default, +{ + #[inline] + fn default() -> Self { + Self { inner: Default::default() } + } +} + #[unstable(feature = "exclusive_wrapper", issue = "98407")] impl fmt::Debug for SyncView { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { @@ -106,6 +117,7 @@ impl fmt::Debug for SyncView { impl SyncView { /// Wrap a value in an `SyncView` #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] pub const fn new(t: T) -> Self { @@ -130,6 +142,7 @@ impl SyncView { /// access to the underlying value, but _pinned_ `SyncView`s only /// produce _pinned_ access to the underlying value. #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] pub const fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { @@ -142,6 +155,7 @@ impl SyncView { /// a _mutable_ reference to a `T`. This allows you to skip /// building an `SyncView` with [`SyncView::new`]. #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] pub const fn from_mut(r: &'_ mut T) -> &'_ mut SyncView { @@ -153,6 +167,7 @@ impl SyncView { /// a _pinned mutable_ reference to a `T`. This allows you to skip /// building an `SyncView` with [`SyncView::new`]. #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] #[must_use] #[inline] pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut SyncView> { @@ -172,9 +187,10 @@ impl const From for SyncView { } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl FnOnce for SyncView +#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] +impl const FnOnce for SyncView where - F: FnOnce, + F: [const] FnOnce, Args: Tuple, { type Output = F::Output; @@ -185,9 +201,10 @@ where } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl FnMut for SyncView +#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] +impl const FnMut for SyncView where - F: FnMut, + F: [const] FnMut, Args: Tuple, { extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output { @@ -196,9 +213,10 @@ where } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl Fn for SyncView +#[rustc_const_unstable(feature = "const_trait_impl", issue = "143874")] +impl const Fn for SyncView where - F: Sync + Fn, + F: Sync + [const] Fn, Args: Tuple, { extern "rust-call" fn call(&self, args: Args) -> Self::Output { @@ -260,9 +278,10 @@ where } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl Clone for SyncView +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +impl const Clone for SyncView where - T: Sync + Clone, + T: Sync + [const] Clone, { #[inline] fn clone(&self) -> Self { @@ -272,15 +291,17 @@ where #[doc(hidden)] #[unstable(feature = "trivial_clone", issue = "none")] -unsafe impl TrivialClone for SyncView where T: Sync + TrivialClone {} +#[rustc_const_unstable(feature = "const_clone", issue = "142757")] +unsafe impl const TrivialClone for SyncView where T: Sync + [const] TrivialClone {} #[unstable(feature = "exclusive_wrapper", issue = "98407")] impl Copy for SyncView where T: Sync + Copy {} #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl PartialEq> for SyncView +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialEq> for SyncView where - T: Sync + PartialEq + ?Sized, + T: Sync + [const] PartialEq + ?Sized, U: Sync + ?Sized, { #[inline] @@ -293,7 +314,8 @@ where impl StructuralPartialEq for SyncView where T: Sync + StructuralPartialEq + ?Sized {} #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl Eq for SyncView where T: Sync + Eq + ?Sized {} +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const Eq for SyncView where T: Sync + [const] Eq + ?Sized {} #[unstable(feature = "exclusive_wrapper", issue = "98407")] impl Hash for SyncView @@ -307,9 +329,10 @@ where } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl PartialOrd> for SyncView +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const PartialOrd> for SyncView where - T: Sync + PartialOrd + ?Sized, + T: Sync + [const] PartialOrd + ?Sized, U: Sync + ?Sized, { #[inline] @@ -319,9 +342,10 @@ where } #[unstable(feature = "exclusive_wrapper", issue = "98407")] -impl Ord for SyncView +#[rustc_const_unstable(feature = "const_cmp", issue = "143800")] +impl const Ord for SyncView where - T: Sync + Ord + ?Sized, + T: Sync + [const] Ord + ?Sized, { #[inline] fn cmp(&self, other: &Self) -> Ordering { From 4b35912a03d230e4adaa9c04ac4889766d61563e Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Mon, 23 Feb 2026 22:41:34 -0800 Subject: [PATCH 4/9] Add core::sync::SyncView::as_pin This completes the existing suite of `as_ref`, `as_mut`, and `as_pin_mut` methods. --- library/core/src/sync/sync_view.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/library/core/src/sync/sync_view.rs b/library/core/src/sync/sync_view.rs index df459469f48dc..c99bda1aa36c5 100644 --- a/library/core/src/sync/sync_view.rs +++ b/library/core/src/sync/sync_view.rs @@ -177,6 +177,24 @@ impl SyncView { } } +impl SyncView { + /// Gets pinned shared access to the underlying value. + /// + /// `SyncView` is considered to _structurally pin_ the underlying + /// value, which means _unpinned_ `SyncView`s can produce _unpinned_ + /// access to the underlying value, but _pinned_ `SyncView`s only + /// produce _pinned_ access to the underlying value. + #[unstable(feature = "exclusive_wrapper", issue = "98407")] + #[rustc_const_unstable(feature = "exclusive_wrapper", issue = "98407")] + #[must_use] + #[inline] + pub const fn as_pin(self: Pin<&Self>) -> Pin<&T> { + // SAFETY: `SyncView` can only produce `&T` if itself is unpinned + // `Pin::map_unchecked` is not const, so we do this conversion manually + unsafe { Pin::new_unchecked(&self.get_ref().inner) } + } +} + #[unstable(feature = "exclusive_wrapper", issue = "98407")] #[rustc_const_unstable(feature = "const_convert", issue = "143773")] impl const From for SyncView { From f5830a71c8422cc3bff5324e3c208955e02eaf5a Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Mon, 23 Feb 2026 23:51:55 -0800 Subject: [PATCH 5/9] core::sync::SyncView: minor doc nits --- library/core/src/sync/sync_view.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/sync/sync_view.rs b/library/core/src/sync/sync_view.rs index c99bda1aa36c5..af1b2bbff22d8 100644 --- a/library/core/src/sync/sync_view.rs +++ b/library/core/src/sync/sync_view.rs @@ -17,11 +17,11 @@ use core::task::{Context, Poll}; /// While this may seem not very useful, it allows `SyncView` to _unconditionally_ /// implement `Sync`. Indeed, the safety requirements of `Sync` state that for `SyncView` /// to be `Sync`, it must be sound to _share_ across threads, that is, it must be sound -/// for `&SyncView` to cross thread boundaries. By design, a `&SyncView` for non-`Sync` T -/// has no API whatsoever, making it useless, thus harmless, thus memory safe. +/// for `&SyncView` to cross thread boundaries. By design, a `&SyncView` for non-`Sync` +/// `T` has no API whatsoever, making it useless, thus harmless, thus memory safe. /// /// Certain constructs like [`Future`]s can only be used with _exclusive_ access, -/// and are often `Send` but not `Sync`, so `SyncView` can be used as hint to the +/// and are often [`Send`] but not `Sync`, so `SyncView` can be used as hint to the /// Rust compiler that something is `Sync` in practice. /// /// ## Examples From 99d09862b1c8f4b4142747950091e47a2cf5cd79 Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Mon, 23 Feb 2026 23:57:08 -0800 Subject: [PATCH 6/9] impl AsyncFn{,Mut,Once} for core::sync::SyncView --- library/core/src/sync/sync_view.rs | 42 ++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/library/core/src/sync/sync_view.rs b/library/core/src/sync/sync_view.rs index af1b2bbff22d8..46ad41135bfff 100644 --- a/library/core/src/sync/sync_view.rs +++ b/library/core/src/sync/sync_view.rs @@ -242,6 +242,48 @@ where } } +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl AsyncFnOnce for SyncView +where + F: AsyncFnOnce, + Args: Tuple, +{ + type CallOnceFuture = F::CallOnceFuture; + + type Output = F::Output; + + extern "rust-call" fn async_call_once(self, args: Args) -> Self::CallOnceFuture { + self.into_inner().async_call_once(args) + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl AsyncFnMut for SyncView +where + F: AsyncFnMut, + Args: Tuple, +{ + type CallRefFuture<'a> + = F::CallRefFuture<'a> + where + F: 'a; + + extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallRefFuture<'_> { + self.as_mut().async_call_mut(args) + } +} + +#[unstable(feature = "exclusive_wrapper", issue = "98407")] +impl AsyncFn for SyncView +where + F: Sync + AsyncFn, + Args: Tuple, +{ + extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_> { + self.as_ref().async_call(args) + } +} + #[unstable(feature = "exclusive_wrapper", issue = "98407")] impl Future for SyncView where From 57d49652bf08828d01f897764c191b56dd257674 Mon Sep 17 00:00:00 2001 From: Laine Taffin Altman Date: Tue, 24 Feb 2026 01:08:32 -0800 Subject: [PATCH 7/9] Update UI tests for SyncView rename --- tests/ui/explicit-tail-calls/callee_is_weird.rs | 4 ++-- tests/ui/explicit-tail-calls/callee_is_weird.stderr | 12 ++++++------ tests/ui/impl-trait/where-allowed.stderr | 2 +- .../traits/next-solver/well-formed-in-relate.stderr | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/ui/explicit-tail-calls/callee_is_weird.rs b/tests/ui/explicit-tail-calls/callee_is_weird.rs index b3ca878c232c2..9e2b1fb8d4b55 100644 --- a/tests/ui/explicit-tail-calls/callee_is_weird.rs +++ b/tests/ui/explicit-tail-calls/callee_is_weird.rs @@ -4,11 +4,11 @@ fn f() {} fn g() { - become std::sync::Exclusive::new(f)() //~ error: tail calls can only be performed with function definitions or pointers + become std::sync::SyncView::new(f)() //~ error: tail calls can only be performed with function definitions or pointers } fn h() { - become (&mut &std::sync::Exclusive::new(f))() //~ error: tail calls can only be performed with function definitions or pointers + become (&mut &std::sync::SyncView::new(f))() //~ error: tail calls can only be performed with function definitions or pointers } fn i() { diff --git a/tests/ui/explicit-tail-calls/callee_is_weird.stderr b/tests/ui/explicit-tail-calls/callee_is_weird.stderr index 9a5da28b559e3..f31c2f08c6c62 100644 --- a/tests/ui/explicit-tail-calls/callee_is_weird.stderr +++ b/tests/ui/explicit-tail-calls/callee_is_weird.stderr @@ -1,18 +1,18 @@ error: tail calls can only be performed with function definitions or pointers --> $DIR/callee_is_weird.rs:7:12 | -LL | become std::sync::Exclusive::new(f)() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | become std::sync::SyncView::new(f)() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: callee has type `Exclusive` + = note: callee has type `SyncView` error: tail calls can only be performed with function definitions or pointers --> $DIR/callee_is_weird.rs:11:12 | -LL | become (&mut &std::sync::Exclusive::new(f))() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | become (&mut &std::sync::SyncView::new(f))() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: callee has type `&Exclusive` + = note: callee has type `&SyncView` error: tail calls can only be performed with function definitions or pointers --> $DIR/callee_is_weird.rs:22:12 diff --git a/tests/ui/impl-trait/where-allowed.stderr b/tests/ui/impl-trait/where-allowed.stderr index 2d925165d583a..52b63ae8177ea 100644 --- a/tests/ui/impl-trait/where-allowed.stderr +++ b/tests/ui/impl-trait/where-allowed.stderr @@ -387,7 +387,7 @@ LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { pani where A: std::marker::Tuple, F: Fn, F: ?Sized; - impl Fn for Box where Args: std::marker::Tuple, F: Fn, A: Allocator, F: ?Sized; - - impl Fn for Exclusive + - impl Fn for SyncView where F: Sync, F: Fn, Args: std::marker::Tuple; error: unconstrained opaque type diff --git a/tests/ui/traits/next-solver/well-formed-in-relate.stderr b/tests/ui/traits/next-solver/well-formed-in-relate.stderr index 264ab9bebbb92..dbe8a656812a5 100644 --- a/tests/ui/traits/next-solver/well-formed-in-relate.stderr +++ b/tests/ui/traits/next-solver/well-formed-in-relate.stderr @@ -12,7 +12,7 @@ LL | x = unconstrained_map(); where A: std::marker::Tuple, F: Fn, F: ?Sized; - impl Fn for Box where Args: std::marker::Tuple, F: Fn, A: Allocator, F: ?Sized; - - impl Fn for Exclusive + - impl Fn for SyncView where F: Sync, F: Fn, Args: std::marker::Tuple; note: required by a bound in `unconstrained_map` --> $DIR/well-formed-in-relate.rs:21:25 From 854d2abd782e901d597c2db5b972d61b90e45680 Mon Sep 17 00:00:00 2001 From: cijiugechu Date: Tue, 7 Apr 2026 22:26:21 +0800 Subject: [PATCH 8/9] fix pattern types rendering in rustdoc --- src/librustdoc/clean/mod.rs | 10 +++++++++- tests/rustdoc-html/pattern-types-implementors.rs | 12 ++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 tests/rustdoc-html/pattern-types-implementors.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d6dae29c932e0..5934e0db70421 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1808,7 +1808,15 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) } } TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))), - TyKind::Pat(ty, pat) => Type::Pat(Box::new(clean_ty(ty, cx)), format!("{pat:?}").into()), + TyKind::Pat(inner_ty, pat) => { + // Local HIR pattern types should print the same way as cross-crate inlined ones, + // so lower to the canonical `rustc_middle::ty::Pattern` representation first. + let pat = match lower_ty(cx.tcx, ty).kind() { + ty::Pat(_, pat) => format!("{pat:?}").into_boxed_str(), + _ => format!("{pat:?}").into(), + }; + Type::Pat(Box::new(clean_ty(inner_ty, cx)), pat) + } TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => { let field_str = if let Some(variant) = variant { format!("{variant}.{field}") diff --git a/tests/rustdoc-html/pattern-types-implementors.rs b/tests/rustdoc-html/pattern-types-implementors.rs new file mode 100644 index 0000000000000..2f49837b27e74 --- /dev/null +++ b/tests/rustdoc-html/pattern-types-implementors.rs @@ -0,0 +1,12 @@ +#![feature(pattern_types, pattern_type_macro)] +#![crate_name = "pattern_types_implementors"] + +use std::pat::pattern_type; + +pub trait MyTrait {} + +impl MyTrait for pattern_type!(*const u8 is !null) {} + +//@ has pattern_types_implementors/trait.MyTrait.html +//@ has - '//*[@id="implementors-list"]/*[@class="impl"]' 'impl MyTrait for *const u8 is !null' +//@ !has - '//*[@id="implementors-list"]/*[@class="impl"]' 'TyPat {' From 6352e8298ffe51c712c0ac682ef0370bba78734a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 25 Mar 2026 09:25:52 +1100 Subject: [PATCH 9/9] Move `maybe_loop_headers` out of `rustc_middle`. `rustc_middle` is enormous and it's always good to move things out of it where possible. `maybe_loop_headers` is easy to move because it has a single use in `jump_threading.rs`. --- compiler/rustc_middle/src/mir/loops.rs | 29 ------------------- compiler/rustc_middle/src/mir/mod.rs | 2 -- .../rustc_mir_transform/src/jump_threading.rs | 28 +++++++++++++++++- 3 files changed, 27 insertions(+), 32 deletions(-) delete mode 100644 compiler/rustc_middle/src/mir/loops.rs diff --git a/compiler/rustc_middle/src/mir/loops.rs b/compiler/rustc_middle/src/mir/loops.rs deleted file mode 100644 index ae332913c6421..0000000000000 --- a/compiler/rustc_middle/src/mir/loops.rs +++ /dev/null @@ -1,29 +0,0 @@ -use rustc_index::bit_set::DenseBitSet; - -use super::*; - -/// Compute the set of loop headers in the given body. A loop header is usually defined as a block -/// which dominates one of its predecessors. This definition is only correct for reducible CFGs. -/// However, computing dominators is expensive, so we approximate according to the post-order -/// traversal order. A loop header for us is a block which is visited after its predecessor in -/// post-order. This is ok as we mostly need a heuristic. -pub fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet { - let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len()); - let mut visited = DenseBitSet::new_empty(body.basic_blocks.len()); - for (bb, bbdata) in traversal::postorder(body) { - // Post-order means we visit successors before the block for acyclic CFGs. - // If the successor is not visited yet, consider it a loop header. - for succ in bbdata.terminator().successors() { - if !visited.contains(succ) { - maybe_loop_headers.insert(succ); - } - } - - // Only mark `bb` as visited after we checked the successors, in case we have a self-loop. - // bb1: goto -> bb1; - let _new = visited.insert(bb); - debug_assert!(_new); - } - - maybe_loop_headers -} diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 892d3bfea653e..1c14b94b8d7d3 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -48,8 +48,6 @@ mod query; mod statement; mod syntax; mod terminator; - -pub mod loops; pub mod traversal; pub mod visit; diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index a1e5d810afc02..c17e18ac664ed 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -97,7 +97,7 @@ impl<'tcx> crate::MirPass<'tcx> for JumpThreading { ecx: InterpCx::new(tcx, DUMMY_SP, typing_env, DummyMachine), body, map: Map::new(tcx, body, PlaceCollectionMode::OnDemand), - maybe_loop_headers: loops::maybe_loop_headers(body), + maybe_loop_headers: maybe_loop_headers(body), entry_states: IndexVec::from_elem(ConditionSet::default(), &body.basic_blocks), }; @@ -1100,3 +1100,29 @@ impl<'a, 'tcx> OpportunitySet<'a, 'tcx> { Some(new_target) } } + +/// Compute the set of loop headers in the given body. A loop header is usually defined as a block +/// which dominates one of its predecessors. This definition is only correct for reducible CFGs. +/// However, computing dominators is expensive, so we approximate according to the post-order +/// traversal order. A loop header for us is a block which is visited after its predecessor in +/// post-order. This is ok as we mostly need a heuristic. +fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet { + let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len()); + let mut visited = DenseBitSet::new_empty(body.basic_blocks.len()); + for (bb, bbdata) in traversal::postorder(body) { + // Post-order means we visit successors before the block for acyclic CFGs. + // If the successor is not visited yet, consider it a loop header. + for succ in bbdata.terminator().successors() { + if !visited.contains(succ) { + maybe_loop_headers.insert(succ); + } + } + + // Only mark `bb` as visited after we checked the successors, in case we have a self-loop. + // bb1: goto -> bb1; + let _new = visited.insert(bb); + debug_assert!(_new); + } + + maybe_loop_headers +}