@@ -29,7 +29,7 @@ use util::elaborate_drops::{DropElaborator, DropStyle, DropFlagMode};
2929use syntax:: ast;
3030use syntax_pos:: Span ;
3131
32- use std:: fmt;
32+ use std:: { fmt, u32 } ;
3333
3434pub struct ElaborateDrops ;
3535
@@ -74,6 +74,7 @@ impl MirPass for ElaborateDrops {
7474 flow_inits,
7575 flow_uninits,
7676 drop_flags : FxHashMap ( ) ,
77+ array_items_drop_flags : FxHashMap ( ) ,
7778 patch : MirPatch :: new ( mir) ,
7879 } . elaborate ( )
7980 } ;
@@ -224,6 +225,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
224225 ( ( some_live, some_dead) , children_count != 1 )
225226 }
226227 } ;
228+
227229 match ( maybe_live, maybe_dead, multipart) {
228230 ( false , _, _) => DropStyle :: Dead ,
229231 ( true , false , _) => DropStyle :: Static ,
@@ -232,7 +234,16 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
232234 }
233235 }
234236
235- fn clear_drop_flag ( & mut self , loc : Location , path : Self :: Path , mode : DropFlagMode ) {
237+ fn clear_drop_flag (
238+ & mut self ,
239+ loc : Location ,
240+ path : Self :: Path ,
241+ mode : DropFlagMode ,
242+ opt_flag : Option < Local > ) {
243+ if let Some ( flag) = opt_flag {
244+ self . ctxt . set_drop_flag_impl ( loc, flag, DropFlagState :: Absent ) ;
245+ return ;
246+ }
236247 match mode {
237248 DropFlagMode :: Shallow => {
238249 self . ctxt . set_drop_flag ( loc, path, DropFlagState :: Absent ) ;
@@ -257,18 +268,37 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
257268 } )
258269 }
259270
260- fn array_subpath ( & self , path : Self :: Path , index : u32 , size : u32 ) -> Option < Self :: Path > {
261- dataflow:: move_path_children_matching ( self . ctxt . move_data ( ) , path, |p| {
262- match p {
263- & Projection {
264- elem : ProjectionElem :: ConstantIndex { offset, min_length : _, from_end : false } , ..
265- } => offset == index,
266- & Projection {
267- elem : ProjectionElem :: ConstantIndex { offset, min_length : _, from_end : true } , ..
268- } => size - offset == index,
269- _ => false
270- }
271- } )
271+ fn array_subpaths ( & self , path : Self :: Path , size : u64 )
272+ -> Vec < ( Place < ' tcx > , Option < Self :: Path > , Option < Local > ) > {
273+ if dataflow:: move_path_children_matching ( self . ctxt . move_data ( ) , path, |_| {
274+ assert ! ( size <= ( u32 :: MAX as u64 ) ,
275+ "move out check doesn't implemented for array bigger then u32" ) ;
276+ true
277+ } ) . is_none ( ) {
278+ return vec ! [ ] ;
279+ }
280+
281+ let size = size as u32 ;
282+ let flags = self . ctxt . array_items_drop_flags . get ( & path) ;
283+ ( 0 ..size) . map ( |i| {
284+ let place = & self . ctxt . move_data ( ) . move_paths [ path] . place ;
285+ ( place. clone ( ) . elem ( ProjectionElem :: ConstantIndex {
286+ offset : i,
287+ min_length : size,
288+ from_end : false
289+ } ) ,
290+ dataflow:: move_path_children_matching ( self . ctxt . move_data ( ) , path, |p|
291+ match p. elem {
292+ ProjectionElem :: ConstantIndex { offset, min_length : _, from_end : false } =>
293+ offset == i,
294+ ProjectionElem :: ConstantIndex { offset, min_length : _, from_end : true } =>
295+ size - offset == i,
296+ ProjectionElem :: Subslice { from, to} => from <= i && i < size - to,
297+ _ => false
298+ }
299+ ) ,
300+ flags. map ( |f| f[ i as usize ] ) )
301+ } ) . collect ( )
272302 }
273303
274304 fn deref_subpath ( & self , path : Self :: Path ) -> Option < Self :: Path > {
@@ -291,18 +321,28 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
291321 } )
292322 }
293323
294- fn get_drop_flag ( & mut self , path : Self :: Path ) -> Option < Operand < ' tcx > > {
295- self . ctxt . drop_flag ( path) . map ( Operand :: Copy )
324+ fn get_drop_flags ( & mut self , path : Self :: Path ) -> Option < Operand < ' tcx > > {
325+ self . ctxt . drop_flag ( path) . map ( |f| match f{
326+ DropFlag :: Single ( l) => Operand :: Copy ( Place :: Local ( * l) ) ,
327+ DropFlag :: Subslice ( _) =>
328+ panic ! ( "get_drop_flags shouldn't be calles for sublice move path" )
329+ } )
296330 }
297331}
298332
333+ enum DropFlag {
334+ Single ( Local ) ,
335+ Subslice ( Vec < Local > ) ,
336+ }
337+
299338struct ElaborateDropsCtxt < ' a , ' tcx : ' a > {
300339 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
301340 mir : & ' a Mir < ' tcx > ,
302341 env : & ' a MoveDataParamEnv < ' tcx , ' tcx > ,
303342 flow_inits : DataflowResults < MaybeInitializedLvals < ' a , ' tcx , ' tcx > > ,
304343 flow_uninits : DataflowResults < MaybeUninitializedLvals < ' a , ' tcx , ' tcx > > ,
305- drop_flags : FxHashMap < MovePathIndex , Local > ,
344+ drop_flags : FxHashMap < MovePathIndex , DropFlag > ,
345+ array_items_drop_flags : FxHashMap < MovePathIndex , Vec < Local > > ,
306346 patch : MirPatch < ' tcx > ,
307347}
308348
@@ -329,15 +369,48 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
329369
330370 fn create_drop_flag ( & mut self , index : MovePathIndex , span : Span ) {
331371 let tcx = self . tcx ;
372+ if let Place :: Projection (
373+ box Projection { ref base, elem : ProjectionElem :: Subslice { from, to} } ) =
374+ self . move_data ( ) . move_paths [ index] . place {
375+ let base_ty = base. ty ( self . mir , self . tcx ) . to_ty ( self . tcx ) ;
376+ if let ty:: TyArray ( _, n) = base_ty. sty {
377+ let flags = {
378+ let n = n. val . to_const_int ( ) . and_then ( |v| v. to_u64 ( ) )
379+ . expect ( "expected u64 size" ) as usize ;
380+ let span = self . mir . span ;
381+ let parent_index = self . move_data ( ) . move_paths [ index] . parent
382+ . expect ( "subslice has parent" ) ;
383+ let patch = & mut self . patch ;
384+ let array_flags = self . array_items_drop_flags . entry ( parent_index)
385+ . or_insert_with ( || {
386+ let flags = ( 0 ..n) . map ( |_| patch. new_internal ( tcx. types . bool , span) )
387+ . collect ( ) ;
388+ debug ! ( "create_drop_flags for array with subslice({:?}, {:?}, {:?})" ,
389+ parent_index, span, flags) ;
390+ flags
391+ } ) ;
392+ let from = from as usize ;
393+ let to = to as usize ;
394+ array_flags[ from .. n-to] . iter ( ) . map ( |x| * x) . collect ( )
395+ } ;
396+
397+ let span = self . mir . span ;
398+ self . drop_flags . entry ( index) . or_insert_with ( || {
399+ debug ! ( "create_drop_flags for subslice({:?}, {:?}, {:?})" , index, span, flags) ;
400+ DropFlag :: Subslice ( flags)
401+ } ) ;
402+ return ;
403+ }
404+ }
332405 let patch = & mut self . patch ;
333406 debug ! ( "create_drop_flag({:?})" , self . mir. span) ;
334407 self . drop_flags . entry ( index) . or_insert_with ( || {
335- patch. new_internal ( tcx. types . bool , span)
408+ DropFlag :: Single ( patch. new_internal ( tcx. types . bool , span) )
336409 } ) ;
337410 }
338411
339- fn drop_flag ( & mut self , index : MovePathIndex ) -> Option < Place < ' tcx > > {
340- self . drop_flags . get ( & index) . map ( |t| Place :: Local ( * t ) )
412+ fn drop_flag ( & mut self , index : MovePathIndex ) -> Option < & DropFlag > {
413+ self . drop_flags . get ( & index)
341414 }
342415
343416 /// create a patch that elaborates all drops in the input
@@ -389,6 +462,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
389462 }
390463 } ;
391464
465+
392466 on_all_drop_children_bits ( self . tcx , self . mir , self . env , path, |child| {
393467 let ( maybe_live, maybe_dead) = init_data. state ( child) ;
394468 debug ! ( "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}" ,
@@ -548,11 +622,20 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
548622 } ) ) )
549623 }
550624
625+ fn set_drop_flag_impl ( & mut self , loc : Location , flag : Local , val : DropFlagState ) {
626+ let span = self . patch . source_info_for_location ( self . mir , loc) . span ;
627+ let val = self . constant_bool ( span, val. value ( ) ) ;
628+ self . patch . add_assign ( loc, Place :: Local ( flag) , val) ;
629+ }
630+
551631 fn set_drop_flag ( & mut self , loc : Location , path : MovePathIndex , val : DropFlagState ) {
552- if let Some ( & flag) = self . drop_flags . get ( & path) {
553- let span = self . patch . source_info_for_location ( self . mir , loc) . span ;
554- let val = self . constant_bool ( span, val. value ( ) ) ;
555- self . patch . add_assign ( loc, Place :: Local ( flag) , val) ;
632+ match self . drop_flags . get ( & path) {
633+ Some ( DropFlag :: Single ( flag) ) => self . set_drop_flag_impl ( loc, * flag, val) ,
634+ Some ( DropFlag :: Subslice ( flags) ) =>
635+ for flag in flags {
636+ self . set_drop_flag_impl ( loc, * flag, val) ;
637+ }
638+ _ => { }
556639 }
557640 }
558641
@@ -561,7 +644,14 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
561644 let span = self . patch . source_info_for_location ( self . mir , loc) . span ;
562645 let false_ = self . constant_bool ( span, false ) ;
563646 for flag in self . drop_flags . values ( ) {
564- self . patch . add_assign ( loc, Place :: Local ( * flag) , false_. clone ( ) ) ;
647+ match flag {
648+ DropFlag :: Single ( flag) =>
649+ self . patch . add_assign ( loc, Place :: Local ( * flag) , false_. clone ( ) ) ,
650+ DropFlag :: Subslice ( flags) =>
651+ for flag in flags {
652+ self . patch . add_assign ( loc, Place :: Local ( * flag) , false_. clone ( ) ) ;
653+ } ,
654+ }
565655 }
566656 }
567657
0 commit comments