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