@@ -56,6 +56,7 @@ use rustc_hir::RangeEnd;
5656use rustc_index:: Idx ;
5757use rustc_middle:: middle:: stability:: EvalResult ;
5858use rustc_middle:: mir;
59+ use rustc_middle:: mir:: interpret:: Scalar ;
5960use rustc_middle:: thir:: { FieldPat , Pat , PatKind , PatRange , PatRangeBoundary } ;
6061use rustc_middle:: ty:: layout:: IntegerExt ;
6162use rustc_middle:: ty:: { self , Ty , TyCtxt , VariantDef } ;
@@ -139,20 +140,32 @@ impl MaybeInfiniteInt {
139140 PatRangeBoundary :: PosInfinity => PosInfinity ,
140141 }
141142 }
143+ // This could change from finite to infinite if we got `usize::MAX+1` after range splitting.
142144 fn to_pat_range_bdy < ' tcx > ( self , ty : Ty < ' tcx > , tcx : TyCtxt < ' tcx > ) -> PatRangeBoundary < ' tcx > {
143145 match self {
144146 NegInfinity => PatRangeBoundary :: NegInfinity ,
145147 Finite ( x) => {
146148 let bias = Self :: signed_bias ( tcx, ty) ;
147149 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+ }
151161 }
152162 JustAfterMax | PosInfinity => PatRangeBoundary :: PosInfinity ,
153163 }
154164 }
155165
166+ fn is_finite ( self ) -> bool {
167+ matches ! ( self , Finite ( _) )
168+ }
156169 fn minus_one ( self ) -> Self {
157170 match self {
158171 Finite ( n) => match n. checked_sub ( 1 ) {
@@ -169,22 +182,24 @@ impl MaybeInfiniteInt {
169182 Some ( m) => Finite ( m) ,
170183 None => JustAfterMax ,
171184 } ,
185+ JustAfterMax => bug ! ( ) ,
172186 x => x,
173187 }
174188 }
175189}
176190
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.
179193///
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`.
182196///
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`.
184199#[ derive( Clone , Copy , PartialEq , Eq ) ]
185200pub ( 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 ,
188203}
189204
190205impl IntRange {
@@ -195,9 +210,7 @@ impl IntRange {
195210
196211 /// Best effort; will not know that e.g. `255u8..` is a singleton.
197212 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 ( )
201214 }
202215
203216 #[ inline]
@@ -310,18 +323,49 @@ impl IntRange {
310323 } )
311324 }
312325
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+ }
313337 /// Only used for displaying the range.
314338 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 ) ;
319343 let value = lo. as_finite ( ) . unwrap ( ) ;
320344 PatKind :: Constant { value }
321- } else if matches ! ( ( self . lo, self . hi) , ( NegInfinity , PosInfinity ) ) {
322- PatKind :: Wild
323345 } 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 } ) )
325369 } ;
326370
327371 Pat { ty, span : DUMMY_SP , kind }
@@ -843,9 +887,7 @@ pub(super) enum ConstructorSet {
843887 Bool ,
844888 /// The type is spanned by integer values. The range or ranges give the set of allowed values.
845889 /// 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 > } ,
849891 /// The type is matched by slices. The usize is the compile-time length of the array, if known.
850892 Slice ( Option < usize > ) ,
851893 /// The type is matched by slices whose elements are uninhabited.
@@ -903,27 +945,37 @@ impl ConstructorSet {
903945 Self :: Integers {
904946 range_1 : make_range ( '\u{0000}' as u128 , '\u{D7FF}' as u128 ) ,
905947 range_2 : Some ( make_range ( '\u{E000}' as u128 , '\u{10FFFF}' as u128 ) ) ,
906- non_exhaustive : false ,
907948 }
908949 }
909950 & 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 }
918964 }
919965 & 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 }
927979 }
928980 ty:: Array ( sub_ty, len) if len. try_eval_target_usize ( cx. tcx , cx. param_env ) . is_some ( ) => {
929981 let len = len. eval_target_usize ( cx. tcx , cx. param_env ) as usize ;
@@ -1078,7 +1130,7 @@ impl ConstructorSet {
10781130 missing. push ( Bool ( true ) ) ;
10791131 }
10801132 }
1081- ConstructorSet :: Integers { range_1, range_2, non_exhaustive } => {
1133+ ConstructorSet :: Integers { range_1, range_2 } => {
10821134 let seen_ranges: Vec < _ > =
10831135 seen. map ( |ctor| ctor. as_int_range ( ) . unwrap ( ) . clone ( ) ) . collect ( ) ;
10841136 for ( seen, splitted_range) in range_1. split ( seen_ranges. iter ( ) . cloned ( ) ) {
@@ -1095,10 +1147,6 @@ impl ConstructorSet {
10951147 }
10961148 }
10971149 }
1098-
1099- if * non_exhaustive {
1100- missing. push ( NonExhaustive ) ;
1101- }
11021150 }
11031151 & ConstructorSet :: Slice ( array_len) => {
11041152 let seen_slices = seen. map ( |c| c. as_slice ( ) . unwrap ( ) ) ;
0 commit comments