11
11
use super :: gather_moves:: { HasMoveData , MoveData , MovePathIndex , LookupResult } ;
12
12
use super :: dataflow:: { MaybeInitializedLvals , MaybeUninitializedLvals } ;
13
13
use super :: dataflow:: { DataflowResults } ;
14
- use super :: { drop_flag_effects_for_location , on_all_children_bits } ;
15
- use super :: on_lookup_result_bits;
14
+ use super :: { on_all_children_bits , on_all_drop_children_bits } ;
15
+ use super :: { drop_flag_effects_for_location , on_lookup_result_bits} ;
16
16
use super :: MoveDataParamEnv ;
17
17
use rustc:: ty:: { self , TyCtxt } ;
18
18
use rustc:: mir:: * ;
@@ -24,6 +24,7 @@ use rustc_data_structures::indexed_vec::Idx;
24
24
use rustc_mir:: util:: patch:: MirPatch ;
25
25
use rustc_mir:: util:: elaborate_drops:: { DropFlagState , elaborate_drop} ;
26
26
use rustc_mir:: util:: elaborate_drops:: { DropElaborator , DropStyle , DropFlagMode } ;
27
+ use syntax:: ast;
27
28
use syntax_pos:: Span ;
28
29
29
30
use std:: fmt;
@@ -49,12 +50,13 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
49
50
move_data : move_data,
50
51
param_env : param_env
51
52
} ;
53
+ let dead_unwinds = find_dead_unwinds ( tcx, mir, id, & env) ;
52
54
let flow_inits =
53
- super :: do_dataflow ( tcx, mir, id, & [ ] ,
55
+ super :: do_dataflow ( tcx, mir, id, & [ ] , & dead_unwinds ,
54
56
MaybeInitializedLvals :: new ( tcx, mir, & env) ,
55
57
|bd, p| & bd. move_data ( ) . move_paths [ p] ) ;
56
58
let flow_uninits =
57
- super :: do_dataflow ( tcx, mir, id, & [ ] ,
59
+ super :: do_dataflow ( tcx, mir, id, & [ ] , & dead_unwinds ,
58
60
MaybeUninitializedLvals :: new ( tcx, mir, & env) ,
59
61
|bd, p| & bd. move_data ( ) . move_paths [ p] ) ;
60
62
@@ -74,6 +76,67 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
74
76
75
77
impl Pass for ElaborateDrops { }
76
78
79
+ /// Return the set of basic blocks whose unwind edges are known
80
+ /// to not be reachable, because they are `drop` terminators
81
+ /// that can't drop anything.
82
+ fn find_dead_unwinds < ' a , ' tcx > (
83
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
84
+ mir : & Mir < ' tcx > ,
85
+ id : ast:: NodeId ,
86
+ env : & MoveDataParamEnv < ' tcx > )
87
+ -> IdxSetBuf < BasicBlock >
88
+ {
89
+ debug ! ( "find_dead_unwinds({:?})" , mir. span) ;
90
+ // We only need to do this pass once, because unwind edges can only
91
+ // reach cleanup blocks, which can't have unwind edges themselves.
92
+ let mut dead_unwinds = IdxSetBuf :: new_empty ( mir. basic_blocks ( ) . len ( ) ) ;
93
+ let flow_inits =
94
+ super :: do_dataflow ( tcx, mir, id, & [ ] , & dead_unwinds,
95
+ MaybeInitializedLvals :: new ( tcx, mir, & env) ,
96
+ |bd, p| & bd. move_data ( ) . move_paths [ p] ) ;
97
+ for ( bb, bb_data) in mir. basic_blocks ( ) . iter_enumerated ( ) {
98
+ match bb_data. terminator ( ) . kind {
99
+ TerminatorKind :: Drop { ref location, unwind : Some ( _) , .. } |
100
+ TerminatorKind :: DropAndReplace { ref location, unwind : Some ( _) , .. } => {
101
+ let mut init_data = InitializationData {
102
+ live : flow_inits. sets ( ) . on_entry_set_for ( bb. index ( ) ) . to_owned ( ) ,
103
+ dead : IdxSetBuf :: new_empty ( env. move_data . move_paths . len ( ) ) ,
104
+ } ;
105
+ debug ! ( "find_dead_unwinds @ {:?}: {:?}; init_data={:?}" ,
106
+ bb, bb_data, init_data. live) ;
107
+ for stmt in 0 ..bb_data. statements . len ( ) {
108
+ let loc = Location { block : bb, statement_index : stmt } ;
109
+ init_data. apply_location ( tcx, mir, env, loc) ;
110
+ }
111
+
112
+ let path = match env. move_data . rev_lookup . find ( location) {
113
+ LookupResult :: Exact ( e) => e,
114
+ LookupResult :: Parent ( ..) => {
115
+ debug ! ( "find_dead_unwinds: has parent; skipping" ) ;
116
+ continue
117
+ }
118
+ } ;
119
+
120
+ debug ! ( "find_dead_unwinds @ {:?}: path({:?})={:?}" , bb, location, path) ;
121
+
122
+ let mut maybe_live = false ;
123
+ on_all_drop_children_bits ( tcx, mir, & env, path, |child| {
124
+ let ( child_maybe_live, _) = init_data. state ( child) ;
125
+ maybe_live |= child_maybe_live;
126
+ } ) ;
127
+
128
+ debug ! ( "find_dead_unwinds @ {:?}: maybe_live={}" , bb, maybe_live) ;
129
+ if !maybe_live {
130
+ dead_unwinds. add ( & bb) ;
131
+ }
132
+ }
133
+ _ => { }
134
+ }
135
+ }
136
+
137
+ dead_unwinds
138
+ }
139
+
77
140
struct InitializationData {
78
141
live : IdxSetBuf < MovePathIndex > ,
79
142
dead : IdxSetBuf < MovePathIndex >
@@ -144,17 +207,14 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
144
207
let mut some_live = false ;
145
208
let mut some_dead = false ;
146
209
let mut children_count = 0 ;
147
- on_all_children_bits (
148
- self . tcx ( ) , self . mir ( ) , self . ctxt . move_data ( ) ,
149
- path, |child| {
150
- if self . ctxt . path_needs_drop ( child) {
151
- let ( live, dead) = self . init_data . state ( child) ;
152
- debug ! ( "elaborate_drop: state({:?}) = {:?}" ,
153
- child, ( live, dead) ) ;
154
- some_live |= live;
155
- some_dead |= dead;
156
- children_count += 1 ;
157
- }
210
+ on_all_drop_children_bits (
211
+ self . tcx ( ) , self . mir ( ) , self . ctxt . env , path, |child| {
212
+ let ( live, dead) = self . init_data . state ( child) ;
213
+ debug ! ( "elaborate_drop: state({:?}) = {:?}" ,
214
+ child, ( live, dead) ) ;
215
+ some_live |= live;
216
+ some_dead |= dead;
217
+ children_count += 1 ;
158
218
} ) ;
159
219
( ( some_live, some_dead) , children_count != 1 )
160
220
}
@@ -276,15 +336,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
276
336
self . patch
277
337
}
278
338
279
- fn path_needs_drop ( & self , path : MovePathIndex ) -> bool
280
- {
281
- let lvalue = & self . move_data ( ) . move_paths [ path] . lvalue ;
282
- let ty = lvalue. ty ( self . mir , self . tcx ) . to_ty ( self . tcx ) ;
283
- debug ! ( "path_needs_drop({:?}, {:?} : {:?})" , path, lvalue, ty) ;
284
-
285
- self . tcx . type_needs_drop_given_env ( ty, self . param_env ( ) )
286
- }
287
-
288
339
fn collect_drop_flags ( & mut self )
289
340
{
290
341
for ( bb, data) in self . mir . basic_blocks ( ) . iter_enumerated ( ) {
@@ -318,14 +369,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
318
369
}
319
370
} ;
320
371
321
- on_all_children_bits ( self . tcx , self . mir , self . move_data ( ) , path, |child| {
322
- if self . path_needs_drop ( child) {
323
- let ( maybe_live, maybe_dead) = init_data. state ( child) ;
324
- debug ! ( "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}" ,
325
- child, location, path, ( maybe_live, maybe_dead) ) ;
326
- if maybe_live && maybe_dead {
327
- self . create_drop_flag ( child)
328
- }
372
+ on_all_drop_children_bits ( self . tcx , self . mir , self . env , path, |child| {
373
+ let ( maybe_live, maybe_dead) = init_data. state ( child) ;
374
+ debug ! ( "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}" ,
375
+ child, location, path, ( maybe_live, maybe_dead) ) ;
376
+ if maybe_live && maybe_dead {
377
+ self . create_drop_flag ( child)
329
378
}
330
379
} ) ;
331
380
}
0 commit comments