@@ -647,7 +647,9 @@ impl<'tcx> Constructor<'tcx> {
647
647
match self {
648
648
// Any base constructor can be used unchanged.
649
649
Single | Variant ( _) | ConstantValue ( _) | FixedLenSlice ( _) => smallvec ! [ self ] ,
650
- ConstantRange ( ..) if should_treat_range_exhaustively ( cx. tcx , & self ) => {
650
+ ConstantRange ( ref lo, ..)
651
+ if IntRange :: should_treat_range_exhaustively ( cx. tcx , lo. ty ) =>
652
+ {
651
653
// Splitting up a range naïvely would mean creating a separate constructor for
652
654
// every single value in the range, which is clearly impractical. We therefore want
653
655
// to keep together subranges for which the specialisation will be identical across
@@ -707,7 +709,7 @@ impl<'tcx> Constructor<'tcx> {
707
709
let row_borders = head_ctors
708
710
. iter ( )
709
711
. flat_map ( |ctor| IntRange :: from_ctor ( cx. tcx , cx. param_env , ctor) )
710
- . flat_map ( |range| ctor_range. intersection ( & range) )
712
+ . flat_map ( |range| ctor_range. intersection ( cx . tcx , & range) )
711
713
. flat_map ( |range| range_borders ( range) ) ;
712
714
let ctor_borders = range_borders ( ctor_range. clone ( ) ) ;
713
715
let mut borders: Vec < _ > = row_borders. chain ( ctor_borders) . collect ( ) ;
@@ -1477,6 +1479,13 @@ impl<'tcx> IntRange<'tcx> {
1477
1479
}
1478
1480
}
1479
1481
1482
+ fn should_treat_range_exhaustively ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> bool {
1483
+ // Don't treat `usize`/`isize` exhaustively unless the `precise_pointer_size_matching`
1484
+ // feature is enabled.
1485
+ IntRange :: is_integral ( ty)
1486
+ && ( !ty. is_ptr_sized_integral ( ) || tcx. features ( ) . precise_pointer_size_matching )
1487
+ }
1488
+
1480
1489
#[ inline]
1481
1490
fn integral_size_and_signed_bias ( tcx : TyCtxt < ' tcx > , ty : Ty < ' _ > ) -> Option < ( Size , u128 ) > {
1482
1491
match ty. kind {
@@ -1625,14 +1634,19 @@ impl<'tcx> IntRange<'tcx> {
1625
1634
remaining_ranges
1626
1635
}
1627
1636
1628
- fn intersection ( & self , other : & Self ) -> Option < Self > {
1637
+ fn intersection ( & self , tcx : TyCtxt < ' tcx > , other : & Self ) -> Option < Self > {
1629
1638
let ty = self . ty ;
1630
1639
let ( lo, hi) = ( * self . range . start ( ) , * self . range . end ( ) ) ;
1631
1640
let ( other_lo, other_hi) = ( * other. range . start ( ) , * other. range . end ( ) ) ;
1632
- if lo <= other_hi && other_lo <= hi {
1633
- Some ( IntRange { range : max ( lo, other_lo) ..=min ( hi, other_hi) , ty } )
1641
+ if Self :: should_treat_range_exhaustively ( tcx, ty) {
1642
+ if lo <= other_hi && other_lo <= hi {
1643
+ Some ( IntRange { range : max ( lo, other_lo) ..=min ( hi, other_hi) , ty } )
1644
+ } else {
1645
+ None
1646
+ }
1634
1647
} else {
1635
- None
1648
+ // If the range sould not be treated exhaustively, fallback to checking for inclusion.
1649
+ if other_lo <= lo && hi <= other_hi { Some ( self . clone ( ) ) } else { None }
1636
1650
}
1637
1651
}
1638
1652
}
@@ -1918,19 +1932,14 @@ fn slice_pat_covered_by_const<'tcx>(
1918
1932
Ok ( true )
1919
1933
}
1920
1934
1921
- // Whether to evaluate a constructor using exhaustive integer matching. This is true if the
1922
- // constructor is a range or constant with an integer type.
1923
- fn should_treat_range_exhaustively ( tcx : TyCtxt < ' tcx > , ctor : & Constructor < ' tcx > ) -> bool {
1935
+ // Whether a constructor is a range or constant with an integer type.
1936
+ fn is_integral_range ( ctor : & Constructor < ' tcx > ) -> bool {
1924
1937
let ty = match ctor {
1925
1938
ConstantValue ( value) => value. ty ,
1926
1939
ConstantRange ( lo, _, _) => lo. ty ,
1927
1940
_ => return false ,
1928
1941
} ;
1929
- if let ty:: Char | ty:: Int ( _) | ty:: Uint ( _) = ty. kind {
1930
- !ty. is_ptr_sized_integral ( ) || tcx. features ( ) . precise_pointer_size_matching
1931
- } else {
1932
- false
1933
- }
1942
+ IntRange :: is_integral ( ty)
1934
1943
}
1935
1944
1936
1945
/// Checks whether there exists any shared value in either `ctor` or `pat` by intersecting them.
@@ -1945,7 +1954,7 @@ fn constructor_intersects_pattern<'p, 'tcx>(
1945
1954
trace ! ( "constructor_intersects_pattern {:#?}, {:#?}" , ctor, pat) ;
1946
1955
if let Single = ctor {
1947
1956
Some ( PatStack :: default ( ) )
1948
- } else if should_treat_range_exhaustively ( tcx , ctor) {
1957
+ } else if is_integral_range ( ctor) {
1949
1958
let range = match * pat. kind {
1950
1959
PatKind :: Constant { value } => ConstantValue ( value) ,
1951
1960
PatKind :: Range ( PatRange { lo, hi, end } ) => ConstantRange ( lo, hi, end) ,
@@ -1954,11 +1963,14 @@ fn constructor_intersects_pattern<'p, 'tcx>(
1954
1963
1955
1964
let pat = IntRange :: from_ctor ( tcx, param_env, & range) ?;
1956
1965
let ctor = IntRange :: from_ctor ( tcx, param_env, ctor) ?;
1957
- ctor. intersection ( & pat) ?;
1966
+ ctor. intersection ( tcx , & pat) ?;
1958
1967
1968
+ // Constructor splitting should ensure that all intersections we encounter are actually
1969
+ // inclusions.
1959
1970
let ( pat_lo, pat_hi) = pat. range . into_inner ( ) ;
1960
1971
let ( ctor_lo, ctor_hi) = ctor. range . into_inner ( ) ;
1961
1972
assert ! ( pat_lo <= ctor_lo && ctor_hi <= pat_hi) ;
1973
+
1962
1974
Some ( PatStack :: default ( ) )
1963
1975
} else {
1964
1976
// Fallback for non-ranges and ranges that involve floating-point numbers, which are not
@@ -1976,10 +1988,10 @@ fn constructor_intersects_pattern<'p, 'tcx>(
1976
1988
} ;
1977
1989
let order_to = compare_const_vals ( tcx, ctor_to, pat_to, param_env, pat_from. ty ) ?;
1978
1990
let order_from = compare_const_vals ( tcx, ctor_from, pat_from, param_env, pat_from. ty ) ?;
1979
- let intersects = ( order_from != Ordering :: Less )
1991
+ let included = ( order_from != Ordering :: Less )
1980
1992
&& ( ( order_to == Ordering :: Less )
1981
1993
|| ( pat_end == ctor_end && order_to == Ordering :: Equal ) ) ;
1982
- if intersects { Some ( PatStack :: default ( ) ) } else { None }
1994
+ if included { Some ( PatStack :: default ( ) ) } else { None }
1983
1995
}
1984
1996
}
1985
1997
0 commit comments