Auto merge of #120671 - matthiaskrgr:rollup-spjnpno, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #113833 (`std::error::Error` -> Trait Implementations: lifetimes consistency improvement)
 - #115386 (PartialEq, PartialOrd: update and synchronize handling of transitive chains)
 - #116284 (make matching on NaN a hard error, and remove the rest of illegal_floating_point_literal_pattern)
 - #118960 (Add LocalWaker and ContextBuilder types to core, and LocalWake trait to alloc.)
 - #120384 (Use `<T, U>` for array/slice equality `impl`s)
 - #120518 (riscv only supports split_debuginfo=off for now)
 - #120657 (Remove unused struct)
 - #120661 (target: default to the medium code model on LoongArch targets)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-02-05 13:23:56 +00:00
commit 86eaa892c0
55 changed files with 1032 additions and 626 deletions

View File

@ -516,6 +516,10 @@ fn register_builtins(store: &mut LintStore) {
"converted into hard error, see PR #118649 \
<https://github.com/rust-lang/rust/pull/118649> for more information",
);
store.register_removed(
"illegal_floating_point_literal_pattern",
"no longer a warning, float patterns behave the same as `==`",
);
}
fn register_internals(store: &mut LintStore) {

View File

@ -45,7 +45,6 @@ declare_lint_pass! {
FUZZY_PROVENANCE_CASTS,
HIDDEN_GLOB_REEXPORTS,
ILL_FORMED_ATTRIBUTE_INPUT,
ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
INCOMPLETE_INCLUDE,
INDIRECT_STRUCTURAL_MATCH,
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
@ -1873,55 +1872,6 @@ declare_lint! {
};
}
declare_lint! {
/// The `illegal_floating_point_literal_pattern` lint detects
/// floating-point literals used in patterns.
///
/// ### Example
///
/// ```rust
/// let x = 42.0;
///
/// match x {
/// 5.0 => {}
/// _ => {}
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Previous versions of the compiler accepted floating-point literals in
/// patterns, but it was later determined this was a mistake. The
/// semantics of comparing floating-point values may not be clear in a
/// pattern when contrasted with "structural equality". Typically you can
/// work around this by using a [match guard], such as:
///
/// ```rust
/// # let x = 42.0;
///
/// match x {
/// y if y == 5.0 => {}
/// _ => {}
/// }
/// ```
///
/// This is a [future-incompatible] lint to transition this to a hard
/// error in the future. See [issue #41620] for more details.
///
/// [issue #41620]: https://github.com/rust-lang/rust/issues/41620
/// [match guard]: https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
Warn,
"floating-point literals cannot be used in patterns",
@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps,
reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
};
}
declare_lint! {
/// The `unstable_name_collisions` lint detects that you have used a name
/// that the standard library plans to add in the future.

View File

@ -418,8 +418,8 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
#[inline]
pub fn to_float<F: Float>(self) -> InterpResult<'tcx, F> {
// Going through `to_uint` to check size and truncation.
Ok(F::from_bits(self.to_uint(Size::from_bits(F::BITS))?))
// Going through `to_bits` to check size and truncation.
Ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?))
}
#[inline]

View File

