@@ -4,7 +4,7 @@ use rustc::ty::{self, TyCtxt};
4
4
use rustc_index:: vec:: IndexVec ;
5
5
use smallvec:: { smallvec, SmallVec } ;
6
6
7
- use std:: collections :: hash_map :: Entry ;
7
+ use std:: convert :: TryInto ;
8
8
use std:: mem;
9
9
10
10
use super :: abs_domain:: Lift ;
@@ -17,19 +17,21 @@ use super::{
17
17
struct MoveDataBuilder < ' a , ' tcx > {
18
18
body : & ' a Body < ' tcx > ,
19
19
tcx : TyCtxt < ' tcx > ,
20
+ param_env : ty:: ParamEnv < ' tcx > ,
20
21
data : MoveData < ' tcx > ,
21
22
errors : Vec < ( Place < ' tcx > , MoveError < ' tcx > ) > ,
22
23
}
23
24
24
25
impl < ' a , ' tcx > MoveDataBuilder < ' a , ' tcx > {
25
- fn new ( body : & ' a Body < ' tcx > , tcx : TyCtxt < ' tcx > ) -> Self {
26
+ fn new ( body : & ' a Body < ' tcx > , tcx : TyCtxt < ' tcx > , param_env : ty :: ParamEnv < ' tcx > ) -> Self {
26
27
let mut move_paths = IndexVec :: new ( ) ;
27
28
let mut path_map = IndexVec :: new ( ) ;
28
29
let mut init_path_map = IndexVec :: new ( ) ;
29
30
30
31
MoveDataBuilder {
31
32
body,
32
33
tcx,
34
+ param_env,
33
35
errors : Vec :: new ( ) ,
34
36
data : MoveData {
35
37
moves : IndexVec :: new ( ) ,
@@ -148,42 +150,47 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
148
150
InteriorOfSliceOrArray { ty : place_ty, is_index : true } ,
149
151
) ) ;
150
152
}
151
- _ => {
152
- // FIXME: still badly broken
153
- }
153
+ _ => { }
154
154
} ,
155
155
_ => { }
156
156
} ;
157
157
158
- let proj = & place. projection [ ..i+1 ] ;
159
- base = match self
160
- . builder
161
- . data
162
- . rev_lookup
163
- . projections
164
- . entry ( ( base, elem. lift ( ) ) )
165
- {
166
- Entry :: Occupied ( ent) => * ent. get ( ) ,
167
- Entry :: Vacant ( ent) => {
168
- let path = MoveDataBuilder :: new_move_path (
169
- & mut self . builder . data . move_paths ,
170
- & mut self . builder . data . path_map ,
171
- & mut self . builder . data . init_path_map ,
172
- Some ( base) ,
173
- Place {
174
- base : place. base . clone ( ) ,
175
- projection : tcx. intern_place_elems ( proj) ,
176
- } ,
177
- ) ;
178
- ent. insert ( path) ;
179
- path
180
- }
181
- } ;
158
+ base = self . add_move_path ( base, elem, |tcx| {
159
+ Place {
160
+ base : place. base . clone ( ) ,
161
+ projection : tcx. intern_place_elems ( & place. projection [ ..i+1 ] ) ,
162
+ }
163
+ } ) ;
182
164
}
183
165
184
166
Ok ( base)
185
167
}
186
168
169
+ fn add_move_path (
170
+ & mut self ,
171
+ base : MovePathIndex ,
172
+ elem : & PlaceElem < ' tcx > ,
173
+ mk_place : impl FnOnce ( TyCtxt < ' tcx > ) -> Place < ' tcx > ,
174
+ ) -> MovePathIndex {
175
+ let MoveDataBuilder {
176
+ data : MoveData { rev_lookup, move_paths, path_map, init_path_map, .. } ,
177
+ tcx,
178
+ ..
179
+ } = self . builder ;
180
+ * rev_lookup. projections
181
+ . entry ( ( base, elem. lift ( ) ) )
182
+ . or_insert_with ( move || {
183
+ let path = MoveDataBuilder :: new_move_path (
184
+ move_paths,
185
+ path_map,
186
+ init_path_map,
187
+ Some ( base) ,
188
+ mk_place ( * tcx) ,
189
+ ) ;
190
+ path
191
+ } )
192
+ }
193
+
187
194
fn create_move_path ( & mut self , place : & Place < ' tcx > ) {
188
195
// This is an non-moving access (such as an overwrite or
189
196
// drop), so this not being a valid move path is OK.
@@ -214,8 +221,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
214
221
pub ( super ) fn gather_moves < ' tcx > (
215
222
body : & Body < ' tcx > ,
216
223
tcx : TyCtxt < ' tcx > ,
224
+ param_env : ty:: ParamEnv < ' tcx > ,
217
225
) -> Result < MoveData < ' tcx > , ( MoveData < ' tcx > , Vec < ( Place < ' tcx > , MoveError < ' tcx > ) > ) > {
218
- let mut builder = MoveDataBuilder :: new ( body, tcx) ;
226
+ let mut builder = MoveDataBuilder :: new ( body, tcx, param_env ) ;
219
227
220
228
builder. gather_args ( ) ;
221
229
@@ -411,20 +419,67 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
411
419
fn gather_move ( & mut self , place : & Place < ' tcx > ) {
412
420
debug ! ( "gather_move({:?}, {:?})" , self . loc, place) ;
413
421
414
- let path = match self . move_path_for ( place) {
415
- Ok ( path) | Err ( MoveError :: UnionMove { path } ) => path,
416
- Err ( error @ MoveError :: IllegalMove { .. } ) => {
417
- self . builder . errors . push ( ( place. clone ( ) , error) ) ;
418
- return ;
422
+ if let [
423
+ ref base @ ..,
424
+ ProjectionElem :: Subslice { from, to, from_end : false } ,
425
+ ] = * * place. projection {
426
+ // Split `Subslice` patterns into the corresponding list of
427
+ // `ConstIndex` patterns. This is done to ensure that all move paths
428
+ // are disjoint, which is expected by drop elaboration.
429
+ let base_place = Place {
430
+ base : place. base . clone ( ) ,
431
+ projection : self . builder . tcx . intern_place_elems ( base) ,
432
+ } ;
433
+ let base_path = match self . move_path_for ( & base_place) {
434
+ Ok ( path) => path,
435
+ Err ( MoveError :: UnionMove { path } ) => {
436
+ self . record_move ( place, path) ;
437
+ return ;
438
+ }
439
+ Err ( error @ MoveError :: IllegalMove { .. } ) => {
440
+ self . builder . errors . push ( ( base_place, error) ) ;
441
+ return ;
442
+ }
443
+ } ;
444
+ let base_ty = base_place. ty ( self . builder . body , self . builder . tcx ) . ty ;
445
+ let len: u32 = match base_ty. kind {
446
+ ty:: Array ( _, size) => {
447
+ let length = size. eval_usize ( self . builder . tcx , self . builder . param_env ) ;
448
+ length. try_into ( ) . expect (
449
+ "slice pattern of array with more than u32::MAX elements"
450
+ )
451
+ }
452
+ _ => bug ! ( "from_end: false slice pattern of non-array type" ) ,
453
+ } ;
454
+ for offset in from..to {
455
+ let elem = ProjectionElem :: ConstantIndex {
456
+ offset,
457
+ min_length : len,
458
+ from_end : false ,
459
+ } ;
460
+ let path = self . add_move_path (
461
+ base_path,
462
+ & elem,
463
+ |tcx| tcx. mk_place_elem ( base_place. clone ( ) , elem) ,
464
+ ) ;
465
+ self . record_move ( place, path) ;
419
466
}
420
- } ;
421
- let move_out = self . builder . data . moves . push ( MoveOut { path : path, source : self . loc } ) ;
467
+ } else {
468
+ match self . move_path_for ( place) {
469
+ Ok ( path) | Err ( MoveError :: UnionMove { path } ) => self . record_move ( place, path) ,
470
+ Err ( error @ MoveError :: IllegalMove { .. } ) => {
471
+ self . builder . errors . push ( ( place. clone ( ) , error) ) ;
472
+ }
473
+ } ;
474
+ }
475
+ }
422
476
477
+ fn record_move ( & mut self , place : & Place < ' tcx > , path : MovePathIndex ) {
478
+ let move_out = self . builder . data . moves . push ( MoveOut { path : path, source : self . loc } ) ;
423
479
debug ! (
424
480
"gather_move({:?}, {:?}): adding move {:?} of {:?}" ,
425
481
self . loc, place, move_out, path
426
482
) ;
427
-
428
483
self . builder . data . path_map [ path] . push ( move_out) ;
429
484
self . builder . data . loc_map [ self . loc ] . push ( move_out) ;
430
485
}
0 commit comments