@@ -178,11 +178,11 @@ use super::{PatternFoldable, PatternFolder, compare_const_vals};
178178
179179use rustc:: hir:: def_id:: DefId ;
180180use 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 } ;
183183
184184use rustc:: mir:: Field ;
185- use rustc:: mir:: interpret:: ConstValue ;
185+ use rustc:: mir:: interpret:: { ConstValue , Pointer , Scalar } ;
186186use rustc:: util:: common:: ErrorReported ;
187187
188188use syntax:: attr:: { SignedInt , UnsignedInt } ;
@@ -200,22 +200,72 @@ use std::u128;
200200pub fn expand_pattern < ' a , ' tcx > ( cx : & MatchCheckCtxt < ' a , ' tcx > , pat : Pattern < ' tcx > )
201201 -> & ' a Pattern < ' tcx >
202202{
203- cx. pattern_arena . alloc ( LiteralExpander . fold_pattern ( & pat) )
203+ cx. pattern_arena . alloc ( LiteralExpander { tcx : cx . tcx } . fold_pattern ( & pat) )
204204}
205205
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 > {
208248 fn fold_pattern ( & mut self , pat : & Pattern < ' tcx > ) -> Pattern < ' tcx > {
209249 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+ ) => {
211257 Pattern {
212258 ty : pat. ty ,
213259 span : pat. span ,
214260 kind : box PatternKind :: Deref {
215261 subpattern : Pattern {
216262 ty : rty,
217263 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+ ) } ,
219269 }
220270 }
221271 }
@@ -732,15 +782,17 @@ fn max_slice_length<'p, 'a: 'p, 'tcx: 'a, I>(
732782 for row in patterns {
733783 match * row. kind {
734784 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+ _ => { } ,
744796 }
745797 }
746798 PatternKind :: Slice { ref prefix, slice : None , ref suffix } => {
@@ -1348,28 +1400,62 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
13481400 }
13491401}
13501402
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 > (
13521407 tcx : TyCtxt < ' _ , ' tcx , ' _ > ,
13531408 _span : Span ,
1354- ctor : & Constructor ,
1409+ const_val : & ty :: Const < ' tcx > ,
13551410 prefix : & [ Pattern < ' tcx > ] ,
13561411 slice : & Option < Pattern < ' tcx > > ,
13571412 suffix : & [ Pattern < ' tcx > ]
13581413) -> 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 ) ;
13701422 }
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+ ) ,
13731459 } ;
13741460
13751461 let pat_len = prefix. len ( ) + suffix. len ( ) ;
@@ -1675,22 +1761,23 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
16751761 // necessarily point to memory, they are usually just integers. The only time
16761762 // they should be pointing to memory is when they are subslices of nonzero
16771763 // 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+ ) ,
16941781 _ => span_bug ! (
16951782 pat. span,
16961783 "unexpected const-val {:?} with ctor {:?}" ,
@@ -1702,8 +1789,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
17021789 // convert a constant slice/array pattern to a list of patterns.
17031790 match ( n, opt_ptr) {
17041791 ( 0 , _) => Some ( SmallVec :: new ( ) ) ,
1705- ( _, Some ( ptr) ) => {
1706- let alloc = cx. tcx . alloc_map . lock ( ) . unwrap_memory ( ptr. alloc_id ) ;
1792+ ( _, Some ( ( ptr, alloc) ) ) => {
17071793 let layout = cx. tcx . layout_of ( cx. param_env . and ( ty) ) . ok ( ) ?;
17081794 ( 0 ..n) . map ( |i| {
17091795 let ptr = ptr. offset ( layout. size * i, & cx. tcx ) . ok ( ) ?;
@@ -1766,10 +1852,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
17661852 None
17671853 }
17681854 }
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) {
17731857 Ok ( true ) => Some ( smallvec ! [ ] ) ,
17741858 Ok ( false ) => None ,
17751859 Err ( ErrorReported ) => None
0 commit comments