@ -249,11 +249,6 @@ impl ScalarInt {
}
}
#[inline]
pub fn try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Result<u64, Size> {
Ok(self.to_bits(tcx.data_layout.pointer_size)? as u64)
}
/// Tries to convert the `ScalarInt` to an unsigned integer of the given size.
/// Fails if the size of the `ScalarInt` is not equal to `size` and returns the
/// `ScalarInt`s size in that case.
@ -262,6 +257,51 @@ impl ScalarInt {
self.to_bits(size)
}
// Tries to convert the `ScalarInt` to `u8`. Fails if the `size` of the `ScalarInt`
// in not equal to `Size { raw: 1 }` and returns the `size` value of the `ScalarInt` in
// that case.
#[inline]
pub fn try_to_u8(self) -> Result<u8, Size> {
self.try_to_uint(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap())
}
/// Tries to convert the `ScalarInt` to `u16`. Fails if the size of the `ScalarInt`
/// in not equal to `Size { raw: 2 }` and returns the `size` value of the `ScalarInt` in
/// that case.
#[inline]
pub fn try_to_u16(self) -> Result<u16, Size> {
self.try_to_uint(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap())
}
/// Tries to convert the `ScalarInt` to `u32`. Fails if the `size` of the `ScalarInt`
/// in not equal to `Size { raw: 4 }` and returns the `size` value of the `ScalarInt` in
/// that case.
#[inline]
pub fn try_to_u32(self) -> Result<u32, Size> {
self.try_to_uint(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap())
}
/// Tries to convert the `ScalarInt` to `u64`. Fails if the `size` of the `ScalarInt`
/// in not equal to `Size { raw: 8 }` and returns the `size` value of the `ScalarInt` in
/// that case.
#[inline]
pub fn try_to_u64(self) -> Result<u64, Size> {
self.try_to_uint(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap())
}
/// Tries to convert the `ScalarInt` to `u128`. Fails if the `size` of the `ScalarInt`
/// in not equal to `Size { raw: 16 }` and returns the `size` value of the `ScalarInt` in
/// that case.
#[inline]
pub fn try_to_u128(self) -> Result<u128, Size> {
self.try_to_uint(Size::from_bits(128))
}
#[inline]
pub fn try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Result<u64, Size> {
self.try_to_uint(tcx.data_layout.pointer_size).map(|v| u64::try_from(v).unwrap())
}
// Tries to convert the `ScalarInt` to `bool`. Fails if the `size` of the `ScalarInt`
// in not equal to `Size { raw: 1 }` or if the value is not 0 or 1 and returns the `size`
// value of the `ScalarInt` in that case.
@ -274,46 +314,6 @@ impl ScalarInt {
}
}
// Tries to convert the `ScalarInt` to `u8`. Fails if the `size` of the `ScalarInt`
// in not equal to `Size { raw: 1 }` and returns the `size` value of the `ScalarInt` in
// that case.
#[inline]
pub fn try_to_u8(self) -> Result<u8, Size> {
self.to_bits(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap())
}
/// Tries to convert the `ScalarInt` to `u16`. Fails if the size of the `ScalarInt`
/// in not equal to `Size { raw: 2 }` and returns the `size` value of the `ScalarInt` in
/// that case.
#[inline]
pub fn try_to_u16(self) -> Result<u16, Size> {
self.to_bits(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap())
}
/// Tries to convert the `ScalarInt` to `u32`. Fails if the `size` of the `ScalarInt`
/// in not equal to `Size { raw: 4 }` and returns the `size` value of the `ScalarInt` in
/// that case.
#[inline]
pub fn try_to_u32(self) -> Result<u32, Size> {
self.to_bits(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap())
}
/// Tries to convert the `ScalarInt` to `u64`. Fails if the `size` of the `ScalarInt`
/// in not equal to `Size { raw: 8 }` and returns the `size` value of the `ScalarInt` in
/// that case.
#[inline]
pub fn try_to_u64(self) -> Result<u64, Size> {
self.to_bits(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap())
}
/// Tries to convert the `ScalarInt` to `u128`. Fails if the `size` of the `ScalarInt`
/// in not equal to `Size { raw: 16 }` and returns the `size` value of the `ScalarInt` in
/// that case.
#[inline]
pub fn try_to_u128(self) -> Result<u128, Size> {
self.to_bits(Size::from_bits(128))
}
/// Tries to convert the `ScalarInt` to a signed integer of the given size.
/// Fails if the size of the `ScalarInt` is not equal to `size` and returns the
/// `ScalarInt`s size in that case.
@ -357,6 +357,27 @@ impl ScalarInt {
pub fn try_to_i128(self) -> Result<i128, Size> {
self.try_to_int(Size::from_bits(128))
}
#[inline]
pub fn try_to_target_isize(&self, tcx: TyCtxt<'_>) -> Result<i64, Size> {
self.try_to_int(tcx.data_layout.pointer_size).map(|v| i64::try_from(v).unwrap())
}
#[inline]
pub fn try_to_float<F: Float>(self) -> Result<F, Size> {
// Going through `to_uint` to check size and truncation.
Ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?))
}
#[inline]
pub fn try_to_f32(self) -> Result<Single, Size> {
self.try_to_float()
}
#[inline]
pub fn try_to_f64(self) -> Result<Double, Size> {
self.try_to_float()
}
}
macro_rules! from {
@ -399,11 +420,7 @@ impl TryFrom<ScalarInt> for bool {
type Error = Size;
#[inline]
fn try_from(int: ScalarInt) -> Result<Self, Size> {
int.to_bits(Size::from_bytes(1)).and_then(|u| match u {
0 => Ok(false),
1 => Ok(true),
_ => Err(Size::from_bytes(1)),
})
int.try_to_bool()
}
}

View File

@ -107,8 +107,6 @@ mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
.note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
.label = use of extern static
mir_build_float_pattern = floating-point types cannot be used in patterns
mir_build_indirect_structural_match =
to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq)]`
@ -232,6 +230,10 @@ mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsa
.note = mutating layout constrained fields cannot statically be checked for valid values
.label = mutation of layout constrained field
mir_build_nan_pattern = cannot use NaN in patterns
.note = NaNs compare inequal to everything, even themselves, so this pattern would never match
.help = try using the `is_nan` method instead
mir_build_non_const_path = runtime values cannot be referenced in patterns
mir_build_non_empty_never_pattern =

View File

@ -780,9 +780,14 @@ pub struct UnsizedPattern<'tcx> {
pub non_sm_ty: Ty<'tcx>,
}
#[derive(LintDiagnostic)]
#[diag(mir_build_float_pattern)]
pub struct FloatPattern;
#[derive(Diagnostic)]
#[diag(mir_build_nan_pattern)]
#[note]
#[help]
pub struct NaNPattern {
#[primary_span]
pub span: Span,
}
#[derive(LintDiagnostic)]
#[diag(mir_build_pointer_pattern)]

View File

@ -1,3 +1,4 @@
use rustc_apfloat::Float;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_index::Idx;
@ -16,7 +17,7 @@ use std::cell::Cell;
use super::PatCtxt;
use crate::errors::{
FloatPattern, IndirectStructuralMatch, InvalidPattern, NonPartialEqMatch,
IndirectStructuralMatch, InvalidPattern, NaNPattern, NonPartialEqMatch,
NontrivialStructuralMatch, PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
};
@ -317,16 +318,6 @@ impl<'tcx> ConstToPat<'tcx> {
let param_env = self.param_env;
let kind = match ty.kind() {
ty::Float(_) => {
self.saw_const_match_lint.set(true);
tcx.emit_node_span_lint(
lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
id,
span,
FloatPattern,
);
return Err(FallbackToOpaqueConst);
}
// If the type is not structurally comparable, just emit the constant directly,
// causing the pattern match code to treat it opaquely.
// FIXME: This code doesn't emit errors itself, the caller emits the errors.
@ -486,6 +477,22 @@ impl<'tcx> ConstToPat<'tcx> {
}
}
},
ty::Float(flt) => {
let v = cv.unwrap_leaf();
let is_nan = match flt {
ty::FloatTy::F32 => v.try_to_f32().unwrap().is_nan(),
ty::FloatTy::F64 => v.try_to_f64().unwrap().is_nan(),
};
if is_nan {
// NaNs are not ever equal to anything so they make no sense as patterns.
// Also see <https://github.com/rust-lang/rfcs/pull/3535>.
let e = tcx.dcx().emit_err(NaNPattern { span });
self.saw_const_match_error.set(Some(e));
return Err(FallbackToOpaqueConst);
} else {
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
}
}
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
// The raw pointers we see here have been "vetted" by valtree construction to be
// just integers, so we simply allow them.

View File

@ -1,4 +1,4 @@
use crate::spec::{base, Target, TargetOptions};
use crate::spec::{base, CodeModel, Target, TargetOptions};
pub fn target() -> Target {
Target {
@ -7,6 +7,7 @@ pub fn target() -> Target {
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
arch: "loongarch64".into(),
options: TargetOptions {
code_model: Some(CodeModel::Medium),
cpu: "generic".into(),
features: "+f,+d".into(),
llvm_abiname: "lp64d".into(),

View File

@ -16,7 +16,7 @@ pub fn target() -> Target {
max_atomic_width: Some(64),
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
code_model: Some(CodeModel::Small),
code_model: Some(CodeModel::Medium),
..Default::default()
},
}

View File

@ -17,7 +17,7 @@ pub fn target() -> Target {
max_atomic_width: Some(64),
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
code_model: Some(CodeModel::Small),
code_model: Some(CodeModel::Medium),
..Default::default()
},
}

View File

@ -1,4 +1,6 @@
use crate::spec::{base, CodeModel, Target, TargetOptions};
use std::borrow::Cow;
use crate::spec::{base, CodeModel, SplitDebuginfo, Target, TargetOptions};
pub fn target() -> Target {
Target {
@ -12,6 +14,7 @@ pub fn target() -> Target {
features: "+m,+a,+f,+d,+c".into(),
llvm_abiname: "ilp32d".into(),
max_atomic_width: Some(32),
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
..base::linux_gnu::opts()
},
}

View File

@ -1,4 +1,6 @@
use crate::spec::{base, CodeModel, Target, TargetOptions};
use std::borrow::Cow;
use crate::spec::{base, CodeModel, SplitDebuginfo, Target, TargetOptions};
pub fn target() -> Target {
Target {
@ -12,6 +14,7 @@ pub fn target() -> Target {
features: "+m,+a,+f,+d,+c".into(),
llvm_abiname: "ilp32d".into(),
max_atomic_width: Some(32),
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
..base::linux_musl::opts()
},
}

View File

@ -1,4 +1,6 @@
use crate::spec::{base, CodeModel, SanitizerSet, Target, TargetOptions};
use std::borrow::Cow;
use crate::spec::{base, CodeModel, SanitizerSet, SplitDebuginfo, Target, TargetOptions};
pub fn target() -> Target {
Target {
@ -13,6 +15,7 @@ pub fn target() -> Target {
llvm_abiname: "lp64d".into(),
supported_sanitizers: SanitizerSet::ADDRESS,
max_atomic_width: Some(64),
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
..base::android::opts()
},
}

View File

@ -1,4 +1,6 @@
use crate::spec::{base, CodeModel, Target, TargetOptions};
use std::borrow::Cow;
use crate::spec::{base, CodeModel, SplitDebuginfo, Target, TargetOptions};
pub fn target() -> Target {
Target {
@ -12,6 +14,7 @@ pub fn target() -> Target {
features: "+m,+a,+f,+d,+c".into(),
llvm_abiname: "lp64d".into(),
max_atomic_width: Some(64),
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
..base::linux_gnu::opts()
},
}

View File

@ -1,4 +1,6 @@
use crate::spec::{base, CodeModel, Target, TargetOptions};
use std::borrow::Cow;
use crate::spec::{base, CodeModel, SplitDebuginfo, Target, TargetOptions};
pub fn target() -> Target {
Target {
@ -12,6 +14,7 @@ pub fn target() -> Target {
features: "+m,+a,+f,+d,+c".into(),
llvm_abiname: "lp64d".into(),
max_atomic_width: Some(64),
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
..base::linux_musl::opts()
},
}

View File

@ -2284,7 +2284,7 @@ impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync +
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
impl From<String> for Box<dyn Error + Send + Sync> {
impl<'a> From<String> for Box<dyn Error + Send + Sync + 'a> {
/// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
///
/// # Examples
@ -2299,7 +2299,7 @@ impl From<String> for Box<dyn Error + Send + Sync> {
/// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
/// ```
#[inline]
fn from(err: String) -> Box<dyn Error + Send + Sync> {
fn from(err: String) -> Box<dyn Error + Send + Sync + 'a> {
struct StringError(String);
impl Error for StringError {
@ -2328,7 +2328,7 @@ impl From<String> for Box<dyn Error + Send + Sync> {
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "string_box_error", since = "1.6.0")]
impl From<String> for Box<dyn Error> {
impl<'a> From<String> for Box<dyn Error + 'a> {
/// Converts a [`String`] into a box of dyn [`Error`].
///
/// # Examples
@ -2341,7 +2341,7 @@ impl From<String> for Box<dyn Error> {
/// let a_boxed_error = Box::<dyn Error>::from(a_string_error);
/// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
/// ```
fn from(str_err: String) -> Box<dyn Error> {
fn from(str_err: String) -> Box<dyn Error + 'a> {
let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
let err2: Box<dyn Error> = err1;
err2
@ -2374,7 +2374,7 @@ impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "string_box_error", since = "1.6.0")]
impl From<&str> for Box<dyn Error> {
impl<'a> From<&str> for Box<dyn Error + 'a> {
/// Converts a [`str`] into a box of dyn [`Error`].
///
/// [`str`]: prim@str
@ -2389,7 +2389,7 @@ impl From<&str> for Box<dyn Error> {
/// let a_boxed_error = Box::<dyn Error>::from(a_str_error);
/// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
/// ```
fn from(err: &str) -> Box<dyn Error> {
fn from(err: &str) -> Box<dyn Error + 'a> {
From::from(String::from(err))
}
}
@ -2418,7 +2418,7 @@ impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "cow_box_error", since = "1.22.0")]
impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + 'a> {
/// Converts a [`Cow`] into a box of dyn [`Error`].
///
/// # Examples
@ -2432,7 +2432,7 @@ impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
/// let a_boxed_error = Box::<dyn Error>::from(a_cow_str_error);
/// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
/// ```
fn from(err: Cow<'a, str>) -> Box<dyn Error> {
fn from(err: Cow<'b, str>) -> Box<dyn Error + 'a> {
From::from(String::from(err))
}
}

View File

@ -135,6 +135,7 @@
#![feature(iter_next_chunk)]
#![feature(iter_repeat_n)]
#![feature(layout_for_ptr)]
#![feature(local_waker)]
#![feature(maybe_uninit_slice)]
#![feature(maybe_uninit_uninit_array)]
#![feature(maybe_uninit_uninit_array_transpose)]
@ -252,7 +253,7 @@ pub mod str;
pub mod string;
#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
pub mod sync;
#[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
#[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync)))]
pub mod task;
#[cfg(test)]
mod tests;

View File

@ -2,14 +2,19 @@
//! Types and Traits for working with asynchronous tasks.
//!
//! **Note**: This module is only available on platforms that support atomic
//! loads and stores of pointers. This may be detected at compile time using
//! **Note**: Some of the types in this module are only available
//! on platforms that support atomic loads and stores of pointers.
//! This may be detected at compile time using
//! `#[cfg(target_has_atomic = "ptr")]`.
use crate::rc::Rc;
use core::mem::ManuallyDrop;
use core::task::{RawWaker, RawWakerVTable, Waker};
use core::task::{LocalWaker, RawWaker, RawWakerVTable};
#[cfg(target_has_atomic = "ptr")]
use crate::sync::Arc;
#[cfg(target_has_atomic = "ptr")]
use core::task::Waker;
/// The implementation of waking a task on an executor.
///
@ -73,6 +78,7 @@ use crate::sync::Arc;
/// println!("Hi from inside a future!");
/// });
/// ```
#[cfg(target_has_atomic = "ptr")]
#[stable(feature = "wake_trait", since = "1.51.0")]
pub trait Wake {
/// Wake this task.
@ -91,7 +97,7 @@ pub trait Wake {
self.clone().wake();
}
}
#[cfg(target_has_atomic = "ptr")]
#[stable(feature = "wake_trait", since = "1.51.0")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
/// Use a `Wake`-able type as a `Waker`.
@ -103,7 +109,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
unsafe { Waker::from_raw(raw_waker(waker)) }
}
}
#[cfg(target_has_atomic = "ptr")]
#[stable(feature = "wake_trait", since = "1.51.0")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
/// Use a `Wake`-able type as a `RawWaker`.
@ -119,6 +125,7 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
// the safety of `From<Arc<W>> for Waker` does not depend on the correct
// trait dispatch - instead both impls call this function directly and
// explicitly.
#[cfg(target_has_atomic = "ptr")]
#[inline(always)]
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
// Increment the reference count of the arc to clone it.
@ -152,3 +159,171 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
&RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
)
}
/// An analogous trait to `Wake` but used to construct a `LocalWaker`. This API
/// works in exactly the same way as `Wake`, except that it uses an `Rc` instead
/// of an `Arc`, and the result is a `LocalWaker` instead of a `Waker`.
///
/// The benefits of using `LocalWaker` over `Waker` are that it allows the local waker
/// to hold data that does not implement `Send` and `Sync`. Additionally, it saves calls
/// to `Arc::clone`, which requires atomic synchronization.
///
///
/// # Examples
///
/// This is a simplified example of a `spawn` and a `block_on` function. The `spawn` function
/// is used to push new tasks onto the run queue, while the block on function will remove them
/// and poll them. When a task is woken, it will put itself back on the run queue to be polled
/// by the executor.
///
/// **Note:** This example trades correctness for simplicity. A real world example would interleave
/// poll calls with calls to an io reactor to wait for events instead of spinning on a loop.
///
/// ```rust
/// #![feature(local_waker)]
/// #![feature(noop_waker)]
/// use std::task::{LocalWake, ContextBuilder, LocalWaker, Waker};
/// use std::future::Future;
/// use std::pin::Pin;
/// use std::rc::Rc;
/// use std::cell::RefCell;
/// use std::collections::VecDeque;
///
///
/// thread_local! {
/// // A queue containing all tasks ready to do progress
/// static RUN_QUEUE: RefCell<VecDeque<Rc<Task>>> = RefCell::default();
/// }
///
/// type BoxedFuture = Pin<Box<dyn Future<Output = ()>>>;
///
/// struct Task(RefCell<BoxedFuture>);
///
/// impl LocalWake for Task {
/// fn wake(self: Rc<Self>) {
/// RUN_QUEUE.with_borrow_mut(|queue| {
/// queue.push_back(self)
/// })
/// }
/// }
///
/// fn spawn<F>(future: F)
/// where
/// F: Future<Output=()> + 'static + Send + Sync
/// {
/// let task = RefCell::new(Box::pin(future));
/// RUN_QUEUE.with_borrow_mut(|queue| {
/// queue.push_back(Rc::new(Task(task)));
/// });
/// }
///
/// fn block_on<F>(future: F)
/// where
/// F: Future<Output=()> + 'static + Sync + Send
/// {
/// spawn(future);
/// loop {
/// let Some(task) = RUN_QUEUE.with_borrow_mut(|queue| queue.pop_front()) else {
/// // we exit, since there are no more tasks remaining on the queue
/// return;
/// };
///
/// // cast the Rc<Task> into a `LocalWaker`
/// let local_waker: LocalWaker = task.clone().into();
/// // Build the context using `ContextBuilder`
/// let mut cx = ContextBuilder::from_waker(Waker::noop())
/// .local_waker(&local_waker)
/// .build();
///
/// // Poll the task
/// let _ = task.0
/// .borrow_mut()
/// .as_mut()
/// .poll(&mut cx);
/// }
/// }
///
/// block_on(async {
/// println!("hello world");
/// });
/// ```
///
#[unstable(feature = "local_waker", issue = "118959")]
pub trait LocalWake {
/// Wake this task.
#[unstable(feature = "local_waker", issue = "118959")]
fn wake(self: Rc<Self>);
/// Wake this task without consuming the local waker.
///
/// If an executor supports a cheaper way to wake without consuming the
/// waker, it should override this method. By default, it clones the
/// [`Rc`] and calls [`wake`] on the clone.
///
/// [`wake`]: LocalWaker::wake
#[unstable(feature = "local_waker", issue = "118959")]
fn wake_by_ref(self: &Rc<Self>) {
self.clone().wake();
}
}
#[unstable(feature = "local_waker", issue = "118959")]
impl<W: LocalWake + 'static> From<Rc<W>> for LocalWaker {
/// Use a `Wake`-able type as a `LocalWaker`.
///
/// No heap allocations or atomic operations are used for this conversion.
fn from(waker: Rc<W>) -> LocalWaker {
// SAFETY: This is safe because raw_waker safely constructs
// a RawWaker from Rc<W>.
unsafe { LocalWaker::from_raw(local_raw_waker(waker)) }
}
}
#[allow(ineffective_unstable_trait_impl)]
#[unstable(feature = "local_waker", issue = "118959")]
impl<W: LocalWake + 'static> From<Rc<W>> for RawWaker {
/// Use a `Wake`-able type as a `RawWaker`.
///
/// No heap allocations or atomic operations are used for this conversion.
fn from(waker: Rc<W>) -> RawWaker {
local_raw_waker(waker)
}
}
// NB: This private function for constructing a RawWaker is used, rather than
// inlining this into the `From<Rc<W>> for RawWaker` impl, to ensure that
// the safety of `From<Rc<W>> for Waker` does not depend on the correct
// trait dispatch - instead both impls call this function directly and
// explicitly.
#[inline(always)]
fn local_raw_waker<W: LocalWake + 'static>(waker: Rc<W>) -> RawWaker {
// Increment the reference count of the Rc to clone it.
unsafe fn clone_waker<W: LocalWake + 'static>(waker: *const ()) -> RawWaker {
unsafe { Rc::increment_strong_count(waker as *const W) };
RawWaker::new(
waker as *const (),
&RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
)
}
// Wake by value, moving the Rc into the LocalWake::wake function
unsafe fn wake<W: LocalWake + 'static>(waker: *const ()) {
let waker = unsafe { Rc::from_raw(waker as *const W) };
<W as LocalWake>::wake(waker);
}
// Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
unsafe fn wake_by_ref<W: LocalWake + 'static>(waker: *const ()) {
let waker = unsafe { ManuallyDrop::new(Rc::from_raw(waker as *const W)) };
<W as LocalWake>::wake_by_ref(&waker);
}
// Decrement the reference count of the Rc on drop
unsafe fn drop_waker<W: LocalWake + 'static>(waker: *const ()) {
unsafe { Rc::decrement_strong_count(waker as *const W) };
}
RawWaker::new(
Rc::into_raw(waker) as *const (),
&RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
)
}

