Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e0d7ed1

Browse files
committedOct 1, 2023
Auto merge of #116281 - Nadrieril:eager-const-eval, r=cjgillot
Cleanup number handling in match exhaustiveness Doing a little bit of cleanup; handling number constants was somewhat messy. In particular, this: - evals float consts once instead of repetitively - reduces `Constructor` from 88 bytes to 56 (`mir::Const` is big!) The `fast_try_eval_bits` function was mostly constructed from inlining existing code but I don't fully understand it; I don't follow how consts work and are evaluated very well.
2 parents 51ddc74 + eac7bcd commit e0d7ed1

File tree

4 files changed

+206
-139
lines changed

4 files changed

+206
-139
lines changed
 

‎compiler/rustc_middle/src/mir/consts.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,16 @@ impl<'tcx> Const<'tcx> {
288288
tcx: TyCtxt<'tcx>,
289289
param_env: ty::ParamEnv<'tcx>,
290290
) -> Option<ScalarInt> {
291-
self.try_eval_scalar(tcx, param_env)?.try_to_int().ok()
291+
match self {
292+
// If the constant is already evaluated, we shortcut here.
293+
Const::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => {
294+
valtree.try_to_scalar_int()
295+
},
296+
// This is a more general form of the previous case.
297+
_ => {
298+
self.try_eval_scalar(tcx, param_env)?.try_to_int().ok()
299+
},
300+
}
292301
}
293302

294303
#[inline]

‎compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs

Lines changed: 119 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ use std::ops::RangeInclusive;
5050

5151
use smallvec::{smallvec, SmallVec};
5252

53+
use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS};
5354
use rustc_data_structures::captures::Captures;
5455
use rustc_hir::{HirId, RangeEnd};
5556
use rustc_index::Idx;
@@ -60,12 +61,11 @@ use rustc_middle::ty::layout::IntegerExt;
6061
use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
6162
use rustc_session::lint;
6263
use rustc_span::{Span, DUMMY_SP};
63-
use rustc_target::abi::{FieldIdx, Integer, Size, VariantIdx, FIRST_VARIANT};
64+
use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
6465

6566
use self::Constructor::*;
6667
use self::SliceKind::*;
6768

68-
use super::compare_const_vals;
6969
use super::usefulness::{MatchCheckCtxt, PatCtxt};
7070
use crate::errors::{Overlap, OverlappingRangeEndpoints};
7171

@@ -99,10 +99,6 @@ fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
9999
#[derive(Clone, PartialEq, Eq)]
100100
pub(crate) struct IntRange {
101101
range: RangeInclusive<u128>,
102-
/// Keeps the bias used for encoding the range. It depends on the type of the range and
103-
/// possibly the pointer size of the current architecture. The algorithm ensures we never
104-
/// compare `IntRange`s with different types/architectures.
105-
bias: u128,
106102
}
107103

108104
impl IntRange {
@@ -120,37 +116,12 @@ impl IntRange {
120116
}
121117

122118
#[inline]
123-
fn integral_size_and_signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Size, u128)> {
124-
match *ty.kind() {
125-
ty::Bool => Some((Size::from_bytes(1), 0)),
126-
ty::Char => Some((Size::from_bytes(4), 0)),
127-
ty::Int(ity) => {
128-
let size = Integer::from_int_ty(&tcx, ity).size();
129-
Some((size, 1u128 << (size.bits() as u128 - 1)))
130-
}
131-
ty::Uint(uty) => Some((Integer::from_uint_ty(&tcx, uty).size(), 0)),
132-
_ => None,
133-
}
134-
}
135-
136-
#[inline]
137-
fn from_constant<'tcx>(
138-
tcx: TyCtxt<'tcx>,
139-
param_env: ty::ParamEnv<'tcx>,
140-
value: mir::Const<'tcx>,
141-
) -> Option<IntRange> {
142-
let ty = value.ty();
143-
let (target_size, bias) = Self::integral_size_and_signed_bias(tcx, ty)?;
144-
let val = match value {
145-
mir::Const::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => {
146-
valtree.unwrap_leaf().to_bits(target_size).ok()
147-
},
148-
// This is a more general form of the previous case.
149-
_ => value.try_eval_bits(tcx, param_env),
150-
}?;
151-
152-
let val = val ^ bias;
153-
Some(IntRange { range: val..=val, bias })
119+
fn from_bits<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, bits: u128) -> IntRange {
120+
let bias = IntRange::signed_bias(tcx, ty);
121+
// Perform a shift if the underlying types are signed,
122+
// which makes the interval arithmetic simpler.
123+
let val = bits ^ bias;
124+
IntRange { range: val..=val }
154125
}
155126

