@@ -61,7 +61,7 @@ use rustc_middle::ty::layout::IntegerExt;
61
61
use rustc_middle:: ty:: { self , Ty , TyCtxt , VariantDef } ;
62
62
use rustc_session:: lint;
63
63
use 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 } ;
65
65
66
66
use self :: Constructor :: * ;
67
67
use self :: SliceKind :: * ;
@@ -86,6 +86,35 @@ fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
86
86
pats
87
87
}
88
88
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
+
89
118
/// An inclusive interval, used for precise integer exhaustiveness checking.
90
119
/// `IntRange`s always store a contiguous range. This means that values are
91
120
/// encoded such that `0` encodes the minimum value for the integer,
@@ -116,37 +145,12 @@ impl IntRange {
116
145
}
117
146
118
147
#[ 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 }
150
154
}
151
155
152
156
#[ inline]
@@ -156,19 +160,17 @@ impl IntRange {
156
160
hi : u128 ,
157
161
ty : Ty < ' tcx > ,
158
162
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) }
172
174
}
173
175
174
176
// The return value of `signed_bias` should be XORed with an endpoint to encode/decode it.
@@ -898,7 +900,7 @@ impl<'tcx> SplitWildcard<'tcx> {
898
900
let make_range = |start, end| {
899
901
IntRange (
900
902
// `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 ) ,
902
904
)
903
905
} ;
904
906
// 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> {
1346
1348
}
1347
1349
}
1348
1350
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 ) => {
1359
1360
let value = rustc_apfloat:: ieee:: Single :: from_bits ( bits) ;
1360
1361
F32Range ( value, value, RangeEnd :: Included )
1361
1362
}
1362
- ty:: FloatTy :: F64 => {
1363
+ ty:: Float ( ty :: FloatTy :: F64 ) => {
1363
1364
let value = rustc_apfloat:: ieee:: Double :: from_bits ( bits) ;
1364
1365
F64Range ( value, value, RangeEnd :: Included )
1365
1366
}
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 ( ) ;
1389
1392
}
1390
1393
}
1391
1394
}
1392
- & PatKind :: Range ( box PatRange { lo, hi, end } ) => {
1395
+ PatKind :: Range ( box PatRange { lo, hi, end } ) => {
1393
1396
use rustc_apfloat:: Float ;
1394
1397
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 ( ) ;
1397
1400
ctor = match ty. kind ( ) {
1398
1401
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) )
1400
1403
}
1401
1404
ty:: Float ( ty:: FloatTy :: F32 ) => {
1402
1405
let lo = rustc_apfloat:: ieee:: Single :: from_bits ( lo) ;
0 commit comments