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/7] 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/7] 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/7] 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/7] 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/7] 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/7] 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/7] 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