156127
#[inline]
@@ -159,20 +130,18 @@ impl IntRange {
159130
lo: u128,
160131
hi: u128,
161132
ty: Ty<'tcx>,
162-
end: &RangeEnd,
163-
) -> Option<IntRange> {
164-
Self::is_integral(ty).then(|| {
165-
// Perform a shift if the underlying types are signed,
166-
// which makes the interval arithmetic simpler.
167-
let bias = IntRange::signed_bias(tcx, ty);
168-
let (lo, hi) = (lo ^ bias, hi ^ bias);
169-
let offset = (*end == RangeEnd::Excluded) as u128;
170-
if lo > hi || (lo == hi && *end == RangeEnd::Excluded) {
171-
// This should have been caught earlier by E0030.
172-
bug!("malformed range pattern: {}..={}", lo, (hi - offset));
173-
}
174-
IntRange { range: lo..=(hi - offset), bias }
175-
})
133+
end: RangeEnd,
134+
) -> IntRange {
135+
// Perform a shift if the underlying types are signed,
136+
// which makes the interval arithmetic simpler.
137+
let bias = IntRange::signed_bias(tcx, ty);
138+
let (lo, hi) = (lo ^ bias, hi ^ bias);
139+
let offset = (end == RangeEnd::Excluded) as u128;
140+
if lo > hi || (lo == hi && end == RangeEnd::Excluded) {
141+
// This should have been caught earlier by E0030.
142+
bug!("malformed range pattern: {}..={}", lo, (hi - offset));
143+
}
144+
IntRange { range: lo..=(hi - offset) }
176145
}
177146

