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