@@ -4,7 +4,7 @@ use rustc::ty::{self, TyCtxt};
44use rustc_index:: vec:: IndexVec ;
55use smallvec:: { smallvec, SmallVec } ;
66
7- use std:: collections :: hash_map :: Entry ;
7+ use std:: convert :: TryInto ;
88use std:: mem;
99
1010use super :: abs_domain:: Lift ;
@@ -17,19 +17,21 @@ use super::{
1717struct MoveDataBuilder < ' a , ' tcx > {
1818 body : & ' a Body < ' tcx > ,
1919 tcx : TyCtxt < ' tcx > ,
20+ param_env : ty:: ParamEnv < ' tcx > ,
2021 data : MoveData < ' tcx > ,
2122 errors : Vec < ( Place < ' tcx > , MoveError < ' tcx > ) > ,
2223}
2324
2425impl < ' 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 {
2627 let mut move_paths = IndexVec :: new ( ) ;
2728 let mut path_map = IndexVec :: new ( ) ;
2829 let mut init_path_map = IndexVec :: new ( ) ;
2930
3031 MoveDataBuilder {
3132 body,
3233 tcx,
34+ param_env,
3335 errors : Vec :: new ( ) ,
3436 data : MoveData {
3537 moves : IndexVec :: new ( ) ,
@@ -148,42 +150,47 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
148150 InteriorOfSliceOrArray { ty : place_ty, is_index : true } ,
149151 ) ) ;
150152 }
151- _ => {
152- // FIXME: still badly broken
153- }
153+ _ => { }
154154 } ,
155155 _ => { }
156156 } ;
157157
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+ } ) ;
182164 }
183165
184166 Ok ( base)
185167 }
186168
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+
187194 fn create_move_path ( & mut self , place : & Place < ' tcx > ) {
188195 // This is an non-moving access (such as an overwrite or
189196 // drop), so this not being a valid move path is OK.
@@ -214,8 +221,9 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
214221pub ( super ) fn gather_moves < ' tcx > (
215222 body : & Body < ' tcx > ,
216223 tcx : TyCtxt < ' tcx > ,
224+ param_env : ty:: ParamEnv < ' tcx > ,
217225) -> 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 ) ;
219227
220228 builder. gather_args ( ) ;
221229
@@ -411,20 +419,67 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
411419 fn gather_move ( & mut self , place : & Place < ' tcx > ) {
412420 debug ! ( "gather_move({:?}, {:?})" , self . loc, place) ;
413421
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) ;
419466 }
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+ }
422476
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 } ) ;
423479 debug ! (
424480 "gather_move({:?}, {:?}): adding move {:?} of {:?}" ,
425481 self . loc, place, move_out, path
426482 ) ;
427-
428483 self . builder . data . path_map [ path] . push ( move_out) ;
429484 self . builder . data . loc_map [ self . loc ] . push ( move_out) ;
430485 }
0 commit comments