@@ -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]
@@ -155,20 +159,18 @@ impl IntRange {
155159 lo : u128 ,
156160 hi : u128 ,
157161 ty : Ty < ' tcx > ,
158- 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- } )
162+ end : RangeEnd ,
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.
@@ -894,7 +896,7 @@ impl<'tcx> SplitWildcard<'tcx> {
894896 let make_range = |start, end| {
895897 IntRange (
896898 // `unwrap()` is ok because we know the type is an integer.
897- IntRange :: from_range ( cx. tcx , start, end, pcx. ty , & RangeEnd :: Included ) . unwrap ( ) ,
899+ IntRange :: from_range ( cx. tcx , start, end, pcx. ty , RangeEnd :: Included ) ,
898900 )
899901 } ;
900902 // This determines the set of all possible constructors for the type `pcx.ty`. For numbers,
@@ -1342,57 +1344,66 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
13421344 }
13431345 }
13441346 PatKind :: Constant { value } => {
1345- if let Some ( int_range) = IntRange :: from_constant ( cx. tcx , cx. param_env , * value) {
1346- ctor = IntRange ( int_range) ;
1347- fields = Fields :: empty ( ) ;
1348- } else {
1349- match pat. ty . kind ( ) {
1350- ty:: Float ( float_ty) => {
1351- let bits = value. eval_bits ( cx. tcx , cx. param_env ) ;
1352- use rustc_apfloat:: Float ;
1353- ctor = match float_ty {
1354- ty:: FloatTy :: F32 => {
1355- let value = rustc_apfloat:: ieee:: Single :: from_bits ( bits) ;
1356- F32Range ( value, value, RangeEnd :: Included )
1357- }
1358- ty:: FloatTy :: F64 => {
1359- let value = rustc_apfloat:: ieee:: Double :: from_bits ( bits) ;
1360- F64Range ( value, value, RangeEnd :: Included )
1361- }
1362- } ;
1363- fields = Fields :: empty ( ) ;
1364- }
1365- ty:: Ref ( _, t, _) if t. is_str ( ) => {
1366- // We want a `&str` constant to behave like a `Deref` pattern, to be compatible
1367- // with other `Deref` patterns. This could have been done in `const_to_pat`,
1368- // but that causes issues with the rest of the matching code.
1369- // So here, the constructor for a `"foo"` pattern is `&` (represented by
1370- // `Single`), and has one field. That field has constructor `Str(value)` and no
1371- // fields.
1372- // Note: `t` is `str`, not `&str`.
1373- let subpattern =
1374- DeconstructedPat :: new ( Str ( * value) , Fields :: empty ( ) , * t, pat. span ) ;
1375- ctor = Single ;
1376- fields = Fields :: singleton ( cx, subpattern)
1377- }
1378- // All constants that can be structurally matched have already been expanded
1379- // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
1380- // opaque.
1381- _ => {
1382- ctor = Opaque ;
1383- fields = Fields :: empty ( ) ;
1384- }
1347+ match pat. ty . kind ( ) {
1348+ ty:: Bool | ty:: Char | ty:: Int ( _) | ty:: Uint ( _) => {
1349+ ctor = match fast_try_eval_bits ( cx. tcx , cx. param_env , value) {
1350+ Some ( bits) => IntRange ( IntRange :: from_bits ( cx. tcx , pat. ty , bits) ) ,
1351+ None => Opaque ,
1352+ } ;
1353+ fields = Fields :: empty ( ) ;
1354+ }
1355+ ty:: Float ( ty:: FloatTy :: F32 ) => {
1356+ ctor = match fast_try_eval_bits ( cx. tcx , cx. param_env , value) {
1357+ Some ( bits) => {
1358+ use rustc_apfloat:: Float ;
1359+ let value = rustc_apfloat:: ieee:: Single :: from_bits ( bits) ;
1360+ F32Range ( value, value, RangeEnd :: Included )
1361+ }
1362+ None => Opaque ,
1363+ } ;
1364+ fields = Fields :: empty ( ) ;
1365+ }
1366+ ty:: Float ( ty:: FloatTy :: F64 ) => {
1367+ ctor = match fast_try_eval_bits ( cx. tcx , cx. param_env , value) {
1368+ Some ( bits) => {
1369+ use rustc_apfloat:: Float ;
1370+ let value = rustc_apfloat:: ieee:: Double :: from_bits ( bits) ;
1371+ F64Range ( value, value, RangeEnd :: Included )
1372+ }
1373+ None => Opaque ,
1374+ } ;
1375+ fields = Fields :: empty ( ) ;
1376+ }
1377+ ty:: Ref ( _, t, _) if t. is_str ( ) => {
1378+ // We want a `&str` constant to behave like a `Deref` pattern, to be compatible
1379+ // with other `Deref` patterns. This could have been done in `const_to_pat`,
1380+ // but that causes issues with the rest of the matching code.
1381+ // So here, the constructor for a `"foo"` pattern is `&` (represented by
1382+ // `Single`), and has one field. That field has constructor `Str(value)` and no
1383+ // fields.
1384+ // Note: `t` is `str`, not `&str`.
1385+ let subpattern =
1386+ DeconstructedPat :: new ( Str ( * value) , Fields :: empty ( ) , * t, pat. span ) ;
1387+ ctor = Single ;
1388+ fields = Fields :: singleton ( cx, subpattern)
1389+ }
1390+ // All constants that can be structurally matched have already been expanded
1391+ // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are
1392+ // opaque.
1393+ _ => {
1394+ ctor = Opaque ;
1395+ fields = Fields :: empty ( ) ;
13851396 }
13861397 }
13871398 }
1388- & PatKind :: Range ( box PatRange { lo, hi, end } ) => {
1399+ PatKind :: Range ( box PatRange { lo, hi, end } ) => {
13891400 use rustc_apfloat:: Float ;
13901401 let ty = lo. ty ( ) ;
1391- let lo = lo . eval_bits ( cx. tcx , cx. param_env ) ;
1392- let hi = hi . eval_bits ( cx. tcx , cx. param_env ) ;
1402+ let lo = fast_try_eval_bits ( cx. tcx , cx. param_env , lo ) . unwrap ( ) ;
1403+ let hi = fast_try_eval_bits ( cx. tcx , cx. param_env , hi ) . unwrap ( ) ;
13931404 ctor = match ty. kind ( ) {
13941405 ty:: Char | ty:: Int ( _) | ty:: Uint ( _) => {
1395- IntRange ( IntRange :: from_range ( cx. tcx , lo, hi, ty, & end) . unwrap ( ) )
1406+ IntRange ( IntRange :: from_range ( cx. tcx , lo, hi, ty, * end) )
13961407 }
13971408 ty:: Float ( ty:: FloatTy :: F32 ) => {
13981409 let lo = rustc_apfloat:: ieee:: Single :: from_bits ( lo) ;
0 commit comments