@@ -471,9 +471,9 @@ fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
471
471
}
472
472
ty:: TyInt ( _) if exhaustive_integer_patterns => {
473
473
let size = cx. tcx . layout_of ( ty:: ParamEnv :: reveal_all ( ) . and ( pcx. ty ) )
474
- . unwrap ( ) . size . bits ( ) as i128 ;
475
- let min = ( 1i128 << ( size - 1 ) ) . wrapping_neg ( ) ;
476
- let max = ( 1i128 << ( size - 1 ) ) . wrapping_sub ( 1 ) ;
474
+ . unwrap ( ) . size . bits ( ) as u128 ;
475
+ let min = ( 1u128 << ( size - 1 ) ) . wrapping_neg ( ) ;
476
+ let max = ( 1u128 << ( size - 1 ) ) . wrapping_sub ( 1 ) ;
477
477
value_constructors = true ;
478
478
vec ! [ ConstantRange ( ty:: Const :: from_bits( cx. tcx, min as u128 , pcx. ty) ,
479
479
ty:: Const :: from_bits( cx. tcx, max as u128 , pcx. ty) ,
@@ -603,13 +603,17 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
603
603
}
604
604
605
605
/// An inclusive interval, used for precise integer exhaustiveness checking.
606
+ /// `Interval`s always store a contiguous range of integers. That means that
607
+ /// signed integers are offset (see `offset_sign`) by their minimum value.
606
608
struct Interval < ' tcx > {
607
609
pub range : RangeInclusive < u128 > ,
608
610
pub ty : Ty < ' tcx > ,
609
611
}
610
612
611
613
impl < ' tcx > Interval < ' tcx > {
612
- fn from_ctor ( ctor : & Constructor < ' tcx > ) -> Option < Interval < ' tcx > > {
614
+ fn from_ctor ( tcx : TyCtxt < ' _ , ' tcx , ' tcx > ,
615
+ ctor : & Constructor < ' tcx > )
616
+ -> Option < Interval < ' tcx > > {
613
617
match ctor {
614
618
ConstantRange ( lo, hi, end) => {
615
619
assert_eq ! ( lo. ty, hi. ty) ;
@@ -618,7 +622,7 @@ impl<'tcx> Interval<'tcx> {
618
622
if let Some ( hi) = hi. assert_bits ( ty) {
619
623
// Perform a shift if the underlying types are signed,
620
624
// which makes the interval arithmetic simpler.
621
- let ( lo, hi) = Interval :: offset_sign ( ty, lo..=hi, true ) ;
625
+ let ( lo, hi) = Self :: offset_sign ( tcx , ty, lo..=hi, true ) ;
622
626
// Make sure the interval is well-formed.
623
627
return if lo > hi || lo == hi && * end == RangeEnd :: Excluded {
624
628
None
@@ -632,38 +636,45 @@ impl<'tcx> Interval<'tcx> {
632
636
}
633
637
ConstantValue ( val) => {
634
638
let ty = val. ty ;
635
- val. assert_bits ( ty) . map ( |val| Interval { range : val..=val, ty } )
639
+ if let Some ( val) = val. assert_bits ( ty) {
640
+ let ( lo, hi) = Self :: offset_sign ( tcx, ty, val..=val, true ) ;
641
+ Some ( Interval { range : lo..=hi, ty } )
642
+ } else {
643
+ None
644
+ }
636
645
}
637
646
Single | Variant ( _) | Slice ( _) => {
638
647
None
639
648
}
640
649
}
641
650
}
642
651
643
- fn offset_sign ( ty : Ty < ' tcx > , range : RangeInclusive < u128 > , forwards : bool ) -> ( u128 , u128 ) {
652
+ fn offset_sign ( tcx : TyCtxt < ' _ , ' tcx , ' tcx > ,
653
+ ty : Ty < ' tcx > ,
654
+ range : RangeInclusive < u128 > ,
655
+ encode : bool )
656
+ -> ( u128 , u128 ) {
657
+ // We ensure that all integer values are contiguous: that is, that their
658
+ // minimum value is represented by 0, so that comparisons and increments/
659
+ // decrements on interval endpoints work consistently whether the endpoints
660
+ // are signed or unsigned.
644
661
let ( lo, hi) = range. into_inner ( ) ;
645
- use syntax:: ast:: IntTy :: * ;
646
662
match ty. sty {
647
- ty:: TyInt ( int_ty) => {
648
- macro_rules! offset_sign_for_ty {
649
- ( $ity: ident, $uty: ty) => { {
650
- let min = Wrapping ( $ity:: MIN as $uty) ;
651
- if forwards {
652
- ( ( Wrapping ( lo as $uty) + min) . 0 as u128 ,
653
- ( Wrapping ( hi as $uty) + min) . 0 as u128 )
654
- } else {
655
- ( ( Wrapping ( lo as $uty) + min) . 0 as $ity as u128 ,
656
- ( Wrapping ( hi as $uty) + min) . 0 as $ity as u128 )
657
- }
658
- } }
659
- }
660
- match int_ty {
661
- Isize => offset_sign_for_ty ! ( isize , usize ) ,
662
- I8 => offset_sign_for_ty ! ( i8 , u8 ) ,
663
- I16 => offset_sign_for_ty ! ( i16 , u16 ) ,
664
- I32 => offset_sign_for_ty ! ( i32 , u32 ) ,
665
- I64 => offset_sign_for_ty ! ( i64 , u64 ) ,
666
- I128 => offset_sign_for_ty ! ( i128 , u128 ) ,
663
+ ty:: TyInt ( _) => {
664
+ let size = tcx. layout_of ( ty:: ParamEnv :: reveal_all ( ) . and ( ty) )
665
+ . unwrap ( ) . size . bits ( ) as u128 ;
666
+ let min = ( 1u128 << ( size - 1 ) ) . wrapping_neg ( ) ;
667
+ let shift = 1u128 . overflowing_shl ( size as u32 ) ;
668
+ let mask = shift. 0 . wrapping_sub ( 1 + ( shift. 1 as u128 ) ) ;
669
+ if encode {
670
+ let offset = |x : u128 | x. wrapping_sub ( min) & mask;
671
+ ( offset ( lo) , offset ( hi) )
672
+ } else {
673
+ let offset = |x : u128 | {
674
+ interpret:: sign_extend ( tcx, x. wrapping_add ( min) & mask, ty)
675
+ . expect ( "layout error for TyInt" )
676
+ } ;
677
+ ( offset ( lo) , offset ( hi) )
667
678
}
668
679
}
669
680
ty:: TyUint ( _) | ty:: TyChar => {
@@ -685,10 +696,10 @@ fn ranges_subtract_pattern<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
685
696
pat_ctor : & Constructor < ' tcx > ,
686
697
ranges : Vec < Constructor < ' tcx > > )
687
698
-> Vec < Constructor < ' tcx > > {
688
- if let Some ( pat_interval) = Interval :: from_ctor ( pat_ctor) {
699
+ if let Some ( pat_interval) = Interval :: from_ctor ( cx . tcx , pat_ctor) {
689
700
let mut remaining_ranges = vec ! [ ] ;
690
701
let mut ranges: Vec < _ > = ranges. into_iter ( ) . filter_map ( |r| {
691
- Interval :: from_ctor ( & r) . map ( |i| i. into_inner ( ) )
702
+ Interval :: from_ctor ( cx . tcx , & r) . map ( |i| i. into_inner ( ) )
692
703
} ) . collect ( ) ;
693
704
let ty = pat_interval. ty ;
694
705
let ( pat_interval_lo, pat_interval_hi) = pat_interval. into_inner ( ) ;
@@ -712,7 +723,7 @@ fn ranges_subtract_pattern<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
712
723
}
713
724
// Convert the remaining ranges from pairs to inclusive `ConstantRange`s.
714
725
remaining_ranges. into_iter ( ) . map ( |r| {
715
- let ( lo, hi) = Interval :: offset_sign ( ty, r, false ) ;
726
+ let ( lo, hi) = Interval :: offset_sign ( cx . tcx , ty, r, false ) ;
716
727
ConstantRange ( ty:: Const :: from_bits ( cx. tcx , lo, ty) ,
717
728
ty:: Const :: from_bits ( cx. tcx , hi, ty) ,
718
729
RangeEnd :: Included )
0 commit comments