View File

@ -2,36 +2,36 @@ use crate::cmp::BytewiseEq;
use crate::convert::TryInto;
#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N]
impl<T, U, const N: usize> PartialEq<[U; N]> for [T; N]
where
A: PartialEq<B>,
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &[B; N]) -> bool {
fn eq(&self, other: &[U; N]) -> bool {
SpecArrayEq::spec_eq(self, other)
}
#[inline]
fn ne(&self, other: &[B; N]) -> bool {
fn ne(&self, other: &[U; N]) -> bool {
SpecArrayEq::spec_ne(self, other)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<[B]> for [A; N]
impl<T, U, const N: usize> PartialEq<[U]> for [T; N]
where
A: PartialEq<B>,
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &[B]) -> bool {
let b: Result<&[B; N], _> = other.try_into();
fn eq(&self, other: &[U]) -> bool {
let b: Result<&[U; N], _> = other.try_into();
match b {
Ok(b) => *self == *b,
Err(_) => false,
}
}
#[inline]
fn ne(&self, other: &[B]) -> bool {
let b: Result<&[B; N], _> = other.try_into();
fn ne(&self, other: &[U]) -> bool {
let b: Result<&[U; N], _> = other.try_into();
match b {
Ok(b) => *self != *b,
Err(_) => true,
@ -40,21 +40,21 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<[A; N]> for [B]
impl<T, U, const N: usize> PartialEq<[U; N]> for [T]
where
B: PartialEq<A>,
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &[A; N]) -> bool {
let b: Result<&[B; N], _> = self.try_into();
fn eq(&self, other: &[U; N]) -> bool {
let b: Result<&[T; N], _> = self.try_into();
match b {
Ok(b) => *b == *other,
Err(_) => false,
}
}
#[inline]
fn ne(&self, other: &[A; N]) -> bool {
let b: Result<&[B; N], _> = self.try_into();
fn ne(&self, other: &[U; N]) -> bool {
let b: Result<&[T; N], _> = self.try_into();
match b {
Ok(b) => *b != *other,
Err(_) => true,
@ -63,61 +63,61 @@ where
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<&[B]> for [A; N]
impl<T, U, const N: usize> PartialEq<&[U]> for [T; N]
where
A: PartialEq<B>,
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &&[B]) -> bool {
fn eq(&self, other: &&[U]) -> bool {
*self == **other
}
#[inline]
fn ne(&self, other: &&[B]) -> bool {
fn ne(&self, other: &&[U]) -> bool {
*self != **other
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<[A; N]> for &[B]
impl<T, U, const N: usize> PartialEq<[U; N]> for &[T]
where
B: PartialEq<A>,
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &[A; N]) -> bool {
fn eq(&self, other: &[U; N]) -> bool {
**self == *other
}
#[inline]
fn ne(&self, other: &[A; N]) -> bool {
fn ne(&self, other: &[U; N]) -> bool {
**self != *other
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<&mut [B]> for [A; N]
impl<T, U, const N: usize> PartialEq<&mut [U]> for [T; N]
where
A: PartialEq<B>,
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &&mut [B]) -> bool {
fn eq(&self, other: &&mut [U]) -> bool {
*self == **other
}
#[inline]
fn ne(&self, other: &&mut [B]) -> bool {
fn ne(&self, other: &&mut [U]) -> bool {
*self != **other
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, const N: usize> PartialEq<[A; N]> for &mut [B]
impl<T, U, const N: usize> PartialEq<[U; N]> for &mut [T]
where
B: PartialEq<A>,
T: PartialEq<U>,
{
#[inline]
fn eq(&self, other: &[A; N]) -> bool {
fn eq(&self, other: &[U; N]) -> bool {
**self == *other
}
#[inline]
fn ne(&self, other: &[A; N]) -> bool {
fn ne(&self, other: &[U; N]) -> bool {
**self != *other
}
}

View File

@ -61,11 +61,13 @@ use self::Ordering::*;
/// The equality relation `==` must satisfy the following conditions
/// (for all `a`, `b`, `c` of type `A`, `B`, `C`):
///
/// - **Symmetric**: if `A: PartialEq<B>` and `B: PartialEq<A>`, then **`a == b`
/// - **Symmetry**: if `A: PartialEq<B>` and `B: PartialEq<A>`, then **`a == b`
/// implies `b == a`**; and
///
/// - **Transitive**: if `A: PartialEq<B>` and `B: PartialEq<C>` and `A:
/// - **Transitivity**: if `A: PartialEq<B>` and `B: PartialEq<C>` and `A:
/// PartialEq<C>`, then **`a == b` and `b == c` implies `a == c`**.
/// This must also work for longer chains, such as when `A: PartialEq<B>`, `B: PartialEq<C>`,
/// `C: PartialEq<D>`, and `A: PartialEq<D>` all exist.
///
/// Note that the `B: PartialEq<A>` (symmetric) and `A: PartialEq<C>`
/// (transitive) impls are not forced to exist, but these requirements apply
@ -76,6 +78,25 @@ use self::Ordering::*;
/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
/// methods.
///
/// ## Cross-crate considerations
///
/// Upholding the requirements stated above can become tricky when one crate implements `PartialEq`
/// for a type of another crate (i.e., to allow comparing one of its own types with a type from the
/// standard library). The recommendation is to never implement this trait for a foreign type. In
/// other words, such a crate should do `impl PartialEq<ForeignType> for LocalType`, but it should
/// *not* do `impl PartialEq<LocalType> for ForeignType`.
///
/// This avoids the problem of transitive chains that criss-cross crate boundaries: for all local
/// types `T`, you may assume that no other crate will add `impl`s that allow comparing `T == U`. In
/// other words, if other crates add `impl`s that allow building longer transitive chains `U1 == ...
/// == T == V1 == ...`, then all the types that appear to the right of `T` must be types that the
/// crate defining `T` already knows about. This rules out transitive chains where downstream crates
/// can add new `impl`s that "stitch together" comparisons of foreign types in ways that violate
/// transitivity.
///
/// Not having such foreign `impl`s also avoids forward compatibility issues where one crate adding
/// more `PartialEq` implementations can cause build failures in downstream crates.
///
/// ## Derivable
///
/// This trait can be used with `#[derive]`. When `derive`d on structs, two
@ -920,20 +941,43 @@ pub macro Ord($item:item) {
/// easy to accidentally make them disagree by deriving some of the traits and manually
/// implementing others.
///
/// The comparison must satisfy, for all `a`, `b` and `c`:
/// The comparison relations must satisfy the following conditions
/// (for all `a`, `b`, `c` of type `A`, `B`, `C`):
///
/// - transitivity: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
/// - duality: `a < b` if and only if `b > a`.
/// - **Transitivity**: if `A: PartialOrd<B>` and `B: PartialOrd<C>` and `A:
/// PartialOrd<C>`, then `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
/// This must also work for longer chains, such as when `A: PartialOrd<B>`, `B: PartialOrd<C>`,
/// `C: 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`.
///
/// Note that these requirements mean that the trait itself must be implemented symmetrically and
/// transitively: if `T: PartialOrd<U>` and `U: PartialOrd<V>` then `U: PartialOrd<T>` and `T:
/// PartialOrd<V>`.
/// Note that the `B: PartialOrd<A>` (dual) and `A: PartialOrd<C>`
/// (transitive) impls are not forced to exist, but these requirements apply
/// whenever they do exist.
///
/// 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
/// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these
/// methods.
///
/// ## Cross-crate considerations
///
/// Upholding the requirements stated above can become tricky when one crate implements `PartialOrd`
/// for a type of another crate (i.e., to allow comparing one of its own types with a type from the
/// standard library). The recommendation is to never implement this trait for a foreign type. In
/// other words, such a crate should do `impl PartialOrd<ForeignType> for LocalType`, but it should
/// *not* do `impl PartialOrd<LocalType> for ForeignType`.
///
/// This avoids the problem of transitive chains that criss-cross crate boundaries: for all local
/// types `T`, you may assume that no other crate will add `impl`s that allow comparing `T < U`. In
/// other words, if other crates add `impl`s that allow building longer transitive chains `U1 < ...
/// < T < V1 < ...`, then all the types that appear to the right of `T` must be types that the crate
/// defining `T` already knows about. This rules out transitive chains where downstream crates can
/// add new `impl`s that "stitch together" comparisons of foreign types in ways that violate
/// transitivity.
///
/// Not having such foreign `impl`s also avoids forward compatibility issues where one crate adding
/// more `PartialOrd` implementations can cause build failures in downstream crates.
///
/// ## Corollaries
///
/// The following corollaries follow from the above requirements:

View File

@ -8,15 +8,15 @@ use super::from_raw_parts;
use super::memchr;
#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B> PartialEq<[B]> for [A]
impl<T, U> PartialEq<[U]> for [T]
where
A: PartialEq<B>,
T: PartialEq<U>,
{
fn eq(&self, other: &[B]) -> bool {
fn eq(&self, other: &[U]) -> bool {
SlicePartialEq::equal(self, other)
}
fn ne(&self, other: &[B]) -> bool {
fn ne(&self, other: &[U]) -> bool {
SlicePartialEq::not_equal(self, other)
}
}

View File

@ -8,7 +8,7 @@ pub use self::poll::Poll;
mod wake;
#[stable(feature = "futures_api", since = "1.36.0")]
pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker};
pub use self::wake::{Context, ContextBuilder, LocalWaker, RawWaker, RawWakerVTable, Waker};
mod ready;
#[stable(feature = "ready_macro", since = "1.64.0")]

View File

@ -1,11 +1,13 @@
#![stable(feature = "futures_api", since = "1.36.0")]
use crate::mem::transmute;
use crate::fmt;
use crate::marker::PhantomData;
use crate::ptr;
/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
/// which provides customized wakeup behavior.
/// or a [`LocalWaker`] which provides customized wakeup behavior.
///
/// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table
///
@ -33,9 +35,18 @@ impl RawWaker {
/// The value of this pointer will get passed to all functions that are part
/// of the `vtable` as the first parameter.
///
/// It is important to consider that the `data` pointer must point to a
/// thread safe type such as an `[Arc]<T: Send + Sync>`
/// when used to construct a [`Waker`]. This restriction is lifted when
/// constructing a [`LocalWaker`], which allows using types that do not implement
/// <code>[Send] + [Sync]</code> like `[Rc]<T>`.
///
/// The `vtable` customizes the behavior of a `Waker` which gets created
/// from a `RawWaker`. For each operation on the `Waker`, the associated
/// function in the `vtable` of the underlying `RawWaker` will be called.
///
/// [`Arc`]: std::sync::Arc
/// [`Rc`]: std::rc::Rc
#[inline]
#[rustc_promotable]
#[stable(feature = "futures_api", since = "1.36.0")]
@ -60,6 +71,21 @@ impl RawWaker {
pub fn vtable(&self) -> &'static RawWakerVTable {
self.vtable
}
#[unstable(feature = "noop_waker", issue = "98286")]
const NOOP: RawWaker = {
const VTABLE: RawWakerVTable = RawWakerVTable::new(
// Cloning just returns a new no-op raw waker
|_| RawWaker::NOOP,
// `wake` does nothing
|_| {},
// `wake_by_ref` does nothing
|_| {},
// Dropping does nothing as we don't allocate anything
|_| {},
);
RawWaker::new(ptr::null(), &VTABLE)
};
}
/// A virtual function pointer table (vtable) that specifies the behavior
@ -73,11 +99,19 @@ impl RawWaker {
/// [`RawWaker`] implementation. Calling one of the contained functions using
/// any other `data` pointer will cause undefined behavior.
///
/// These functions must all be thread-safe (even though [`RawWaker`] is
/// <code>\![Send] + \![Sync]</code>)
/// because [`Waker`] is <code>[Send] + [Sync]</code>, and thus wakers may be moved to
/// arbitrary threads or invoked by `&` reference. For example, this means that if the
/// `clone` and `drop` functions manage a reference count, they must do so atomically.
/// # Thread safety
/// If the [`RawWaker`] will be used to construct a [`Waker`] then
/// these functions must all be thread-safe (even though [`RawWaker`] is
/// <code>\![Send] + \![Sync]</code>). This is because [`Waker`] is <code>[Send] + [Sync]</code>,
/// and it may be moved to arbitrary threads or invoked by `&` reference. For example,
/// this means that if the `clone` and `drop` functions manage a reference count,
/// they must do so atomically.
///
/// However, if the [`RawWaker`] will be used to construct a [`LocalWaker`] instead, then
/// these functions don't need to be thread safe. This means that <code>\![Send] + \![Sync]</code>
/// data can be stored in the data pointer, and reference counting does not need any atomic
/// synchronization. This is because [`LocalWaker`] is not thread safe itself, so it cannot
/// be sent across threads.
#[stable(feature = "futures_api", since = "1.36.0")]
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
@ -117,16 +151,22 @@ impl RawWakerVTable {
/// Creates a new `RawWakerVTable` from the provided `clone`, `wake`,
/// `wake_by_ref`, and `drop` functions.
///
/// These functions must all be thread-safe (even though [`RawWaker`] is
/// <code>\![Send] + \![Sync]</code>)
/// because [`Waker`] is <code>[Send] + [Sync]</code>, and thus wakers may be moved to
/// arbitrary threads or invoked by `&` reference. For example, this means that if the
/// `clone` and `drop` functions manage a reference count, they must do so atomically.
/// If the [`RawWaker`] will be used to construct a [`Waker`] then
/// these functions must all be thread-safe (even though [`RawWaker`] is
/// <code>\![Send] + \![Sync]</code>). This is because [`Waker`] is <code>[Send] + [Sync]</code>,
/// and it may be moved to arbitrary threads or invoked by `&` reference. For example,
/// this means that if the `clone` and `drop` functions manage a reference count,
/// they must do so atomically.
///
/// However, if the [`RawWaker`] will be used to construct a [`LocalWaker`] instead, then
/// these functions don't need to be thread safe. This means that <code>\![Send] + \![Sync]</code>
/// data can be stored in the data pointer, and reference counting does not need any atomic
/// synchronization. This is because [`LocalWaker`] is not thread safe itself, so it cannot
/// be sent across threads.
/// # `clone`
///
/// This function will be called when the [`RawWaker`] gets cloned, e.g. when
/// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
/// the [`Waker`]/[`LocalWaker`] in which the [`RawWaker`] is stored gets cloned.
///
/// The implementation of this function must retain all resources that are
/// required for this additional instance of a [`RawWaker`] and associated
@ -152,7 +192,7 @@ impl RawWakerVTable {
///
/// # `drop`
///
/// This function gets called when a [`Waker`] gets dropped.
/// This function gets called when a [`Waker`]/[`LocalWaker`] gets dropped.
///
/// The implementation of this function must make sure to release any
/// resources that are associated with this instance of a [`RawWaker`] and
@ -178,6 +218,7 @@ impl RawWakerVTable {
#[lang = "Context"]
pub struct Context<'a> {
waker: &'a Waker,
local_waker: &'a LocalWaker,
// Ensure we future-proof against variance changes by forcing
// the lifetime to be invariant (argument-position lifetimes
// are contravariant while return-position lifetimes are
@ -195,17 +236,24 @@ impl<'a> Context<'a> {
#[must_use]
#[inline]
pub const fn from_waker(waker: &'a Waker) -> Self {
Context { waker, _marker: PhantomData, _marker2: PhantomData }
ContextBuilder::from_waker(waker).build()
}
/// Returns a reference to the [`Waker`] for the current task.
#[inline]
#[must_use]
#[stable(feature = "futures_api", since = "1.36.0")]
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
#[must_use]
#[inline]
pub const fn waker(&self) -> &'a Waker {
&self.waker
}
/// Returns a reference to the [`LocalWaker`] for the current task.
#[inline]
#[unstable(feature = "local_waker", issue = "118959")]
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
pub const fn local_waker(&self) -> &'a LocalWaker {
&self.local_waker
}
}
#[stable(feature = "futures_api", since = "1.36.0")]
@ -215,6 +263,72 @@ impl fmt::Debug for Context<'_> {
}
}
/// A Builder used to construct a `Context` instance
/// with support for `LocalWaker`.
///
/// # Examples
/// ```
/// #![feature(local_waker)]
/// #![feature(noop_waker)]
/// use std::task::{ContextBuilder, LocalWaker, Waker, Poll};
/// use std::future::Future;
///
/// let local_waker = LocalWaker::noop();
/// let waker = Waker::noop();
///
/// let mut cx = ContextBuilder::from_waker(&waker)
/// .local_waker(&local_waker)
/// .build();
///
/// let mut future = std::pin::pin!(async { 20 });
/// let poll = future.as_mut().poll(&mut cx);
/// assert_eq!(poll, Poll::Ready(20));
///
/// ```
#[unstable(feature = "local_waker", issue = "118959")]
#[derive(Debug)]
pub struct ContextBuilder<'a> {
waker: &'a Waker,
local_waker: &'a LocalWaker,
// Ensure we future-proof against variance changes by forcing
// the lifetime to be invariant (argument-position lifetimes
// are contravariant while return-position lifetimes are
// covariant).
_marker: PhantomData<fn(&'a ()) -> &'a ()>,
// Ensure `Context` is `!Send` and `!Sync` in order to allow
// for future `!Send` and / or `!Sync` fields.
_marker2: PhantomData<*mut ()>,
}
impl<'a> ContextBuilder<'a> {
/// Create a ContextBuilder from a Waker.
#[inline]
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
#[unstable(feature = "local_waker", issue = "118959")]
pub const fn from_waker(waker: &'a Waker) -> Self {
// SAFETY: LocalWaker is just Waker without thread safety
let local_waker = unsafe { transmute(waker) };
Self { waker: waker, local_waker, _marker: PhantomData, _marker2: PhantomData }
}
/// This method is used to set the value for the local waker on `Context`.
#[inline]
#[unstable(feature = "local_waker", issue = "118959")]
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
pub const fn local_waker(self, local_waker: &'a LocalWaker) -> Self {
Self { local_waker, ..self }
}
/// Builds the `Context`.
#[inline]
#[unstable(feature = "local_waker", issue = "118959")]
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
pub const fn build(self) -> Context<'a> {
let ContextBuilder { waker, local_waker, _marker, _marker2 } = self;
Context { waker, local_waker, _marker, _marker2 }
}
}
/// A `Waker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
@ -354,25 +468,8 @@ impl Waker {
#[must_use]
#[unstable(feature = "noop_waker", issue = "98286")]
pub const fn noop() -> &'static Waker {
// Ideally all this data would be explicitly `static` because it is used by reference and
// only ever needs one copy. But `const fn`s (and `const` items) cannot refer to statics,
// even though their values can be promoted to static. (That might change; see #119618.)
// An alternative would be a `pub static NOOP: &Waker`, but associated static items are not
// currently allowed either, and making it non-associated would be unergonomic.
const VTABLE: RawWakerVTable = RawWakerVTable::new(
// Cloning just returns a new no-op raw waker
|_| RAW,
// `wake` does nothing
|_| {},
// `wake_by_ref` does nothing
|_| {},
// Dropping does nothing as we don't allocate anything
|_| {},
);
const RAW: RawWaker = RawWaker::new(ptr::null(), &VTABLE);
const WAKER_REF: &Waker = &Waker { waker: RAW };
WAKER_REF
const WAKER: &Waker = &Waker { waker: RawWaker::NOOP };
WAKER
}
/// Get a reference to the underlying [`RawWaker`].
@ -425,3 +522,222 @@ impl fmt::Debug for Waker {
.finish()
}
}
/// A `LocalWaker` is analogous to a [`Waker`], but it does not implement [`Send`] or [`Sync`].
///
/// This handle encapsulates a [`RawWaker`] instance, which defines the
/// executor-specific wakeup behavior.
///
/// Local wakers can be requested from a `Context` with the [`local_waker`] method.
///
/// The typical life of a `LocalWaker` is that it is constructed by an executor, wrapped in a
/// [`Context`] using [`ContextBuilder`], then passed to [`Future::poll()`]. Then, if the future chooses to return
/// [`Poll::Pending`], it must also store the waker somehow and call [`LocalWaker::wake()`] when
/// the future should be polled again.
///
/// Implements [`Clone`], but neither [`Send`] nor [`Sync`]; therefore, a local waker may
/// not be moved to other threads. In general, when deciding to use wakers or local wakers,
/// local wakers are preferable unless the waker needs to be sent across threads. This is because
/// wakers can incur in additional cost related to memory synchronization.
///
/// Note that it is preferable to use `local_waker.clone_from(&new_waker)` instead
/// of `*local_waker = new_waker.clone()`, as the former will avoid cloning the waker
/// unnecessarily if the two wakers [wake the same task](Self::will_wake).
///
/// # Examples
/// Usage of a local waker to implement a future analogous to `std::thread::yield_now()`.
/// ```
/// #![feature(local_waker)]
/// use std::future::{Future, poll_fn};
/// use std::task::Poll;
///
/// // a future that returns pending once.
/// fn yield_now() -> impl Future<Output=()> + Unpin {
/// let mut yielded = false;
/// poll_fn(move |cx| {
/// if !yielded {
/// yielded = true;
/// cx.local_waker().wake_by_ref();
/// return Poll::Pending;
/// }
/// return Poll::Ready(())
/// })
/// }
///
/// # async fn __() {
/// yield_now().await;
/// # }
/// ```
///
/// [`Future::poll()`]: core::future::Future::poll
/// [`Poll::Pending`]: core::task::Poll::Pending
/// [`local_waker`]: core::task::Context::local_waker
#[unstable(feature = "local_waker", issue = "118959")]
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/66401
pub struct LocalWaker {
waker: RawWaker,
}
#[unstable(feature = "local_waker", issue = "118959")]
impl Unpin for LocalWaker {}
impl LocalWaker {
/// Wake up the task associated with this `LocalWaker`.
///
/// As long as the executor keeps running and the task is not finished, it is
/// guaranteed that each invocation of [`wake()`](Self::wake) (or
/// [`wake_by_ref()`](Self::wake_by_ref)) will be followed by at least one
/// [`poll()`] of the task to which this `LocalWaker` belongs. This makes
/// it possible to temporarily yield to other tasks while running potentially
/// unbounded processing loops.
///
/// Note that the above implies that multiple wake-ups may be coalesced into a
/// single [`poll()`] invocation by the runtime.
///
/// Also note that yielding to competing tasks is not guaranteed: it is the
/// executors choice which task to run and the executor may choose to run the
/// current task again.
///
/// [`poll()`]: crate::future::Future::poll
#[inline]
#[stable(feature = "futures_api", since = "1.36.0")]
pub fn wake(self) {
// The actual wakeup call is delegated through a virtual function call
// to the implementation which is defined by the executor.
let wake = self.waker.vtable.wake;
let data = self.waker.data;
// Don't call `drop` -- the waker will be consumed by `wake`.
crate::mem::forget(self);
// SAFETY: This is safe because `Waker::from_raw` is the only way
// to initialize `wake` and `data` requiring the user to acknowledge
// that the contract of `RawWaker` is upheld.
unsafe { (wake)(data) };
}
/// Wake up the task associated with this `LocalWaker` without consuming the `LocalWaker`.
///
/// This is similar to [`wake()`](Self::wake), but may be slightly less efficient in
/// the case where an owned `Waker` is available. This method should be preferred to
/// calling `waker.clone().wake()`.
#[inline]
#[stable(feature = "futures_api", since = "1.36.0")]
pub fn wake_by_ref(&self) {
// The actual wakeup call is delegated through a virtual function call
// to the implementation which is defined by the executor.
// SAFETY: see `wake`
unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) }
}
/// Returns `true` if this `LocalWaker` and another `LocalWaker` would awake the same task.
///
/// This function works on a best-effort basis, and may return false even
/// when the `Waker`s would awaken the same task. However, if this function
/// returns `true`, it is guaranteed that the `Waker`s will awaken the same task.
///
/// This function is primarily used for optimization purposes — for example,
/// this type's [`clone_from`](Self::clone_from) implementation uses it to
/// avoid cloning the waker when they would wake the same task anyway.
#[inline]
#[must_use]
#[stable(feature = "futures_api", since = "1.36.0")]
pub fn will_wake(&self, other: &LocalWaker) -> bool {
self.waker == other.waker
}
/// Creates a new `LocalWaker` from [`RawWaker`].
///
/// The behavior of the returned `LocalWaker` is undefined if the contract defined
/// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
/// Therefore this method is unsafe.
#[inline]
#[must_use]
#[stable(feature = "futures_api", since = "1.36.0")]
#[rustc_const_unstable(feature = "const_waker", issue = "102012")]
pub const unsafe fn from_raw(waker: RawWaker) -> LocalWaker {
Self { waker }
}
/// Creates a new `LocalWaker` that does nothing when `wake` is called.
///
/// This is mostly useful for writing tests that need a [`Context`] to poll
/// some futures, but are not expecting those futures to wake the waker or
/// do not need to do anything specific if it happens.
///
/// # Examples
///
/// ```
/// #![feature(local_waker)]
/// #![feature(noop_waker)]
///
/// use std::future::Future;
/// use std::task::{ContextBuilder, LocalWaker, Waker, Poll};
///
/// let mut cx = ContextBuilder::from_waker(Waker::noop())
/// .local_waker(LocalWaker::noop())
/// .build();
///
/// let mut future = Box::pin(async { 10 });
/// assert_eq!(future.as_mut().poll(&mut cx), Poll::Ready(10));
/// ```
#[inline]
#[must_use]
#[unstable(feature = "noop_waker", issue = "98286")]
pub const fn noop() -> &'static LocalWaker {
const WAKER: &LocalWaker = &LocalWaker { waker: RawWaker::NOOP };
WAKER
}
/// Get a reference to the underlying [`RawWaker`].
#[inline]
#[must_use]
#[unstable(feature = "waker_getters", issue = "96992")]
pub fn as_raw(&self) -> &RawWaker {
&self.waker
}
}
#[unstable(feature = "local_waker", issue = "118959")]
impl Clone for LocalWaker {
#[inline]
fn clone(&self) -> Self {
LocalWaker {
// SAFETY: This is safe because `Waker::from_raw` is the only way
// to initialize `clone` and `data` requiring the user to acknowledge
// that the contract of [`RawWaker`] is upheld.
waker: unsafe { (self.waker.vtable.clone)(self.waker.data) },
}
}
#[inline]
fn clone_from(&mut self, source: &Self) {
if !self.will_wake(source) {
*self = source.clone();
}
}
}
#[unstable(feature = "local_waker", issue = "118959")]
impl AsRef<LocalWaker> for Waker {
fn as_ref(&self) -> &LocalWaker {
// SAFETY: LocalWaker is just Waker without thread safety
unsafe { transmute(self) }
}
}
#[stable(feature = "futures_api", since = "1.36.0")]
impl fmt::Debug for LocalWaker {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let vtable_ptr = self.waker.vtable as *const RawWakerVTable;
f.debug_struct("LocalWaker")
.field("data", &self.waker.data)
.field("vtable", &vtable_ptr)
.finish()
}
}
#[unstable(feature = "local_waker", issue = "118959")]
impl !Send for LocalWaker {}
#[unstable(feature = "local_waker", issue = "118959")]
impl !Sync for LocalWaker {}

View File

@ -542,7 +542,4 @@ pub mod netc {
pub sin6_flowinfo: u32,
pub sin6_scope_id: u32,
}
#[derive(Copy, Clone)]
pub struct sockaddr {}
}

View File

@ -364,9 +364,6 @@ pub mod netc {
pub sin6_flowinfo: u32,
pub sin6_scope_id: u32,
}
#[derive(Copy, Clone)]
pub struct sockaddr {}
}
pub type Socket = UdpSocket;

View File

@ -78,7 +78,4 @@ pub mod netc {
pub sin6_flowinfo: u32,
pub sin6_scope_id: u32,
}
#[derive(Copy, Clone)]
pub struct sockaddr {}
}

View File

@ -20,12 +20,8 @@ mod rustc_ok {
pub fn rustc_lints() {
let x = 42.0;
#[expect(illegal_floating_point_literal_pattern)]
match x {
5.0 => {}
6.0 => {}
_ => {}
}
#[expect(invalid_nan_comparisons)]
let _b = x == f32::NAN;
}
}
@ -38,13 +34,9 @@ mod rustc_warn {
pub fn rustc_lints() {
let x = 42;
#[expect(illegal_floating_point_literal_pattern)]
#[expect(invalid_nan_comparisons)]
//~^ ERROR: this lint expectation is unfulfilled
match x {
5 => {}
6 => {}
_ => {}
}
let _b = x == 5;
}
}

View File

@ -1,5 +1,5 @@
error: this lint expectation is unfulfilled
--> $DIR/expect_tool_lint_rfc_2383.rs:35:14
--> $DIR/expect_tool_lint_rfc_2383.rs:31:14
|
LL | #[expect(dead_code)]
| ^^^^^^^^^
@ -8,31 +8,31 @@ LL | #[expect(dead_code)]
= help: to override `-D warnings` add `#[allow(unfulfilled_lint_expectations)]`
error: this lint expectation is unfulfilled
--> $DIR/expect_tool_lint_rfc_2383.rs:41:18
--> $DIR/expect_tool_lint_rfc_2383.rs:37:18
|
LL | #[expect(illegal_floating_point_literal_pattern)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[expect(invalid_nan_comparisons)]
| ^^^^^^^^^^^^^^^^^^^^^^^
error: this lint expectation is unfulfilled
--> $DIR/expect_tool_lint_rfc_2383.rs:116:14
--> $DIR/expect_tool_lint_rfc_2383.rs:108:14
|
LL | #[expect(clippy::almost_swapped)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: this lint expectation is unfulfilled
--> $DIR/expect_tool_lint_rfc_2383.rs:124:14
--> $DIR/expect_tool_lint_rfc_2383.rs:116:14
|
LL | #[expect(clippy::bytes_nth)]
| ^^^^^^^^^^^^^^^^^
error: this lint expectation is unfulfilled
--> $DIR/expect_tool_lint_rfc_2383.rs:130:14
--> $DIR/expect_tool_lint_rfc_2383.rs:122:14
|
LL | #[expect(clippy::if_same_then_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: this lint expectation is unfulfilled
--> $DIR/expect_tool_lint_rfc_2383.rs:136:14
--> $DIR/expect_tool_lint_rfc_2383.rs:128:14
|
LL | #[expect(clippy::overly_complex_bool_expr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -24,10 +24,9 @@ mod rustc_ok {
pub fn rustc_lints() {
let x = 42.0;
#[expect(illegal_floating_point_literal_pattern)]
#[expect(invalid_nan_comparisons)]
match x {
5.0 => {}
6.0 => {}
f32::NAN => {}
_ => {}
}
}
@ -40,7 +39,7 @@ mod rustc_warn {
pub fn rustc_lints() {
let x = 42;
#[expect(illegal_floating_point_literal_pattern)]
#[expect(invalid_nan_comparisons)]
match x {
5 => {}
6 => {}

View File

@ -7,19 +7,19 @@ LL | #![expect(rustdoc::missing_crate_level_docs)]
= note: `#[warn(unfulfilled_lint_expectations)]` on by default
warning: this lint expectation is unfulfilled
--> $DIR/expect-tool-lint-rfc-2383.rs:71:14
--> $DIR/expect-tool-lint-rfc-2383.rs:70:14
|
LL | #[expect(rustdoc::broken_intra_doc_links)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: this lint expectation is unfulfilled
--> $DIR/expect-tool-lint-rfc-2383.rs:76:14
--> $DIR/expect-tool-lint-rfc-2383.rs:75:14
|
LL | #[expect(rustdoc::invalid_html_tags)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: this lint expectation is unfulfilled
--> $DIR/expect-tool-lint-rfc-2383.rs:81:14
--> $DIR/expect-tool-lint-rfc-2383.rs:80:14
|
LL | #[expect(rustdoc::bare_urls)]
| ^^^^^^^^^^^^^^^^^^

View File

@ -1,5 +1,4 @@
// run-pass
#![allow(illegal_floating_point_literal_pattern)] // FIXME #41620
pub fn main() {
let x = [1, 2, 3];

View File

@ -1,5 +1,4 @@
// run-pass
#![allow(illegal_floating_point_literal_pattern)] // FIXME #41620
#![feature(exclusive_range_pattern)]
pub fn main() {

View File

@ -22,13 +22,13 @@ LL | [5; Self::HOST_SIZE] == [6; 0]
|
= help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; Self::HOST_SIZE]`
= help: the following other types implement trait `PartialEq<Rhs>`:
<[A; N] as PartialEq<[B; N]>>
<[A; N] as PartialEq<[B]>>
<[A; N] as PartialEq<&[B]>>
<[A; N] as PartialEq<&mut [B]>>
<[T; N] as PartialEq<[U; N]>>
<[T; N] as PartialEq<[U]>>
<[T; N] as PartialEq<&[U]>>
<[T; N] as PartialEq<&mut [U]>>
<[T] as PartialEq<Vec<U, A>>>
<[A] as PartialEq<[B]>>
<[B] as PartialEq<[A; N]>>
<[T] as PartialEq<[U; N]>>
<[T] as PartialEq<[U]>>
<&[T] as PartialEq<Vec<U, A>>>
and 3 others

View File

@ -1,7 +1,6 @@
// Test various non-exhaustive matches for `X..`, `..=X` and `..X` ranges.
#![feature(exclusive_range_pattern)]
#![allow(illegal_floating_point_literal_pattern)]
fn main() {}

View File

@ -1,5 +1,5 @@
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:15:8
--> $DIR/half-open-range-pats-exhaustive-fail.rs:14:8
|
LL | m!(0f32, f32::NEG_INFINITY..);
| ^^^^ pattern `_` not covered
@ -11,7 +11,7 @@ LL | match $s { $($t)+ => {}, _ => todo!() }
| ++++++++++++++
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:16:8
--> $DIR/half-open-range-pats-exhaustive-fail.rs:15:8
|
LL | m!(0f32, ..f32::INFINITY);
| ^^^^ pattern `_` not covered
@ -23,7 +23,7 @@ LL | match $s { $($t)+ => {}, _ => todo!() }
| ++++++++++++++
error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:25:8
--> $DIR/half-open-range-pats-exhaustive-fail.rs:24:8
|
LL | m!('a', ..core::char::MAX);
| ^^^ pattern `'\u{10ffff}'` not covered
@ -35,7 +35,7 @@ LL | match $s { $($t)+ => {}, '\u{10ffff}' => todo!() }
| +++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8
--> $DIR/half-open-range-pats-exhaustive-fail.rs:25:8
|
LL | m!('a', ..ALMOST_MAX);
| ^^^ pattern `'\u{10fffe}'..='\u{10ffff}'` not covered
@ -47,7 +47,7 @@ LL | match $s { $($t)+ => {}, '\u{10fffe}'..='\u{10ffff}' => todo!() }
| ++++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `'\0'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8
--> $DIR/half-open-range-pats-exhaustive-fail.rs:26:8
|
LL | m!('a', ALMOST_MIN..);
| ^^^ pattern `'\0'` not covered
@ -59,7 +59,7 @@ LL | match $s { $($t)+ => {}, '\0' => todo!() }
| +++++++++++++++++
error[E0004]: non-exhaustive patterns: `'\u{10ffff}'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8
--> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8
|
LL | m!('a', ..=ALMOST_MAX);
| ^^^ pattern `'\u{10ffff}'` not covered
@ -71,7 +71,7 @@ LL | match $s { $($t)+ => {}, '\u{10ffff}' => todo!() }
| +++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `'b'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8
--> $DIR/half-open-range-pats-exhaustive-fail.rs:28:8
|
LL | m!('a', ..=VAL | VAL_2..);
| ^^^ pattern `'b'` not covered
@ -83,7 +83,7 @@ LL | match $s { $($t)+ => {}, 'b' => todo!() }
| ++++++++++++++++
error[E0004]: non-exhaustive patterns: `'b'` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:30:8
--> $DIR/half-open-range-pats-exhaustive-fail.rs:29:8
|
LL | m!('a', ..VAL_1 | VAL_2..);
| ^^^ pattern `'b'` not covered
@ -95,7 +95,7 @@ LL | match $s { $($t)+ => {}, 'b' => todo!() }
| ++++++++++++++++
error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:40:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:39:12
|
LL | m!(0, ..u8::MAX);
| ^ pattern `u8::MAX` not covered
@ -107,7 +107,7 @@ LL | match $s { $($t)+ => {}, u8::MAX => todo!() }
| ++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:40:12
|
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `254_u8..=u8::MAX` not covered
@ -119,7 +119,7 @@ LL | match $s { $($t)+ => {}, 254_u8..=u8::MAX => todo!() }
| +++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `0_u8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:41:12
|
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u8` not covered
@ -131,7 +131,7 @@ LL | match $s { $($t)+ => {}, 0_u8 => todo!() }
| +++++++++++++++++
error[E0004]: non-exhaustive patterns: `u8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12
|
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u8::MAX` not covered
@ -143,7 +143,7 @@ LL | match $s { $($t)+ => {}, u8::MAX => todo!() }
| ++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_u8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:43:12
|
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u8` not covered
@ -155,7 +155,7 @@ LL | match $s { $($t)+ => {}, 43_u8 => todo!() }
| ++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_u8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:45:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:44:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u8` not covered
@ -167,7 +167,7 @@ LL | match $s { $($t)+ => {}, 43_u8 => todo!() }
| ++++++++++++++++++
error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:53:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:52:12
|
LL | m!(0, ..u16::MAX);
| ^ pattern `u16::MAX` not covered
@ -179,7 +179,7 @@ LL | match $s { $($t)+ => {}, u16::MAX => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:53:12
|
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `65534_u16..=u16::MAX` not covered
@ -191,7 +191,7 @@ LL | match $s { $($t)+ => {}, 65534_u16..=u16::MAX => todo!() }
| +++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `0_u16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:54:12
|
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u16` not covered
@ -203,7 +203,7 @@ LL | match $s { $($t)+ => {}, 0_u16 => todo!() }
| ++++++++++++++++++
error[E0004]: non-exhaustive patterns: `u16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12
|
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u16::MAX` not covered
@ -215,7 +215,7 @@ LL | match $s { $($t)+ => {}, u16::MAX => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_u16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:56:12
|
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u16` not covered
@ -227,7 +227,7 @@ LL | match $s { $($t)+ => {}, 43_u16 => todo!() }
| +++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_u16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:58:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:57:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u16` not covered
@ -239,7 +239,7 @@ LL | match $s { $($t)+ => {}, 43_u16 => todo!() }
| +++++++++++++++++++
error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:66:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:65:12
|
LL | m!(0, ..u32::MAX);
| ^ pattern `u32::MAX` not covered
@ -251,7 +251,7 @@ LL | match $s { $($t)+ => {}, u32::MAX => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:66:12
|
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `4294967294_u32..=u32::MAX` not covered
@ -263,7 +263,7 @@ LL | match $s { $($t)+ => {}, 4294967294_u32..=u32::MAX => todo!() }
| ++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `0_u32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:67:12
|
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u32` not covered
@ -275,7 +275,7 @@ LL | match $s { $($t)+ => {}, 0_u32 => todo!() }
| ++++++++++++++++++
error[E0004]: non-exhaustive patterns: `u32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12
|
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u32::MAX` not covered
@ -287,7 +287,7 @@ LL | match $s { $($t)+ => {}, u32::MAX => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_u32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:69:12
|
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u32` not covered
@ -299,7 +299,7 @@ LL | match $s { $($t)+ => {}, 43_u32 => todo!() }
| +++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_u32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:71:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:70:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u32` not covered
@ -311,7 +311,7 @@ LL | match $s { $($t)+ => {}, 43_u32 => todo!() }
| +++++++++++++++++++
error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:79:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:78:12
|
LL | m!(0, ..u64::MAX);
| ^ pattern `u64::MAX` not covered
@ -323,7 +323,7 @@ LL | match $s { $($t)+ => {}, u64::MAX => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:79:12
|
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `18446744073709551614_u64..=u64::MAX` not covered
@ -335,7 +335,7 @@ LL | match $s { $($t)+ => {}, 18446744073709551614_u64..=u64::MAX => tod
| ++++++++++++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `0_u64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:80:12
|
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u64` not covered
@ -347,7 +347,7 @@ LL | match $s { $($t)+ => {}, 0_u64 => todo!() }
| ++++++++++++++++++
error[E0004]: non-exhaustive patterns: `u64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12
|
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u64::MAX` not covered
@ -359,7 +359,7 @@ LL | match $s { $($t)+ => {}, u64::MAX => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_u64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:82:12
|
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u64` not covered
@ -371,7 +371,7 @@ LL | match $s { $($t)+ => {}, 43_u64 => todo!() }
| +++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_u64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:84:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:83:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u64` not covered
@ -383,7 +383,7 @@ LL | match $s { $($t)+ => {}, 43_u64 => todo!() }
| +++++++++++++++++++
error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:92:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:91:12
|
LL | m!(0, ..u128::MAX);
| ^ pattern `u128::MAX` not covered
@ -395,7 +395,7 @@ LL | match $s { $($t)+ => {}, u128::MAX => todo!() }
| ++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:92:12
|
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered
@ -407,7 +407,7 @@ LL | match $s { $($t)+ => {}, 340282366920938463463374607431768211454_u1
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `0_u128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:93:12
|
LL | m!(0, ALMOST_MIN..);
| ^ pattern `0_u128` not covered
@ -419,7 +419,7 @@ LL | match $s { $($t)+ => {}, 0_u128 => todo!() }
| +++++++++++++++++++
error[E0004]: non-exhaustive patterns: `u128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12
|
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `u128::MAX` not covered
@ -431,7 +431,7 @@ LL | match $s { $($t)+ => {}, u128::MAX => todo!() }
| ++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_u128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:95:12
|
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_u128` not covered
@ -443,7 +443,7 @@ LL | match $s { $($t)+ => {}, 43_u128 => todo!() }
| ++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_u128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:97:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:96:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_u128` not covered
@ -455,7 +455,7 @@ LL | match $s { $($t)+ => {}, 43_u128 => todo!() }
| ++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:108:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:107:12
|
LL | m!(0, ..i8::MAX);
| ^ pattern `i8::MAX` not covered
@ -467,7 +467,7 @@ LL | match $s { $($t)+ => {}, i8::MAX => todo!() }
| ++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:108:12
|
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `126_i8..=i8::MAX` not covered
@ -479,7 +479,7 @@ LL | match $s { $($t)+ => {}, 126_i8..=i8::MAX => todo!() }
| +++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i8::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:109:12
|
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i8::MIN` not covered
@ -491,7 +491,7 @@ LL | match $s { $($t)+ => {}, i8::MIN => todo!() }
| ++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i8::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12
|
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i8::MAX` not covered
@ -503,7 +503,7 @@ LL | match $s { $($t)+ => {}, i8::MAX => todo!() }
| ++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_i8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:111:12
|
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i8` not covered
@ -515,7 +515,7 @@ LL | match $s { $($t)+ => {}, 43_i8 => todo!() }
| ++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_i8` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:113:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:112:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i8` not covered
@ -527,7 +527,7 @@ LL | match $s { $($t)+ => {}, 43_i8 => todo!() }
| ++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:121:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:120:12
|
LL | m!(0, ..i16::MAX);
| ^ pattern `i16::MAX` not covered
@ -539,7 +539,7 @@ LL | match $s { $($t)+ => {}, i16::MAX => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:121:12
|
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `32766_i16..=i16::MAX` not covered
@ -551,7 +551,7 @@ LL | match $s { $($t)+ => {}, 32766_i16..=i16::MAX => todo!() }
| +++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i16::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:122:12
|
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i16::MIN` not covered
@ -563,7 +563,7 @@ LL | match $s { $($t)+ => {}, i16::MIN => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i16::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12
|
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i16::MAX` not covered
@ -575,7 +575,7 @@ LL | match $s { $($t)+ => {}, i16::MAX => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_i16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:124:12
|
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i16` not covered
@ -587,7 +587,7 @@ LL | match $s { $($t)+ => {}, 43_i16 => todo!() }
| +++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_i16` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:126:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:125:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i16` not covered
@ -599,7 +599,7 @@ LL | match $s { $($t)+ => {}, 43_i16 => todo!() }
| +++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:134:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:133:12
|
LL | m!(0, ..i32::MAX);
| ^ pattern `i32::MAX` not covered
@ -611,7 +611,7 @@ LL | match $s { $($t)+ => {}, i32::MAX => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:134:12
|
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `2147483646_i32..=i32::MAX` not covered
@ -623,7 +623,7 @@ LL | match $s { $($t)+ => {}, 2147483646_i32..=i32::MAX => todo!() }
| ++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i32::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:135:12
|
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i32::MIN` not covered
@ -635,7 +635,7 @@ LL | match $s { $($t)+ => {}, i32::MIN => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i32::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12
|
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i32::MAX` not covered
@ -647,7 +647,7 @@ LL | match $s { $($t)+ => {}, i32::MAX => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_i32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:137:12
|
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i32` not covered
@ -659,7 +659,7 @@ LL | match $s { $($t)+ => {}, 43_i32 => todo!() }
| +++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_i32` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:139:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:138:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i32` not covered
@ -671,7 +671,7 @@ LL | match $s { $($t)+ => {}, 43_i32 => todo!() }
| +++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:147:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:146:12
|
LL | m!(0, ..i64::MAX);
| ^ pattern `i64::MAX` not covered
@ -683,7 +683,7 @@ LL | match $s { $($t)+ => {}, i64::MAX => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:147:12
|
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `9223372036854775806_i64..=i64::MAX` not covered
@ -695,7 +695,7 @@ LL | match $s { $($t)+ => {}, 9223372036854775806_i64..=i64::MAX => todo
| +++++++++++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i64::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:148:12
|
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i64::MIN` not covered
@ -707,7 +707,7 @@ LL | match $s { $($t)+ => {}, i64::MIN => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i64::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12
|
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i64::MAX` not covered
@ -719,7 +719,7 @@ LL | match $s { $($t)+ => {}, i64::MAX => todo!() }
| +++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_i64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:150:12
|
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i64` not covered
@ -731,7 +731,7 @@ LL | match $s { $($t)+ => {}, 43_i64 => todo!() }
| +++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_i64` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:152:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:151:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i64` not covered
@ -743,7 +743,7 @@ LL | match $s { $($t)+ => {}, 43_i64 => todo!() }
| +++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:160:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:159:12
|
LL | m!(0, ..i128::MAX);
| ^ pattern `i128::MAX` not covered
@ -755,7 +755,7 @@ LL | match $s { $($t)+ => {}, i128::MAX => todo!() }
| ++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:160:12
|
LL | m!(0, ..ALMOST_MAX);
| ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered
@ -767,7 +767,7 @@ LL | match $s { $($t)+ => {}, 170141183460469231731687303715884105726_i1
| +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i128::MIN` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:161:12
|
LL | m!(0, ALMOST_MIN..);
| ^ pattern `i128::MIN` not covered
@ -779,7 +779,7 @@ LL | match $s { $($t)+ => {}, i128::MIN => todo!() }
| ++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `i128::MAX` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12
|
LL | m!(0, ..=ALMOST_MAX);
| ^ pattern `i128::MAX` not covered
@ -791,7 +791,7 @@ LL | match $s { $($t)+ => {}, i128::MAX => todo!() }
| ++++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_i128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:163:12
|
LL | m!(0, ..=VAL | VAL_2..);
| ^ pattern `43_i128` not covered
@ -803,7 +803,7 @@ LL | match $s { $($t)+ => {}, 43_i128 => todo!() }
| ++++++++++++++++++++
error[E0004]: non-exhaustive patterns: `43_i128` not covered
--> $DIR/half-open-range-pats-exhaustive-fail.rs:165:12
--> $DIR/half-open-range-pats-exhaustive-fail.rs:164:12
|
LL | m!(0, ..VAL_1 | VAL_2..);
| ^ pattern `43_i128` not covered

View File

@ -4,7 +4,6 @@
// via `.contains(...)` and make sure the dynamic semantics match.
#![feature(exclusive_range_pattern)]
#![allow(illegal_floating_point_literal_pattern)]
#![allow(unreachable_patterns)]
macro_rules! yes {

View File

@ -1,5 +1,4 @@
#![feature(exclusive_range_pattern)]
#![allow(illegal_floating_point_literal_pattern)]
macro_rules! m {
($s:expr, $($t:tt)+) => {

View File

@ -1,77 +1,77 @@
error[E0579]: lower range bound must be less than upper
--> $DIR/half-open-range-pats-thir-lower-empty.rs:11:11
--> $DIR/half-open-range-pats-thir-lower-empty.rs:10:11
|
LL | m!(0, ..u8::MIN);
| ^^^^^^^^^
error[E0579]: lower range bound must be less than upper
--> $DIR/half-open-range-pats-thir-lower-empty.rs:13:11
--> $DIR/half-open-range-pats-thir-lower-empty.rs:12:11
|
LL | m!(0, ..u16::MIN);
| ^^^^^^^^^^
error[E0579]: lower range bound must be less than upper
--> $DIR/half-open-range-pats-thir-lower-empty.rs:15:11
--> $DIR/half-open-range-pats-thir-lower-empty.rs:14:11
|
LL | m!(0, ..u32::MIN);
| ^^^^^^^^^^
error[E0579]: lower range bound must be less than upper
--> $DIR/half-open-range-pats-thir-lower-empty.rs:17:11
--> $DIR/half-open-range-pats-thir-lower-empty.rs:16:11
|
LL | m!(0, ..u64::MIN);
| ^^^^^^^^^^
error[E0579]: lower range bound must be less than upper
--> $DIR/half-open-range-pats-thir-lower-empty.rs:19:11
--> $DIR/half-open-range-pats-thir-lower-empty.rs:18:11
|
LL | m!(0, ..u128::MIN);
| ^^^^^^^^^^^
error[E0579]: lower range bound must be less than upper
--> $DIR/half-open-range-pats-thir-lower-empty.rs:22:11
--> $DIR/half-open-range-pats-thir-lower-empty.rs:21:11
|
LL | m!(0, ..i8::MIN);
| ^^^^^^^^^
error[E0579]: lower range bound must be less than upper
--> $DIR/half-open-range-pats-thir-lower-empty.rs:24:11
--> $DIR/half-open-range-pats-thir-lower-empty.rs:23:11
|
LL | m!(0, ..i16::MIN);
| ^^^^^^^^^^
error[E0579]: lower range bound must be less than upper
--> $DIR/half-open-range-pats-thir-lower-empty.rs:26:11
--> $DIR/half-open-range-pats-thir-lower-empty.rs:25:11
|
LL | m!(0, ..i32::MIN);
| ^^^^^^^^^^
error[E0579]: lower range bound must be less than upper
--> $DIR/half-open-range-pats-thir-lower-empty.rs:28:11
--> $DIR/half-open-range-pats-thir-lower-empty.rs:27:11
|
LL | m!(0, ..i64::MIN);
| ^^^^^^^^^^
error[E0579]: lower range bound must be less than upper
--> $DIR/half-open-range-pats-thir-lower-empty.rs:30:11
--> $DIR/half-open-range-pats-thir-lower-empty.rs:29:11
|
LL | m!(0, ..i128::MIN);
| ^^^^^^^^^^^
error[E0579]: lower range bound must be less than upper
--> $DIR/half-open-range-pats-thir-lower-empty.rs:33:14
--> $DIR/half-open-range-pats-thir-lower-empty.rs:32:14
|
LL | m!(0f32, ..f32::NEG_INFINITY);
| ^^^^^^^^^^^^^^^^^^^
error[E0579]: lower range bound must be less than upper
--> $DIR/half-open-range-pats-thir-lower-empty.rs:35:14
--> $DIR/half-open-range-pats-thir-lower-empty.rs:34:14
|
LL | m!(0f64, ..f64::NEG_INFINITY);
| ^^^^^^^^^^^^^^^^^^^
error[E0579]: lower range bound must be less than upper
--> $DIR/half-open-range-pats-thir-lower-empty.rs:38:13
--> $DIR/half-open-range-pats-thir-lower-empty.rs:37:13
|
LL | m!('a', ..'\u{0}');
| ^^^^^^^^^

View File

@ -1,15 +0,0 @@
// Regression test for #86600, where an instance of the
// `illegal_floating_point_literal_pattern` lint was issued twice.
// check-pass
fn main() {
let x = 42.0;
match x {
5.0 => {}
//~^ WARNING: floating-point types cannot be used in patterns
//~| WARNING: this was previously accepted by the compiler
_ => {}
}
}

View File

@ -1,12 +0,0 @@
warning: floating-point types cannot be used in patterns
--> $DIR/issue-86600-lint-twice.rs:10:9
|
LL | 5.0 => {}
| ^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
= note: `#[warn(illegal_floating_point_literal_pattern)]` on by default
warning: 1 warning emitted

View File

@ -22,12 +22,8 @@ mod rustc_ok {
pub fn rustc_lints() {
let x = 42.0;
#[expect(illegal_floating_point_literal_pattern)]
match x {
5.0 => {}
6.0 => {}
_ => {}
}
#[expect(invalid_nan_comparisons)]
let _b = x == f32::NAN;
}
}
@ -40,13 +36,9 @@ mod rustc_warn {
pub fn rustc_lints() {
let x = 42;
#[expect(illegal_floating_point_literal_pattern)]
#[expect(invalid_nan_comparisons)]
//~^ WARNING this lint expectation is unfulfilled [unfulfilled_lint_expectations]
match x {
5 => {}
6 => {}
_ => {}
}
let _b = x == 5;
}
}

View File

@ -1,5 +1,5 @@
warning: this lint expectation is unfulfilled
--> $DIR/expect_tool_lint_rfc_2383.rs:37:14
--> $DIR/expect_tool_lint_rfc_2383.rs:33:14
|
LL | #[expect(dead_code)]
| ^^^^^^^^^
@ -7,10 +7,10 @@ LL | #[expect(dead_code)]
= note: `#[warn(unfulfilled_lint_expectations)]` on by default
warning: this lint expectation is unfulfilled
--> $DIR/expect_tool_lint_rfc_2383.rs:43:18
--> $DIR/expect_tool_lint_rfc_2383.rs:39:18
|
LL | #[expect(illegal_floating_point_literal_pattern)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | #[expect(invalid_nan_comparisons)]
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: 2 warnings emitted

View File

@ -1,50 +0,0 @@
// Matching against float literals should result in a linter error
#![feature(exclusive_range_pattern)]
#![allow(unused)]
#![forbid(illegal_floating_point_literal_pattern)]
fn main() {
let x = 42.0;
match x {
5.0 => {}, //~ ERROR floating-point types cannot be used in patterns
//~| WARNING hard error
5.0f32 => {}, //~ ERROR floating-point types cannot be used in patterns
//~| WARNING hard error
-5.0 => {}, //~ ERROR floating-point types cannot be used in patterns
//~| WARNING hard error
1.0 .. 33.0 => {}, //~ ERROR floating-point types cannot be used in patterns
//~| WARNING hard error
//~| ERROR floating-point types cannot be used in patterns
//~| WARNING hard error
39.0 ..= 70.0 => {}, //~ ERROR floating-point types cannot be used in patterns
//~| ERROR floating-point types cannot be used in patterns
//~| WARNING hard error
//~| WARNING hard error
..71.0 => {}
//~^ ERROR floating-point types cannot be used in patterns
//~| WARNING this was previously accepted by the compiler
..=72.0 => {}
//~^ ERROR floating-point types cannot be used in patterns
//~| WARNING this was previously accepted by the compiler
71.0.. => {}
//~^ ERROR floating-point types cannot be used in patterns
//~| WARNING this was previously accepted by the compiler
_ => {},
};
let y = 5.0;
// Same for tuples
match (x, 5) {
(3.14, 1) => {}, //~ ERROR floating-point types cannot be used
//~| WARNING hard error
_ => {},
}
// Or structs
struct Foo { x: f32 };
match (Foo { x }) {
Foo { x: 2.0 } => {}, //~ ERROR floating-point types cannot be used
//~| WARNING hard error
_ => {},
}
}

View File

@ -1,115 +0,0 @@
error: floating-point types cannot be used in patterns
--> $DIR/issue-41255.rs:10:9
|
LL | 5.0 => {},
| ^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
note: the lint level is defined here
--> $DIR/issue-41255.rs:5:11
|
LL | #![forbid(illegal_floating_point_literal_pattern)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: floating-point types cannot be used in patterns
--> $DIR/issue-41255.rs:12:9
|
LL | 5.0f32 => {},
| ^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
error: floating-point types cannot be used in patterns
--> $DIR/issue-41255.rs:14:10
|
LL | -5.0 => {},
| ^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
error: floating-point types cannot be used in patterns
--> $DIR/issue-41255.rs:16:9
|
LL | 1.0 .. 33.0 => {},
| ^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
error: floating-point types cannot be used in patterns
--> $DIR/issue-41255.rs:16:16
|
LL | 1.0 .. 33.0 => {},
| ^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
error: floating-point types cannot be used in patterns
--> $DIR/issue-41255.rs:20:9
|
LL | 39.0 ..= 70.0 => {},
| ^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
error: floating-point types cannot be used in patterns
--> $DIR/issue-41255.rs:20:18
|
LL | 39.0 ..= 70.0 => {},
| ^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
error: floating-point types cannot be used in patterns
--> $DIR/issue-41255.rs:25:11
|
LL | ..71.0 => {}
| ^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
error: floating-point types cannot be used in patterns
--> $DIR/issue-41255.rs:28:12
|
LL | ..=72.0 => {}
| ^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
error: floating-point types cannot be used in patterns
--> $DIR/issue-41255.rs:31:9
|
LL | 71.0.. => {}
| ^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
error: floating-point types cannot be used in patterns
--> $DIR/issue-41255.rs:39:10
|
LL | (3.14, 1) => {},
| ^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
error: floating-point types cannot be used in patterns
--> $DIR/issue-41255.rs:46:18
|
LL | Foo { x: 2.0 } => {},
| ^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
error: aborting due to 12 previous errors

View File

@ -0,0 +1,11 @@
// run-pass
// Makes sure we use `==` (not bitwise) semantics for float comparison.
fn main() {
const F1: f32 = 0.0;
const F2: f32 = -0.0;
assert_eq!(F1, F2);
assert_ne!(F1.to_bits(), F2.to_bits());
assert!(matches!(F1, F2));
assert!(matches!(F2, F1));
}

View File

@ -1,6 +1,5 @@
// run-pass
// pretty-expanded FIXME #23616
#![allow(illegal_floating_point_literal_pattern)] // FIXME #41620
pub fn main() {
const FOO: f64 = 10.0;

View File

@ -1,5 +1,4 @@
#![feature(exclusive_range_pattern)]
#![allow(illegal_floating_point_literal_pattern)]
#![deny(unreachable_patterns)]
fn main() {

View File

@ -1,5 +1,5 @@
error[E0004]: non-exhaustive patterns: `_` not covered
--> $DIR/floats.rs:11:11
--> $DIR/floats.rs:10:11
|
LL | match 0.0 {
| ^^^ pattern `_` not covered
@ -12,49 +12,49 @@ LL + _ => todo!()
|
error: unreachable pattern
--> $DIR/floats.rs:19:9
--> $DIR/floats.rs:18:9
|
LL | 0.01f64 => {}
| ^^^^^^^
|
note: the lint level is defined here
--> $DIR/floats.rs:3:9
--> $DIR/floats.rs:2:9
|
LL | #![deny(unreachable_patterns)]
| ^^^^^^^^^^^^^^^^^^^^
error: unreachable pattern
--> $DIR/floats.rs:20:9
--> $DIR/floats.rs:19:9
|
LL | 0.02f64 => {}
| ^^^^^^^
error: unreachable pattern
--> $DIR/floats.rs:21:9
--> $DIR/floats.rs:20:9
|
LL | 6.5f64 => {}
| ^^^^^^
error: unreachable pattern
--> $DIR/floats.rs:23:9
--> $DIR/floats.rs:22:9
|
LL | 1.0f64..=4.0f64 => {}
| ^^^^^^^^^^^^^^^
error: unreachable pattern
--> $DIR/floats.rs:35:9
--> $DIR/floats.rs:34:9
|
LL | 0.01f32 => {}
| ^^^^^^^
error: unreachable pattern
--> $DIR/floats.rs:36:9
--> $DIR/floats.rs:35:9
|
LL | 0.02f32 => {}
| ^^^^^^^
error: unreachable pattern
--> $DIR/floats.rs:37:9
--> $DIR/floats.rs:36:9
|
LL | 6.5f32 => {}
| ^^^^^^

View File

@ -1,5 +1,3 @@
#![allow(illegal_floating_point_literal_pattern)]
enum T { A, B }
fn main() {

View File

@ -1,11 +1,11 @@
error[E0004]: non-exhaustive patterns: `T::A` not covered
--> $DIR/non-exhaustive-match.rs:7:11
--> $DIR/non-exhaustive-match.rs:5:11
|
LL | match x { T::B => { } }
| ^ pattern `T::A` not covered
|
note: `T` defined here
--> $DIR/non-exhaustive-match.rs:3:6
--> $DIR/non-exhaustive-match.rs:1:6
|
LL | enum T { A, B }
| ^ - not covered
@ -16,7 +16,7 @@ LL | match x { T::B => { }, T::A => todo!() }
| +++++++++++++++++
error[E0004]: non-exhaustive patterns: `false` not covered
--> $DIR/non-exhaustive-match.rs:8:11
--> $DIR/non-exhaustive-match.rs:6:11
|
LL | match true {
| ^^^^ pattern `false` not covered
@ -29,7 +29,7 @@ LL + false => todo!()
|
error[E0004]: non-exhaustive patterns: `Some(_)` not covered
--> $DIR/non-exhaustive-match.rs:11:11
--> $DIR/non-exhaustive-match.rs:9:11
|
LL | match Some(10) {
| ^^^^^^^^ pattern `Some(_)` not covered
@ -47,7 +47,7 @@ LL + Some(_) => todo!()
|
error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
--> $DIR/non-exhaustive-match.rs:14:11
--> $DIR/non-exhaustive-match.rs:12:11
|
LL | match (2, 3, 4) {
| ^^^^^^^^^ patterns `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered
@ -60,7 +60,7 @@ LL + (_, _, i32::MIN..=3_i32) | (_, _, 5_i32..=i32::MAX) => todo!()
|
error[E0004]: non-exhaustive patterns: `(T::A, T::A)` and `(T::B, T::B)` not covered
--> $DIR/non-exhaustive-match.rs:18:11
--> $DIR/non-exhaustive-match.rs:16:11
|
LL | match (T::A, T::A) {
| ^^^^^^^^^^^^ patterns `(T::A, T::A)` and `(T::B, T::B)` not covered
@ -73,13 +73,13 @@ LL + (T::A, T::A) | (T::B, T::B) => todo!()
|
error[E0004]: non-exhaustive patterns: `T::B` not covered
--> $DIR/non-exhaustive-match.rs:22:11
--> $DIR/non-exhaustive-match.rs:20:11
|
LL | match T::A {
| ^^^^ pattern `T::B` not covered
|
note: `T` defined here
--> $DIR/non-exhaustive-match.rs:3:6
--> $DIR/non-exhaustive-match.rs:1:6
|
LL | enum T { A, B }
| ^ - not covered
@ -91,7 +91,7 @@ LL + T::B => todo!()
|
error[E0004]: non-exhaustive patterns: `[]` not covered
--> $DIR/non-exhaustive-match.rs:33:11
--> $DIR/non-exhaustive-match.rs:31:11
|
LL | match *vec {
| ^^^^ pattern `[]` not covered
@ -104,7 +104,7 @@ LL + [] => todo!()
|
error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered
--> $DIR/non-exhaustive-match.rs:46:11
--> $DIR/non-exhaustive-match.rs:44:11
|
LL | match *vec {
| ^^^^ pattern `[_, _, _, _, ..]` not covered

View File

@ -0,0 +1,41 @@
// Matching against NaN should result in an error
#![feature(exclusive_range_pattern)]
#![allow(unused)]
const NAN: f64 = f64::NAN;
#[derive(PartialEq, Eq)]
struct MyType<T>(T);
const C: MyType<f32> = MyType(f32::NAN);
fn main() {
let x = NAN;
match x {
NAN => {}, //~ ERROR cannot use NaN in patterns
_ => {},
};
match [x, 1.0] {
[NAN, _] => {}, //~ ERROR cannot use NaN in patterns
_ => {},
};
match MyType(1.0f32) {
C => {}, //~ ERROR cannot use NaN in patterns
_ => {},
}
// Also cover range patterns
match x {
NAN..=1.0 => {}, //~ ERROR cannot use NaN in patterns
//~^ ERROR lower range bound must be less than or equal to upper
-1.0..=NAN => {}, //~ ERROR cannot use NaN in patterns
//~^ ERROR lower range bound must be less than or equal to upper
NAN.. => {}, //~ ERROR cannot use NaN in patterns
//~^ ERROR lower range bound must be less than or equal to upper
..NAN => {}, //~ ERROR cannot use NaN in patterns
//~^ ERROR lower range bound must be less than upper
_ => {},
};
}

View File

@ -0,0 +1,91 @@
error: cannot use NaN in patterns
--> $DIR/issue-6804-nan-match.rs:15:9
|
LL | NAN => {},
| ^^^
|
= note: NaNs compare inequal to everything, even themselves, so this pattern would never match
= help: try using the `is_nan` method instead
error: cannot use NaN in patterns
--> $DIR/issue-6804-nan-match.rs:20:10
|
LL | [NAN, _] => {},
| ^^^
|
= note: NaNs compare inequal to everything, even themselves, so this pattern would never match
= help: try using the `is_nan` method instead
error: cannot use NaN in patterns
--> $DIR/issue-6804-nan-match.rs:25:9
|
LL | C => {},
| ^
|
= note: NaNs compare inequal to everything, even themselves, so this pattern would never match
= help: try using the `is_nan` method instead
error: cannot use NaN in patterns
--> $DIR/issue-6804-nan-match.rs:31:9
|
LL | NAN..=1.0 => {},
| ^^^
|
= note: NaNs compare inequal to everything, even themselves, so this pattern would never match
= help: try using the `is_nan` method instead
error[E0030]: lower range bound must be less than or equal to upper
--> $DIR/issue-6804-nan-match.rs:31:9
|
LL | NAN..=1.0 => {},
| ^^^^^^^^^ lower bound larger than upper bound
error: cannot use NaN in patterns
--> $DIR/issue-6804-nan-match.rs:33:16
|
LL | -1.0..=NAN => {},
| ^^^
|
= note: NaNs compare inequal to everything, even themselves, so this pattern would never match
= help: try using the `is_nan` method instead
error[E0030]: lower range bound must be less than or equal to upper
--> $DIR/issue-6804-nan-match.rs:33:9
|
LL | -1.0..=NAN => {},
| ^^^^^^^^^^ lower bound larger than upper bound
error: cannot use NaN in patterns
--> $DIR/issue-6804-nan-match.rs:35:9
|
LL | NAN.. => {},
| ^^^
|
= note: NaNs compare inequal to everything, even themselves, so this pattern would never match
= help: try using the `is_nan` method instead
error[E0030]: lower range bound must be less than or equal to upper
--> $DIR/issue-6804-nan-match.rs:35:9
|
LL | NAN.. => {},
| ^^^^^ lower bound larger than upper bound
error: cannot use NaN in patterns
--> $DIR/issue-6804-nan-match.rs:37:11
|
LL | ..NAN => {},
| ^^^
|
= note: NaNs compare inequal to everything, even themselves, so this pattern would never match
= help: try using the `is_nan` method instead
error[E0579]: lower range bound must be less than upper
--> $DIR/issue-6804-nan-match.rs:37:9
|
LL | ..NAN => {},
| ^^^^^
error: aborting due to 11 previous errors
Some errors have detailed explanations: E0030, E0579.
For more information about an error, try `rustc --explain E0030`.

View File

@ -1,21 +0,0 @@
// Matching against NaN should result in a warning
#![allow(unused)]
#![deny(illegal_floating_point_literal_pattern)]
const NAN: f64 = f64::NAN;
fn main() {
let x = NAN;
match x {
NAN => {}, //~ ERROR floating-point types cannot be used
//~| WARN this was previously accepted by the compiler but is being phased out
_ => {},
};
match [x, 1.0] {
[NAN, _] => {}, //~ ERROR floating-point types cannot be used
//~| WARN this was previously accepted by the compiler but is being phased out
_ => {},
};
}

View File

@ -1,25 +0,0 @@
error: floating-point types cannot be used in patterns
--> $DIR/issue-6804.rs:11:9
|
LL | NAN => {},
| ^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
note: the lint level is defined here
--> $DIR/issue-6804.rs:4:9
|
LL | #![deny(illegal_floating_point_literal_pattern)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: floating-point types cannot be used in patterns
--> $DIR/issue-6804.rs:17:10
|
LL | [NAN, _] => {},
| ^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
error: aborting due to 2 previous errors

View File

@ -1,7 +1,6 @@
// run-pass
#![allow(dead_code)]
#![allow(illegal_floating_point_literal_pattern)]
#[repr(u32)]
enum Tag {