]>
Commit | Line | Data |
---|---|---|
c295e0f8 | 1 | use crate::MirPass; |
dfeec247 | 2 | use rustc_data_structures::fx::FxHashMap; |
e74abb32 | 3 | use rustc_index::bit_set::BitSet; |
c295e0f8 | 4 | use rustc_middle::mir::patch::MirPatch; |
ba9703b0 XL |
5 | use rustc_middle::mir::*; |
6 | use rustc_middle::ty::{self, TyCtxt}; | |
c295e0f8 XL |
7 | use rustc_mir_dataflow::elaborate_drops::{elaborate_drop, DropFlagState, Unwind}; |
8 | use rustc_mir_dataflow::elaborate_drops::{DropElaborator, DropFlagMode, DropStyle}; | |
9 | use rustc_mir_dataflow::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; | |
10 | use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; | |
11 | use rustc_mir_dataflow::on_lookup_result_bits; | |
12 | use rustc_mir_dataflow::MoveDataParamEnv; | |
13 | use rustc_mir_dataflow::{on_all_children_bits, on_all_drop_children_bits}; | |
14 | use rustc_mir_dataflow::{Analysis, ResultsCursor}; | |
dfeec247 | 15 | use rustc_span::Span; |
ba9703b0 | 16 | use rustc_target::abi::VariantIdx; |
0bf4aa26 | 17 | use std::fmt; |
3157f602 XL |
18 | |
19 | pub struct ElaborateDrops; | |
20 | ||
e1599b0c | 21 | impl<'tcx> MirPass<'tcx> for ElaborateDrops { |
29967ef6 XL |
22 | fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { |
23 | debug!("elaborate_drops({:?} @ {:?})", body.source, body.span); | |
abe05a73 | 24 | |
29967ef6 XL |
25 | let def_id = body.source.def_id(); |
26 | let param_env = tcx.param_env_reveal_all_normalized(def_id); | |
60c5eb7d | 27 | let move_data = match MoveData::gather_moves(body, tcx, param_env) { |
8faf50e0 | 28 | Ok(move_data) => move_data, |
dfeec247 XL |
29 | Err((move_data, _)) => { |
30 | tcx.sess.delay_span_bug( | |
31 | body.span, | |
32 | "No `move_errors` should be allowed in MIR borrowck", | |
33 | ); | |
34 | move_data | |
35 | } | |
8faf50e0 | 36 | }; |
3157f602 | 37 | let elaborate_patch = { |
dc9dc135 | 38 | let body = &*body; |
dfeec247 | 39 | let env = MoveDataParamEnv { move_data, param_env }; |
29967ef6 | 40 | let dead_unwinds = find_dead_unwinds(tcx, body, &env); |
74b04a01 XL |
41 | |
42 | let inits = MaybeInitializedPlaces::new(tcx, body, &env) | |
29967ef6 | 43 | .into_engine(tcx, body) |
74b04a01 | 44 | .dead_unwinds(&dead_unwinds) |
1b1a35ee | 45 | .pass_name("elaborate_drops") |
74b04a01 XL |
46 | .iterate_to_fixpoint() |
47 | .into_results_cursor(body); | |
48 | ||
49 | let uninits = MaybeUninitializedPlaces::new(tcx, body, &env) | |
f035d41b | 50 | .mark_inactive_variants_as_uninit() |
29967ef6 | 51 | .into_engine(tcx, body) |
74b04a01 | 52 | .dead_unwinds(&dead_unwinds) |
1b1a35ee | 53 | .pass_name("elaborate_drops") |
74b04a01 XL |
54 | .iterate_to_fixpoint() |
55 | .into_results_cursor(body); | |
3157f602 XL |
56 | |
57 | ElaborateDropsCtxt { | |
3b2f2976 | 58 | tcx, |
dc9dc135 | 59 | body, |
3157f602 | 60 | env: &env, |
74b04a01 | 61 | init_data: InitializationData { inits, uninits }, |
0bf4aa26 | 62 | drop_flags: Default::default(), |
dc9dc135 | 63 | patch: MirPatch::new(body), |
dfeec247 XL |
64 | } |
65 | .elaborate() | |
3157f602 | 66 | }; |
dc9dc135 | 67 | elaborate_patch.apply(body); |
3157f602 XL |
68 | } |
69 | } | |
70 | ||
9fa01778 | 71 | /// Returns the set of basic blocks whose unwind edges are known |
cc61c64b XL |
72 | /// to not be reachable, because they are `drop` terminators |
73 | /// that can't drop anything. | |
dc9dc135 XL |
74 | fn find_dead_unwinds<'tcx>( |
75 | tcx: TyCtxt<'tcx>, | |
76 | body: &Body<'tcx>, | |
dc9dc135 XL |
77 | env: &MoveDataParamEnv<'tcx>, |
78 | ) -> BitSet<BasicBlock> { | |
79 | debug!("find_dead_unwinds({:?})", body.span); | |
cc61c64b XL |
80 | // We only need to do this pass once, because unwind edges can only |
81 | // reach cleanup blocks, which can't have unwind edges themselves. | |
dc9dc135 | 82 | let mut dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); |
74b04a01 | 83 | let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &env) |
29967ef6 | 84 | .into_engine(tcx, body) |
1b1a35ee | 85 | .pass_name("find_dead_unwinds") |
74b04a01 XL |
86 | .iterate_to_fixpoint() |
87 | .into_results_cursor(body); | |
dc9dc135 | 88 | for (bb, bb_data) in body.basic_blocks().iter_enumerated() { |
f035d41b XL |
89 | let place = match bb_data.terminator().kind { |
90 | TerminatorKind::Drop { ref place, unwind: Some(_), .. } | |
91 | | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => place, | |
ea8adc8c XL |
92 | _ => continue, |
93 | }; | |
cc61c64b | 94 | |
74b04a01 | 95 | debug!("find_dead_unwinds @ {:?}: {:?}", bb, bb_data); |
cc61c64b | 96 | |
f035d41b | 97 | let path = match env.move_data.rev_lookup.find(place.as_ref()) { |
ea8adc8c XL |
98 | LookupResult::Exact(e) => e, |
99 | LookupResult::Parent(..) => { | |
100 | debug!("find_dead_unwinds: has parent; skipping"); | |
dfeec247 | 101 | continue; |
ea8adc8c XL |
102 | } |
103 | }; | |
cc61c64b | 104 | |
f9f354fc | 105 | flow_inits.seek_before_primary_effect(body.terminator_loc(bb)); |
74b04a01 XL |
106 | debug!( |
107 | "find_dead_unwinds @ {:?}: path({:?})={:?}; init_data={:?}", | |
108 | bb, | |
f035d41b | 109 | place, |
74b04a01 XL |
110 | path, |
111 | flow_inits.get() | |
112 | ); | |
cc61c64b | 113 | |
ea8adc8c | 114 | let mut maybe_live = false; |
dc9dc135 | 115 | on_all_drop_children_bits(tcx, body, &env, path, |child| { |
74b04a01 | 116 | maybe_live |= flow_inits.contains(child); |
ea8adc8c XL |
117 | }); |
118 | ||
119 | debug!("find_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live); | |
120 | if !maybe_live { | |
0bf4aa26 | 121 | dead_unwinds.insert(bb); |
cc61c64b XL |
122 | } |
123 | } | |
124 | ||
125 | dead_unwinds | |
126 | } | |
127 | ||
74b04a01 XL |
128 | struct InitializationData<'mir, 'tcx> { |
129 | inits: ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, | |
130 | uninits: ResultsCursor<'mir, 'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>, | |
3157f602 XL |
131 | } |
132 | ||
74b04a01 XL |
133 | impl InitializationData<'_, '_> { |
134 | fn seek_before(&mut self, loc: Location) { | |
f9f354fc XL |
135 | self.inits.seek_before_primary_effect(loc); |
136 | self.uninits.seek_before_primary_effect(loc); | |
3157f602 XL |
137 | } |
138 | ||
74b04a01 XL |
139 | fn maybe_live_dead(&self, path: MovePathIndex) -> (bool, bool) { |
140 | (self.inits.contains(path), self.uninits.contains(path)) | |
3157f602 XL |
141 | } |
142 | } | |
143 | ||
dc9dc135 | 144 | struct Elaborator<'a, 'b, 'tcx> { |
cc61c64b XL |
145 | ctxt: &'a mut ElaborateDropsCtxt<'b, 'tcx>, |
146 | } | |
147 | ||
148 | impl<'a, 'b, 'tcx> fmt::Debug for Elaborator<'a, 'b, 'tcx> { | |
9fa01778 | 149 | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { |
3157f602 XL |
150 | Ok(()) |
151 | } | |
152 | } | |
153 | ||
cc61c64b XL |
154 | impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { |
155 | type Path = MovePathIndex; | |
156 | ||
157 | fn patch(&mut self) -> &mut MirPatch<'tcx> { | |
158 | &mut self.ctxt.patch | |
159 | } | |
160 | ||
dc9dc135 XL |
161 | fn body(&self) -> &'a Body<'tcx> { |
162 | self.ctxt.body | |
cc61c64b XL |
163 | } |
164 | ||
dc9dc135 | 165 | fn tcx(&self) -> TyCtxt<'tcx> { |
cc61c64b XL |
166 | self.ctxt.tcx |
167 | } | |
168 | ||
7cac9316 | 169 | fn param_env(&self) -> ty::ParamEnv<'tcx> { |
cc61c64b XL |
170 | self.ctxt.param_env() |
171 | } | |
172 | ||
173 | fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle { | |
174 | let ((maybe_live, maybe_dead), multipart) = match mode { | |
74b04a01 | 175 | DropFlagMode::Shallow => (self.ctxt.init_data.maybe_live_dead(path), false), |
cc61c64b XL |
176 | DropFlagMode::Deep => { |
177 | let mut some_live = false; | |
178 | let mut some_dead = false; | |
179 | let mut children_count = 0; | |
dfeec247 | 180 | on_all_drop_children_bits(self.tcx(), self.body(), self.ctxt.env, path, |child| { |
74b04a01 | 181 | let (live, dead) = self.ctxt.init_data.maybe_live_dead(child); |
dfeec247 XL |
182 | debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead)); |
183 | some_live |= live; | |
184 | some_dead |= dead; | |
185 | children_count += 1; | |
186 | }); | |
cc61c64b XL |
187 | ((some_live, some_dead), children_count != 1) |
188 | } | |
189 | }; | |
190 | match (maybe_live, maybe_dead, multipart) { | |
191 | (false, _, _) => DropStyle::Dead, | |
192 | (true, false, _) => DropStyle::Static, | |
193 | (true, true, false) => DropStyle::Conditional, | |
194 | (true, true, true) => DropStyle::Open, | |
195 | } | |
196 | } | |
197 | ||
198 | fn clear_drop_flag(&mut self, loc: Location, path: Self::Path, mode: DropFlagMode) { | |
199 | match mode { | |
200 | DropFlagMode::Shallow => { | |
201 | self.ctxt.set_drop_flag(loc, path, DropFlagState::Absent); | |
202 | } | |
203 | DropFlagMode::Deep => { | |
204 | on_all_children_bits( | |
dfeec247 XL |
205 | self.tcx(), |
206 | self.body(), | |
207 | self.ctxt.move_data(), | |
208 | path, | |
209 | |child| self.ctxt.set_drop_flag(loc, child, DropFlagState::Absent), | |
210 | ); | |
cc61c64b XL |
211 | } |
212 | } | |
213 | } | |
214 | ||
215 | fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> { | |
c295e0f8 | 216 | rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { |
f9f354fc | 217 | ProjectionElem::Field(idx, _) => idx == field, |
e1599b0c | 218 | _ => false, |
cc61c64b XL |
219 | }) |
220 | } | |
221 | ||
1b1a35ee | 222 | fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option<Self::Path> { |
c295e0f8 | 223 | rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { |
60c5eb7d | 224 | ProjectionElem::ConstantIndex { offset, min_length, from_end } => { |
f9f354fc | 225 | debug_assert!(size == min_length, "min_length should be exact for arrays"); |
60c5eb7d | 226 | assert!(!from_end, "from_end should not be used for array element ConstantIndex"); |
f9f354fc | 227 | offset == index |
e1599b0c | 228 | } |
e1599b0c | 229 | _ => false, |
ff7c6d11 XL |
230 | }) |
231 | } | |
232 | ||
cc61c64b | 233 | fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> { |
c295e0f8 | 234 | rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| { |
f9f354fc | 235 | e == ProjectionElem::Deref |
cc61c64b XL |
236 | }) |
237 | } | |
238 | ||
a1dfa0c6 | 239 | fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option<Self::Path> { |
c295e0f8 | 240 | rustc_mir_dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e { |
f9f354fc | 241 | ProjectionElem::Downcast(_, idx) => idx == variant, |
dfeec247 | 242 | _ => false, |
cc61c64b XL |
243 | }) |
244 | } | |
245 | ||
246 | fn get_drop_flag(&mut self, path: Self::Path) -> Option<Operand<'tcx>> { | |
ff7c6d11 | 247 | self.ctxt.drop_flag(path).map(Operand::Copy) |
cc61c64b XL |
248 | } |
249 | } | |
250 | ||
dc9dc135 XL |
251 | struct ElaborateDropsCtxt<'a, 'tcx> { |
252 | tcx: TyCtxt<'tcx>, | |
253 | body: &'a Body<'tcx>, | |
254 | env: &'a MoveDataParamEnv<'tcx>, | |
74b04a01 | 255 | init_data: InitializationData<'a, 'tcx>, |
476ff2be | 256 | drop_flags: FxHashMap<MovePathIndex, Local>, |
3157f602 XL |
257 | patch: MirPatch<'tcx>, |
258 | } | |
259 | ||
3157f602 | 260 | impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { |
dfeec247 XL |
261 | fn move_data(&self) -> &'b MoveData<'tcx> { |
262 | &self.env.move_data | |
263 | } | |
7cac9316 XL |
264 | |
265 | fn param_env(&self) -> ty::ParamEnv<'tcx> { | |
266 | self.env.param_env | |
3157f602 XL |
267 | } |
268 | ||
cc61c64b | 269 | fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) { |
3157f602 XL |
270 | let tcx = self.tcx; |
271 | let patch = &mut self.patch; | |
dc9dc135 | 272 | debug!("create_drop_flag({:?})", self.body.span); |
dfeec247 | 273 | self.drop_flags.entry(index).or_insert_with(|| patch.new_internal(tcx.types.bool, span)); |
3157f602 XL |
274 | } |
275 | ||
ff7c6d11 | 276 | fn drop_flag(&mut self, index: MovePathIndex) -> Option<Place<'tcx>> { |
dc9dc135 | 277 | self.drop_flags.get(&index).map(|t| Place::from(*t)) |
3157f602 XL |
278 | } |
279 | ||
280 | /// create a patch that elaborates all drops in the input | |
281 | /// MIR. | |
dfeec247 | 282 | fn elaborate(mut self) -> MirPatch<'tcx> { |
3157f602 XL |
283 | self.collect_drop_flags(); |
284 | ||
285 | self.elaborate_drops(); | |
286 | ||
287 | self.drop_flags_on_init(); | |
288 | self.drop_flags_for_fn_rets(); | |
289 | self.drop_flags_for_args(); | |
290 | self.drop_flags_for_locs(); | |
291 | ||
292 | self.patch | |
293 | } | |
294 | ||
dfeec247 | 295 | fn collect_drop_flags(&mut self) { |
dc9dc135 | 296 | for (bb, data) in self.body.basic_blocks().iter_enumerated() { |
3157f602 | 297 | let terminator = data.terminator(); |
f035d41b XL |
298 | let place = match terminator.kind { |
299 | TerminatorKind::Drop { ref place, .. } | |
300 | | TerminatorKind::DropAndReplace { ref place, .. } => place, | |
dfeec247 | 301 | _ => continue, |
3157f602 XL |
302 | }; |
303 | ||
74b04a01 | 304 | self.init_data.seek_before(self.body.terminator_loc(bb)); |
3157f602 | 305 | |
f035d41b XL |
306 | let path = self.move_data().rev_lookup.find(place.as_ref()); |
307 | debug!("collect_drop_flags: {:?}, place {:?} ({:?})", bb, place, path); | |
3157f602 | 308 | |
9e0c209e SL |
309 | let path = match path { |
310 | LookupResult::Exact(e) => e, | |
311 | LookupResult::Parent(None) => continue, | |
312 | LookupResult::Parent(Some(parent)) => { | |
74b04a01 | 313 | let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent); |
9e0c209e | 314 | if maybe_dead { |
dfeec247 XL |
315 | span_bug!( |
316 | terminator.source_info.span, | |
317 | "drop of untracked, uninitialized value {:?}, place {:?} ({:?})", | |
318 | bb, | |
f035d41b | 319 | place, |
dfeec247 XL |
320 | path |
321 | ); | |
9e0c209e | 322 | } |
dfeec247 | 323 | continue; |
9e0c209e SL |
324 | } |
325 | }; | |
326 | ||
dc9dc135 | 327 | on_all_drop_children_bits(self.tcx, self.body, self.env, path, |child| { |
74b04a01 | 328 | let (maybe_live, maybe_dead) = self.init_data.maybe_live_dead(child); |
dfeec247 XL |
329 | debug!( |
330 | "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", | |
331 | child, | |
f035d41b | 332 | place, |
dfeec247 XL |
333 | path, |
334 | (maybe_live, maybe_dead) | |
335 | ); | |
cc61c64b XL |
336 | if maybe_live && maybe_dead { |
337 | self.create_drop_flag(child, terminator.source_info.span) | |
3157f602 XL |
338 | } |
339 | }); | |
340 | } | |
341 | } | |
342 | ||
dfeec247 | 343 | fn elaborate_drops(&mut self) { |
dc9dc135 | 344 | for (bb, data) in self.body.basic_blocks().iter_enumerated() { |
9e0c209e | 345 | let loc = Location { block: bb, statement_index: data.statements.len() }; |
3157f602 XL |
346 | let terminator = data.terminator(); |
347 | ||
348 | let resume_block = self.patch.resume_block(); | |
349 | match terminator.kind { | |
f035d41b | 350 | TerminatorKind::Drop { place, target, unwind } => { |
74b04a01 | 351 | self.init_data.seek_before(loc); |
f035d41b | 352 | match self.move_data().rev_lookup.find(place.as_ref()) { |
dfeec247 | 353 | LookupResult::Exact(path) => elaborate_drop( |
74b04a01 | 354 | &mut Elaborator { ctxt: self }, |
dfeec247 | 355 | terminator.source_info, |
f035d41b | 356 | place, |
dfeec247 XL |
357 | path, |
358 | target, | |
359 | if data.is_cleanup { | |
360 | Unwind::InCleanup | |
361 | } else { | |
362 | Unwind::To(Option::unwrap_or(unwind, resume_block)) | |
363 | }, | |
364 | bb, | |
365 | ), | |
9e0c209e | 366 | LookupResult::Parent(..) => { |
dfeec247 XL |
367 | span_bug!( |
368 | terminator.source_info.span, | |
369 | "drop of untracked value {:?}", | |
370 | bb | |
371 | ); | |
9e0c209e SL |
372 | } |
373 | } | |
3157f602 | 374 | } |
f035d41b | 375 | TerminatorKind::DropAndReplace { place, ref value, target, unwind } => { |
3157f602 XL |
376 | assert!(!data.is_cleanup); |
377 | ||
f035d41b | 378 | self.elaborate_replace(loc, place, value, target, unwind); |
3157f602 | 379 | } |
dfeec247 | 380 | _ => continue, |
3157f602 XL |
381 | } |
382 | } | |
383 | } | |
384 | ||
385 | /// Elaborate a MIR `replace` terminator. This instruction | |
94b46f34 | 386 | /// is not directly handled by codegen, and therefore |
3157f602 XL |
387 | /// must be desugared. |
388 | /// | |
389 | /// The desugaring drops the location if needed, and then writes | |
390 | /// the value (including setting the drop flag) over it in *both* arms. | |
391 | /// | |
ff7c6d11 | 392 | /// The `replace` terminator can also be called on places that |
3157f602 XL |
393 | /// are not tracked by elaboration (for example, |
394 | /// `replace x[i] <- tmp0`). The borrow checker requires that | |
395 | /// these locations are initialized before the assignment, | |
396 | /// so we just generate an unconditional drop. | |
397 | fn elaborate_replace( | |
398 | &mut self, | |
399 | loc: Location, | |
f035d41b | 400 | place: Place<'tcx>, |
3157f602 XL |
401 | value: &Operand<'tcx>, |
402 | target: BasicBlock, | |
dfeec247 XL |
403 | unwind: Option<BasicBlock>, |
404 | ) { | |
3157f602 | 405 | let bb = loc.block; |
dc9dc135 | 406 | let data = &self.body[bb]; |
3157f602 | 407 | let terminator = data.terminator(); |
7cac9316 | 408 | assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported"); |
3157f602 XL |
409 | |
410 | let assign = Statement { | |
94222f64 | 411 | kind: StatementKind::Assign(Box::new((place, Rvalue::Use(value.clone())))), |
dfeec247 | 412 | source_info: terminator.source_info, |
3157f602 XL |
413 | }; |
414 | ||
0bf4aa26 | 415 | let unwind = unwind.unwrap_or_else(|| self.patch.resume_block()); |
3157f602 XL |
416 | let unwind = self.patch.new_block(BasicBlockData { |
417 | statements: vec![assign.clone()], | |
418 | terminator: Some(Terminator { | |
419 | kind: TerminatorKind::Goto { target: unwind }, | |
420 | ..*terminator | |
421 | }), | |
dfeec247 | 422 | is_cleanup: true, |
3157f602 XL |
423 | }); |
424 | ||
425 | let target = self.patch.new_block(BasicBlockData { | |
426 | statements: vec![assign], | |
dfeec247 | 427 | terminator: Some(Terminator { kind: TerminatorKind::Goto { target }, ..*terminator }), |
7cac9316 | 428 | is_cleanup: false, |
3157f602 XL |
429 | }); |
430 | ||
f035d41b | 431 | match self.move_data().rev_lookup.find(place.as_ref()) { |
9e0c209e SL |
432 | LookupResult::Exact(path) => { |
433 | debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path); | |
74b04a01 | 434 | self.init_data.seek_before(loc); |
cc61c64b | 435 | elaborate_drop( |
74b04a01 | 436 | &mut Elaborator { ctxt: self }, |
cc61c64b | 437 | terminator.source_info, |
f035d41b | 438 | place, |
cc61c64b XL |
439 | path, |
440 | target, | |
7cac9316 | 441 | Unwind::To(unwind), |
dfeec247 XL |
442 | bb, |
443 | ); | |
dc9dc135 | 444 | on_all_children_bits(self.tcx, self.body, self.move_data(), path, |child| { |
dfeec247 XL |
445 | self.set_drop_flag( |
446 | Location { block: target, statement_index: 0 }, | |
447 | child, | |
448 | DropFlagState::Present, | |
449 | ); | |
450 | self.set_drop_flag( | |
451 | Location { block: unwind, statement_index: 0 }, | |
452 | child, | |
453 | DropFlagState::Present, | |
454 | ); | |
9e0c209e SL |
455 | }); |
456 | } | |
457 | LookupResult::Parent(parent) => { | |
458 | // drop and replace behind a pointer/array/whatever. The location | |
459 | // must be initialized. | |
460 | debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent); | |
dfeec247 XL |
461 | self.patch.patch_terminator( |
462 | bb, | |
f035d41b | 463 | TerminatorKind::Drop { place, target, unwind: Some(unwind) }, |
dfeec247 | 464 | ); |
9e0c209e | 465 | } |
3157f602 XL |
466 | } |
467 | } | |
468 | ||
3157f602 | 469 | fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> { |
cc61c64b | 470 | Rvalue::Use(Operand::Constant(Box::new(Constant { |
3b2f2976 | 471 | span, |
b7449926 | 472 | user_ty: None, |
6a06907d | 473 | literal: ty::Const::from_bool(self.tcx, val).into(), |
cc61c64b | 474 | }))) |
3157f602 XL |
475 | } |
476 | ||
477 | fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) { | |
478 | if let Some(&flag) = self.drop_flags.get(&path) { | |
dc9dc135 | 479 | let span = self.patch.source_info_for_location(self.body, loc).span; |
3157f602 | 480 | let val = self.constant_bool(span, val.value()); |
dc9dc135 | 481 | self.patch.add_assign(loc, Place::from(flag), val); |
3157f602 XL |
482 | } |
483 | } | |
484 | ||
485 | fn drop_flags_on_init(&mut self) { | |
83c7162d | 486 | let loc = Location::START; |
dc9dc135 | 487 | let span = self.patch.source_info_for_location(self.body, loc).span; |
3157f602 XL |
488 | let false_ = self.constant_bool(span, false); |
489 | for flag in self.drop_flags.values() { | |
dc9dc135 | 490 | self.patch.add_assign(loc, Place::from(*flag), false_.clone()); |
3157f602 XL |
491 | } |
492 | } | |
493 | ||
494 | fn drop_flags_for_fn_rets(&mut self) { | |
dc9dc135 | 495 | for (bb, data) in self.body.basic_blocks().iter_enumerated() { |
3157f602 | 496 | if let TerminatorKind::Call { |
dfeec247 XL |
497 | destination: Some((ref place, tgt)), |
498 | cleanup: Some(_), | |
499 | .. | |
500 | } = data.terminator().kind | |
501 | { | |
3157f602 XL |
502 | assert!(!self.patch.is_patched(bb)); |
503 | ||
9e0c209e | 504 | let loc = Location { block: tgt, statement_index: 0 }; |
416331ca | 505 | let path = self.move_data().rev_lookup.find(place.as_ref()); |
dfeec247 XL |
506 | on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| { |
507 | self.set_drop_flag(loc, child, DropFlagState::Present) | |
508 | }); | |
3157f602 XL |
509 | } |
510 | } | |
511 | } | |
512 | ||
513 | fn drop_flags_for_args(&mut self) { | |
83c7162d | 514 | let loc = Location::START; |
c295e0f8 XL |
515 | rustc_mir_dataflow::drop_flag_effects_for_function_entry( |
516 | self.tcx, | |
517 | self.body, | |
518 | self.env, | |
519 | |path, ds| { | |
520 | self.set_drop_flag(loc, path, ds); | |
521 | }, | |
522 | ) | |
3157f602 XL |
523 | } |
524 | ||
525 | fn drop_flags_for_locs(&mut self) { | |
526 | // We intentionally iterate only over the *old* basic blocks. | |
527 | // | |
528 | // Basic blocks created by drop elaboration update their | |
529 | // drop flags by themselves, to avoid the drop flags being | |
530 | // clobbered before they are read. | |
531 | ||
dc9dc135 | 532 | for (bb, data) in self.body.basic_blocks().iter_enumerated() { |
3157f602 | 533 | debug!("drop_flags_for_locs({:?})", data); |
dfeec247 | 534 | for i in 0..(data.statements.len() + 1) { |
3157f602 XL |
535 | debug!("drop_flag_for_locs: stmt {}", i); |
536 | let mut allow_initializations = true; | |
537 | if i == data.statements.len() { | |
538 | match data.terminator().kind { | |
539 | TerminatorKind::Drop { .. } => { | |
540 | // drop elaboration should handle that by itself | |
dfeec247 | 541 | continue; |
3157f602 XL |
542 | } |
543 | TerminatorKind::DropAndReplace { .. } => { | |
544 | // this contains the move of the source and | |
545 | // the initialization of the destination. We | |
546 | // only want the former - the latter is handled | |
547 | // by the elaboration code and must be done | |
548 | // *after* the destination is dropped. | |
549 | assert!(self.patch.is_patched(bb)); | |
550 | allow_initializations = false; | |
551 | } | |
041b39d2 XL |
552 | TerminatorKind::Resume => { |
553 | // It is possible for `Resume` to be patched | |
554 | // (in particular it can be patched to be replaced with | |
555 | // a Goto; see `MirPatch::new`). | |
556 | } | |
3157f602 XL |
557 | _ => { |
558 | assert!(!self.patch.is_patched(bb)); | |
559 | } | |
560 | } | |
561 | } | |
9e0c209e | 562 | let loc = Location { block: bb, statement_index: i }; |
c295e0f8 | 563 | rustc_mir_dataflow::drop_flag_effects_for_location( |
dfeec247 XL |
564 | self.tcx, |
565 | self.body, | |
566 | self.env, | |
567 | loc, | |
568 | |path, ds| { | |
3157f602 XL |
569 | if ds == DropFlagState::Absent || allow_initializations { |
570 | self.set_drop_flag(loc, path, ds) | |
571 | } | |
dfeec247 | 572 | }, |
3157f602 XL |
573 | ) |
574 | } | |
575 | ||
576 | // There may be a critical edge after this call, | |
577 | // so mark the return as initialized *before* the | |
578 | // call. | |
579 | if let TerminatorKind::Call { | |
ff7c6d11 | 580 | destination: Some((ref place, _)), cleanup: None, .. |
dfeec247 XL |
581 | } = data.terminator().kind |
582 | { | |
3157f602 XL |
583 | assert!(!self.patch.is_patched(bb)); |
584 | ||
9e0c209e | 585 | let loc = Location { block: bb, statement_index: data.statements.len() }; |
416331ca | 586 | let path = self.move_data().rev_lookup.find(place.as_ref()); |
dfeec247 XL |
587 | on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| { |
588 | self.set_drop_flag(loc, child, DropFlagState::Present) | |
589 | }); | |
3157f602 XL |
590 | } |
591 | } | |
592 | } | |
3157f602 | 593 | } |