178147
// The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
@@ -194,7 +163,7 @@ impl IntRange {
194163
let (lo, hi) = self.boundaries();
195164
let (other_lo, other_hi) = other.boundaries();
196165
if lo <= other_hi && other_lo <= hi {
197-
Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi), bias: self.bias })
166+
Some(IntRange { range: max(lo, other_lo)..=min(hi, other_hi) })
198167
} else {
199168
None
200169
}
@@ -221,7 +190,7 @@ impl IntRange {
221190
fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> {
222191
let (lo, hi) = self.boundaries();
223192

224-
let bias = self.bias;
193+
let bias = IntRange::signed_bias(tcx, ty);
225194
let (lo, hi) = (lo ^ bias, hi ^ bias);
226195

227196
let env = ty::ParamEnv::empty().and(ty);
@@ -304,8 +273,6 @@ impl IntRange {
304273
impl fmt::Debug for IntRange {
305274
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306275
let (lo, hi) = self.boundaries();
307-
let bias = self.bias;
308-
let (lo, hi) = (lo ^ bias, hi ^ bias);
309276
write!(f, "{lo}")?;
310277
write!(f, "{}", RangeEnd::Included)?;
311278
write!(f, "{hi}")
@@ -402,7 +369,7 @@ impl SplitIntRange {
402369
(JustBefore(n), AfterMax) => n..=u128::MAX,
403370
_ => unreachable!(), // Ruled out by the sorting and filtering we did
404371
};
405-
IntRange { range, bias: self.range.bias }
372+
IntRange { range }
406373
})
407374
}
408375
}
@@ -619,7 +586,8 @@ pub(super) enum Constructor<'tcx> {
619586
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
620587
IntRange(IntRange),
621588
/// Ranges of floating-point literal values (`2.0..=5.2`).
622-
FloatRange(mir::Const<'tcx>, mir::Const<'tcx>, RangeEnd),
589+
F32Range(IeeeFloat<SingleS>, IeeeFloat<SingleS>, RangeEnd),
590+
F64Range(IeeeFloat<DoubleS>, IeeeFloat<DoubleS>, RangeEnd),
623591
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
624592
Str(mir::Const<'tcx>),
625593
/// Array and slice patterns.
@@ -634,7 +602,9 @@ pub(super) enum Constructor<'tcx> {
634602
/// Stands for constructors that are not seen in the matrix, as explained in the documentation
635603
/// for [`SplitWildcard`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns`
636604
/// lint.
637-
Missing { nonexhaustive_enum_missing_real_variants: bool },
605+
Missing {
606+
nonexhaustive_enum_missing_real_variants: bool,
607+
},
638608
/// Wildcard pattern.
639609
Wildcard,
640610
/// Or-pattern.
@@ -722,7 +692,8 @@ impl<'tcx> Constructor<'tcx> {
722692
},
723693
Slice(slice) => slice.arity(),
724694
Str(..)
725-
| FloatRange(..)
695+
| F32Range(..)
696+
| F64Range(..)
726697
| IntRange(..)
727698
| NonExhaustive
728699
| Opaque
@@ -795,21 +766,21 @@ impl<'tcx> Constructor<'tcx> {
795766
(Variant(self_id), Variant(other_id)) => self_id == other_id,
796767

797768
(IntRange(self_range), IntRange(other_range)) => self_range.is_covered_by(other_range),
798-
(
799-
FloatRange(self_from, self_to, self_end),
800-
FloatRange(other_from, other_to, other_end),
801-
) => {
802-
match (
803-
compare_const_vals(pcx.cx.tcx, *self_to, *other_to, pcx.cx.param_env),
804-
compare_const_vals(pcx.cx.tcx, *self_from, *other_from, pcx.cx.param_env),
805-
) {
806-
(Some(to), Some(from)) => {
807-
(from == Ordering::Greater || from == Ordering::Equal)
808-
&& (to == Ordering::Less
809-
|| (other_end == self_end && to == Ordering::Equal))
769+
(F32Range(self_from, self_to, self_end), F32Range(other_from, other_to, other_end)) => {
770+
self_from.ge(other_from)
771+
&& match self_to.partial_cmp(other_to) {
772+
Some(Ordering::Less) => true,
773+
Some(Ordering::Equal) => other_end == self_end,
774+
_ => false,
775+
}
776+
}
777+
(F64Range(self_from, self_to, self_end), F64Range(other_from, other_to, other_end)) => {
778+
self_from.ge(other_from)
779+
&& match self_to.partial_cmp(other_to) {
780+
Some(Ordering::Less) => true,
781+
Some(Ordering::Equal) => other_end == self_end,
782+
_ => false,
810783
}
811-
_ => false,
812-
}
813784
}
814785
(Str(self_val), Str(other_val)) => {
815786
// FIXME Once valtrees are available we can directly use the bytes
@@ -859,7 +830,7 @@ impl<'tcx> Constructor<'tcx> {
859830
.any(|other| slice.is_covered_by(other)),
860831
// This constructor is never covered by anything else
861832
NonExhaustive => false,
862-
Str(..) | FloatRange(..) | Opaque | Missing { .. } | Wildcard | Or => {
833+
Str(..) | F32Range(..) | F64Range(..) | Opaque | Missing { .. } | Wildcard | Or => {
863834
span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self)
864835
}
865836
}
@@ -896,7 +867,7 @@ impl<'tcx> SplitWildcard<'tcx> {
896867
let make_range = |start, end| {
897868
IntRange(
898869
// `unwrap()` is ok because we know the type is an integer.
899-
IntRange::from_range(cx.tcx, start, end, pcx.ty, &RangeEnd::Included).unwrap(),
870+
IntRange::from_range(cx.tcx, start, end, pcx.ty, RangeEnd::Included),
900871
)
901872
};
902873
// This determines the set of all possible constructors for the type `pcx.ty`. For numbers,
@@ -1203,7 +1174,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12031174
_ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
12041175
},
12051176
Str(..)
1206-
| FloatRange(..)
1177+
| F32Range(..)
1178+
| F64Range(..)
12071179
| IntRange(..)
12081180
| NonExhaustive
12091181
| Opaque
@@ -1343,50 +1315,78 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
13431315
}
13441316
}
13451317
PatKind::Constant { value } => {
1346-
if let Some(int_range) = IntRange::from_constant(cx.tcx, cx.param_env, *value) {
1347-
ctor = IntRange(int_range);
1348-
fields = Fields::empty();
1349-
} else {
1350-
match pat.ty.kind() {
1351-
ty::Float(_) => {
1352-
ctor = FloatRange(*value, *value, RangeEnd::Included);
1353-
fields = Fields::empty();
1354-
}
1355-
ty::Ref(_, t, _) if t.is_str() => {
1356-
// We want a `&str` constant to behave like a `Deref` pattern, to be compatible
1357-
// with other `Deref` patterns. This could have been done in `const_to_pat`,
1358-
// but that causes issues with the rest of the matching code.
1359-
// So here, the constructor for a `"foo"` pattern is `&` (represented by
1360-
// `Single`), and has one field. That field has constructor `Str(value)` and no
1361-
// fields.
1362-
// Note: `t` is `str`, not `&str`.
1363-
let subpattern =
1364-
DeconstructedPat::new(Str(*value), Fields::empty(), *t, pat.span);
1365-
ctor = Single;
1366-
fields = Fields::singleton(cx, subpattern)
1367-
}
1368-
// All constants that can be structurally matched have already been expanded
1369-
// into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
1370-
// opaque.
1371-
_ => {
1372-
ctor = Opaque;
1373-
fields = Fields::empty();
1374-
}
1318+
match pat.ty.kind() {
1319+
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => {
1320+
ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
1321+
Some(bits) => IntRange(IntRange::from_bits(cx.tcx, pat.ty, bits)),
1322+
None => Opaque,
1323+
};
1324+
fields = Fields::empty();
1325+
}
1326+
ty::Float(ty::FloatTy::F32) => {
1327+
ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
1328+
Some(bits) => {
1329+
use rustc_apfloat::Float;
1330+
let value = rustc_apfloat::ieee::Single::from_bits(bits);
1331+
F32Range(value, value, RangeEnd::Included)
1332+
}
1333+
None => Opaque,
1334+
};
1335+
fields = Fields::empty();
1336+
}
1337+
ty::Float(ty::FloatTy::F64) => {
1338+
ctor = match value.try_eval_bits(cx.tcx, cx.param_env) {
1339+
Some(bits) => {
1340+
use rustc_apfloat::Float;
1341+
let value = rustc_apfloat::ieee::Double::from_bits(bits);
1342+
F64Range(value, value, RangeEnd::Included)
1343+
}
1344+
None => Opaque,
1345+
};
1346+
fields = Fields::empty();
1347+
}
1348+
ty::Ref(_, t, _) if t.is_str() => {
1349+
// We want a `&str` constant to behave like a `Deref` pattern, to be compatible
1350+
// with other `Deref` patterns. This could have been done in `const_to_pat`,
1351+
// but that causes issues with the rest of the matching code.
1352+
// So here, the constructor for a `"foo"` pattern is `&` (represented by
1353+
// `Single`), and has one field. That field has constructor `Str(value)` and no
1354+
// fields.
1355+
// Note: `t` is `str`, not `&str`.
1356+
let subpattern =
1357+
DeconstructedPat::new(Str(*value), Fields::empty(), *t, pat.span);
1358+
ctor = Single;
1359+
fields = Fields::singleton(cx, subpattern)
1360+
}
1361+
// All constants that can be structurally matched have already been expanded
1362+
// into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
1363+
// opaque.
1364+
_ => {
1365+
ctor = Opaque;
1366+
fields = Fields::empty();
13751367
}
13761368
}
13771369
}
1378-
&PatKind::Range(box PatRange { lo, hi, end }) => {
1370+
PatKind::Range(box PatRange { lo, hi, end }) => {
1371+
use rustc_apfloat::Float;
13791372
let ty = lo.ty();
1380-
ctor = if let Some(int_range) = IntRange::from_range(
1381-
cx.tcx,
1382-
lo.eval_bits(cx.tcx, cx.param_env),
1383-
hi.eval_bits(cx.tcx, cx.param_env),
1384-
ty,
1385-
&end,
1386-
) {
1387-
IntRange(int_range)
1388-
} else {
1389-
FloatRange(lo, hi, end)
1373+
let lo = lo.try_eval_bits(cx.tcx, cx.param_env).unwrap();
1374+
let hi = hi.try_eval_bits(cx.tcx, cx.param_env).unwrap();
1375+
ctor = match ty.kind() {
1376+
ty::Char | ty::Int(_) | ty::Uint(_) => {
1377+
IntRange(IntRange::from_range(cx.tcx, lo, hi, ty, *end))
1378+
}
1379+
ty::Float(ty::FloatTy::F32) => {
1380+
let lo = rustc_apfloat::ieee::Single::from_bits(lo);
1381+
let hi = rustc_apfloat::ieee::Single::from_bits(hi);
1382+
F32Range(lo, hi, *end)
1383+
}
1384+
ty::Float(ty::FloatTy::F64) => {
1385+
let lo = rustc_apfloat::ieee::Double::from_bits(lo);
1386+
let hi = rustc_apfloat::ieee::Double::from_bits(hi);
1387+
F64Range(lo, hi, *end)
1388+
}
1389+
_ => bug!("invalid type for range pattern: {}", ty),
13901390
};
13911391
fields = Fields::empty();
13921392
}
@@ -1491,14 +1491,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
14911491
}
14921492
}
14931493
&Str(value) => PatKind::Constant { value },
1494-
&FloatRange(lo, hi, end) => PatKind::Range(Box::new(PatRange { lo, hi, end })),
14951494
IntRange(range) => return range.to_pat(cx.tcx, self.ty),
14961495
Wildcard | NonExhaustive => PatKind::Wild,
14971496
Missing { .. } => bug!(
14981497
"trying to convert a `Missing` constructor into a `Pat`; this is probably a bug,
14991498
`Missing` should have been processed in `apply_constructors`"
15001499
),
1501-
Opaque | Or => {
1500+
F32Range(..) | F64Range(..) | Opaque | Or => {
15021501
bug!("can't convert to pattern: {:?}", self)
15031502
}
15041503
};
@@ -1673,11 +1672,8 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
16731672
}
16741673
write!(f, "]")
16751674
}
1676-
&FloatRange(lo, hi, end) => {
1677-
write!(f, "{lo}")?;
1678-
write!(f, "{end}")?;
1679-
write!(f, "{hi}")
1680-
}
1675+
F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
1676+
F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
16811677
IntRange(range) => write!(f, "{range:?}"), // Best-effort, will render e.g. `false` as `0..=0`
16821678
Wildcard | Missing { .. } | NonExhaustive => write!(f, "_ : {:?}", self.ty),
16831679
Or => {

‎tests/ui/pattern/usefulness/floats.rs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,45 @@
1+
#![feature(exclusive_range_pattern)]
12
#![allow(illegal_floating_point_literal_pattern)]
23
#![deny(unreachable_patterns)]
34

45
fn main() {
56
match 0.0 {
6-
0.0..=1.0 => {}
7-
_ => {} // ok
7+
0.0..=1.0 => {}
8+
_ => {} // ok
89
}
910

10-
match 0.0 { //~ ERROR non-exhaustive patterns
11-
0.0..=1.0 => {}
11+
match 0.0 {
12+
//~^ ERROR non-exhaustive patterns
13+
0.0..=1.0 => {}
1214
}
1315

1416
match 1.0f64 {
15-
0.01f64 ..= 6.5f64 => {}
16-
0.02f64 => {} //~ ERROR unreachable pattern
17-
_ => {}
17+
0.01f64..=6.5f64 => {}
18+
0.005f64 => {}
19+
0.01f64 => {} //~ ERROR unreachable pattern
20+
0.02f64 => {} //~ ERROR unreachable pattern
21+
6.5f64 => {} //~ ERROR unreachable pattern
22+
6.6f64 => {}
23+
1.0f64..=4.0f64 => {} //~ ERROR unreachable pattern
24+
5.0f64..=7.0f64 => {}
25+
_ => {}
26+
};
27+
match 1.0f64 {
28+
0.01f64..6.5f64 => {}
29+
6.5f64 => {} // this is reachable
30+
_ => {}
31+
};
32+
33+
match 1.0f32 {
34+
0.01f32..=6.5f32 => {}
35+
0.01f32 => {} //~ ERROR unreachable pattern
36+
0.02f32 => {} //~ ERROR unreachable pattern
37+
6.5f32 => {} //~ ERROR unreachable pattern
38+
_ => {}
39+
};
40+
match 1.0f32 {
41+
0.01f32..6.5f32 => {}
42+
6.5f32 => {} // this is reachable
43+
_ => {}
1844
};
1945
}
Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,64 @@
11
error[E0004]: non-exhaustive patterns: `_` not covered
2-
--> $DIR/floats.rs:10:11
2+
--> $DIR/floats.rs:11:11
33
|
44
LL | match 0.0 {
55
| ^^^ pattern `_` not covered
66
|
77
= note: the matched value is of type `f64`
88
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
99
|
10-
LL ~ 0.0..=1.0 => {},
11-
LL + _ => todo!()
10+
LL ~ 0.0..=1.0 => {},
11+
LL + _ => todo!()
1212
|
1313

1414
error: unreachable pattern
15-
--> $DIR/floats.rs:16:7
15+
--> $DIR/floats.rs:19:9
1616
|
17-
LL | 0.02f64 => {}
18-
| ^^^^^^^
17+
LL | 0.01f64 => {}
18+
| ^^^^^^^
1919
|
2020
note: the lint level is defined here
21-
--> $DIR/floats.rs:2:9
21+
--> $DIR/floats.rs:3:9
2222
|
2323
LL | #![deny(unreachable_patterns)]
2424
| ^^^^^^^^^^^^^^^^^^^^
2525

26-
error: aborting due to 2 previous errors
26+
error: unreachable pattern
27+
--> $DIR/floats.rs:20:9
28+
|
29+
LL | 0.02f64 => {}
30+
| ^^^^^^^
31+
32+
error: unreachable pattern
33+
--> $DIR/floats.rs:21:9
34+
|
35+
LL | 6.5f64 => {}
36+
| ^^^^^^
37+
38+
error: unreachable pattern
39+
--> $DIR/floats.rs:23:9
40+
|
41+
LL | 1.0f64..=4.0f64 => {}
42+
| ^^^^^^^^^^^^^^^
43+
44+
error: unreachable pattern
45+
--> $DIR/floats.rs:35:9
46+
|
47+
LL | 0.01f32 => {}
48+
| ^^^^^^^
49+
50+
error: unreachable pattern
51+
--> $DIR/floats.rs:36:9
52+
|
53+
LL | 0.02f32 => {}
54+
| ^^^^^^^
55+
56+
error: unreachable pattern
57+
--> $DIR/floats.rs:37:9
58+
|
59+
LL | 6.5f32 => {}
60+
| ^^^^^^
61+
62+
error: aborting due to 8 previous errors
2763

2864
For more information about this error, try `rustc --explain E0004`.

0 commit comments

Comments
 (0)
Please sign in to comment.