about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs98
-rw-r--r--tests/ui/pattern/usefulness/floats.rs40
-rw-r--r--tests/ui/pattern/usefulness/floats.stderr52
3 files changed, 136 insertions, 54 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index b79beb1c537..fba3c7ee9c1 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -50,6 +50,7 @@ use std::ops::RangeInclusive;
 
 use smallvec::{smallvec, SmallVec};
 
+use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
 use rustc_data_structures::captures::Captures;
 use rustc_hir::{HirId, RangeEnd};
 use rustc_index::Idx;
@@ -65,7 +66,6 @@ use rustc_target::abi::{FieldIdx, Integer, Size, VariantIdx, FIRST_VARIANT};
 use self::Constructor::*;
 use self::SliceKind::*;
 
-use super::compare_const_vals;
 use super::usefulness::{MatchCheckCtxt, PatCtxt};
 use crate::errors::{Overlap, OverlappingRangeEndpoints};
 
@@ -619,7 +619,8 @@ pub(super) enum Constructor<'tcx> {
     /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
     IntRange(IntRange),
     /// Ranges of floating-point literal values (`2.0..=5.2`).
-    FloatRange(mir::Const<'tcx>, mir::Const<'tcx>, RangeEnd),
+    F32Range(IeeeFloat<SingleS>, IeeeFloat<SingleS>, RangeEnd),
+    F64Range(IeeeFloat<DoubleS>, IeeeFloat<DoubleS>, RangeEnd),
     /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
     Str(mir::Const<'tcx>),
     /// Array and slice patterns.
@@ -634,7 +635,9 @@ pub(super) enum Constructor<'tcx> {
     /// Stands for constructors that are not seen in the matrix, as explained in the documentation
     /// for [`SplitWildcard`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns`
     /// lint.
-    Missing { nonexhaustive_enum_missing_real_variants: bool },
+    Missing {
+        nonexhaustive_enum_missing_real_variants: bool,
+    },
     /// Wildcard pattern.
     Wildcard,
     /// Or-pattern.
@@ -722,7 +725,8 @@ impl<'tcx> Constructor<'tcx> {
             },
             Slice(slice) => slice.arity(),
             Str(..)
-            | FloatRange(..)
+            | F32Range(..)
+            | F64Range(..)
             | IntRange(..)
             | NonExhaustive
             | Opaque
@@ -795,21 +799,21 @@ impl<'tcx> Constructor<'tcx> {
             (Variant(self_id), Variant(other_id)) => self_id == other_id,
 
             (IntRange(self_range), IntRange(other_range)) => self_range.is_covered_by(other_range),
-            (
-                FloatRange(self_from, self_to, self_end),
-                FloatRange(other_from, other_to, other_end),
-            ) => {
-                match (
-                    compare_const_vals(pcx.cx.tcx, *self_to, *other_to, pcx.cx.param_env),
-                    compare_const_vals(pcx.cx.tcx, *self_from, *other_from, pcx.cx.param_env),
-                ) {
-                    (Some(to), Some(from)) => {
-                        (from == Ordering::Greater || from == Ordering::Equal)
-                            && (to == Ordering::Less
-                                || (other_end == self_end && to == Ordering::Equal))
+            (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) {
+                        Some(Ordering::Less) => true,
+                        Some(Ordering::Equal) => other_end == self_end,
+                        _ => false,
+                    }
+            }
+            (F64Range(self_from, self_to, self_end), F64Range(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,
                     }
-                    _ => false,
-                }
             }
             (Str(self_val), Str(other_val)) => {
                 // FIXME Once valtrees are available we can directly use the bytes
@@ -859,7 +863,7 @@ impl<'tcx> Constructor<'tcx> {
                 .any(|other| slice.is_covered_by(other)),
             // This constructor is never covered by anything else
             NonExhaustive => false,
-            Str(..) | FloatRange(..) | Opaque | Missing { .. } | Wildcard | Or => {
+            Str(..) | F32Range(..) | F64Range(..) | Opaque | Missing { .. } | Wildcard | Or => {
                 span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self)
             }
         }
@@ -1203,7 +1207,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
                 _ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
             },
             Str(..)
-            | FloatRange(..)
+            | F32Range(..)
+            | F64Range(..)
             | IntRange(..)
             | NonExhaustive
             | Opaque
@@ -1348,8 +1353,19 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
                     fields = Fields::empty();
                 } else {
                     match pat.ty.kind() {
-                        ty::Float(_) => {
-                            ctor = FloatRange(*value, *value, RangeEnd::Included);
+                        ty::Float(float_ty) => {
+                            let bits = value.eval_bits(cx.tcx, cx.param_env);
+                            use rustc_apfloat::Float;
+                            ctor = match float_ty {
+                                ty::FloatTy::F32 => {
+                                    let value = rustc_apfloat::ieee::Single::from_bits(bits);
+                                    F32Range(value, value, RangeEnd::Included)
+                                }
+                                ty::FloatTy::F64 => {
+                                    let value = rustc_apfloat::ieee::Double::from_bits(bits);
+                                    F64Range(value, value, RangeEnd::Included)
+                                }
+                            };
                             fields = Fields::empty();
                         }
                         ty::Ref(_, t, _) if t.is_str() => {
@@ -1376,17 +1392,25 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
                 }
             }
             &PatKind::Range(box PatRange { lo, hi, end }) => {
+                use rustc_apfloat::Float;
                 let ty = lo.ty();
-                ctor = if let Some(int_range) = IntRange::from_range(
-                    cx.tcx,
-                    lo.eval_bits(cx.tcx, cx.param_env),
-                    hi.eval_bits(cx.tcx, cx.param_env),
-                    ty,
-                    &end,
-                ) {
-                    IntRange(int_range)
-                } else {
-                    FloatRange(lo, hi, end)
+                let lo = lo.eval_bits(cx.tcx, cx.param_env);
+                let hi = hi.eval_bits(cx.tcx, cx.param_env);
+                ctor = match ty.kind() {
+                    ty::Char | ty::Int(_) | ty::Uint(_) => {
+                        IntRange(IntRange::from_range(cx.tcx, lo, hi, ty, &end).unwrap())
+                    }
+                    ty::Float(ty::FloatTy::F32) => {
+                        let lo = rustc_apfloat::ieee::Single::from_bits(lo);
+                        let hi = rustc_apfloat::ieee::Single::from_bits(hi);
+                        F32Range(lo, hi, *end)
+                    }
+                    ty::Float(ty::FloatTy::F64) => {
+                        let lo = rustc_apfloat::ieee::Double::from_bits(lo);
+                        let hi = rustc_apfloat::ieee::Double::from_bits(hi);
+                        F64Range(lo, hi, *end)
+                    }
+                    _ => bug!("invalid type for range pattern: {}", ty),
                 };
                 fields = Fields::empty();
             }
@@ -1491,14 +1515,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
                 }
             }
             &Str(value) => PatKind::Constant { value },
-            &FloatRange(lo, hi, end) => PatKind::Range(Box::new(PatRange { lo, hi, end })),
             IntRange(range) => return range.to_pat(cx.tcx, self.ty),
             Wildcard | NonExhaustive => PatKind::Wild,
             Missing { .. } => bug!(
                 "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
                 `Missing` should have been processed in `apply_constructors`"
             ),
-            Opaque | Or => {
+            F32Range(..) | F64Range(..) | Opaque | Or => {
                 bug!("can't convert to pattern: {:?}", self)
             }
         };
@@ -1673,11 +1696,8 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
                 }
                 write!(f, "]")
             }
-            &FloatRange(lo, hi, end) => {
-                write!(f, "{lo}")?;
-                write!(f, "{end}")?;
-                write!(f, "{hi}")
-            }
+            F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
+            F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
             IntRange(range) => write!(f, "{range:?}"), // Best-effort, will render e.g. `false` as `0..=0`
             Wildcard | Missing { .. } | NonExhaustive => write!(f, "_ : {:?}", self.ty),
             Or => {
diff --git a/tests/ui/pattern/usefulness/floats.rs b/tests/ui/pattern/usefulness/floats.rs
index 095f5ac9a89..2616dfadb85 100644
--- a/tests/ui/pattern/usefulness/floats.rs
+++ b/tests/ui/pattern/usefulness/floats.rs
@@ -1,19 +1,45 @@
+#![feature(exclusive_range_pattern)]
 #![allow(illegal_floating_point_literal_pattern)]
 #![deny(unreachable_patterns)]
 
 fn main() {
     match 0.0 {
-      0.0..=1.0 => {}
-      _ => {} // ok
+        0.0..=1.0 => {}
+        _ => {} // ok
     }
 
-    match 0.0 { //~ ERROR non-exhaustive patterns
-      0.0..=1.0 => {}
+    match 0.0 {
+        //~^ ERROR non-exhaustive patterns
+        0.0..=1.0 => {}
     }
 
     match 1.0f64 {
-      0.01f64 ..= 6.5f64 => {}
-      0.02f64 => {} //~ ERROR unreachable pattern
-      _ => {}
+        0.01f64..=6.5f64 => {}
+        0.005f64 => {}
+        0.01f64 => {} //~ ERROR unreachable pattern
+        0.02f64 => {} //~ ERROR unreachable pattern
+        6.5f64 => {}  //~ ERROR unreachable pattern
+        6.6f64 => {}
+        1.0f64..=4.0f64 => {} //~ ERROR unreachable pattern
+        5.0f64..=7.0f64 => {}
+        _ => {}
+    };
+    match 1.0f64 {
+        0.01f64..6.5f64 => {}
+        6.5f64 => {} // 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
+        _ => {}
     };
 }
diff --git a/tests/ui/pattern/usefulness/floats.stderr b/tests/ui/pattern/usefulness/floats.stderr
index d66d4ba298b..f5041911824 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:10:11
+  --> $DIR/floats.rs:11:11
    |
 LL |     match 0.0 {
    |           ^^^ pattern `_` not covered
@@ -7,22 +7,58 @@ LL |     match 0.0 {
    = note: the matched value is of type `f64`
 help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
    |
-LL ~       0.0..=1.0 => {},
-LL +       _ => todo!()
+LL ~         0.0..=1.0 => {},
+LL +         _ => todo!()
    |
 
 error: unreachable pattern
-  --> $DIR/floats.rs:16:7
+  --> $DIR/floats.rs:19:9
    |
-LL |       0.02f64 => {}
-   |       ^^^^^^^
+LL |         0.01f64 => {}
+   |         ^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/floats.rs:2:9
+  --> $DIR/floats.rs:3:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: unreachable pattern
+  --> $DIR/floats.rs:20:9
+   |
+LL |         0.02f64 => {}
+   |         ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/floats.rs:21:9
+   |
+LL |         6.5f64 => {}
+   |         ^^^^^^
+
+error: unreachable pattern
+  --> $DIR/floats.rs:23:9
+   |
+LL |         1.0f64..=4.0f64 => {}
+   |         ^^^^^^^^^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/floats.rs:35:9
+   |
+LL |         0.01f32 => {}
+   |         ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/floats.rs:36:9
+   |
+LL |         0.02f32 => {}
+   |         ^^^^^^^
+
+error: unreachable pattern
+  --> $DIR/floats.rs:37:9
+   |
+LL |         6.5f32 => {}
+   |         ^^^^^^
+
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0004`.