@@ -178,11 +178,11 @@ use super::{PatternFoldable, PatternFolder, compare_const_vals};
178
178
179
179
use rustc:: hir:: def_id:: DefId ;
180
180
use rustc:: hir:: RangeEnd ;
181
- use rustc:: ty:: { self , Ty , TyCtxt , TypeFoldable } ;
182
- use rustc:: ty:: layout:: { Integer , IntegerExt , VariantIdx } ;
181
+ use rustc:: ty:: { self , Ty , TyCtxt , TypeFoldable , Const } ;
182
+ use rustc:: ty:: layout:: { Integer , IntegerExt , VariantIdx , Size } ;
183
183
184
184
use rustc:: mir:: Field ;
185
- use rustc:: mir:: interpret:: ConstValue ;
185
+ use rustc:: mir:: interpret:: { ConstValue , Pointer , Scalar } ;
186
186
use rustc:: util:: common:: ErrorReported ;
187
187
188
188
use syntax:: attr:: { SignedInt , UnsignedInt } ;
@@ -200,22 +200,72 @@ use std::u128;
200
200
pub fn expand_pattern < ' a , ' tcx > ( cx : & MatchCheckCtxt < ' a , ' tcx > , pat : Pattern < ' tcx > )
201
201
-> & ' a Pattern < ' tcx >
202
202
{
203
- cx. pattern_arena . alloc ( LiteralExpander . fold_pattern ( & pat) )
203
+ cx. pattern_arena . alloc ( LiteralExpander { tcx : cx . tcx } . fold_pattern ( & pat) )
204
204
}
205
205
206
- struct LiteralExpander ;
207
- impl < ' tcx > PatternFolder < ' tcx > for LiteralExpander {
206
+ struct LiteralExpander < ' a , ' tcx > {
207
+ tcx : TyCtxt < ' a , ' tcx , ' tcx >
208
+ }
209
+
210
+ impl < ' a , ' tcx > LiteralExpander < ' a , ' tcx > {
211
+ /// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice.
212
+ ///
213
+ /// `crty` and `rty` can differ because you can use array constants in the presence of slice
214
+ /// patterns. So the pattern may end up being a slice, but the constant is an array. We convert
215
+ /// the array to a slice in that case.
216
+ fn fold_const_value_deref (
217
+ & mut self ,
218
+ val : ConstValue < ' tcx > ,
219
+ // the pattern's pointee type
220
+ rty : Ty < ' tcx > ,
221
+ // the constant's pointee type
222
+ crty : Ty < ' tcx > ,
223
+ ) -> ConstValue < ' tcx > {
224
+ match ( val, & crty. sty , & rty. sty ) {
225
+ // the easy case, deref a reference
226
+ ( ConstValue :: Scalar ( Scalar :: Ptr ( p) ) , x, y) if x == y => ConstValue :: ByRef (
227
+ p. alloc_id ,
228
+ self . tcx . alloc_map . lock ( ) . unwrap_memory ( p. alloc_id ) ,
229
+ p. offset ,
230
+ ) ,
231
+ // unsize array to slice if pattern is array but match value or other patterns are slice
232
+ ( ConstValue :: Scalar ( Scalar :: Ptr ( p) ) , ty:: Array ( t, n) , ty:: Slice ( u) ) => {
233
+ assert_eq ! ( t, u) ;
234
+ ConstValue :: ScalarPair (
235
+ Scalar :: Ptr ( p) ,
236
+ n. val . try_to_scalar ( ) . unwrap ( ) ,
237
+ )
238
+ } ,
239
+ // fat pointers stay the same
240
+ ( ConstValue :: ScalarPair ( ..) , _, _) => val,
241
+ // FIXME(oli-obk): this is reachable for `const FOO: &&&u32 = &&&42;` being used
242
+ _ => bug ! ( "cannot deref {:#?}, {} -> {}" , val, crty, rty) ,
243
+ }
244
+ }
245
+ }
246
+
247
+ impl < ' a , ' tcx > PatternFolder < ' tcx > for LiteralExpander < ' a , ' tcx > {
208
248
fn fold_pattern ( & mut self , pat : & Pattern < ' tcx > ) -> Pattern < ' tcx > {
209
249
match ( & pat. ty . sty , & * pat. kind ) {
210
- ( & ty:: Ref ( _, rty, _) , & PatternKind :: Constant { ref value } ) => {
250
+ (
251
+ & ty:: Ref ( _, rty, _) ,
252
+ & PatternKind :: Constant { value : Const {
253
+ val,
254
+ ty : ty:: TyS { sty : ty:: Ref ( _, crty, _) , .. } ,
255
+ } } ,
256
+ ) => {
211
257
Pattern {
212
258
ty : pat. ty ,
213
259
span : pat. span ,
214
260
kind : box PatternKind :: Deref {
215
261
subpattern : Pattern {
216
262
ty : rty,
217
263
span : pat. span ,
218
- kind : box PatternKind :: Constant { value : value. clone ( ) } ,
264
+ kind : box PatternKind :: Constant { value : Const :: from_const_value (
265
+ self . tcx ,
266
+ self . fold_const_value_deref ( * val, rty, crty) ,
267
+ rty,
268
+ ) } ,
219
269
}
220
270
}
221
271
}
@@ -732,15 +782,17 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
732
782
for row in patterns {
733
783
match * row. kind {
734
784
PatternKind :: Constant { value } => {
735
- if let Some ( ptr) = value. to_ptr ( ) {
736
- let is_array_ptr = value. ty
737
- . builtin_deref ( true )
738
- . and_then ( |t| t. ty . builtin_index ( ) )
739
- . map_or ( false , |t| t == cx. tcx . types . u8 ) ;
740
- if is_array_ptr {
741
- let alloc = cx. tcx . alloc_map . lock ( ) . unwrap_memory ( ptr. alloc_id ) ;
742
- max_fixed_len = cmp:: max ( max_fixed_len, alloc. bytes . len ( ) as u64 ) ;
743
- }
785
+ // extract the length of an array/slice from a constant
786
+ match ( value. val , & value. ty . sty ) {
787
+ ( _, ty:: Array ( _, n) ) => max_fixed_len = cmp:: max (
788
+ max_fixed_len,
789
+ n. unwrap_usize ( cx. tcx ) ,
790
+ ) ,
791
+ ( ConstValue :: ScalarPair ( _, n) , ty:: Slice ( _) ) => max_fixed_len = cmp:: max (
792
+ max_fixed_len,
793
+ n. to_usize ( & cx. tcx ) . unwrap ( ) ,
794
+ ) ,
795
+ _ => { } ,
744
796
}
745
797
}
746
798
PatternKind :: Slice { ref prefix, slice : None , ref suffix } => {
@@ -1348,28 +1400,62 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
1348
1400
}
1349
1401
}
1350
1402
1351
- fn slice_pat_covered_by_constructor < ' tcx > (
1403
+ // checks whether a constant is equal to a user-written slice pattern. Only supports byte slices,
1404
+ // meaning all other types will compare unequal and thus equal patterns often do not cause the
1405
+ // second pattern to lint about unreachable match arms.
1406
+ fn slice_pat_covered_by_const < ' tcx > (
1352
1407
tcx : TyCtxt < ' _ , ' tcx , ' _ > ,
1353
1408
_span : Span ,
1354
- ctor : & Constructor ,
1409
+ const_val : & ty :: Const < ' tcx > ,
1355
1410
prefix : & [ Pattern < ' tcx > ] ,
1356
1411
slice : & Option < Pattern < ' tcx > > ,
1357
1412
suffix : & [ Pattern < ' tcx > ]
1358
1413
) -> Result < bool , ErrorReported > {
1359
- let data: & [ u8 ] = match * ctor {
1360
- ConstantValue ( const_val) => {
1361
- let val = match const_val. val {
1362
- ConstValue :: Unevaluated ( ..) |
1363
- ConstValue :: ByRef ( ..) => bug ! ( "unexpected ConstValue: {:?}" , const_val) ,
1364
- ConstValue :: Scalar ( val) | ConstValue :: ScalarPair ( val, _) => val,
1365
- } ;
1366
- if let Ok ( ptr) = val. to_ptr ( ) {
1367
- tcx. alloc_map . lock ( ) . unwrap_memory ( ptr. alloc_id ) . bytes . as_ref ( )
1368
- } else {
1369
- bug ! ( "unexpected non-ptr ConstantValue" )
1414
+ let data: & [ u8 ] = match ( const_val. val , & const_val. ty . sty ) {
1415
+ ( ConstValue :: ByRef ( id, alloc, offset) , ty:: Array ( t, n) ) => {
1416
+ if * t != tcx. types . u8 {
1417
+ // FIXME(oli-obk): can't mix const patterns with slice patterns and get
1418
+ // any sort of exhaustiveness/unreachable check yet
1419
+ // This solely means that we don't lint about unreachable patterns, even if some
1420
+ // are definitely unreachable.
1421
+ return Ok ( false ) ;
1370
1422
}
1371
- }
1372
- _ => bug ! ( )
1423
+ let ptr = Pointer :: new ( id, offset) ;
1424
+ let n = n. assert_usize ( tcx) . unwrap ( ) ;
1425
+ alloc. get_bytes ( & tcx, ptr, Size :: from_bytes ( n) ) . unwrap ( )
1426
+ } ,
1427
+ // a slice fat pointer to a zero length slice
1428
+ ( ConstValue :: ScalarPair ( Scalar :: Bits { .. } , n) , ty:: Slice ( t) ) => {
1429
+ if * t != tcx. types . u8 {
1430
+ // FIXME(oli-obk): can't mix const patterns with slice patterns and get
1431
+ // any sort of exhaustiveness/unreachable check yet
1432
+ // This solely means that we don't lint about unreachable patterns, even if some
1433
+ // are definitely unreachable.
1434
+ return Ok ( false ) ;
1435
+ }
1436
+ assert_eq ! ( n. to_usize( & tcx) . unwrap( ) , 0 ) ;
1437
+ & [ ]
1438
+ } ,
1439
+ //
1440
+ ( ConstValue :: ScalarPair ( Scalar :: Ptr ( ptr) , n) , ty:: Slice ( t) ) => {
1441
+ if * t != tcx. types . u8 {
1442
+ // FIXME(oli-obk): can't mix const patterns with slice patterns and get
1443
+ // any sort of exhaustiveness/unreachable check yet
1444
+ // This solely means that we don't lint about unreachable patterns, even if some
1445
+ // are definitely unreachable.
1446
+ return Ok ( false ) ;
1447
+ }
1448
+ let n = n. to_usize ( & tcx) . unwrap ( ) ;
1449
+ tcx. alloc_map
1450
+ . lock ( )
1451
+ . unwrap_memory ( ptr. alloc_id )
1452
+ . get_bytes ( & tcx, ptr, Size :: from_bytes ( n) )
1453
+ . unwrap ( )
1454
+ } ,
1455
+ _ => bug ! (
1456
+ "slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}" ,
1457
+ const_val, prefix, slice, suffix,
1458
+ ) ,
1373
1459
} ;
1374
1460
1375
1461
let pat_len = prefix. len ( ) + suffix. len ( ) ;
@@ -1675,22 +1761,23 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
1675
1761
// necessarily point to memory, they are usually just integers. The only time
1676
1762
// they should be pointing to memory is when they are subslices of nonzero
1677
1763
// slices
1678
- let ( opt_ptr, n, ty) = match value. ty . builtin_deref ( false ) . unwrap ( ) . ty . sty {
1679
- ty:: TyKind :: Array ( t, n) => ( value. to_ptr ( ) , n. unwrap_usize ( cx. tcx ) , t) ,
1680
- ty:: TyKind :: Slice ( t) => {
1681
- match value. val {
1682
- ConstValue :: ScalarPair ( ptr, n) => (
1683
- ptr. to_ptr ( ) . ok ( ) ,
1684
- n. to_bits ( cx. tcx . data_layout . pointer_size ) . unwrap ( ) as u64 ,
1685
- t,
1686
- ) ,
1687
- _ => span_bug ! (
1688
- pat. span,
1689
- "slice pattern constant must be scalar pair but is {:?}" ,
1690
- value,
1691
- ) ,
1692
- }
1693
- } ,
1764
+ let ( opt_ptr, n, ty) = match ( value. val , & value. ty . sty ) {
1765
+ ( ConstValue :: ByRef ( id, alloc, offset) , ty:: TyKind :: Array ( t, n) ) => (
1766
+ Some ( (
1767
+ Pointer :: new ( id, offset) ,
1768
+ alloc,
1769
+ ) ) ,
1770
+ n. unwrap_usize ( cx. tcx ) ,
1771
+ t,
1772
+ ) ,
1773
+ ( ConstValue :: ScalarPair ( ptr, n) , ty:: TyKind :: Slice ( t) ) => (
1774
+ ptr. to_ptr ( ) . ok ( ) . map ( |ptr| (
1775
+ ptr,
1776
+ cx. tcx . alloc_map . lock ( ) . unwrap_memory ( ptr. alloc_id ) ,
1777
+ ) ) ,
1778
+ n. to_bits ( cx. tcx . data_layout . pointer_size ) . unwrap ( ) as u64 ,
1779
+ t,
1780
+ ) ,
1694
1781
_ => span_bug ! (
1695
1782
pat. span,
1696
1783
"unexpected const-val {:?} with ctor {:?}" ,
@@ -1702,8 +1789,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
1702
1789
// convert a constant slice/array pattern to a list of patterns.
1703
1790
match ( n, opt_ptr) {
1704
1791
( 0 , _) => Some ( SmallVec :: new ( ) ) ,
1705
- ( _, Some ( ptr) ) => {
1706
- let alloc = cx. tcx . alloc_map . lock ( ) . unwrap_memory ( ptr. alloc_id ) ;
1792
+ ( _, Some ( ( ptr, alloc) ) ) => {
1707
1793
let layout = cx. tcx . layout_of ( cx. param_env . and ( ty) ) . ok ( ) ?;
1708
1794
( 0 ..n) . map ( |i| {
1709
1795
let ptr = ptr. offset ( layout. size * i, & cx. tcx ) . ok ( ) ?;
@@ -1766,10 +1852,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
1766
1852
None
1767
1853
}
1768
1854
}
1769
- ConstantValue ( ..) => {
1770
- match slice_pat_covered_by_constructor (
1771
- cx. tcx , pat. span , constructor, prefix, slice, suffix
1772
- ) {
1855
+ ConstantValue ( cv) => {
1856
+ match slice_pat_covered_by_const ( cx. tcx , pat. span , cv, prefix, slice, suffix) {
1773
1857
Ok ( true ) => Some ( smallvec ! [ ] ) ,
1774
1858
Ok ( false ) => None ,
1775
1859
Err ( ErrorReported ) => None
0 commit comments