]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/transform/elaborate_drops.rs
Auto merge of #46393 - kennytm:45861-step-2-3-make-tools-job-not-fail-fast, r=alexcri...
[rust.git] / src / librustc_mir / transform / elaborate_drops.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex, LookupResult};
12 use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
13 use dataflow::{DataflowResults};
14 use dataflow::{on_all_children_bits, on_all_drop_children_bits};
15 use dataflow::{drop_flag_effects_for_location, on_lookup_result_bits};
16 use dataflow::MoveDataParamEnv;
17 use dataflow;
18 use rustc::hir;
19 use rustc::ty::{self, TyCtxt};
20 use rustc::mir::*;
21 use rustc::middle::const_val::ConstVal;
22 use rustc::util::nodemap::FxHashMap;
23 use rustc_data_structures::indexed_set::IdxSetBuf;
24 use rustc_data_structures::indexed_vec::Idx;
25 use transform::{MirPass, MirSource};
26 use util::patch::MirPatch;
27 use util::elaborate_drops::{DropFlagState, Unwind, elaborate_drop};
28 use util::elaborate_drops::{DropElaborator, DropStyle, DropFlagMode};
29 use syntax::ast;
30 use syntax_pos::Span;
31
32 use std::fmt;
33
34 pub struct ElaborateDrops;
35
36 impl MirPass for ElaborateDrops {
37     fn run_pass<'a, 'tcx>(&self,
38                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
39                           src: MirSource,
40                           mir: &mut Mir<'tcx>)
41     {
42         debug!("elaborate_drops({:?} @ {:?})", src, mir.span);
43
44         // Don't run on constant MIR, because trans might not be able to
45         // evaluate the modified MIR.
46         // FIXME(eddyb) Remove check after miri is merged.
47         let id = tcx.hir.as_local_node_id(src.def_id).unwrap();
48         match (tcx.hir.body_owner_kind(id), src.promoted) {
49             (hir::BodyOwnerKind::Fn, None) => {},
50             _ => return
51         }
52         let param_env = tcx.param_env(src.def_id);
53         let move_data = MoveData::gather_moves(mir, tcx).unwrap();
54         let elaborate_patch = {
55             let mir = &*mir;
56             let env = MoveDataParamEnv {
57                 move_data,
58                 param_env,
59             };
60             let dead_unwinds = find_dead_unwinds(tcx, mir, id, &env);
61             let flow_inits =
62                 dataflow::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
63                                       MaybeInitializedLvals::new(tcx, mir, &env),
64                                       |bd, p| &bd.move_data().move_paths[p]);
65             let flow_uninits =
66                 dataflow::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
67                                       MaybeUninitializedLvals::new(tcx, mir, &env),
68                                       |bd, p| &bd.move_data().move_paths[p]);
69
70             ElaborateDropsCtxt {
71                 tcx,
72                 mir,
73                 env: &env,
74                 flow_inits,
75                 flow_uninits,
76                 drop_flags: FxHashMap(),
77                 patch: MirPatch::new(mir),
78             }.elaborate()
79         };
80         elaborate_patch.apply(mir);
81     }
82 }
83
84 /// Return the set of basic blocks whose unwind edges are known
85 /// to not be reachable, because they are `drop` terminators
86 /// that can't drop anything.
87 fn find_dead_unwinds<'a, 'tcx>(
88     tcx: TyCtxt<'a, 'tcx, 'tcx>,
89     mir: &Mir<'tcx>,
90     id: ast::NodeId,
91     env: &MoveDataParamEnv<'tcx, 'tcx>)
92     -> IdxSetBuf<BasicBlock>
93 {
94     debug!("find_dead_unwinds({:?})", mir.span);
95     // We only need to do this pass once, because unwind edges can only
96     // reach cleanup blocks, which can't have unwind edges themselves.
97     let mut dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
98     let flow_inits =
99         dataflow::do_dataflow(tcx, mir, id, &[], &dead_unwinds,
100                            MaybeInitializedLvals::new(tcx, mir, &env),
101                            |bd, p| &bd.move_data().move_paths[p]);
102     for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
103         let location = match bb_data.terminator().kind {
104             TerminatorKind::Drop { ref location, unwind: Some(_), .. } |
105             TerminatorKind::DropAndReplace { ref location, unwind: Some(_), .. } => location,
106             _ => continue,
107         };
108
109         let mut init_data = InitializationData {
110             live: flow_inits.sets().on_entry_set_for(bb.index()).to_owned(),
111             dead: IdxSetBuf::new_empty(env.move_data.move_paths.len()),
112         };
113         debug!("find_dead_unwinds @ {:?}: {:?}; init_data={:?}",
114                bb, bb_data, init_data.live);
115         for stmt in 0..bb_data.statements.len() {
116             let loc = Location { block: bb, statement_index: stmt };
117             init_data.apply_location(tcx, mir, env, loc);
118         }
119
120         let path = match env.move_data.rev_lookup.find(location) {
121             LookupResult::Exact(e) => e,
122             LookupResult::Parent(..) => {
123                 debug!("find_dead_unwinds: has parent; skipping");
124                 continue
125             }
126         };
127
128         debug!("find_dead_unwinds @ {:?}: path({:?})={:?}", bb, location, path);
129
130         let mut maybe_live = false;
131         on_all_drop_children_bits(tcx, mir, &env, path, |child| {
132             let (child_maybe_live, _) = init_data.state(child);
133             maybe_live |= child_maybe_live;
134         });
135
136         debug!("find_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live);
137         if !maybe_live {
138             dead_unwinds.add(&bb);
139         }
140     }
141
142     dead_unwinds
143 }
144
145 struct InitializationData {
146     live: IdxSetBuf<MovePathIndex>,
147     dead: IdxSetBuf<MovePathIndex>
148 }
149
150 impl InitializationData {
151     fn apply_location<'a,'tcx>(&mut self,
152                                tcx: TyCtxt<'a, 'tcx, 'tcx>,
153                                mir: &Mir<'tcx>,
154                                env: &MoveDataParamEnv<'tcx, 'tcx>,
155                                loc: Location)
156     {
157         drop_flag_effects_for_location(tcx, mir, env, loc, |path, df| {
158             debug!("at location {:?}: setting {:?} to {:?}",
159                    loc, path, df);
160             match df {
161                 DropFlagState::Present => {
162                     self.live.add(&path);
163                     self.dead.remove(&path);
164                 }
165                 DropFlagState::Absent => {
166                     self.dead.add(&path);
167                     self.live.remove(&path);
168                 }
169             }
170         });
171     }
172
173     fn state(&self, path: MovePathIndex) -> (bool, bool) {
174         (self.live.contains(&path), self.dead.contains(&path))
175     }
176 }
177
178 struct Elaborator<'a, 'b: 'a, 'tcx: 'b> {
179     init_data: &'a InitializationData,
180     ctxt: &'a mut ElaborateDropsCtxt<'b, 'tcx>,
181 }
182
183 impl<'a, 'b, 'tcx> fmt::Debug for Elaborator<'a, 'b, 'tcx> {
184     fn fmt(&self, _f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
185         Ok(())
186     }
187 }
188
189 impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
190     type Path = MovePathIndex;
191
192     fn patch(&mut self) -> &mut MirPatch<'tcx> {
193         &mut self.ctxt.patch
194     }
195
196     fn mir(&self) -> &'a Mir<'tcx> {
197         self.ctxt.mir
198     }
199
200     fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
201         self.ctxt.tcx
202     }
203
204     fn param_env(&self) -> ty::ParamEnv<'tcx> {
205         self.ctxt.param_env()
206     }
207
208     fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle {
209         let ((maybe_live, maybe_dead), multipart) = match mode {
210             DropFlagMode::Shallow => (self.init_data.state(path), false),
211             DropFlagMode::Deep => {
212                 let mut some_live = false;
213                 let mut some_dead = false;
214                 let mut children_count = 0;
215                 on_all_drop_children_bits(
216                     self.tcx(), self.mir(), self.ctxt.env, path, |child| {
217                         let (live, dead) = self.init_data.state(child);
218                         debug!("elaborate_drop: state({:?}) = {:?}",
219                                child, (live, dead));
220                         some_live |= live;
221                         some_dead |= dead;
222                         children_count += 1;
223                     });
224                 ((some_live, some_dead), children_count != 1)
225             }
226         };
227         match (maybe_live, maybe_dead, multipart) {
228             (false, _, _) => DropStyle::Dead,
229             (true, false, _) => DropStyle::Static,
230             (true, true, false) => DropStyle::Conditional,
231             (true, true, true) => DropStyle::Open,
232         }
233     }
234
235     fn clear_drop_flag(&mut self, loc: Location, path: Self::Path, mode: DropFlagMode) {
236         match mode {
237             DropFlagMode::Shallow => {
238                 self.ctxt.set_drop_flag(loc, path, DropFlagState::Absent);
239             }
240             DropFlagMode::Deep => {
241                 on_all_children_bits(
242                     self.tcx(), self.mir(), self.ctxt.move_data(), path,
243                     |child| self.ctxt.set_drop_flag(loc, child, DropFlagState::Absent)
244                  );
245             }
246         }
247     }
248
249     fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> {
250         dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
251             match p {
252                 &Projection {
253                     elem: ProjectionElem::Field(idx, _), ..
254                 } => idx == field,
255                 _ => false
256             }
257         })
258     }
259
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         })
272     }
273
274     fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
275         dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
276             match p {
277                 &Projection { elem: ProjectionElem::Deref, .. } => true,
278                 _ => false
279             }
280         })
281     }
282
283     fn downcast_subpath(&self, path: Self::Path, variant: usize) -> Option<Self::Path> {
284         dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
285             match p {
286                 &Projection {
287                     elem: ProjectionElem::Downcast(_, idx), ..
288                 } => idx == variant,
289                 _ => false
290             }
291         })
292     }
293
294     fn get_drop_flag(&mut self, path: Self::Path) -> Option<Operand<'tcx>> {
295         self.ctxt.drop_flag(path).map(Operand::Copy)
296     }
297 }
298
299 struct ElaborateDropsCtxt<'a, 'tcx: 'a> {
300     tcx: TyCtxt<'a, 'tcx, 'tcx>,
301     mir: &'a Mir<'tcx>,
302     env: &'a MoveDataParamEnv<'tcx, 'tcx>,
303     flow_inits: DataflowResults<MaybeInitializedLvals<'a, 'tcx, 'tcx>>,
304     flow_uninits:  DataflowResults<MaybeUninitializedLvals<'a, 'tcx, 'tcx>>,
305     drop_flags: FxHashMap<MovePathIndex, Local>,
306     patch: MirPatch<'tcx>,
307 }
308
309 impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
310     fn move_data(&self) -> &'b MoveData<'tcx> { &self.env.move_data }
311
312     fn param_env(&self) -> ty::ParamEnv<'tcx> {
313         self.env.param_env
314     }
315
316     fn initialization_data_at(&self, loc: Location) -> InitializationData {
317         let mut data = InitializationData {
318             live: self.flow_inits.sets().on_entry_set_for(loc.block.index())
319                 .to_owned(),
320             dead: self.flow_uninits.sets().on_entry_set_for(loc.block.index())
321                 .to_owned(),
322         };
323         for stmt in 0..loc.statement_index {
324             data.apply_location(self.tcx, self.mir, self.env,
325                                 Location { block: loc.block, statement_index: stmt });
326         }
327         data
328     }
329
330     fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) {
331         let tcx = self.tcx;
332         let patch = &mut self.patch;
333         debug!("create_drop_flag({:?})", self.mir.span);
334         self.drop_flags.entry(index).or_insert_with(|| {
335             patch.new_internal(tcx.types.bool, span)
336         });
337     }
338
339     fn drop_flag(&mut self, index: MovePathIndex) -> Option<Place<'tcx>> {
340         self.drop_flags.get(&index).map(|t| Place::Local(*t))
341     }
342
343     /// create a patch that elaborates all drops in the input
344     /// MIR.
345     fn elaborate(mut self) -> MirPatch<'tcx>
346     {
347         self.collect_drop_flags();
348
349         self.elaborate_drops();
350
351         self.drop_flags_on_init();
352         self.drop_flags_for_fn_rets();
353         self.drop_flags_for_args();
354         self.drop_flags_for_locs();
355
356         self.patch
357     }
358
359     fn collect_drop_flags(&mut self)
360     {
361         for (bb, data) in self.mir.basic_blocks().iter_enumerated() {
362             let terminator = data.terminator();
363             let location = match terminator.kind {
364                 TerminatorKind::Drop { ref location, .. } |
365                 TerminatorKind::DropAndReplace { ref location, .. } => location,
366                 _ => continue
367             };
368
369             let init_data = self.initialization_data_at(Location {
370                 block: bb,
371                 statement_index: data.statements.len()
372             });
373
374             let path = self.move_data().rev_lookup.find(location);
375             debug!("collect_drop_flags: {:?}, place {:?} ({:?})",
376                    bb, location, path);
377
378             let path = match path {
379                 LookupResult::Exact(e) => e,
380                 LookupResult::Parent(None) => continue,
381                 LookupResult::Parent(Some(parent)) => {
382                     let (_maybe_live, maybe_dead) = init_data.state(parent);
383                     if maybe_dead {
384                         span_bug!(terminator.source_info.span,
385                                   "drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
386                                   bb, location, path);
387                     }
388                     continue
389                 }
390             };
391
392             on_all_drop_children_bits(self.tcx, self.mir, self.env, path, |child| {
393                 let (maybe_live, maybe_dead) = init_data.state(child);
394                 debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}",
395                        child, location, path, (maybe_live, maybe_dead));
396                 if maybe_live && maybe_dead {
397                     self.create_drop_flag(child, terminator.source_info.span)
398                 }
399             });
400         }
401     }
402
403     fn elaborate_drops(&mut self)
404     {
405         for (bb, data) in self.mir.basic_blocks().iter_enumerated() {
406             let loc = Location { block: bb, statement_index: data.statements.len() };
407             let terminator = data.terminator();
408
409             let resume_block = self.patch.resume_block();
410             match terminator.kind {
411                 TerminatorKind::Drop { ref location, target, unwind } => {
412                     let init_data = self.initialization_data_at(loc);
413                     match self.move_data().rev_lookup.find(location) {
414                         LookupResult::Exact(path) => {
415                             elaborate_drop(
416                                 &mut Elaborator {
417                                     init_data: &init_data,
418                                     ctxt: self
419                                 },
420                                 terminator.source_info,
421                                 location,
422                                 path,
423                                 target,
424                                 if data.is_cleanup {
425                                     Unwind::InCleanup
426                                 } else {
427                                     Unwind::To(Option::unwrap_or(unwind, resume_block))
428                                 },
429                                 bb)
430                         }
431                         LookupResult::Parent(..) => {
432                             span_bug!(terminator.source_info.span,
433                                       "drop of untracked value {:?}", bb);
434                         }
435                     }
436                 }
437                 TerminatorKind::DropAndReplace { ref location, ref value,
438                                                  target, unwind } =>
439                 {
440                     assert!(!data.is_cleanup);
441
442                     self.elaborate_replace(
443                         loc,
444                         location, value,
445                         target, unwind
446                     );
447                 }
448                 _ => continue
449             }
450         }
451     }
452
453     /// Elaborate a MIR `replace` terminator. This instruction
454     /// is not directly handled by translation, and therefore
455     /// must be desugared.
456     ///
457     /// The desugaring drops the location if needed, and then writes
458     /// the value (including setting the drop flag) over it in *both* arms.
459     ///
460     /// The `replace` terminator can also be called on places that
461     /// are not tracked by elaboration (for example,
462     /// `replace x[i] <- tmp0`). The borrow checker requires that
463     /// these locations are initialized before the assignment,
464     /// so we just generate an unconditional drop.
465     fn elaborate_replace(
466         &mut self,
467         loc: Location,
468         location: &Place<'tcx>,
469         value: &Operand<'tcx>,
470         target: BasicBlock,
471         unwind: Option<BasicBlock>)
472     {
473         let bb = loc.block;
474         let data = &self.mir[bb];
475         let terminator = data.terminator();
476         assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
477
478         let assign = Statement {
479             kind: StatementKind::Assign(location.clone(), Rvalue::Use(value.clone())),
480             source_info: terminator.source_info
481         };
482
483         let unwind = unwind.unwrap_or(self.patch.resume_block());
484         let unwind = self.patch.new_block(BasicBlockData {
485             statements: vec![assign.clone()],
486             terminator: Some(Terminator {
487                 kind: TerminatorKind::Goto { target: unwind },
488                 ..*terminator
489             }),
490             is_cleanup: true
491         });
492
493         let target = self.patch.new_block(BasicBlockData {
494             statements: vec![assign],
495             terminator: Some(Terminator {
496                 kind: TerminatorKind::Goto { target: target },
497                 ..*terminator
498             }),
499             is_cleanup: false,
500         });
501
502         match self.move_data().rev_lookup.find(location) {
503             LookupResult::Exact(path) => {
504                 debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path);
505                 let init_data = self.initialization_data_at(loc);
506
507                 elaborate_drop(
508                     &mut Elaborator {
509                         init_data: &init_data,
510                         ctxt: self
511                     },
512                     terminator.source_info,
513                     location,
514                     path,
515                     target,
516                     Unwind::To(unwind),
517                     bb);
518                 on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| {
519                     self.set_drop_flag(Location { block: target, statement_index: 0 },
520                                        child, DropFlagState::Present);
521                     self.set_drop_flag(Location { block: unwind, statement_index: 0 },
522                                        child, DropFlagState::Present);
523                 });
524             }
525             LookupResult::Parent(parent) => {
526                 // drop and replace behind a pointer/array/whatever. The location
527                 // must be initialized.
528                 debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent);
529                 self.patch.patch_terminator(bb, TerminatorKind::Drop {
530                     location: location.clone(),
531                     target,
532                     unwind: Some(unwind)
533                 });
534             }
535         }
536     }
537
538     fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> {
539         Rvalue::Use(Operand::Constant(Box::new(Constant {
540             span,
541             ty: self.tcx.types.bool,
542             literal: Literal::Value {
543                 value: self.tcx.mk_const(ty::Const {
544                     val: ConstVal::Bool(val),
545                     ty: self.tcx.types.bool
546                 })
547             }
548         })))
549     }
550
551     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);
556         }
557     }
558
559     fn drop_flags_on_init(&mut self) {
560         let loc = Location { block: START_BLOCK, statement_index: 0 };
561         let span = self.patch.source_info_for_location(self.mir, loc).span;
562         let false_ = self.constant_bool(span, false);
563         for flag in self.drop_flags.values() {
564             self.patch.add_assign(loc, Place::Local(*flag), false_.clone());
565         }
566     }
567
568     fn drop_flags_for_fn_rets(&mut self) {
569         for (bb, data) in self.mir.basic_blocks().iter_enumerated() {
570             if let TerminatorKind::Call {
571                 destination: Some((ref place, tgt)), cleanup: Some(_), ..
572             } = data.terminator().kind {
573                 assert!(!self.patch.is_patched(bb));
574
575                 let loc = Location { block: tgt, statement_index: 0 };
576                 let path = self.move_data().rev_lookup.find(place);
577                 on_lookup_result_bits(
578                     self.tcx, self.mir, self.move_data(), path,
579                     |child| self.set_drop_flag(loc, child, DropFlagState::Present)
580                 );
581             }
582         }
583     }
584
585     fn drop_flags_for_args(&mut self) {
586         let loc = Location { block: START_BLOCK, statement_index: 0 };
587         dataflow::drop_flag_effects_for_function_entry(
588             self.tcx, self.mir, self.env, |path, ds| {
589                 self.set_drop_flag(loc, path, ds);
590             }
591         )
592     }
593
594     fn drop_flags_for_locs(&mut self) {
595         // We intentionally iterate only over the *old* basic blocks.
596         //
597         // Basic blocks created by drop elaboration update their
598         // drop flags by themselves, to avoid the drop flags being
599         // clobbered before they are read.
600
601         for (bb, data) in self.mir.basic_blocks().iter_enumerated() {
602             debug!("drop_flags_for_locs({:?})", data);
603             for i in 0..(data.statements.len()+1) {
604                 debug!("drop_flag_for_locs: stmt {}", i);
605                 let mut allow_initializations = true;
606                 if i == data.statements.len() {
607                     match data.terminator().kind {
608                         TerminatorKind::Drop { .. } => {
609                             // drop elaboration should handle that by itself
610                             continue
611                         }
612                         TerminatorKind::DropAndReplace { .. } => {
613                             // this contains the move of the source and
614                             // the initialization of the destination. We
615                             // only want the former - the latter is handled
616                             // by the elaboration code and must be done
617                             // *after* the destination is dropped.
618                             assert!(self.patch.is_patched(bb));
619                             allow_initializations = false;
620                         }
621                         TerminatorKind::Resume => {
622                             // It is possible for `Resume` to be patched
623                             // (in particular it can be patched to be replaced with
624                             // a Goto; see `MirPatch::new`).
625                         }
626                         _ => {
627                             assert!(!self.patch.is_patched(bb));
628                         }
629                     }
630                 }
631                 let loc = Location { block: bb, statement_index: i };
632                 dataflow::drop_flag_effects_for_location(
633                     self.tcx, self.mir, self.env, loc, |path, ds| {
634                         if ds == DropFlagState::Absent || allow_initializations {
635                             self.set_drop_flag(loc, path, ds)
636                         }
637                     }
638                 )
639             }
640
641             // There may be a critical edge after this call,
642             // so mark the return as initialized *before* the
643             // call.
644             if let TerminatorKind::Call {
645                 destination: Some((ref place, _)), cleanup: None, ..
646             } = data.terminator().kind {
647                 assert!(!self.patch.is_patched(bb));
648
649                 let loc = Location { block: bb, statement_index: data.statements.len() };
650                 let path = self.move_data().rev_lookup.find(place);
651                 on_lookup_result_bits(
652                     self.tcx, self.mir, self.move_data(), path,
653                     |child| self.set_drop_flag(loc, child, DropFlagState::Present)
654                 );
655             }
656         }
657     }
658 }