@@ -56,6 +56,7 @@ use rustc_hir::{HirId, 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 } ;
@@ -141,20 +142,32 @@ impl MaybeInfiniteInt {
141142 PatRangeBoundary :: PosInfinity => PosInfinity ,
142143 }
143144 }
145+ // This could change from finite to infinite if we got `usize::MAX+1` out of range splitting.
144146 fn to_pat_range_bdy < ' tcx > ( self , ty : Ty < ' tcx > , tcx : TyCtxt < ' tcx > ) -> PatRangeBoundary < ' tcx > {
145147 match self {
146148 NegInfinity => PatRangeBoundary :: NegInfinity ,
147149 Finite ( x) => {
148150 let bias = Self :: signed_bias ( tcx, ty) ;
149151 let bits = x ^ bias;
150- let env = ty:: ParamEnv :: empty ( ) . and ( ty) ;
151- let value = mir:: Const :: from_bits ( tcx, bits, env) ;
152- PatRangeBoundary :: Finite ( value)
152+ let size = ty. primitive_size ( tcx) ;
153+ match Scalar :: try_from_uint ( bits, size) {
154+ Some ( scalar) => {
155+ let value = mir:: Const :: from_scalar ( tcx, scalar, ty) ;
156+ PatRangeBoundary :: Finite ( value)
157+ }
158+ // The value doesn't fit. Since `x >= 0` and 0 always encodes the minimum value
159+ // for a type, the problem isn't that the value is too small. So it must be too
160+ // large.
161+ None => PatRangeBoundary :: PosInfinity ,
162+ }
153163 }
154164 JustAfterMax | PosInfinity => PatRangeBoundary :: PosInfinity ,
155165 }
156166 }
157167
168+ fn is_finite ( self ) -> bool {
169+ matches ! ( self , Finite ( _) )
170+ }
158171 fn minus_one ( self ) -> Self {
159172 match self {
160173 Finite ( n) => match n. checked_sub ( 1 ) {
@@ -171,22 +184,24 @@ impl MaybeInfiniteInt {
171184 Some ( m) => Finite ( m) ,
172185 None => JustAfterMax ,
173186 } ,
187+ JustAfterMax => bug ! ( ) ,
174188 x => x,
175189 }
176190 }
177191}
178192
179- /// An inclusive interval, used for precise integer exhaustiveness checking.
180- /// `IntRange`s always store a contiguous range.
193+ /// An inclusive interval, used for precise integer exhaustiveness checking. `IntRange`s always
194+ /// store a contiguous range.
181195///
182- /// `IntRange` is never used to encode an empty range or a "range" that wraps
183- /// around the (offset) space: i.e., `range.lo <= range.hi`.
196+ /// `IntRange` is never used to encode an empty range or a "range" that wraps around the (offset)
197+ /// space: i.e., `range.lo <= range.hi`.
184198///
185- /// The range can have open ends.
199+ /// Note: the range can be `NegInfinity..=NegInfinity` or `PosInfinity..=PosInfinity` to represent
200+ /// the values before `isize::MIN` and after `isize::MAX`/`usize::MAX`.
186201#[ derive( Clone , Copy , PartialEq , Eq ) ]
187202pub ( crate ) struct IntRange {
188- lo : MaybeInfiniteInt , // Must not be `PosInfinity`.
189- hi : MaybeInfiniteInt , // Must not be `NegInfinity`.
203+ lo : MaybeInfiniteInt ,
204+ hi : MaybeInfiniteInt ,
190205}
191206
192207impl IntRange {
@@ -197,7 +212,7 @@ impl IntRange {
197212
198213 /// Best effort; will not know that e.g. `255u8..` is a singleton.
199214 fn is_singleton ( & self ) -> bool {
200- self . lo == self . hi
215+ self . lo == self . hi && self . lo . is_finite ( )
201216 }
202217
203218 #[ inline]
@@ -242,7 +257,8 @@ impl IntRange {
242257 // `true` in the following cases:
243258 // 1 ------- // 1 -------
244259 // 2 -------- // 2 -------
245- ( self . lo == other. hi || self . hi == other. lo )
260+ ( ( self . lo == other. hi && self . lo . is_finite ( ) )
261+ || ( self . hi == other. lo && self . hi . is_finite ( ) ) )
246262 && !self . is_singleton ( )
247263 && !other. is_singleton ( )
248264 }
@@ -327,18 +343,49 @@ impl IntRange {
327343 } )
328344 }
329345
346+ /// Whether the range denotes the values before `isize::MIN` or the values after
347+ /// `usize::MAX`/`isize::MAX`.
348+ pub ( crate ) fn is_beyond_boundaries < ' tcx > ( & self , ty : Ty < ' tcx > , tcx : TyCtxt < ' tcx > ) -> bool {
349+ // First check if we are usize/isize to avoid unnecessary `to_pat_range_bdy`.
350+ ty. is_ptr_sized_integral ( ) && !tcx. features ( ) . precise_pointer_size_matching && {
351+ let lo = self . lo . to_pat_range_bdy ( ty, tcx) ;
352+ let hi = self . hi . to_pat_range_bdy ( ty, tcx) ;
353+ matches ! ( lo, PatRangeBoundary :: PosInfinity )
354+ || matches ! ( hi, PatRangeBoundary :: NegInfinity )
355+ }
356+ }
330357 /// Only used for displaying the range.
331358 fn to_pat < ' tcx > ( & self , ty : Ty < ' tcx > , tcx : TyCtxt < ' tcx > ) -> Pat < ' tcx > {
332- let lo = self . lo . to_pat_range_bdy ( ty , tcx ) ;
333- let hi = self . hi . to_pat_range_bdy ( ty , tcx ) ;
334-
335- let kind = if self . is_singleton ( ) {
359+ let kind = if matches ! ( ( self . lo, self . hi ) , ( NegInfinity , PosInfinity ) ) {
360+ PatKind :: Wild
361+ } else if self . is_singleton ( ) {
362+ let lo = self . lo . to_pat_range_bdy ( ty , tcx ) ;
336363 let value = lo. as_finite ( ) . unwrap ( ) ;
337364 PatKind :: Constant { value }
338- } else if matches ! ( ( self . lo, self . hi) , ( NegInfinity , PosInfinity ) ) {
339- PatKind :: Wild
340365 } else {
341- PatKind :: Range ( Box :: new ( PatRange { lo, hi, end : RangeEnd :: Included , ty } ) )
366+ let mut lo = self . lo . to_pat_range_bdy ( ty, tcx) ;
367+ let mut hi = self . hi . to_pat_range_bdy ( ty, tcx) ;
368+ let end = if hi. is_finite ( ) {
369+ RangeEnd :: Included
370+ } else {
371+ // `0..=` isn't a valid pattern.
372+ RangeEnd :: Excluded
373+ } ;
374+ if matches ! ( hi, PatRangeBoundary :: NegInfinity ) {
375+ // The range denotes the values before `isize::MIN`.
376+ let c = ty. numeric_min_val ( tcx) . unwrap ( ) ;
377+ let value = mir:: Const :: from_ty_const ( c, tcx) ;
378+ hi = PatRangeBoundary :: Finite ( value) ;
379+ }
380+ if matches ! ( lo, PatRangeBoundary :: PosInfinity ) {
381+ // The range denotes the values after `usize::MAX`/`isize::MAX`.
382+ // We represent this as `usize::MAX..` which is slightly incorrect but probably
383+ // clear enough.
384+ let c = ty. numeric_max_val ( tcx) . unwrap ( ) ;
385+ let value = mir:: Const :: from_ty_const ( c, tcx) ;
386+ lo = PatRangeBoundary :: Finite ( value) ;
387+ }
388+ PatKind :: Range ( Box :: new ( PatRange { lo, hi, end, ty } ) )
342389 } ;
343390
344391 Pat { ty, span : DUMMY_SP , kind }
@@ -918,9 +965,7 @@ pub(super) enum ConstructorSet {
918965 Bool ,
919966 /// The type is spanned by integer values. The range or ranges give the set of allowed values.
920967 /// The second range is only useful for `char`.
921- /// `non_exhaustive` is used when the range is not allowed to be matched exhaustively (that's
922- /// for usize/isize).
923- Integers { range_1 : IntRange , range_2 : Option < IntRange > , non_exhaustive : bool } ,
968+ Integers { range_1 : IntRange , range_2 : Option < IntRange > } ,
924969 /// The type is matched by slices. The usize is the compile-time length of the array, if known.
925970 Slice ( Option < usize > ) ,
926971 /// The type is matched by slices whose elements are uninhabited.
@@ -980,27 +1025,37 @@ impl ConstructorSet {
9801025 Self :: Integers {
9811026 range_1 : make_range ( '\u{0000}' as u128 , '\u{D7FF}' as u128 ) ,
9821027 range_2 : Some ( make_range ( '\u{E000}' as u128 , '\u{10FFFF}' as u128 ) ) ,
983- non_exhaustive : false ,
9841028 }
9851029 }
9861030 & ty:: Int ( ity) => {
987- // `usize`/`isize` are not allowed to be matched exhaustively unless the
988- // `precise_pointer_size_matching` feature is enabled.
989- let non_exhaustive =
990- ty. is_ptr_sized_integral ( ) && !cx. tcx . features ( ) . precise_pointer_size_matching ;
991- let bits = Integer :: from_int_ty ( & cx. tcx , ity) . size ( ) . bits ( ) as u128 ;
992- let min = 1u128 << ( bits - 1 ) ;
993- let max = min - 1 ;
994- Self :: Integers { range_1 : make_range ( min, max) , non_exhaustive, range_2 : None }
1031+ let range = if ty. is_ptr_sized_integral ( )
1032+ && !cx. tcx . features ( ) . precise_pointer_size_matching
1033+ {
1034+ // The min/max values of `isize` are not allowed to be observed unless the
1035+ // `precise_pointer_size_matching` feature is enabled.
1036+ IntRange { lo : NegInfinity , hi : PosInfinity }
1037+ } else {
1038+ let bits = Integer :: from_int_ty ( & cx. tcx , ity) . size ( ) . bits ( ) as u128 ;
1039+ let min = 1u128 << ( bits - 1 ) ;
1040+ let max = min - 1 ;
1041+ make_range ( min, max)
1042+ } ;
1043+ Self :: Integers { range_1 : range, range_2 : None }
9951044 }
9961045 & ty:: Uint ( uty) => {
997- // `usize`/`isize` are not allowed to be matched exhaustively unless the
998- // `precise_pointer_size_matching` feature is enabled.
999- let non_exhaustive =
1000- ty. is_ptr_sized_integral ( ) && !cx. tcx . features ( ) . precise_pointer_size_matching ;
1001- let size = Integer :: from_uint_ty ( & cx. tcx , uty) . size ( ) ;
1002- let max = size. truncate ( u128:: MAX ) ;
1003- Self :: Integers { range_1 : make_range ( 0 , max) , non_exhaustive, range_2 : None }
1046+ let range = if ty. is_ptr_sized_integral ( )
1047+ && !cx. tcx . features ( ) . precise_pointer_size_matching
1048+ {
1049+ // The max value of `usize` is not allowed to be observed unless the
1050+ // `precise_pointer_size_matching` feature is enabled.
1051+ let lo = MaybeInfiniteInt :: new_finite ( cx. tcx , ty, 0 ) ;
1052+ IntRange { lo, hi : PosInfinity }
1053+ } else {
1054+ let size = Integer :: from_uint_ty ( & cx. tcx , uty) . size ( ) ;
1055+ let max = size. truncate ( u128:: MAX ) ;
1056+ make_range ( 0 , max)
1057+ } ;
1058+ Self :: Integers { range_1 : range, range_2 : None }
10041059 }
10051060 ty:: Array ( sub_ty, len) if len. try_eval_target_usize ( cx. tcx , cx. param_env ) . is_some ( ) => {
10061061 let len = len. eval_target_usize ( cx. tcx , cx. param_env ) as usize ;
@@ -1149,7 +1204,7 @@ impl ConstructorSet {
11491204 }
11501205 }
11511206 }
1152- ConstructorSet :: Integers { range_1, range_2, non_exhaustive } => {
1207+ ConstructorSet :: Integers { range_1, range_2 } => {
11531208 let seen_ranges: Vec < _ > =
11541209 seen. map ( |ctor| ctor. as_int_range ( ) . unwrap ( ) . clone ( ) ) . collect ( ) ;
11551210 for ( seen, splitted_range) in range_1. split ( seen_ranges. iter ( ) . cloned ( ) ) {
@@ -1166,10 +1221,6 @@ impl ConstructorSet {
11661221 }
11671222 }
11681223 }
1169-
1170- if * non_exhaustive {
1171- missing. push ( NonExhaustive ) ;
1172- }
11731224 }
11741225 & ConstructorSet :: Slice ( array_len) => {
11751226 let seen_slices = seen. map ( |c| c. as_slice ( ) . unwrap ( ) ) ;
0 commit comments