@@ -29,7 +29,7 @@ use util::elaborate_drops::{DropElaborator, DropStyle, DropFlagMode};
29
29
use syntax:: ast;
30
30
use syntax_pos:: Span ;
31
31
32
- use std:: fmt;
32
+ use std:: { fmt, u32 } ;
33
33
34
34
pub struct ElaborateDrops ;
35
35
@@ -74,6 +74,7 @@ impl MirPass for ElaborateDrops {
74
74
flow_inits,
75
75
flow_uninits,
76
76
drop_flags : FxHashMap ( ) ,
77
+ array_items_drop_flags : FxHashMap ( ) ,
77
78
patch : MirPatch :: new ( mir) ,
78
79
} . elaborate ( )
79
80
} ;
@@ -224,6 +225,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
224
225
( ( some_live, some_dead) , children_count != 1 )
225
226
}
226
227
} ;
228
+
227
229
match ( maybe_live, maybe_dead, multipart) {
228
230
( false , _, _) => DropStyle :: Dead ,
229
231
( true , false , _) => DropStyle :: Static ,
@@ -232,7 +234,16 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
232
234
}
233
235
}
234
236
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
+ }
236
247
match mode {
237
248
DropFlagMode :: Shallow => {
238
249
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> {
257
268
} )
258
269
}
259
270
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 ( )
272
302
}
273
303
274
304
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> {
291
321
} )
292
322
}
293
323
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
+ } )
296
330
}
297
331
}
298
332
333
+ enum DropFlag {
334
+ Single ( Local ) ,
335
+ Subslice ( Vec < Local > ) ,
336
+ }
337
+
299
338
struct ElaborateDropsCtxt < ' a , ' tcx : ' a > {
300
339
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
301
340
mir : & ' a Mir < ' tcx > ,
302
341
env : & ' a MoveDataParamEnv < ' tcx , ' tcx > ,
303
342
flow_inits : DataflowResults < MaybeInitializedLvals < ' a , ' tcx , ' tcx > > ,
304
343
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 > > ,
306
346
patch : MirPatch < ' tcx > ,
307
347
}
308
348
@@ -329,15 +369,48 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
329
369
330
370
fn create_drop_flag ( & mut self , index : MovePathIndex , span : Span ) {
331
371
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
+ }
332
405
let patch = & mut self . patch ;
333
406
debug ! ( "create_drop_flag({:?})" , self . mir. span) ;
334
407
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) )
336
409
} ) ;
337
410
}
338
411
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)
341
414
}
342
415
343
416
/// create a patch that elaborates all drops in the input
@@ -389,6 +462,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
389
462
}
390
463
} ;
391
464
465
+
392
466
on_all_drop_children_bits ( self . tcx , self . mir , self . env , path, |child| {
393
467
let ( maybe_live, maybe_dead) = init_data. state ( child) ;
394
468
debug ! ( "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}" ,
@@ -548,11 +622,20 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
548
622
} ) ) )
549
623
}
550
624
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
+
551
631
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
+ _ => { }
556
639
}
557
640
}
558
641
@@ -561,7 +644,14 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
561
644
let span = self . patch . source_info_for_location ( self . mir , loc) . span ;
562
645
let false_ = self . constant_bool ( span, false ) ;
563
646
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
+ }
565
655
}
566
656
}
567
657
0 commit comments