Auto merge of #131029 - matthiaskrgr:rollup-rh66wir, r=matthiaskrgr
Rollup of 4 pull requests Successful merges: - #123932 (restate GlobalAlloc method safety preconditions in terms of what the caller has to do for greater clarity) - #129003 (Improve Ord docs) - #130972 (stabilize const_cell_into_inner) - #130990 (try to get rid of mir::Const::normalize) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
7608018cbd
13 changed files with 299 additions and 217 deletions
|
@ -82,19 +82,6 @@ index d9de37e..8293fce 100644
|
||||||
#[cfg(target_has_atomic_load_store = "ptr")]
|
#[cfg(target_has_atomic_load_store = "ptr")]
|
||||||
macro_rules! atomic_int_ptr_sized {
|
macro_rules! atomic_int_ptr_sized {
|
||||||
( $($target_pointer_width:literal $align:literal)* ) => { $(
|
( $($target_pointer_width:literal $align:literal)* ) => { $(
|
||||||
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
|
|
||||||
index 58b9ba4..91bbd0a 100644
|
|
||||||
--- a/library/core/src/cell.rs
|
|
||||||
+++ b/library/core/src/cell.rs
|
|
||||||
@@ -2246,8 +2246,6 @@ unsafe_cell_primitive_into_inner! {
|
|
||||||
u32 "32"
|
|
||||||
i64 "64"
|
|
||||||
u64 "64"
|
|
||||||
- i128 "128"
|
|
||||||
- u128 "128"
|
|
||||||
isize "ptr"
|
|
||||||
usize "ptr"
|
|
||||||
}
|
|
||||||
--
|
--
|
||||||
2.26.2.7.g19db9cfb68
|
2.26.2.7.g19db9cfb68
|
||||||
|
|
||||||
|
|
|
@ -221,7 +221,9 @@ pub enum Const<'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Const<'tcx> {
|
impl<'tcx> Const<'tcx> {
|
||||||
pub fn identity_unevaluated(
|
/// Creates an unevaluated const from a `DefId` for a const item.
|
||||||
|
/// The binders of the const item still need to be instantiated.
|
||||||
|
pub fn from_unevaluated(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
|
) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
|
||||||
|
@ -329,18 +331,6 @@ impl<'tcx> Const<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Normalizes the constant to a value or an error if possible.
|
|
||||||
#[inline]
|
|
||||||
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
|
|
||||||
match self.eval(tcx, param_env, DUMMY_SP) {
|
|
||||||
Ok(val) => Self::Val(val, self.ty()),
|
|
||||||
Err(ErrorHandled::Reported(guar, _span)) => {
|
|
||||||
Self::Ty(Ty::new_error(tcx, guar.into()), ty::Const::new_error(tcx, guar.into()))
|
|
||||||
}
|
|
||||||
Err(ErrorHandled::TooGeneric(_span)) => self,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn try_eval_scalar(
|
pub fn try_eval_scalar(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -699,23 +699,17 @@ impl<'tcx> Cx<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::InlineAsmOperand::Const { ref anon_const } => {
|
hir::InlineAsmOperand::Const { ref anon_const } => {
|
||||||
let value = mir::Const::identity_unevaluated(
|
let value =
|
||||||
tcx,
|
mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id())
|
||||||
anon_const.def_id.to_def_id(),
|
.instantiate_identity();
|
||||||
)
|
|
||||||
.instantiate_identity()
|
|
||||||
.normalize(tcx, self.param_env);
|
|
||||||
let span = tcx.def_span(anon_const.def_id);
|
let span = tcx.def_span(anon_const.def_id);
|
||||||
|
|
||||||
InlineAsmOperand::Const { value, span }
|
InlineAsmOperand::Const { value, span }
|
||||||
}
|
}
|
||||||
hir::InlineAsmOperand::SymFn { ref anon_const } => {
|
hir::InlineAsmOperand::SymFn { ref anon_const } => {
|
||||||
let value = mir::Const::identity_unevaluated(
|
let value =
|
||||||
tcx,
|
mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id())
|
||||||
anon_const.def_id.to_def_id(),
|
.instantiate_identity();
|
||||||
)
|
|
||||||
.instantiate_identity()
|
|
||||||
.normalize(tcx, self.param_env);
|
|
||||||
let span = tcx.def_span(anon_const.def_id);
|
let span = tcx.def_span(anon_const.def_id);
|
||||||
|
|
||||||
InlineAsmOperand::SymFn { value, span }
|
InlineAsmOperand::SymFn { value, span }
|
||||||
|
|
|
@ -516,9 +516,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
|
||||||
// Avoid handling them, though this could be extended in the future.
|
// Avoid handling them, though this could be extended in the future.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let Some(value) =
|
let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.param_env) else {
|
||||||
value.const_.normalize(self.tcx, self.param_env).try_to_scalar_int()
|
|
||||||
else {
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let conds = conditions.map(self.arena, |c| Condition {
|
let conds = conditions.map(self.arena, |c| Condition {
|
||||||
|
|
|
@ -124,8 +124,8 @@ pub unsafe trait GlobalAlloc {
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This function is unsafe because undefined behavior can result
|
/// `layout` must have non-zero size. Attempting to allocate for a zero-sized `layout` may
|
||||||
/// if the caller does not ensure that `layout` has non-zero size.
|
/// result in undefined behavior.
|
||||||
///
|
///
|
||||||
/// (Extension subtraits might provide more specific bounds on
|
/// (Extension subtraits might provide more specific bounds on
|
||||||
/// behavior, e.g., guarantee a sentinel address or a null pointer
|
/// behavior, e.g., guarantee a sentinel address or a null pointer
|
||||||
|
@ -156,14 +156,14 @@ pub unsafe trait GlobalAlloc {
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This function is unsafe because undefined behavior can result
|
/// The caller must ensure:
|
||||||
/// if the caller does not ensure all of the following:
|
|
||||||
///
|
///
|
||||||
/// * `ptr` must denote a block of memory currently allocated via
|
/// * `ptr` is a block of memory currently allocated via this allocator and,
|
||||||
/// this allocator,
|
|
||||||
///
|
///
|
||||||
/// * `layout` must be the same layout that was used
|
/// * `layout` is the same layout that was used to allocate that block of
|
||||||
/// to allocate that block of memory.
|
/// memory.
|
||||||
|
///
|
||||||
|
/// Otherwise undefined behavior can result.
|
||||||
#[stable(feature = "global_alloc", since = "1.28.0")]
|
#[stable(feature = "global_alloc", since = "1.28.0")]
|
||||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
|
||||||
|
|
||||||
|
@ -172,7 +172,8 @@ pub unsafe trait GlobalAlloc {
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This function is unsafe for the same reasons that `alloc` is.
|
/// The caller has to ensure that `layout` has non-zero size. Like `alloc`
|
||||||
|
/// zero sized `layout` can result in undefined behaviour.
|
||||||
/// However the allocated block of memory is guaranteed to be initialized.
|
/// However the allocated block of memory is guaranteed to be initialized.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
|
@ -220,20 +221,21 @@ pub unsafe trait GlobalAlloc {
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This function is unsafe because undefined behavior can result
|
/// The caller must ensure that:
|
||||||
/// if the caller does not ensure all of the following:
|
|
||||||
///
|
///
|
||||||
/// * `ptr` must be currently allocated via this allocator,
|
/// * `ptr` is allocated via this allocator,
|
||||||
///
|
///
|
||||||
/// * `layout` must be the same layout that was used
|
/// * `layout` is the same layout that was used
|
||||||
/// to allocate that block of memory,
|
/// to allocate that block of memory,
|
||||||
///
|
///
|
||||||
/// * `new_size` must be greater than zero.
|
/// * `new_size` is greater than zero.
|
||||||
///
|
///
|
||||||
/// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
|
/// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
|
||||||
/// must not overflow `isize` (i.e., the rounded value must be less than or
|
/// does not overflow `isize` (i.e., the rounded value must be less than or
|
||||||
/// equal to `isize::MAX`).
|
/// equal to `isize::MAX`).
|
||||||
///
|
///
|
||||||
|
/// If these are not followed, undefined behaviour can result.
|
||||||
|
///
|
||||||
/// (Extension subtraits might provide more specific bounds on
|
/// (Extension subtraits might provide more specific bounds on
|
||||||
/// behavior, e.g., guarantee a sentinel address or a null pointer
|
/// behavior, e.g., guarantee a sentinel address or a null pointer
|
||||||
/// in response to a zero-size allocation request.)
|
/// in response to a zero-size allocation request.)
|
||||||
|
|
|
@ -514,7 +514,8 @@ impl<T> Cell<T> {
|
||||||
/// assert_eq!(five, 5);
|
/// assert_eq!(five, 5);
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "move_cell", since = "1.17.0")]
|
#[stable(feature = "move_cell", since = "1.17.0")]
|
||||||
#[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
|
#[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")]
|
||||||
|
#[rustc_allow_const_fn_unstable(const_precise_live_drops)]
|
||||||
pub const fn into_inner(self) -> T {
|
pub const fn into_inner(self) -> T {
|
||||||
self.value.into_inner()
|
self.value.into_inner()
|
||||||
}
|
}
|
||||||
|
@ -857,7 +858,8 @@ impl<T> RefCell<T> {
|
||||||
/// let five = c.into_inner();
|
/// let five = c.into_inner();
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
|
#[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")]
|
||||||
|
#[rustc_allow_const_fn_unstable(const_precise_live_drops)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn into_inner(self) -> T {
|
pub const fn into_inner(self) -> T {
|
||||||
// Since this function takes `self` (the `RefCell`) by value, the
|
// Since this function takes `self` (the `RefCell`) by value, the
|
||||||
|
@ -2100,8 +2102,8 @@ impl<T> UnsafeCell<T> {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
// When this is const stabilized, please remove `primitive_into_inner` below.
|
#[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")]
|
||||||
#[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
|
#[rustc_allow_const_fn_unstable(const_precise_live_drops)]
|
||||||
pub const fn into_inner(self) -> T {
|
pub const fn into_inner(self) -> T {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
@ -2247,47 +2249,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
|
||||||
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
|
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
|
||||||
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {}
|
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {}
|
||||||
|
|
||||||
// Special cases of UnsafeCell::into_inner where T is a primitive. These are
|
|
||||||
// used by Atomic*::into_inner.
|
|
||||||
//
|
|
||||||
// The real UnsafeCell::into_inner cannot be used yet in a stable const function.
|
|
||||||
// That is blocked on a "precise drop analysis" unstable const feature.
|
|
||||||
// https://github.com/rust-lang/rust/issues/73255
|
|
||||||
macro_rules! unsafe_cell_primitive_into_inner {
|
|
||||||
($($primitive:ident $atomic:literal)*) => {
|
|
||||||
$(
|
|
||||||
#[cfg(target_has_atomic_load_store = $atomic)]
|
|
||||||
impl UnsafeCell<$primitive> {
|
|
||||||
pub(crate) const fn primitive_into_inner(self) -> $primitive {
|
|
||||||
self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe_cell_primitive_into_inner! {
|
|
||||||
i8 "8"
|
|
||||||
u8 "8"
|
|
||||||
i16 "16"
|
|
||||||
u16 "16"
|
|
||||||
i32 "32"
|
|
||||||
u32 "32"
|
|
||||||
i64 "64"
|
|
||||||
u64 "64"
|
|
||||||
i128 "128"
|
|
||||||
u128 "128"
|
|
||||||
isize "ptr"
|
|
||||||
usize "ptr"
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_has_atomic_load_store = "ptr")]
|
|
||||||
impl<T> UnsafeCell<*mut T> {
|
|
||||||
pub(crate) const fn primitive_into_inner(self) -> *mut T {
|
|
||||||
self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// [`UnsafeCell`], but [`Sync`].
|
/// [`UnsafeCell`], but [`Sync`].
|
||||||
///
|
///
|
||||||
/// This is just an `UnsafeCell`, except it implements `Sync`
|
/// This is just an `UnsafeCell`, except it implements `Sync`
|
||||||
|
|
|
@ -309,7 +309,8 @@ impl<T> OnceCell<T> {
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "once_cell", since = "1.70.0")]
|
#[stable(feature = "once_cell", since = "1.70.0")]
|
||||||
#[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
|
#[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")]
|
||||||
|
#[rustc_allow_const_fn_unstable(const_precise_live_drops)]
|
||||||
pub const fn into_inner(self) -> Option<T> {
|
pub const fn into_inner(self) -> Option<T> {
|
||||||
// Because `into_inner` takes `self` by value, the compiler statically verifies
|
// Because `into_inner` takes `self` by value, the compiler statically verifies
|
||||||
// that it is not currently borrowed. So it is safe to move out `Option<T>`.
|
// that it is not currently borrowed. So it is safe to move out `Option<T>`.
|
||||||
|
|
|
@ -275,49 +275,56 @@ pub macro PartialEq($item:item) {
|
||||||
/// Trait for comparisons corresponding to [equivalence relations](
|
/// Trait for comparisons corresponding to [equivalence relations](
|
||||||
/// https://en.wikipedia.org/wiki/Equivalence_relation).
|
/// https://en.wikipedia.org/wiki/Equivalence_relation).
|
||||||
///
|
///
|
||||||
/// This means, that in addition to `a == b` and `a != b` being strict inverses,
|
/// The primary difference to [`PartialEq`] is the additional requirement for reflexivity. A type
|
||||||
/// the relation must be (for all `a`, `b` and `c`):
|
/// that implements [`PartialEq`] guarantees that for all `a`, `b` and `c`:
|
||||||
///
|
///
|
||||||
/// - reflexive: `a == a`;
|
/// - symmetric: `a == b` implies `b == a` and `a != b` implies `!(a == b)`
|
||||||
/// - symmetric: `a == b` implies `b == a` (required by `PartialEq` as well); and
|
/// - transitive: `a == b` and `b == c` implies `a == c`
|
||||||
/// - transitive: `a == b` and `b == c` implies `a == c` (required by `PartialEq` as well).
|
|
||||||
///
|
///
|
||||||
/// This property cannot be checked by the compiler, and therefore `Eq` implies
|
/// `Eq`, which builds on top of [`PartialEq`] also implies:
|
||||||
/// [`PartialEq`], and has no extra methods.
|
///
|
||||||
|
/// - reflexive: `a == a`
|
||||||
|
///
|
||||||
|
/// This property cannot be checked by the compiler, and therefore `Eq` is a trait without methods.
|
||||||
///
|
///
|
||||||
/// Violating this property is a logic error. The behavior resulting from a logic error is not
|
/// Violating this property is a logic error. The behavior resulting from a logic error is not
|
||||||
/// specified, but users of the trait must ensure that such logic errors do *not* result in
|
/// specified, but users of the trait must ensure that such logic errors do *not* result in
|
||||||
/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
|
/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
|
||||||
/// methods.
|
/// methods.
|
||||||
///
|
///
|
||||||
/// Implement `Eq` in addition to `PartialEq` if it's guaranteed that
|
/// Floating point types such as [`f32`] and [`f64`] implement only [`PartialEq`] but *not* `Eq`
|
||||||
/// `PartialEq::eq(a, a)` always returns `true` (reflexivity), in addition to
|
/// because `NaN` != `NaN`.
|
||||||
/// the symmetric and transitive properties already required by `PartialEq`.
|
|
||||||
///
|
///
|
||||||
/// ## Derivable
|
/// ## Derivable
|
||||||
///
|
///
|
||||||
/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has
|
/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has no extra methods, it
|
||||||
/// no extra methods, it is only informing the compiler that this is an
|
/// is only informing the compiler that this is an equivalence relation rather than a partial
|
||||||
/// equivalence relation rather than a partial equivalence relation. Note that
|
/// equivalence relation. Note that the `derive` strategy requires all fields are `Eq`, which isn't
|
||||||
/// the `derive` strategy requires all fields are `Eq`, which isn't
|
|
||||||
/// always desired.
|
/// always desired.
|
||||||
///
|
///
|
||||||
/// ## How can I implement `Eq`?
|
/// ## How can I implement `Eq`?
|
||||||
///
|
///
|
||||||
/// If you cannot use the `derive` strategy, specify that your type implements
|
/// If you cannot use the `derive` strategy, specify that your type implements `Eq`, which has no
|
||||||
/// `Eq`, which has no methods:
|
/// extra methods:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// enum BookFormat { Paperback, Hardback, Ebook }
|
/// enum BookFormat {
|
||||||
|
/// Paperback,
|
||||||
|
/// Hardback,
|
||||||
|
/// Ebook,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
/// struct Book {
|
/// struct Book {
|
||||||
/// isbn: i32,
|
/// isbn: i32,
|
||||||
/// format: BookFormat,
|
/// format: BookFormat,
|
||||||
/// }
|
/// }
|
||||||
|
///
|
||||||
/// impl PartialEq for Book {
|
/// impl PartialEq for Book {
|
||||||
/// fn eq(&self, other: &Self) -> bool {
|
/// fn eq(&self, other: &Self) -> bool {
|
||||||
/// self.isbn == other.isbn
|
/// self.isbn == other.isbn
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
|
///
|
||||||
/// impl Eq for Book {}
|
/// impl Eq for Book {}
|
||||||
/// ```
|
/// ```
|
||||||
#[doc(alias = "==")]
|
#[doc(alias = "==")]
|
||||||
|
@ -325,11 +332,9 @@ pub macro PartialEq($item:item) {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_diagnostic_item = "Eq"]
|
#[rustc_diagnostic_item = "Eq"]
|
||||||
pub trait Eq: PartialEq<Self> {
|
pub trait Eq: PartialEq<Self> {
|
||||||
// this method is used solely by #[derive(Eq)] to assert
|
// this method is used solely by `impl Eq or #[derive(Eq)]` to assert that every component of a
|
||||||
// that every component of a type implements `Eq`
|
// type implements `Eq` itself. The current deriving infrastructure means doing this assertion
|
||||||
// itself. The current deriving infrastructure means doing this
|
// without using a method on this trait is nearly impossible.
|
||||||
// assertion without using a method on this trait is nearly
|
|
||||||
// impossible.
|
|
||||||
//
|
//
|
||||||
// This should never be implemented by hand.
|
// This should never be implemented by hand.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -693,17 +698,14 @@ impl<T: Clone> Clone for Reverse<T> {
|
||||||
|
|
||||||
/// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order).
|
/// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order).
|
||||||
///
|
///
|
||||||
/// Implementations must be consistent with the [`PartialOrd`] implementation, and ensure
|
/// Implementations must be consistent with the [`PartialOrd`] implementation, and ensure `max`,
|
||||||
/// `max`, `min`, and `clamp` are consistent with `cmp`:
|
/// `min`, and `clamp` are consistent with `cmp`:
|
||||||
///
|
///
|
||||||
/// - `partial_cmp(a, b) == Some(cmp(a, b))`.
|
/// - `partial_cmp(a, b) == Some(cmp(a, b))`.
|
||||||
/// - `max(a, b) == max_by(a, b, cmp)` (ensured by the default implementation).
|
/// - `max(a, b) == max_by(a, b, cmp)` (ensured by the default implementation).
|
||||||
/// - `min(a, b) == min_by(a, b, cmp)` (ensured by the default implementation).
|
/// - `min(a, b) == min_by(a, b, cmp)` (ensured by the default implementation).
|
||||||
/// - For `a.clamp(min, max)`, see the [method docs](#method.clamp)
|
/// - For `a.clamp(min, max)`, see the [method docs](#method.clamp) (ensured by the default
|
||||||
/// (ensured by the default implementation).
|
/// implementation).
|
||||||
///
|
|
||||||
/// It's easy to accidentally make `cmp` and `partial_cmp` disagree by
|
|
||||||
/// deriving some of the traits and manually implementing others.
|
|
||||||
///
|
///
|
||||||
/// Violating these requirements is a logic error. The behavior resulting from a logic error is not
|
/// Violating these requirements is a logic error. The behavior resulting from a logic error is not
|
||||||
/// specified, but users of the trait must ensure that such logic errors do *not* result in
|
/// specified, but users of the trait must ensure that such logic errors do *not* result in
|
||||||
|
@ -712,15 +714,14 @@ impl<T: Clone> Clone for Reverse<T> {
|
||||||
///
|
///
|
||||||
/// ## Corollaries
|
/// ## Corollaries
|
||||||
///
|
///
|
||||||
/// From the above and the requirements of `PartialOrd`, it follows that for
|
/// From the above and the requirements of `PartialOrd`, it follows that for all `a`, `b` and `c`:
|
||||||
/// all `a`, `b` and `c`:
|
|
||||||
///
|
///
|
||||||
/// - exactly one of `a < b`, `a == b` or `a > b` is true; and
|
/// - exactly one of `a < b`, `a == b` or `a > b` is true; and
|
||||||
/// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
|
/// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and
|
||||||
|
/// `>`.
|
||||||
///
|
///
|
||||||
/// Mathematically speaking, the `<` operator defines a strict [weak order]. In
|
/// Mathematically speaking, the `<` operator defines a strict [weak order]. In cases where `==`
|
||||||
/// cases where `==` conforms to mathematical equality, it also defines a
|
/// conforms to mathematical equality, it also defines a strict [total order].
|
||||||
/// strict [total order].
|
|
||||||
///
|
///
|
||||||
/// [weak order]: https://en.wikipedia.org/wiki/Weak_ordering
|
/// [weak order]: https://en.wikipedia.org/wiki/Weak_ordering
|
||||||
/// [total order]: https://en.wikipedia.org/wiki/Total_order
|
/// [total order]: https://en.wikipedia.org/wiki/Total_order
|
||||||
|
@ -730,13 +731,12 @@ impl<T: Clone> Clone for Reverse<T> {
|
||||||
/// This trait can be used with `#[derive]`.
|
/// This trait can be used with `#[derive]`.
|
||||||
///
|
///
|
||||||
/// When `derive`d on structs, it will produce a
|
/// When `derive`d on structs, it will produce a
|
||||||
/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering
|
/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering based on the
|
||||||
/// based on the top-to-bottom declaration order of the struct's members.
|
/// top-to-bottom declaration order of the struct's members.
|
||||||
///
|
///
|
||||||
/// When `derive`d on enums, variants are ordered primarily by their discriminants.
|
/// When `derive`d on enums, variants are ordered primarily by their discriminants. Secondarily,
|
||||||
/// Secondarily, they are ordered by their fields.
|
/// they are ordered by their fields. By default, the discriminant is smallest for variants at the
|
||||||
/// By default, the discriminant is smallest for variants at the top, and
|
/// top, and largest for variants at the bottom. Here's an example:
|
||||||
/// largest for variants at the bottom. Here's an example:
|
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #[derive(PartialEq, Eq, PartialOrd, Ord)]
|
/// #[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
@ -748,8 +748,7 @@ impl<T: Clone> Clone for Reverse<T> {
|
||||||
/// assert!(E::Top < E::Bottom);
|
/// assert!(E::Top < E::Bottom);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// However, manually setting the discriminants can override this default
|
/// However, manually setting the discriminants can override this default behavior:
|
||||||
/// behavior:
|
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #[derive(PartialEq, Eq, PartialOrd, Ord)]
|
/// #[derive(PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
@ -765,51 +764,178 @@ impl<T: Clone> Clone for Reverse<T> {
|
||||||
///
|
///
|
||||||
/// Lexicographical comparison is an operation with the following properties:
|
/// Lexicographical comparison is an operation with the following properties:
|
||||||
/// - Two sequences are compared element by element.
|
/// - Two sequences are compared element by element.
|
||||||
/// - The first mismatching element defines which sequence is lexicographically less or greater than the other.
|
/// - The first mismatching element defines which sequence is lexicographically less or greater
|
||||||
/// - If one sequence is a prefix of another, the shorter sequence is lexicographically less than the other.
|
/// than the other.
|
||||||
/// - If two sequences have equivalent elements and are of the same length, then the sequences are lexicographically equal.
|
/// - If one sequence is a prefix of another, the shorter sequence is lexicographically less than
|
||||||
|
/// the other.
|
||||||
|
/// - If two sequences have equivalent elements and are of the same length, then the sequences are
|
||||||
|
/// lexicographically equal.
|
||||||
/// - An empty sequence is lexicographically less than any non-empty sequence.
|
/// - An empty sequence is lexicographically less than any non-empty sequence.
|
||||||
/// - Two empty sequences are lexicographically equal.
|
/// - Two empty sequences are lexicographically equal.
|
||||||
///
|
///
|
||||||
/// ## How can I implement `Ord`?
|
/// ## How can I implement `Ord`?
|
||||||
///
|
///
|
||||||
/// `Ord` requires that the type also be [`PartialOrd`] and [`Eq`] (which requires [`PartialEq`]).
|
/// `Ord` requires that the type also be [`PartialOrd`], [`PartialEq`], and [`Eq`].
|
||||||
///
|
///
|
||||||
/// Then you must define an implementation for [`cmp`]. You may find it useful to use
|
/// Because `Ord` implies a stronger ordering relationship than [`PartialOrd`], and both `Ord` and
|
||||||
/// [`cmp`] on your type's fields.
|
/// [`PartialOrd`] must agree, you must choose how to implement `Ord` **first**. You can choose to
|
||||||
|
/// derive it, or implement it manually. If you derive it, you should derive all four traits. If you
|
||||||
|
/// implement it manually, you should manually implement all four traits, based on the
|
||||||
|
/// implementation of `Ord`.
|
||||||
///
|
///
|
||||||
/// Here's an example where you want to sort people by height only, disregarding `id`
|
/// Here's an example where you want to define the `Character` comparison by `health` and
|
||||||
/// and `name`:
|
/// `experience` only, disregarding the field `mana`:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::cmp::Ordering;
|
/// use std::cmp::Ordering;
|
||||||
///
|
///
|
||||||
/// #[derive(Eq)]
|
/// struct Character {
|
||||||
/// struct Person {
|
/// health: u32,
|
||||||
/// id: u32,
|
/// experience: u32,
|
||||||
/// name: String,
|
/// mana: f32,
|
||||||
/// height: u32,
|
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl Ord for Person {
|
/// impl Ord for Character {
|
||||||
/// fn cmp(&self, other: &Self) -> Ordering {
|
/// fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
/// self.height.cmp(&other.height)
|
/// self.experience
|
||||||
|
/// .cmp(&other.experience)
|
||||||
|
/// .then(self.health.cmp(&other.health))
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl PartialOrd for Person {
|
/// impl PartialOrd for Character {
|
||||||
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
/// Some(self.cmp(other))
|
/// Some(self.cmp(other))
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl PartialEq for Person {
|
/// impl PartialEq for Character {
|
||||||
/// fn eq(&self, other: &Self) -> bool {
|
/// fn eq(&self, other: &Self) -> bool {
|
||||||
/// self.height == other.height
|
/// self.health == other.health && self.experience == other.experience
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
|
///
|
||||||
|
/// impl Eq for Character {}
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// If all you need is to `slice::sort` a type by a field value, it can be simpler to use
|
||||||
|
/// `slice::sort_by_key`.
|
||||||
|
///
|
||||||
|
/// ## Examples of incorrect `Ord` implementations
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::cmp::Ordering;
|
||||||
|
///
|
||||||
|
/// #[derive(Debug)]
|
||||||
|
/// struct Character {
|
||||||
|
/// health: f32,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl Ord for Character {
|
||||||
|
/// fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
/// if self.health < other.health {
|
||||||
|
/// Ordering::Less
|
||||||
|
/// } else if self.health > other.health {
|
||||||
|
/// Ordering::Greater
|
||||||
|
/// } else {
|
||||||
|
/// Ordering::Equal
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl PartialOrd for Character {
|
||||||
|
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
/// Some(self.cmp(other))
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl PartialEq for Character {
|
||||||
|
/// fn eq(&self, other: &Self) -> bool {
|
||||||
|
/// self.health == other.health
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl Eq for Character {}
|
||||||
|
///
|
||||||
|
/// let a = Character { health: 4.5 };
|
||||||
|
/// let b = Character { health: f32::NAN };
|
||||||
|
///
|
||||||
|
/// // Mistake: floating-point values do not form a total order and using the built-in comparison
|
||||||
|
/// // operands to implement `Ord` irregardless of that reality does not change it. Use
|
||||||
|
/// // `f32::total_cmp` if you need a total order for floating-point values.
|
||||||
|
///
|
||||||
|
/// // Reflexivity requirement of `Ord` is not given.
|
||||||
|
/// assert!(a == a);
|
||||||
|
/// assert!(b != b);
|
||||||
|
///
|
||||||
|
/// // Antisymmetry requirement of `Ord` is not given. Only one of a < c and c < a is allowed to be
|
||||||
|
/// // true, not both or neither.
|
||||||
|
/// assert_eq!((a < b) as u8 + (b < a) as u8, 0);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::cmp::Ordering;
|
||||||
|
///
|
||||||
|
/// #[derive(Debug)]
|
||||||
|
/// struct Character {
|
||||||
|
/// health: u32,
|
||||||
|
/// experience: u32,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl PartialOrd for Character {
|
||||||
|
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
/// Some(self.cmp(other))
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl Ord for Character {
|
||||||
|
/// fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
/// if self.health < 50 {
|
||||||
|
/// self.health.cmp(&other.health)
|
||||||
|
/// } else {
|
||||||
|
/// self.experience.cmp(&other.experience)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // For performance reasons implementing `PartialEq` this way is not the idiomatic way, but it
|
||||||
|
/// // ensures consistent behavior between `PartialEq`, `PartialOrd` and `Ord` in this example.
|
||||||
|
/// impl PartialEq for Character {
|
||||||
|
/// fn eq(&self, other: &Self) -> bool {
|
||||||
|
/// self.cmp(other) == Ordering::Equal
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl Eq for Character {}
|
||||||
|
///
|
||||||
|
/// let a = Character {
|
||||||
|
/// health: 3,
|
||||||
|
/// experience: 5,
|
||||||
|
/// };
|
||||||
|
/// let b = Character {
|
||||||
|
/// health: 10,
|
||||||
|
/// experience: 77,
|
||||||
|
/// };
|
||||||
|
/// let c = Character {
|
||||||
|
/// health: 143,
|
||||||
|
/// experience: 2,
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // Mistake: The implementation of `Ord` compares different fields depending on the value of
|
||||||
|
/// // `self.health`, the resulting order is not total.
|
||||||
|
///
|
||||||
|
/// // Transitivity requirement of `Ord` is not given. If a is smaller than b and b is smaller than
|
||||||
|
/// // c, by transitive property a must also be smaller than c.
|
||||||
|
/// assert!(a < b && b < c && c < a);
|
||||||
|
///
|
||||||
|
/// // Antisymmetry requirement of `Ord` is not given. Only one of a < c and c < a is allowed to be
|
||||||
|
/// // true, not both or neither.
|
||||||
|
/// assert_eq!((a < c) as u8 + (c < a) as u8, 2);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The documentation of [`PartialOrd`] contains further examples, for example it's wrong for
|
||||||
|
/// [`PartialOrd`] and [`PartialEq`] to disagree.
|
||||||
|
///
|
||||||
/// [`cmp`]: Ord::cmp
|
/// [`cmp`]: Ord::cmp
|
||||||
#[doc(alias = "<")]
|
#[doc(alias = "<")]
|
||||||
#[doc(alias = ">")]
|
#[doc(alias = ">")]
|
||||||
|
@ -924,8 +1050,12 @@ pub macro Ord($item:item) {
|
||||||
|
|
||||||
/// Trait for types that form a [partial order](https://en.wikipedia.org/wiki/Partial_order).
|
/// Trait for types that form a [partial order](https://en.wikipedia.org/wiki/Partial_order).
|
||||||
///
|
///
|
||||||
/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using
|
/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using the `<`, `<=`, `>`, and
|
||||||
/// the `<`, `<=`, `>`, and `>=` operators, respectively.
|
/// `>=` operators, respectively.
|
||||||
|
///
|
||||||
|
/// This trait should **only** contain the comparison logic for a type **if one plans on only
|
||||||
|
/// implementing `PartialOrd` but not [`Ord`]**. Otherwise the comparison logic should be in [`Ord`]
|
||||||
|
/// and this trait implemented with `Some(self.cmp(other))`.
|
||||||
///
|
///
|
||||||
/// The methods of this trait must be consistent with each other and with those of [`PartialEq`].
|
/// The methods of this trait must be consistent with each other and with those of [`PartialEq`].
|
||||||
/// The following conditions must hold:
|
/// The following conditions must hold:
|
||||||
|
@ -937,26 +1067,25 @@ pub macro Ord($item:item) {
|
||||||
/// 5. `a >= b` if and only if `a > b || a == b`
|
/// 5. `a >= b` if and only if `a > b || a == b`
|
||||||
/// 6. `a != b` if and only if `!(a == b)`.
|
/// 6. `a != b` if and only if `!(a == b)`.
|
||||||
///
|
///
|
||||||
/// Conditions 2–5 above are ensured by the default implementation.
|
/// Conditions 2–5 above are ensured by the default implementation. Condition 6 is already ensured
|
||||||
/// Condition 6 is already ensured by [`PartialEq`].
|
/// by [`PartialEq`].
|
||||||
///
|
///
|
||||||
/// If [`Ord`] is also implemented for `Self` and `Rhs`, it must also be consistent with
|
/// If [`Ord`] is also implemented for `Self` and `Rhs`, it must also be consistent with
|
||||||
/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's
|
/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's easy to
|
||||||
/// easy to accidentally make them disagree by deriving some of the traits and manually
|
/// accidentally make them disagree by deriving some of the traits and manually implementing others.
|
||||||
/// implementing others.
|
|
||||||
///
|
///
|
||||||
/// The comparison relations must satisfy the following conditions
|
/// The comparison relations must satisfy the following conditions (for all `a`, `b`, `c` of type
|
||||||
/// (for all `a`, `b`, `c` of type `A`, `B`, `C`):
|
/// `A`, `B`, `C`):
|
||||||
///
|
///
|
||||||
/// - **Transitivity**: if `A: PartialOrd<B>` and `B: PartialOrd<C>` and `A:
|
/// - **Transitivity**: if `A: PartialOrd<B>` and `B: PartialOrd<C>` and `A: PartialOrd<C>`, then `a
|
||||||
/// PartialOrd<C>`, then `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
|
/// < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. This must also
|
||||||
/// This must also work for longer chains, such as when `A: PartialOrd<B>`, `B: PartialOrd<C>`,
|
/// work for longer chains, such as when `A: PartialOrd<B>`, `B: PartialOrd<C>`, `C:
|
||||||
/// `C: PartialOrd<D>`, and `A: PartialOrd<D>` all exist.
|
/// PartialOrd<D>`, and `A: PartialOrd<D>` all exist.
|
||||||
/// - **Duality**: if `A: PartialOrd<B>` and `B: PartialOrd<A>`, then `a < b` if and only if `b > a`.
|
/// - **Duality**: if `A: PartialOrd<B>` and `B: PartialOrd<A>`, then `a < b` if and only if `b >
|
||||||
|
/// a`.
|
||||||
///
|
///
|
||||||
/// Note that the `B: PartialOrd<A>` (dual) and `A: PartialOrd<C>`
|
/// Note that the `B: PartialOrd<A>` (dual) and `A: PartialOrd<C>` (transitive) impls are not forced
|
||||||
/// (transitive) impls are not forced to exist, but these requirements apply
|
/// to exist, but these requirements apply whenever they do exist.
|
||||||
/// whenever they do exist.
|
|
||||||
///
|
///
|
||||||
/// Violating these requirements is a logic error. The behavior resulting from a logic error is not
|
/// Violating these requirements is a logic error. The behavior resulting from a logic error is not
|
||||||
/// specified, but users of the trait must ensure that such logic errors do *not* result in
|
/// specified, but users of the trait must ensure that such logic errors do *not* result in
|
||||||
|
@ -992,12 +1121,10 @@ pub macro Ord($item:item) {
|
||||||
///
|
///
|
||||||
/// ## Strict and non-strict partial orders
|
/// ## Strict and non-strict partial orders
|
||||||
///
|
///
|
||||||
/// The `<` and `>` operators behave according to a *strict* partial order.
|
/// The `<` and `>` operators behave according to a *strict* partial order. However, `<=` and `>=`
|
||||||
/// However, `<=` and `>=` do **not** behave according to a *non-strict*
|
/// do **not** behave according to a *non-strict* partial order. That is because mathematically, a
|
||||||
/// partial order.
|
/// non-strict partial order would require reflexivity, i.e. `a <= a` would need to be true for
|
||||||
/// That is because mathematically, a non-strict partial order would require
|
/// every `a`. This isn't always the case for types that implement `PartialOrd`, for example:
|
||||||
/// reflexivity, i.e. `a <= a` would need to be true for every `a`. This isn't
|
|
||||||
/// always the case for types that implement `PartialOrd`, for example:
|
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let a = f64::sqrt(-1.0);
|
/// let a = f64::sqrt(-1.0);
|
||||||
|
@ -1009,13 +1136,12 @@ pub macro Ord($item:item) {
|
||||||
/// This trait can be used with `#[derive]`.
|
/// This trait can be used with `#[derive]`.
|
||||||
///
|
///
|
||||||
/// When `derive`d on structs, it will produce a
|
/// When `derive`d on structs, it will produce a
|
||||||
/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering
|
/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering based on the
|
||||||
/// based on the top-to-bottom declaration order of the struct's members.
|
/// top-to-bottom declaration order of the struct's members.
|
||||||
///
|
///
|
||||||
/// When `derive`d on enums, variants are primarily ordered by their discriminants.
|
/// When `derive`d on enums, variants are primarily ordered by their discriminants. Secondarily,
|
||||||
/// Secondarily, they are ordered by their fields.
|
/// they are ordered by their fields. By default, the discriminant is smallest for variants at the
|
||||||
/// By default, the discriminant is smallest for variants at the top, and
|
/// top, and largest for variants at the bottom. Here's an example:
|
||||||
/// largest for variants at the bottom. Here's an example:
|
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #[derive(PartialEq, PartialOrd)]
|
/// #[derive(PartialEq, PartialOrd)]
|
||||||
|
@ -1027,8 +1153,7 @@ pub macro Ord($item:item) {
|
||||||
/// assert!(E::Top < E::Bottom);
|
/// assert!(E::Top < E::Bottom);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// However, manually setting the discriminants can override this default
|
/// However, manually setting the discriminants can override this default behavior:
|
||||||
/// behavior:
|
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #[derive(PartialEq, PartialOrd)]
|
/// #[derive(PartialEq, PartialOrd)]
|
||||||
|
@ -1046,8 +1171,8 @@ pub macro Ord($item:item) {
|
||||||
/// generated from default implementations.
|
/// generated from default implementations.
|
||||||
///
|
///
|
||||||
/// However it remains possible to implement the others separately for types which do not have a
|
/// However it remains possible to implement the others separately for types which do not have a
|
||||||
/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 ==
|
/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 == false`
|
||||||
/// false` (cf. IEEE 754-2008 section 5.11).
|
/// (cf. IEEE 754-2008 section 5.11).
|
||||||
///
|
///
|
||||||
/// `PartialOrd` requires your type to be [`PartialEq`].
|
/// `PartialOrd` requires your type to be [`PartialEq`].
|
||||||
///
|
///
|
||||||
|
@ -1056,7 +1181,6 @@ pub macro Ord($item:item) {
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::cmp::Ordering;
|
/// use std::cmp::Ordering;
|
||||||
///
|
///
|
||||||
/// #[derive(Eq)]
|
|
||||||
/// struct Person {
|
/// struct Person {
|
||||||
/// id: u32,
|
/// id: u32,
|
||||||
/// name: String,
|
/// name: String,
|
||||||
|
@ -1080,11 +1204,13 @@ pub macro Ord($item:item) {
|
||||||
/// self.height == other.height
|
/// self.height == other.height
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
|
///
|
||||||
|
/// impl Eq for Person {}
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// You may also find it useful to use [`partial_cmp`] on your type's fields. Here
|
/// You may also find it useful to use [`partial_cmp`] on your type's fields. Here is an example of
|
||||||
/// is an example of `Person` types who have a floating-point `height` field that
|
/// `Person` types who have a floating-point `height` field that is the only field to be used for
|
||||||
/// is the only field to be used for sorting:
|
/// sorting:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::cmp::Ordering;
|
/// use std::cmp::Ordering;
|
||||||
|
@ -1108,6 +1234,38 @@ pub macro Ord($item:item) {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
|
/// ## Examples of incorrect `PartialOrd` implementations
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::cmp::Ordering;
|
||||||
|
///
|
||||||
|
/// #[derive(PartialEq, Debug)]
|
||||||
|
/// struct Character {
|
||||||
|
/// health: u32,
|
||||||
|
/// experience: u32,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl PartialOrd for Character {
|
||||||
|
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
/// Some(self.health.cmp(&other.health))
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let a = Character {
|
||||||
|
/// health: 10,
|
||||||
|
/// experience: 5,
|
||||||
|
/// };
|
||||||
|
/// let b = Character {
|
||||||
|
/// health: 10,
|
||||||
|
/// experience: 77,
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// // Mistake: `PartialEq` and `PartialOrd` disagree with each other.
|
||||||
|
///
|
||||||
|
/// assert_eq!(a.partial_cmp(&b).unwrap(), Ordering::Equal); // a == b according to `PartialOrd`.
|
||||||
|
/// assert_ne!(a, b); // a != b according to `PartialEq`.
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -118,7 +118,6 @@
|
||||||
#![feature(const_array_into_iter_constructors)]
|
#![feature(const_array_into_iter_constructors)]
|
||||||
#![feature(const_bigint_helper_methods)]
|
#![feature(const_bigint_helper_methods)]
|
||||||
#![feature(const_black_box)]
|
#![feature(const_black_box)]
|
||||||
#![feature(const_cell_into_inner)]
|
|
||||||
#![feature(const_char_encode_utf16)]
|
#![feature(const_char_encode_utf16)]
|
||||||
#![feature(const_char_encode_utf8)]
|
#![feature(const_char_encode_utf8)]
|
||||||
#![feature(const_eval_select)]
|
#![feature(const_eval_select)]
|
||||||
|
|
|
@ -596,7 +596,7 @@ impl AtomicBool {
|
||||||
#[stable(feature = "atomic_access", since = "1.15.0")]
|
#[stable(feature = "atomic_access", since = "1.15.0")]
|
||||||
#[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")]
|
#[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")]
|
||||||
pub const fn into_inner(self) -> bool {
|
pub const fn into_inner(self) -> bool {
|
||||||
self.v.primitive_into_inner() != 0
|
self.v.into_inner() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads a value from the bool.
|
/// Loads a value from the bool.
|
||||||
|
@ -1413,7 +1413,7 @@ impl<T> AtomicPtr<T> {
|
||||||
#[stable(feature = "atomic_access", since = "1.15.0")]
|
#[stable(feature = "atomic_access", since = "1.15.0")]
|
||||||
#[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")]
|
#[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")]
|
||||||
pub const fn into_inner(self) -> *mut T {
|
pub const fn into_inner(self) -> *mut T {
|
||||||
self.p.primitive_into_inner()
|
self.p.into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads a value from the pointer.
|
/// Loads a value from the pointer.
|
||||||
|
@ -2408,7 +2408,7 @@ macro_rules! atomic_int {
|
||||||
#[$stable_access]
|
#[$stable_access]
|
||||||
#[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")]
|
#[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")]
|
||||||
pub const fn into_inner(self) -> $int_type {
|
pub const fn into_inner(self) -> $int_type {
|
||||||
self.v.primitive_into_inner()
|
self.v.into_inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads a value from the atomic integer.
|
/// Loads a value from the atomic integer.
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
#![feature(const_align_offset)]
|
#![feature(const_align_offset)]
|
||||||
#![feature(const_array_from_ref)]
|
#![feature(const_array_from_ref)]
|
||||||
#![feature(const_black_box)]
|
#![feature(const_black_box)]
|
||||||
#![feature(const_cell_into_inner)]
|
|
||||||
#![feature(const_hash)]
|
#![feature(const_hash)]
|
||||||
#![feature(const_heap)]
|
#![feature(const_heap)]
|
||||||
#![feature(const_ip)]
|
#![feature(const_ip)]
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
//@ only-x86_64
|
//@ only-x86_64
|
||||||
//@ needs-asm-support
|
//@ needs-asm-support
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
// Test to make sure that we emit const errors eagerly for inline asm
|
// Test to make sure that we emit const errors late for inline asm,
|
||||||
|
// which is consistent with inline const blocks.
|
||||||
|
|
||||||
use std::arch::asm;
|
use std::arch::asm;
|
||||||
|
|
||||||
fn test<T>() {
|
fn test<T>() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
// No error here, as this does not get monomorphized.
|
||||||
asm!("/* {} */", const 1 / 0);
|
asm!("/* {} */", const 1 / 0);
|
||||||
//~^ ERROR evaluation of
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
error[E0080]: evaluation of `test::<T>::{constant#0}` failed
|
|
||||||
--> $DIR/const-error.rs:10:32
|
|
||||||
|
|
|
||||||
LL | asm!("/* {} */", const 1 / 0);
|
|
||||||
| ^^^^^ attempt to divide `1_i32` by zero
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0080`.
|
|
Loading…
Add table
Add a link
Reference in a new issue