@@ -61,7 +61,7 @@ use rustc_middle::ty::layout::IntegerExt;
6161use rustc_middle:: ty:: { self , Ty , TyCtxt , VariantDef } ;
6262use rustc_session:: lint;
6363use rustc_span:: { Span , DUMMY_SP } ;
64- use rustc_target:: abi:: { FieldIdx , Integer , Size , VariantIdx , FIRST_VARIANT } ;
64+ use rustc_target:: abi:: { FieldIdx , Integer , Primitive , Size , VariantIdx , FIRST_VARIANT } ;
6565
6666use self :: Constructor :: * ;
6767use self :: SliceKind :: * ;
@@ -86,6 +86,35 @@ fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
8686 pats
8787}
8888
89+ /// Evaluate an int constant, with a faster branch for a common case.
90+ #[ inline]
91+ fn fast_try_eval_bits < ' tcx > (
92+ tcx : TyCtxt < ' tcx > ,
93+ param_env : ty:: ParamEnv < ' tcx > ,
94+ value : & mir:: Const < ' tcx > ,
95+ ) -> Option < u128 > {
96+ let int = match value {
97+ // If the constant is already evaluated, we shortcut here.
98+ mir:: Const :: Ty ( c) if let ty:: ConstKind :: Value ( valtree) = c. kind ( ) => {
99+ valtree. unwrap_leaf ( )
100+ } ,
101+ // This is a more general form of the previous case.
102+ _ => {
103+ value. try_eval_scalar_int ( tcx, param_env) ?
104+ } ,
105+ } ;
106+ let size = match value. ty ( ) . kind ( ) {
107+ ty:: Bool => Size :: from_bytes ( 1 ) ,
108+ ty:: Char => Size :: from_bytes ( 4 ) ,
109+ ty:: Int ( ity) => Integer :: from_int_ty ( & tcx, * ity) . size ( ) ,
110+ ty:: Uint ( uty) => Integer :: from_uint_ty ( & tcx, * uty) . size ( ) ,
111+ ty:: Float ( ty:: FloatTy :: F32 ) => Primitive :: F32 . size ( & tcx) ,
112+ ty:: Float ( ty:: FloatTy :: F64 ) => Primitive :: F64 . size ( & tcx) ,
113+ _ => return None ,
114+ } ;
115+ int. to_bits ( size) . ok ( )
116+ }
117+
89118/// An inclusive interval, used for precise integer exhaustiveness checking.
90119/// `IntRange`s always store a contiguous range. This means that values are
91120/// encoded such that `0` encodes the minimum value for the integer,
@@ -116,37 +145,12 @@ impl IntRange {
116145 }
117146
118147 #[ inline]
119- fn integral_size_and_signed_bias ( tcx : TyCtxt < ' _ > , ty : Ty < ' _ > ) -> Option < ( Size , u128 ) > {
120- match * ty. kind ( ) {
121- ty:: Bool => Some ( ( Size :: from_bytes ( 1 ) , 0 ) ) ,
122- ty:: Char => Some ( ( Size :: from_bytes ( 4 ) , 0 ) ) ,
123- ty:: Int ( ity) => {
124- let size = Integer :: from_int_ty ( & tcx, ity) . size ( ) ;
125- Some ( ( size, 1u128 << ( size. bits ( ) as u128 - 1 ) ) )
126- }
127- ty:: Uint ( uty) => Some ( ( Integer :: from_uint_ty ( & tcx, uty) . size ( ) , 0 ) ) ,
128- _ => None ,
129- }
130- }
131-
132- #[ inline]
133- fn from_constant < ' tcx > (
134- tcx : TyCtxt < ' tcx > ,
135- param_env : ty:: ParamEnv < ' tcx > ,
136- value : mir:: Const < ' tcx > ,
137- ) -> Option < IntRange > {
138- let ty = value. ty ( ) ;
139- let ( target_size, bias) = Self :: integral_size_and_signed_bias ( tcx, ty) ?;
140- let val = match value {
141- mir:: Const :: Ty ( c) if let ty:: ConstKind :: Value ( valtree) = c. kind ( ) => {
142- valtree. unwrap_leaf ( ) . to_bits ( target_size) . ok ( )
143- } ,
144- // This is a more general form of the previous case.
145- _ => value. try_eval_bits ( tcx, param_env) ,
146- } ?;
147-
148- let val = val ^ bias;
149- Some ( IntRange { range : val..=val } )
148+ fn from_bits < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > , bits : u128 ) -> IntRange {
149+ let bias = IntRange :: signed_bias ( tcx, ty) ;
150+ // Perform a shift if the underlying types are signed,
151+ // which makes the interval arithmetic simpler.
152+ let val = bits ^ bias;
153+ IntRange { range : val..=val }
150154 }
151155
152156 #[ inline]
@@ -156,19 +160,17 @@ impl IntRange {
156160 hi : u128 ,
157161 ty : Ty < ' tcx > ,
158162 end : & RangeEnd ,
159- ) -> Option < IntRange > {
160- Self :: is_integral ( ty) . then ( || {
161- // Perform a shift if the underlying types are signed,
162- // which makes the interval arithmetic simpler.
163- let bias = IntRange :: signed_bias ( tcx, ty) ;
164- let ( lo, hi) = ( lo ^ bias, hi ^ bias) ;
165- let offset = ( * end == RangeEnd :: Excluded ) as u128 ;
166- if lo > hi || ( lo == hi && * end == RangeEnd :: Excluded ) {
167- // This should have been caught earlier by E0030.
168- bug ! ( "malformed range pattern: {}..={}" , lo, ( hi - offset) ) ;
169- }
170- IntRange { range : lo..=( hi - offset) }
171- } )
163+ ) -> IntRange {
164+ // Perform a shift if the underlying types are signed,
165+ // which makes the interval arithmetic simpler.
166+ let bias = IntRange :: signed_bias ( tcx, ty) ;
167+ let ( lo, hi) = ( lo ^ bias, hi ^ bias) ;
168+ let offset = ( * end == RangeEnd :: Excluded ) as u128 ;
169+ if lo > hi || ( lo == hi && * end == RangeEnd :: Excluded ) {
170+ // This should have been caught earlier by E0030.
171+ bug ! ( "malformed range pattern: {}..={}" , lo, ( hi - offset) ) ;
172+ }
173+ IntRange { range : lo..=( hi - offset) }
172174 }
173175
174176 // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
@@ -898,7 +900,7 @@ impl<'tcx> SplitWildcard<'tcx> {
898900 let make_range = |start, end| {
899901 IntRange (
900902 // `unwrap()` is ok because we know the type is an integer.
901- IntRange :: from_range ( cx. tcx , start, end, pcx. ty , & RangeEnd :: Included ) . unwrap ( ) ,
903+ IntRange :: from_range ( cx. tcx , start, end, pcx. ty , & RangeEnd :: Included ) ,
902904 )
903905 } ;
904906 // This determines the set of all possible constructors for the type `pcx.ty`. For numbers,
@@ -1346,57 +1348,58 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
13461348 }
13471349 }
13481350 PatKind :: Constant { value } => {
1349- if let Some ( int_range) = IntRange :: from_constant ( cx. tcx , cx. param_env , * value) {
1350- ctor = IntRange ( int_range) ;
1351- fields = Fields :: empty ( ) ;
1352- } else {
1353- match pat. ty . kind ( ) {
1354- ty:: Float ( float_ty) => {
1355- let bits = value. eval_bits ( cx. tcx , cx. param_env ) ;
1356- use rustc_apfloat:: Float ;
1357- ctor = match float_ty {
1358- ty:: FloatTy :: F32 => {
1351+ match pat. ty . kind ( ) {
1352+ ty:: Bool | ty:: Char | ty:: Int ( _) | ty:: Uint ( _) | ty:: Float ( _) => {
1353+ use rustc_apfloat:: Float ;
1354+ ctor = match fast_try_eval_bits ( cx. tcx , cx. param_env , value) {
1355+ Some ( bits) => match pat. ty . kind ( ) {
1356+ ty:: Bool | ty:: Char | ty:: Int ( _) | ty:: Uint ( _) => {
1357+ IntRange ( IntRange :: from_bits ( cx. tcx , pat. ty , bits) )
1358+ }
1359+ ty:: Float ( ty:: FloatTy :: F32 ) => {
13591360 let value = rustc_apfloat:: ieee:: Single :: from_bits ( bits) ;
13601361 F32Range ( value, value, RangeEnd :: Included )
13611362 }
1362- ty:: FloatTy :: F64 => {
1363+ ty:: Float ( ty :: FloatTy :: F64 ) => {
13631364 let value = rustc_apfloat:: ieee:: Double :: from_bits ( bits) ;
13641365 F64Range ( value, value, RangeEnd :: Included )
13651366 }
1366- } ;
1367- fields = Fields :: empty ( ) ;
1368- }
1369- ty:: Ref ( _, t, _) if t. is_str ( ) => {
1370- // We want a `&str` constant to behave like a `Deref` pattern, to be compatible
1371- // with other `Deref` patterns. This could have been done in `const_to_pat`,
1372- // but that causes issues with the rest of the matching code.
1373- // So here, the constructor for a `"foo"` pattern is `&` (represented by
1374- // `Single`), and has one field. That field has constructor `Str(value)` and no
1375- // fields.
1376- // Note: `t` is `str`, not `&str`.
1377- let subpattern =
1378- DeconstructedPat :: new ( Str ( * value) , Fields :: empty ( ) , * t, pat. span ) ;
1379- ctor = Single ;
1380- fields = Fields :: singleton ( cx, subpattern)
1381- }
1382- // All constants that can be structurally matched have already been expanded
1383- // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
1384- // opaque.
1385- _ => {
1386- ctor = Opaque ;
1387- fields = Fields :: empty ( ) ;
1388- }
1367+ _ => unreachable ! ( ) ,
1368+ } ,
1369+ None => Opaque ,
1370+ } ;
1371+ fields = Fields :: empty ( ) ;
1372+ }
1373+ ty:: Ref ( _, t, _) if t. is_str ( ) => {
1374+ // We want a `&str` constant to behave like a `Deref` pattern, to be compatible
1375+ // with other `Deref` patterns. This could have been done in `const_to_pat`,
1376+ // but that causes issues with the rest of the matching code.
1377+ // So here, the constructor for a `"foo"` pattern is `&` (represented by
1378+ // `Single`), and has one field. That field has constructor `Str(value)` and no
1379+ // fields.
1380+ // Note: `t` is `str`, not `&str`.
1381+ let subpattern =
1382+ DeconstructedPat :: new ( Str ( * value) , Fields :: empty ( ) , * t, pat. span ) ;
1383+ ctor = Single ;
1384+ fields = Fields :: singleton ( cx, subpattern)
1385+ }
1386+ // All constants that can be structurally matched have already been expanded
1387+ // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
1388+ // opaque.
1389+ _ => {
1390+ ctor = Opaque ;
1391+ fields = Fields :: empty ( ) ;
13891392 }
13901393 }
13911394 }
1392- & PatKind :: Range ( box PatRange { lo, hi, end } ) => {
1395+ PatKind :: Range ( box PatRange { lo, hi, end } ) => {
13931396 use rustc_apfloat:: Float ;
13941397 let ty = lo. ty ( ) ;
1395- let lo = lo . eval_bits ( cx. tcx , cx. param_env ) ;
1396- let hi = hi . eval_bits ( cx. tcx , cx. param_env ) ;
1398+ let lo = fast_try_eval_bits ( cx. tcx , cx. param_env , lo ) . unwrap ( ) ;
1399+ let hi = fast_try_eval_bits ( cx. tcx , cx. param_env , hi ) . unwrap ( ) ;
13971400 ctor = match ty. kind ( ) {
13981401 ty:: Char | ty:: Int ( _) | ty:: Uint ( _) => {
1399- IntRange ( IntRange :: from_range ( cx. tcx , lo, hi, ty, & end) . unwrap ( ) )
1402+ IntRange ( IntRange :: from_range ( cx. tcx , lo, hi, ty, & end) )
14001403 }
14011404 ty:: Float ( ty:: FloatTy :: F32 ) => {
14021405 let lo = rustc_apfloat:: ieee:: Single :: from_bits ( lo) ;
0 commit comments