@@ -56,6 +56,7 @@ use rustc_hir::RangeEnd;
56
56
use rustc_index:: Idx ;
57
57
use rustc_middle:: middle:: stability:: EvalResult ;
58
58
use rustc_middle:: mir;
59
+ use rustc_middle:: mir:: interpret:: Scalar ;
59
60
use rustc_middle:: thir:: { FieldPat , Pat , PatKind , PatRange , PatRangeBoundary } ;
60
61
use rustc_middle:: ty:: layout:: IntegerExt ;
61
62
use rustc_middle:: ty:: { self , Ty , TyCtxt , VariantDef } ;
@@ -139,20 +140,32 @@ impl MaybeInfiniteInt {
139
140
PatRangeBoundary :: PosInfinity => PosInfinity ,
140
141
}
141
142
}
143
+ // This could change from finite to infinite if we got `usize::MAX+1` after range splitting.
142
144
fn to_pat_range_bdy < ' tcx > ( self , ty : Ty < ' tcx > , tcx : TyCtxt < ' tcx > ) -> PatRangeBoundary < ' tcx > {
143
145
match self {
144
146
NegInfinity => PatRangeBoundary :: NegInfinity ,
145
147
Finite ( x) => {
146
148
let bias = Self :: signed_bias ( tcx, ty) ;
147
149
let bits = x ^ bias;
148
- let env = ty:: ParamEnv :: empty ( ) . and ( ty) ;
149
- let value = mir:: Const :: from_bits ( tcx, bits, env) ;
150
- PatRangeBoundary :: Finite ( value)
150
+ let size = ty. primitive_size ( tcx) ;
151
+ match Scalar :: try_from_uint ( bits, size) {
152
+ Some ( scalar) => {
153
+ let value = mir:: Const :: from_scalar ( tcx, scalar, ty) ;
154
+ PatRangeBoundary :: Finite ( value)
155
+ }
156
+ // The value doesn't fit. Since `x >= 0` and 0 always encodes the minimum value
157
+ // for a type, the problem isn't that the value is too small. So it must be too
158
+ // large.
159
+ None => PatRangeBoundary :: PosInfinity ,
160
+ }
151
161
}
152
162
JustAfterMax | PosInfinity => PatRangeBoundary :: PosInfinity ,
153
163
}
154
164
}
155
165
166
+ fn is_finite ( self ) -> bool {
167
+ matches ! ( self , Finite ( _) )
168
+ }
156
169
fn minus_one ( self ) -> Self {
157
170
match self {
158
171
Finite ( n) => match n. checked_sub ( 1 ) {
@@ -169,22 +182,24 @@ impl MaybeInfiniteInt {
169
182
Some ( m) => Finite ( m) ,
170
183
None => JustAfterMax ,
171
184
} ,
185
+ JustAfterMax => bug ! ( ) ,
172
186
x => x,
173
187
}
174
188
}
175
189
}
176
190
177
- /// An inclusive interval, used for precise integer exhaustiveness checking.
178
- /// `IntRange`s always store a contiguous range.
191
+ /// An inclusive interval, used for precise integer exhaustiveness checking. `IntRange`s always
192
+ /// store a contiguous range.
179
193
///
180
- /// `IntRange` is never used to encode an empty range or a "range" that wraps
181
- /// around the (offset) space: i.e., `range.lo <= range.hi`.
194
+ /// `IntRange` is never used to encode an empty range or a "range" that wraps around the (offset)
195
+ /// space: i.e., `range.lo <= range.hi`.
182
196
///
183
- /// The range can have open ends.
197
+ /// Note: the range can be `NegInfinity..=NegInfinity` or `PosInfinity..=PosInfinity` to represent
198
+ /// the values before `isize::MIN` and after `isize::MAX`/`usize::MAX`.
184
199
#[ derive( Clone , Copy , PartialEq , Eq ) ]
185
200
pub ( crate ) struct IntRange {
186
- pub ( crate ) lo : MaybeInfiniteInt , // Must not be `PosInfinity`.
187
- pub ( crate ) hi : MaybeInfiniteInt , // Must not be `NegInfinity`.
201
+ pub ( crate ) lo : MaybeInfiniteInt ,
202
+ pub ( crate ) hi : MaybeInfiniteInt ,
188
203
}
189
204
190
205
impl IntRange {
@@ -195,9 +210,7 @@ impl IntRange {
195
210
196
211
/// Best effort; will not know that e.g. `255u8..` is a singleton.
197
212
pub ( super ) fn is_singleton ( & self ) -> bool {
198
- // Since `lo` and `hi` can't be the same `Infinity`, this correctly only detects a
199
- // `Finite(x)` singleton.
200
- self . lo == self . hi
213
+ self . lo == self . hi && self . lo . is_finite ( )
201
214
}
202
215
203
216
#[ inline]
@@ -310,18 +323,49 @@ impl IntRange {
310
323
} )
311
324
}
312
325
326
+ /// Whether the range denotes the values before `isize::MIN` or the values after
327
+ /// `usize::MAX`/`isize::MAX`.
328
+ pub ( crate ) fn is_beyond_boundaries < ' tcx > ( & self , ty : Ty < ' tcx > , tcx : TyCtxt < ' tcx > ) -> bool {
329
+ // First check if we are usize/isize to avoid unnecessary `to_pat_range_bdy`.
330
+ ty. is_ptr_sized_integral ( ) && !tcx. features ( ) . precise_pointer_size_matching && {
331
+ let lo = self . lo . to_pat_range_bdy ( ty, tcx) ;
332
+ let hi = self . hi . to_pat_range_bdy ( ty, tcx) ;
333
+ matches ! ( lo, PatRangeBoundary :: PosInfinity )
334
+ || matches ! ( hi, PatRangeBoundary :: NegInfinity )
335
+ }
336
+ }
313
337
/// Only used for displaying the range.
314
338
pub ( super ) fn to_pat < ' tcx > ( & self , ty : Ty < ' tcx > , tcx : TyCtxt < ' tcx > ) -> Pat < ' tcx > {
315
- let lo = self . lo . to_pat_range_bdy ( ty , tcx ) ;
316
- let hi = self . hi . to_pat_range_bdy ( ty , tcx ) ;
317
-
318
- let kind = if self . is_singleton ( ) {
339
+ let kind = if matches ! ( ( self . lo, self . hi ) , ( NegInfinity , PosInfinity ) ) {
340
+ PatKind :: Wild
341
+ } else if self . is_singleton ( ) {
342
+ let lo = self . lo . to_pat_range_bdy ( ty , tcx ) ;
319
343
let value = lo. as_finite ( ) . unwrap ( ) ;
320
344
PatKind :: Constant { value }
321
- } else if matches ! ( ( self . lo, self . hi) , ( NegInfinity , PosInfinity ) ) {
322
- PatKind :: Wild
323
345
} else {
324
- PatKind :: Range ( Box :: new ( PatRange { lo, hi, end : RangeEnd :: Included , ty } ) )
346
+ let mut lo = self . lo . to_pat_range_bdy ( ty, tcx) ;
347
+ let mut hi = self . hi . to_pat_range_bdy ( ty, tcx) ;
348
+ let end = if hi. is_finite ( ) {
349
+ RangeEnd :: Included
350
+ } else {
351
+ // `0..=` isn't a valid pattern.
352
+ RangeEnd :: Excluded
353
+ } ;
354
+ if matches ! ( hi, PatRangeBoundary :: NegInfinity ) {
355
+ // The range denotes the values before `isize::MIN`.
356
+ let c = ty. numeric_min_val ( tcx) . unwrap ( ) ;
357
+ let value = mir:: Const :: from_ty_const ( c, tcx) ;
358
+ hi = PatRangeBoundary :: Finite ( value) ;
359
+ }
360
+ if matches ! ( lo, PatRangeBoundary :: PosInfinity ) {
361
+ // The range denotes the values after `usize::MAX`/`isize::MAX`.
362
+ // We represent this as `usize::MAX..` which is slightly incorrect but probably
363
+ // clear enough.
364
+ let c = ty. numeric_max_val ( tcx) . unwrap ( ) ;
365
+ let value = mir:: Const :: from_ty_const ( c, tcx) ;
366
+ lo = PatRangeBoundary :: Finite ( value) ;
367
+ }
368
+ PatKind :: Range ( Box :: new ( PatRange { lo, hi, end, ty } ) )
325
369
} ;
326
370
327
371
Pat { ty, span : DUMMY_SP , kind }
@@ -843,9 +887,7 @@ pub(super) enum ConstructorSet {
843
887
Bool ,
844
888
/// The type is spanned by integer values. The range or ranges give the set of allowed values.
845
889
/// The second range is only useful for `char`.
846
- /// `non_exhaustive` is used when the range is not allowed to be matched exhaustively (that's
847
- /// for usize/isize).
848
- Integers { range_1 : IntRange , range_2 : Option < IntRange > , non_exhaustive : bool } ,
890
+ Integers { range_1 : IntRange , range_2 : Option < IntRange > } ,
849
891
/// The type is matched by slices. The usize is the compile-time length of the array, if known.
850
892
Slice ( Option < usize > ) ,
851
893
/// The type is matched by slices whose elements are uninhabited.
@@ -903,27 +945,37 @@ impl ConstructorSet {
903
945
Self :: Integers {
904
946
range_1 : make_range ( '\u{0000}' as u128 , '\u{D7FF}' as u128 ) ,
905
947
range_2 : Some ( make_range ( '\u{E000}' as u128 , '\u{10FFFF}' as u128 ) ) ,
906
- non_exhaustive : false ,
907
948
}
908
949
}
909
950
& ty:: Int ( ity) => {
910
- // `usize`/`isize` are not allowed to be matched exhaustively unless the
911
- // `precise_pointer_size_matching` feature is enabled.
912
- let non_exhaustive =
913
- ty. is_ptr_sized_integral ( ) && !cx. tcx . features ( ) . precise_pointer_size_matching ;
914
- let bits = Integer :: from_int_ty ( & cx. tcx , ity) . size ( ) . bits ( ) as u128 ;
915
- let min = 1u128 << ( bits - 1 ) ;
916
- let max = min - 1 ;
917
- Self :: Integers { range_1 : make_range ( min, max) , non_exhaustive, range_2 : None }
951
+ let range = if ty. is_ptr_sized_integral ( )
952
+ && !cx. tcx . features ( ) . precise_pointer_size_matching
953
+ {
954
+ // The min/max values of `isize` are not allowed to be observed unless the
955
+ // `precise_pointer_size_matching` feature is enabled.
956
+ IntRange { lo : NegInfinity , hi : PosInfinity }
957
+ } else {
958
+ let bits = Integer :: from_int_ty ( & cx. tcx , ity) . size ( ) . bits ( ) as u128 ;
959
+ let min = 1u128 << ( bits - 1 ) ;
960
+ let max = min - 1 ;
961
+ make_range ( min, max)
962
+ } ;
963
+ Self :: Integers { range_1 : range, range_2 : None }
918
964
}
919
965
& ty:: Uint ( uty) => {
920
- // `usize`/`isize` are not allowed to be matched exhaustively unless the
921
- // `precise_pointer_size_matching` feature is enabled.
922
- let non_exhaustive =
923
- ty. is_ptr_sized_integral ( ) && !cx. tcx . features ( ) . precise_pointer_size_matching ;
924
- let size = Integer :: from_uint_ty ( & cx. tcx , uty) . size ( ) ;
925
- let max = size. truncate ( u128:: MAX ) ;
926
- Self :: Integers { range_1 : make_range ( 0 , max) , non_exhaustive, range_2 : None }
966
+ let range = if ty. is_ptr_sized_integral ( )
967
+ && !cx. tcx . features ( ) . precise_pointer_size_matching
968
+ {
969
+ // The max value of `usize` is not allowed to be observed unless the
970
+ // `precise_pointer_size_matching` feature is enabled.
971
+ let lo = MaybeInfiniteInt :: new_finite ( cx. tcx , ty, 0 ) ;
972
+ IntRange { lo, hi : PosInfinity }
973
+ } else {
974
+ let size = Integer :: from_uint_ty ( & cx. tcx , uty) . size ( ) ;
975
+ let max = size. truncate ( u128:: MAX ) ;
976
+ make_range ( 0 , max)
977
+ } ;
978
+ Self :: Integers { range_1 : range, range_2 : None }
927
979
}
928
980
ty:: Array ( sub_ty, len) if len. try_eval_target_usize ( cx. tcx , cx. param_env ) . is_some ( ) => {
929
981
let len = len. eval_target_usize ( cx. tcx , cx. param_env ) as usize ;
@@ -1078,7 +1130,7 @@ impl ConstructorSet {
1078
1130
missing. push ( Bool ( true ) ) ;
1079
1131
}
1080
1132
}
1081
- ConstructorSet :: Integers { range_1, range_2, non_exhaustive } => {
1133
+ ConstructorSet :: Integers { range_1, range_2 } => {
1082
1134
let seen_ranges: Vec < _ > =
1083
1135
seen. map ( |ctor| ctor. as_int_range ( ) . unwrap ( ) . clone ( ) ) . collect ( ) ;
1084
1136
for ( seen, splitted_range) in range_1. split ( seen_ranges. iter ( ) . cloned ( ) ) {
@@ -1095,10 +1147,6 @@ impl ConstructorSet {
1095
1147
}
1096
1148
}
1097
1149
}
1098
-
1099
- if * non_exhaustive {
1100
- missing. push ( NonExhaustive ) ;
1101
- }
1102
1150
}
1103
1151
& ConstructorSet :: Slice ( array_len) => {
1104
1152
let seen_slices = seen. map ( |c| c. as_slice ( ) . unwrap ( ) ) ;
0 commit comments