From 1b62868446faadd266693c2534c846182f8f7678 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 26 Mar 2024 06:01:09 -0400 Subject: [PATCH] Replace `f16` and `f128` pattern matching stubs with real implementations This section of code depends on `rustc_apfloat` rather than our internal types, so this is one potential ICE that we should be able to melt now. This also fixes some missing range and match handling in `rustc_middle`. --- compiler/rustc_middle/src/thir.rs | 12 ++++ compiler/rustc_middle/src/ty/util.rs | 4 +- .../src/thir/pattern/const_to_pat.rs | 4 +- .../rustc_pattern_analysis/src/constructor.rs | 27 ++++++- compiler/rustc_pattern_analysis/src/rustc.rs | 50 +++++++++++-- .../half-open-range-pats-semantics.rs | 54 ++++++++++++++ .../half-open-range-pats-thir-lower-empty.rs | 1 + ...lf-open-range-pats-thir-lower-empty.stderr | 6 +- tests/ui/match/match-float.rs | 39 +++++++++- tests/ui/pattern/usefulness/floats.rs | 48 ++++++++++--- tests/ui/pattern/usefulness/floats.stderr | 72 +++++++++++++++---- 11 files changed, 279 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 7c8b0ec671a41..c97af68c29e5f 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -1047,6 +1047,12 @@ impl<'tcx> PatRangeBoundary<'tcx> { let b = other.eval_bits(ty, tcx, param_env); match ty.kind() { + ty::Float(ty::FloatTy::F16) => { + use rustc_apfloat::Float; + let a = rustc_apfloat::ieee::Half::from_bits(a); + let b = rustc_apfloat::ieee::Half::from_bits(b); + a.partial_cmp(&b) + } ty::Float(ty::FloatTy::F32) => { use rustc_apfloat::Float; let a = rustc_apfloat::ieee::Single::from_bits(a); @@ -1059,6 +1065,12 @@ impl<'tcx> PatRangeBoundary<'tcx> { let b = rustc_apfloat::ieee::Double::from_bits(b); a.partial_cmp(&b) } + ty::Float(ty::FloatTy::F128) => { + use rustc_apfloat::Float; + let a = rustc_apfloat::ieee::Quad::from_bits(a); + let b = rustc_apfloat::ieee::Quad::from_bits(b); + a.partial_cmp(&b) + } ty::Int(ity) => { let size = rustc_target::abi::Integer::from_int_ty(&tcx, *ity).size(); let a = size.sign_extend(a) as i128; diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index b079ed521d34c..6fc9f6dd0b3c7 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1196,7 +1196,7 @@ impl<'tcx> Ty<'tcx> { /// Returns the minimum and maximum values for the given numeric type (including `char`s) or /// returns `None` if the type is not numeric. pub fn numeric_min_and_max_as_bits(self, tcx: TyCtxt<'tcx>) -> Option<(u128, u128)> { - use rustc_apfloat::ieee::{Double, Single}; + use rustc_apfloat::ieee::{Double, Half, Quad, Single}; Some(match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = self.int_size_and_signed(tcx); @@ -1206,12 +1206,14 @@ impl<'tcx> Ty<'tcx> { (min, max) } ty::Char => (0, std::char::MAX as u128), + ty::Float(ty::FloatTy::F16) => ((-Half::INFINITY).to_bits(), Half::INFINITY.to_bits()), ty::Float(ty::FloatTy::F32) => { ((-Single::INFINITY).to_bits(), Single::INFINITY.to_bits()) } ty::Float(ty::FloatTy::F64) => { ((-Double::INFINITY).to_bits(), Double::INFINITY.to_bits()) } + ty::Float(ty::FloatTy::F128) => ((-Quad::INFINITY).to_bits(), Quad::INFINITY.to_bits()), _ => return None, }) } diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 192d706bce2c7..dda6c88008bb0 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -369,10 +369,10 @@ impl<'tcx> ConstToPat<'tcx> { ty::Float(flt) => { let v = cv.unwrap_leaf(); let is_nan = match flt { - ty::FloatTy::F16 => unimplemented!("f16_f128"), + ty::FloatTy::F16 => v.to_f16().is_nan(), ty::FloatTy::F32 => v.to_f32().is_nan(), ty::FloatTy::F64 => v.to_f64().is_nan(), - ty::FloatTy::F128 => unimplemented!("f16_f128"), + ty::FloatTy::F128 => v.to_f128().is_nan(), }; if is_nan { // NaNs are not ever equal to anything so they make no sense as patterns. diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 44f09b66bf6c6..fb10370547597 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -182,7 +182,7 @@ use std::iter::once; use smallvec::SmallVec; -use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS}; +use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, SingleS}; use rustc_index::bit_set::{BitSet, GrowableBitSet}; use rustc_index::IndexVec; @@ -692,8 +692,10 @@ pub enum Constructor { /// Ranges of integer literal values (`2`, `2..=5` or `2..5`). IntRange(IntRange), /// Ranges of floating-point literal values (`2.0..=5.2`). + F16Range(IeeeFloat, IeeeFloat, RangeEnd), F32Range(IeeeFloat, IeeeFloat, RangeEnd), F64Range(IeeeFloat, IeeeFloat, RangeEnd), + F128Range(IeeeFloat, IeeeFloat, RangeEnd), /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. Str(Cx::StrLit), /// Constants that must not be matched structurally. They are treated as black boxes for the @@ -735,8 +737,10 @@ impl Clone for Constructor { Constructor::UnionField => Constructor::UnionField, Constructor::Bool(b) => Constructor::Bool(*b), Constructor::IntRange(range) => Constructor::IntRange(*range), + Constructor::F16Range(lo, hi, end) => Constructor::F16Range(lo.clone(), *hi, *end), Constructor::F32Range(lo, hi, end) => Constructor::F32Range(lo.clone(), *hi, *end), Constructor::F64Range(lo, hi, end) => Constructor::F64Range(lo.clone(), *hi, *end), + Constructor::F128Range(lo, hi, end) => Constructor::F128Range(lo.clone(), *hi, *end), Constructor::Str(value) => Constructor::Str(value.clone()), Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()), Constructor::Or => Constructor::Or, @@ -812,6 +816,14 @@ impl Constructor { (Bool(self_b), Bool(other_b)) => self_b == other_b, (IntRange(self_range), IntRange(other_range)) => self_range.is_subrange(other_range), + (F16Range(self_from, self_to, self_end), F16Range(other_from, other_to, other_end)) => { + self_from.ge(other_from) + && match self_to.partial_cmp(other_to) { + Some(Ordering::Less) => true, + Some(Ordering::Equal) => other_end == self_end, + _ => false, + } + } (F32Range(self_from, self_to, self_end), F32Range(other_from, other_to, other_end)) => { self_from.ge(other_from) && match self_to.partial_cmp(other_to) { @@ -828,6 +840,17 @@ impl Constructor { _ => false, } } + ( + F128Range(self_from, self_to, self_end), + F128Range(other_from, other_to, other_end), + ) => { + self_from.ge(other_from) + && match self_to.partial_cmp(other_to) { + Some(Ordering::Less) => true, + Some(Ordering::Equal) => other_end == self_end, + _ => false, + } + } (Str(self_val), Str(other_val)) => { // FIXME Once valtrees are available we can directly use the bytes // in the `Str` variant of the valtree for the comparison here. @@ -906,8 +929,10 @@ impl Constructor { Bool(b) => write!(f, "{b}")?, // Best-effort, will render signed ranges incorrectly IntRange(range) => write!(f, "{range:?}")?, + F16Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, + F128Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, Str(value) => write!(f, "{value:?}")?, Opaque(..) => write!(f, "")?, Or => { diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 8391c694c64b2..d4dd4dd858c28 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -247,8 +247,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } _ => bug!("bad slice pattern {:?} {:?}", ctor, ty), }, - Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => &[], + Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) + | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing + | PrivateUninhabited | Wildcard => &[], Or => { bug!("called `Fields::wildcards` on an `Or` ctor") } @@ -275,8 +276,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { }, Ref => 1, Slice(slice) => slice.arity(), - Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) - | Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => 0, + Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) + | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing + | PrivateUninhabited | Wildcard => 0, Or => bug!("The `Or` constructor doesn't have a fixed arity"), } } @@ -546,6 +548,18 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { fields = vec![]; arity = 0; } + ty::Float(ty::FloatTy::F16) => { + ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { + Some(bits) => { + use rustc_apfloat::Float; + let value = rustc_apfloat::ieee::Half::from_bits(bits); + F16Range(value, value, RangeEnd::Included) + } + None => Opaque(OpaqueId::new()), + }; + fields = vec![]; + arity = 0; + } ty::Float(ty::FloatTy::F32) => { ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { Some(bits) => { @@ -570,6 +584,18 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { fields = vec![]; arity = 0; } + ty::Float(ty::FloatTy::F128) => { + ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { + Some(bits) => { + use rustc_apfloat::Float; + let value = rustc_apfloat::ieee::Quad::from_bits(bits); + F128Range(value, value, RangeEnd::Included) + } + None => Opaque(OpaqueId::new()), + }; + fields = vec![]; + arity = 0; + } ty::Ref(_, t, _) if t.is_str() => { // We want a `&str` constant to behave like a `Deref` pattern, to be compatible // with other `Deref` patterns. This could have been done in `const_to_pat`, @@ -611,7 +637,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let lo = lo.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env)); let hi = hi.as_finite().map(|c| c.eval_bits(cx.tcx, cx.param_env)); match fty { - ty::FloatTy::F16 => unimplemented!("f16_f128"), + ty::FloatTy::F16 => { + use rustc_apfloat::ieee::Half; + let lo = lo.map(Half::from_bits).unwrap_or(-Half::INFINITY); + let hi = hi.map(Half::from_bits).unwrap_or(Half::INFINITY); + F16Range(lo, hi, end) + } ty::FloatTy::F32 => { use rustc_apfloat::ieee::Single; let lo = lo.map(Single::from_bits).unwrap_or(-Single::INFINITY); @@ -624,7 +655,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let hi = hi.map(Double::from_bits).unwrap_or(Double::INFINITY); F64Range(lo, hi, end) } - ty::FloatTy::F128 => unimplemented!("f16_f128"), + ty::FloatTy::F128 => { + use rustc_apfloat::ieee::Quad; + let lo = lo.map(Quad::from_bits).unwrap_or(-Quad::INFINITY); + let hi = hi.map(Quad::from_bits).unwrap_or(Quad::INFINITY); + F128Range(lo, hi, end) + } } } _ => bug!("invalid type for range pattern: {}", ty.inner()), @@ -837,7 +873,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, `Missing` should have been processed in `apply_constructors`" ), - F32Range(..) | F64Range(..) | Opaque(..) | Or => { + F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Opaque(..) | Or => { bug!("can't convert to pattern: {:?}", pat) } }; diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs index 3487bac528249..9d8d4c76326ed 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-semantics.rs @@ -4,6 +4,8 @@ // via `.contains(...)` and make sure the dynamic semantics match. #![allow(unreachable_patterns)] +#![feature(f128)] +#![feature(f16)] macro_rules! yes { ($scrutinee:expr, $($t:tt)+) => { @@ -39,6 +41,13 @@ fn range_to_inclusive() { assert!(yes!('a', ..='a')); assert!(!yes!('b', ..='a')); + // f16; `..=X` + // FIXME(f16_f128): enable infinity tests when constants are available + // assert!(yes!(f16::NEG_INFINITY, ..=f16::NEG_INFINITY)); + // assert!(yes!(f16::NEG_INFINITY, ..=1.0f16)); + assert!(yes!(1.5f16, ..=1.5f16)); + assert!(!yes!(1.6f16, ..=-1.5f16)); + // f32; `..=X` assert!(yes!(f32::NEG_INFINITY, ..=f32::NEG_INFINITY)); assert!(yes!(f32::NEG_INFINITY, ..=1.0f32)); @@ -50,6 +59,13 @@ fn range_to_inclusive() { assert!(yes!(f64::NEG_INFINITY, ..=1.0f64)); assert!(yes!(1.5f64, ..=1.5f64)); assert!(!yes!(1.6f64, ..=-1.5f64)); + + // f128; `..=X` + // FIXME(f16_f128): enable infinity tests when constants are available + // assert!(yes!(f128::NEG_INFINITY, ..=f128::NEG_INFINITY)); + // assert!(yes!(f128::NEG_INFINITY, ..=1.0f128)); + assert!(yes!(1.5f128, ..=1.5f128)); + assert!(!yes!(1.6f128, ..=-1.5f128)); } fn range_to() { @@ -83,6 +99,14 @@ fn range_to() { assert!(!yes!('a', ..'a')); assert!(!yes!('b', ..'a')); + // f16; `..X` + // FIXME(f16_f128): enable infinity tests when constants are available + // assert!(yes!(f16::NEG_INFINITY, ..1.0f16)); + assert!(!yes!(1.5f16, ..1.5f16)); + const E16: f16 = 1.5f16 + f16::EPSILON; + assert!(yes!(1.5f16, ..E16)); + assert!(!yes!(1.6f16, ..1.5f16)); + // f32; `..X` assert!(yes!(f32::NEG_INFINITY, ..1.0f32)); assert!(!yes!(1.5f32, ..1.5f32)); @@ -96,6 +120,14 @@ fn range_to() { const E64: f64 = 1.5f64 + f64::EPSILON; assert!(yes!(1.5f64, ..E64)); assert!(!yes!(1.6f64, ..1.5f64)); + + // f128; `..X` + // FIXME(f16_f128): enable infinity tests when constants are available + // assert!(yes!(f128::NEG_INFINITY, ..1.0f128)); + assert!(!yes!(1.5f128, ..1.5f128)); + const E128: f128 = 1.5f128 + f128::EPSILON; + assert!(yes!(1.5f128, ..E128)); + assert!(!yes!(1.6f128, ..1.5f128)); } fn range_from() { @@ -129,6 +161,17 @@ fn range_from() { assert!(!yes!('a', 'b'..)); assert!(yes!(core::char::MAX, core::char::MAX..)); + // f16; `X..` + // FIXME(f16_f128): enable infinity tests when constants are available + // assert!(yes!(f16::NEG_INFINITY, f16::NEG_INFINITY..)); + // assert!(yes!(f16::INFINITY, f16::NEG_INFINITY..)); + // assert!(!yes!(f16::NEG_INFINITY, 1.0f16..)); + // assert!(yes!(f16::INFINITY, 1.0f16..)); + assert!(!yes!(1.0f16 - f16::EPSILON, 1.0f16..)); + assert!(yes!(1.0f16, 1.0f16..)); + // assert!(yes!(f16::INFINITY, 1.0f16..)); + // assert!(yes!(f16::INFINITY, f16::INFINITY..)); + // f32; `X..` assert!(yes!(f32::NEG_INFINITY, f32::NEG_INFINITY..)); assert!(yes!(f32::INFINITY, f32::NEG_INFINITY..)); @@ -148,6 +191,17 @@ fn range_from() { assert!(yes!(1.0f64, 1.0f64..)); assert!(yes!(f64::INFINITY, 1.0f64..)); assert!(yes!(f64::INFINITY, f64::INFINITY..)); + + // f128; `X..` + // FIXME(f16_f128): enable infinity tests when constants are available + // assert!(yes!(f128::NEG_INFINITY, f128::NEG_INFINITY..)); + // assert!(yes!(f128::INFINITY, f128::NEG_INFINITY..)); + // assert!(!yes!(f128::NEG_INFINITY, 1.0f128..)); + // assert!(yes!(f128::INFINITY, 1.0f128..)); + assert!(!yes!(1.0f128 - f128::EPSILON, 1.0f128..)); + assert!(yes!(1.0f128, 1.0f128..)); + // assert!(yes!(f128::INFINITY, 1.0f128..)); + // assert!(yes!(f128::INFINITY, f128::INFINITY..)); } fn main() { diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs index 9ca8dd25ed76f..a35bb51acbca3 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.rs @@ -27,6 +27,7 @@ fn main() { m!(0, ..i128::MIN); //~^ ERROR lower range bound must be less than upper + // FIXME(f16_f128): add tests when NEG_INFINITY is available m!(0f32, ..f32::NEG_INFINITY); //~^ ERROR lower range bound must be less than upper m!(0f64, ..f64::NEG_INFINITY); diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr index 668b5c858f06c..fb2f1841a6dfc 100644 --- a/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr +++ b/tests/ui/half-open-range-patterns/half-open-range-pats-thir-lower-empty.stderr @@ -59,19 +59,19 @@ LL | m!(0, ..i128::MIN); | ^^^^^^^^^^^ error[E0579]: lower range bound must be less than upper - --> $DIR/half-open-range-pats-thir-lower-empty.rs:30:14 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:31: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:32:14 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:33: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:35:13 + --> $DIR/half-open-range-pats-thir-lower-empty.rs:36:13 | LL | m!('a', ..'\u{0}'); | ^^^^^^^^^ diff --git a/tests/ui/match/match-float.rs b/tests/ui/match/match-float.rs index f8514568d157c..83da57023d094 100644 --- a/tests/ui/match/match-float.rs +++ b/tests/ui/match/match-float.rs @@ -1,7 +1,19 @@ //@ run-pass // Makes sure we use `==` (not bitwise) semantics for float comparison. -fn main() { +#![feature(f128)] +#![feature(f16)] + +fn check_f16() { + const F1: f16 = 0.0; + const F2: f16 = -0.0; + assert_eq!(F1, F2); + assert_ne!(F1.to_bits(), F2.to_bits()); + assert!(matches!(F1, F2)); + assert!(matches!(F2, F1)); +} + +fn check_f32() { const F1: f32 = 0.0; const F2: f32 = -0.0; assert_eq!(F1, F2); @@ -9,3 +21,28 @@ fn main() { assert!(matches!(F1, F2)); assert!(matches!(F2, F1)); } + +fn check_f64() { + const F1: f64 = 0.0; + const F2: f64 = -0.0; + assert_eq!(F1, F2); + assert_ne!(F1.to_bits(), F2.to_bits()); + assert!(matches!(F1, F2)); + assert!(matches!(F2, F1)); +} + +fn check_f128() { + const F1: f128 = 0.0; + const F2: f128 = -0.0; + assert_eq!(F1, F2); + assert_ne!(F1.to_bits(), F2.to_bits()); + assert!(matches!(F1, F2)); + assert!(matches!(F2, F1)); +} + +fn main() { + check_f16(); + check_f32(); + check_f64(); + check_f128(); +} diff --git a/tests/ui/pattern/usefulness/floats.rs b/tests/ui/pattern/usefulness/floats.rs index b3d49ba8e15e5..0b27e33e4ef2e 100644 --- a/tests/ui/pattern/usefulness/floats.rs +++ b/tests/ui/pattern/usefulness/floats.rs @@ -1,4 +1,6 @@ #![deny(unreachable_patterns)] +#![feature(f128)] +#![feature(f16)] fn main() { match 0.0 { @@ -11,6 +13,32 @@ fn main() { 0.0..=1.0 => {} } + match 1.0f16 { + 0.01f16..=6.5f16 => {} + 0.01f16 => {} //~ ERROR unreachable pattern + 0.02f16 => {} //~ ERROR unreachable pattern + 6.5f16 => {} //~ ERROR unreachable pattern + _ => {} + }; + match 1.0f16 { + 0.01f16..6.5f16 => {} + 6.5f16 => {} // this is reachable + _ => {} + }; + + match 1.0f32 { + 0.01f32..=6.5f32 => {} + 0.01f32 => {} //~ ERROR unreachable pattern + 0.02f32 => {} //~ ERROR unreachable pattern + 6.5f32 => {} //~ ERROR unreachable pattern + _ => {} + }; + match 1.0f32 { + 0.01f32..6.5f32 => {} + 6.5f32 => {} // this is reachable + _ => {} + }; + match 1.0f64 { 0.01f64..=6.5f64 => {} 0.005f64 => {} @@ -28,16 +56,20 @@ fn main() { _ => {} }; - match 1.0f32 { - 0.01f32..=6.5f32 => {} - 0.01f32 => {} //~ ERROR unreachable pattern - 0.02f32 => {} //~ ERROR unreachable pattern - 6.5f32 => {} //~ ERROR unreachable pattern + match 1.0f128 { + 0.01f128..=6.5f128 => {} + 0.005f128 => {} + 0.01f128 => {} //~ ERROR unreachable pattern + 0.02f128 => {} //~ ERROR unreachable pattern + 6.5f128 => {} //~ ERROR unreachable pattern + 6.6f128 => {} + 1.0f128..=4.0f128 => {} //~ ERROR unreachable pattern + 5.0f128..=7.0f128 => {} _ => {} }; - match 1.0f32 { - 0.01f32..6.5f32 => {} - 6.5f32 => {} // this is reachable + match 1.0f128 { + 0.01f128..6.5f128 => {} + 6.5f128 => {} // this is reachable _ => {} }; } diff --git a/tests/ui/pattern/usefulness/floats.stderr b/tests/ui/pattern/usefulness/floats.stderr index 04f2fe3cd94f4..684f6c93a16c0 100644 --- a/tests/ui/pattern/usefulness/floats.stderr +++ b/tests/ui/pattern/usefulness/floats.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: `_` not covered - --> $DIR/floats.rs:9:11 + --> $DIR/floats.rs:11:11 | LL | match 0.0 { | ^^^ pattern `_` not covered @@ -12,9 +12,9 @@ LL + _ => todo!() | error: unreachable pattern - --> $DIR/floats.rs:17:9 + --> $DIR/floats.rs:18:9 | -LL | 0.01f64 => {} +LL | 0.01f16 => {} | ^^^^^^^ | note: the lint level is defined here @@ -24,41 +24,83 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:18:9 + --> $DIR/floats.rs:19:9 + | +LL | 0.02f16 => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:20:9 + | +LL | 6.5f16 => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:31:9 + | +LL | 0.01f32 => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:32:9 + | +LL | 0.02f32 => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:33:9 + | +LL | 6.5f32 => {} + | ^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:45:9 + | +LL | 0.01f64 => {} + | ^^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:46:9 | LL | 0.02f64 => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:19:9 + --> $DIR/floats.rs:47:9 | LL | 6.5f64 => {} | ^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:21:9 + --> $DIR/floats.rs:49:9 | LL | 1.0f64..=4.0f64 => {} | ^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:33:9 + --> $DIR/floats.rs:62:9 | -LL | 0.01f32 => {} - | ^^^^^^^ +LL | 0.01f128 => {} + | ^^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:34:9 + --> $DIR/floats.rs:63:9 | -LL | 0.02f32 => {} +LL | 0.02f128 => {} + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/floats.rs:64:9 + | +LL | 6.5f128 => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/floats.rs:35:9 + --> $DIR/floats.rs:66:9 | -LL | 6.5f32 => {} - | ^^^^^^ +LL | 1.0f128..=4.0f128 => {} + | ^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0004`.