Skip to content

Rollup of 5 pull requests #98703

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 11 commits into from
4 changes: 1 addition & 3 deletions compiler/rustc_ast_lowering/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
}

fn visit_pat(&mut self, pat: &'hir Pat<'hir>) {
let node =
if let PatKind::Binding(..) = pat.kind { Node::Binding(pat) } else { Node::Pat(pat) };
self.insert(pat.span, pat.hir_id, node);
self.insert(pat.span, pat.hir_id, Node::Pat(pat));

self.with_parent(pat.hir_id, |this| {
intravisit::walk_pat(this, pat);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {

let upvar_hir_id = captured_place.get_root_variable();

if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
&& let hir::PatKind::Binding(
hir::BindingAnnotation::Unannotated,
_,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
// for a generator).
let var_hir_id = captured_place.get_root_variable();
let node = self.ecx.tcx.hir().get(var_hir_id);
if let hir::Node::Binding(pat) = node {
if let hir::Node::Pat(pat) = node {
if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
name = Some(ident.name);
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_errors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,7 @@ impl HandlerInner {
self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0),
) {
(1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
(0, _) | (1, _) => {}
(0 | 1, _) => {}
(count, as_bug) => panic!(
"aborting after {} errors due to `-Z treat-err-as-bug={}`",
count, as_bug,
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3326,7 +3326,6 @@ pub enum Node<'hir> {
Ty(&'hir Ty<'hir>),
TypeBinding(&'hir TypeBinding<'hir>),
TraitRef(&'hir TraitRef<'hir>),
Binding(&'hir Pat<'hir>),
Pat(&'hir Pat<'hir>),
Arm(&'hir Arm<'hir>),
Block(&'hir Block<'hir>),
Expand Down Expand Up @@ -3378,7 +3377,6 @@ impl<'hir> Node<'hir> {
| Node::Block(..)
| Node::Ctor(..)
| Node::Pat(..)
| Node::Binding(..)
| Node::Arm(..)
| Node::Local(..)
| Node::Crate(..)
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ impl<'a> State<'a> {
Node::Ty(a) => self.print_type(&a),
Node::TypeBinding(a) => self.print_type_binding(&a),
Node::TraitRef(a) => self.print_trait_ref(&a),
Node::Binding(a) | Node::Pat(a) => self.print_pat(&a),
Node::Pat(a) => self.print_pat(&a),
Node::Arm(a) => self.print_arm(&a),
Node::Infer(_) => self.word("_"),
Node::Block(a) => {
Expand Down
5 changes: 1 addition & 4 deletions compiler/rustc_middle/src/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,6 @@ impl<'hir> Map<'hir> {
| Node::Infer(_)
| Node::TraitRef(_)
| Node::Pat(_)
| Node::Binding(_)
| Node::Local(_)
| Node::Param(_)
| Node::Arm(_)
Expand Down Expand Up @@ -901,7 +900,7 @@ impl<'hir> Map<'hir> {
#[inline]
fn opt_ident(self, id: HirId) -> Option<Ident> {
match self.get(id) {
Node::Binding(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
// A `Ctor` doesn't have an identifier itself, but its parent
// struct/variant does. Compare with `hir::Map::opt_span`.
Node::Ctor(..) => match self.find(self.get_parent_node(id))? {
Expand Down Expand Up @@ -969,7 +968,6 @@ impl<'hir> Map<'hir> {
Node::Ty(ty) => ty.span,
Node::TypeBinding(tb) => tb.span,
Node::TraitRef(tr) => tr.path.span,
Node::Binding(pat) => pat.span,
Node::Pat(pat) => pat.span,
Node::Arm(arm) => arm.span,
Node::Block(block) => block.span,
Expand Down Expand Up @@ -1203,7 +1201,6 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
Some(Node::Ty(_)) => node_str("type"),
Some(Node::TypeBinding(_)) => node_str("type binding"),
Some(Node::TraitRef(_)) => node_str("trait ref"),
Some(Node::Binding(_)) => node_str("local"),
Some(Node::Pat(_)) => node_str("pat"),
Some(Node::Param(_)) => node_str("param"),
Some(Node::Arm(_)) => node_str("arm"),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
continue;
};
let pat = match tcx.hir().get(arg.pat.hir_id) {
Node::Pat(pat) | Node::Binding(pat) => pat,
Node::Pat(pat) => pat,
node => bug!("pattern became {:?}", node),
};
let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/cx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl<'tcx> Cx<'tcx> {
#[tracing::instrument(level = "debug", skip(self))]
pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> {
let p = match self.tcx.hir().get(p.hir_id) {
Node::Pat(p) | Node::Binding(p) => p,
Node::Pat(p) => p,
node => bug!("pattern became {:?}", node),
};
pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p)
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_save_analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -623,9 +623,9 @@ impl<'tcx> SaveContext<'tcx> {
}
},

Node::Binding(&hir::Pat {
kind: hir::PatKind::Binding(_, canonical_id, ..), ..
}) => Res::Local(canonical_id),
Node::Pat(&hir::Pat { kind: hir::PatKind::Binding(_, canonical_id, ..), .. }) => {
Res::Local(canonical_id)
}

_ => Res::Err,
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None,
hir::Path { res: hir::def::Res::Local(hir_id), .. },
)) => {
if let Some(hir::Node::Binding(pat)) = self.tcx.hir().find(*hir_id) {
if let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(*hir_id) {
let parent = self.tcx.hir().get_parent_node(pat.hir_id);
primary_span = pat.span;
secondary_span = pat.span;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,6 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
| hir::Node::Ty(..)
| hir::Node::TypeBinding(..)
| hir::Node::TraitRef(..)
| hir::Node::Binding(..)
| hir::Node::Pat(..)
| hir::Node::Arm(..)
| hir::Node::Local(..)
Expand Down
173 changes: 173 additions & 0 deletions library/core/src/sync/exclusive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
//! Defines [`Exclusive`].

use core::fmt;
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};

/// `Exclusive` provides only _mutable_ access, also referred to as _exclusive_
/// access to the underlying value. It provides no _immutable_, or _shared_
/// access to the underlying value.
///
/// While this may seem not very useful, it allows `Exclusive` to _unconditionally_
/// implement [`Sync`]. Indeed, the safety requirements of `Sync` state that for `Exclusive`
/// 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` 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
/// rust compiler that something is `Sync` in practice.
///
/// ## Examples
/// Using a non-`Sync` future prevents the wrapping struct from being `Sync`
/// ```compile_fail
/// use core::cell::Cell;
///
/// async fn other() {}
/// fn assert_sync<T: Sync>(t: T) {}
/// struct State<F> {
/// future: F
/// }
///
/// assert_sync(State {
/// future: async {
/// let cell = Cell::new(1);
/// let cell_ref = &cell;
/// other().await;
/// let value = cell_ref.get();
/// }
/// });
/// ```
///
/// `Exclusive` ensures the struct is `Sync` without stripping the future of its
/// functionality.
/// ```
/// #![feature(exclusive_wrapper)]
/// use core::cell::Cell;
/// use core::sync::Exclusive;
///
/// async fn other() {}
/// fn assert_sync<T: Sync>(t: T) {}
/// struct State<F> {
/// future: Exclusive<F>
/// }
///
/// assert_sync(State {
/// future: Exclusive::new(async {
/// let cell = Cell::new(1);
/// let cell_ref = &cell;
/// other().await;
/// let value = cell_ref.get();
/// })
/// });
/// ```
///
/// ## Parallels with a mutex
/// In some sense, `Exclusive` 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_
/// version of a read-write lock.
///
///
/// [`Sync`]: core::marker::Sync
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[doc(alias = "SyncWrapper")]
#[doc(alias = "SyncCell")]
#[doc(alias = "Unique")]
// `Exclusive` can't have `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<T: ?Sized> {
inner: T,
}

// See `Exclusive`'s docs for justification.
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
unsafe impl<T: ?Sized> Sync for Exclusive<T> {}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
impl<T: ?Sized> fmt::Debug for Exclusive<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("Exclusive").finish_non_exhaustive()
}
}

impl<T: Sized> Exclusive<T> {
/// Wrap a value in an `Exclusive`
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
pub const fn new(t: T) -> Self {
Self { inner: t }
}

/// Unwrap the value contained in the `Exclusive`
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
pub const fn into_inner(self) -> T {
self.inner
}
}

impl<T: ?Sized> Exclusive<T> {
/// Get exclusive access to the underlying value.
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
pub const fn get_mut(&mut self) -> &mut T {
&mut self.inner
}

/// Get 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
/// produce _pinned_ access to the underlying value.
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
pub const fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
// SAFETY: `Exclusive` 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_ references to an `Exclusive<T>` from
/// a _mutable_ reference to a `T`. This allows you to skip
/// building an `Exclusive` with [`Exclusive::new`].
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
pub const fn from_mut(r: &'_ mut T) -> &'_ mut Exclusive<T> {
// 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<T>) }
}

/// Build a _pinned mutable_ references to an `Exclusive<T>` from
/// a _pinned mutable_ reference to a `T`. This allows you to skip
/// building an `Exclusive` with [`Exclusive::new`].
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
#[must_use]
pub const fn from_pin_mut(r: Pin<&'_ mut T>) -> Pin<&'_ mut Exclusive<T>> {
// SAFETY: `Exclusive` 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())) }
}
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
impl<T> From<T> for Exclusive<T> {
fn from(t: T) -> Self {
Self::new(t)
}
}

#[unstable(feature = "exclusive_wrapper", issue = "98407")]
impl<T: Future + ?Sized> Future for Exclusive<T> {
type Output = T::Output;

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.get_pin_mut().poll(cx)
}
}
3 changes: 3 additions & 0 deletions library/core/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
#![stable(feature = "rust1", since = "1.0.0")]

pub mod atomic;
mod exclusive;
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
pub use exclusive::Exclusive;
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@
#![feature(duration_checked_float)]
#![feature(duration_constants)]
#![feature(exact_size_is_empty)]
#![feature(exclusive_wrapper)]
#![feature(extend_one)]
#![feature(float_minimum_maximum)]
#![feature(hasher_prefixfree_extras)]
Expand Down
2 changes: 2 additions & 0 deletions library/std/src/sync/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@
pub use alloc_crate::sync::{Arc, Weak};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::sync::atomic;
#[unstable(feature = "exclusive_wrapper", issue = "98407")]
pub use core::sync::Exclusive;

#[stable(feature = "rust1", since = "1.0.0")]
pub use self::barrier::{Barrier, BarrierWaitResult};
Expand Down
Loading