]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_mir_build/src/build/scope.rs
Implement lowering of if-let guards to MIR
[rust.git] / compiler / rustc_mir_build / src / build / scope.rs
1 /*!
2 Managing the scope stack. The scopes are tied to lexical scopes, so as
3 we descend the THIR, we push a scope on the stack, build its
4 contents, and then pop it off. Every scope is named by a
5 `region::Scope`.
6
7 ### SEME Regions
8
9 When pushing a new [Scope], we record the current point in the graph (a
10 basic block); this marks the entry to the scope. We then generate more
11 stuff in the control-flow graph. Whenever the scope is exited, either
12 via a `break` or `return` or just by fallthrough, that marks an exit
13 from the scope. Each lexical scope thus corresponds to a single-entry,
14 multiple-exit (SEME) region in the control-flow graph.
15
16 For now, we record the `region::Scope` to each SEME region for later reference
17 (see caveat in next paragraph). This is because destruction scopes are tied to
18 them. This may change in the future so that MIR lowering determines its own
19 destruction scopes.
20
21 ### Not so SEME Regions
22
23 In the course of building matches, it sometimes happens that certain code
24 (namely guards) gets executed multiple times. This means that the scope lexical
25 scope may in fact correspond to multiple, disjoint SEME regions. So in fact our
26 mapping is from one scope to a vector of SEME regions. Since the SEME regions
27 are disjoint, the mapping is still one-to-one for the set of SEME regions that
28 we're currently in.
29
30 Also in matches, the scopes assigned to arms are not always even SEME regions!
31 Each arm has a single region with one entry for each pattern. We manually
32 manipulate the scheduled drops in this scope to avoid dropping things multiple
33 times.
34
35 ### Drops
36
37 The primary purpose for scopes is to insert drops: while building
38 the contents, we also accumulate places that need to be dropped upon
39 exit from each scope. This is done by calling `schedule_drop`. Once a
40 drop is scheduled, whenever we branch out we will insert drops of all
41 those places onto the outgoing edge. Note that we don't know the full
42 set of scheduled drops up front, and so whenever we exit from the
43 scope we only drop the values scheduled thus far. For example, consider
44 the scope S corresponding to this loop:
45
46 ```
47 # let cond = true;
48 loop {
49     let x = ..;
50     if cond { break; }
51     let y = ..;
52 }
53 ```
54
55 When processing the `let x`, we will add one drop to the scope for
56 `x`.  The break will then insert a drop for `x`. When we process `let
57 y`, we will add another drop (in fact, to a subscope, but let's ignore
58 that for now); any later drops would also drop `y`.
59
60 ### Early exit
61
62 There are numerous "normal" ways to early exit a scope: `break`,
63 `continue`, `return` (panics are handled separately). Whenever an
64 early exit occurs, the method `break_scope` is called. It is given the
65 current point in execution where the early exit occurs, as well as the
66 scope you want to branch to (note that all early exits from to some
67 other enclosing scope). `break_scope` will record the set of drops currently
68 scheduled in a [DropTree]. Later, before `in_breakable_scope` exits, the drops
69 will be added to the CFG.
70
71 Panics are handled in a similar fashion, except that the drops are added to the
72 MIR once the rest of the function has finished being lowered. If a terminator
73 can panic, call `diverge_from(block)` with the block containing the terminator
74 `block`.
75
76 ### Breakable scopes
77
78 In addition to the normal scope stack, we track a loop scope stack
79 that contains only loops and breakable blocks. It tracks where a `break`,
80 `continue` or `return` should go to.
81
82 */
83
84 use crate::build::matches::{ArmHasGuard, Candidate};
85 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
86 use crate::thir::{Arm, Expr, ExprRef, LintLevel};
87 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
88 use rustc_hir as hir;
89 use rustc_index::vec::IndexVec;
90 use rustc_middle::middle::region;
91 use rustc_middle::mir::*;
92 use rustc_span::{Span, DUMMY_SP};
93
94 #[derive(Debug)]
95 pub struct Scopes<'tcx> {
96     scopes: Vec<Scope>,
97     /// The current set of breakable scopes. See module comment for more details.
98     breakable_scopes: Vec<BreakableScope<'tcx>>,
99
100     /// Drops that need to be done on unwind paths. See the comment on
101     /// [DropTree] for more details.
102     unwind_drops: DropTree,
103
104     /// Drops that need to be done on paths to the `GeneratorDrop` terminator.
105     generator_drops: DropTree,
106 }
107
108 #[derive(Debug)]
109 struct Scope {
110     /// The source scope this scope was created in.
111     source_scope: SourceScope,
112
113     /// the region span of this scope within source code.
114     region_scope: region::Scope,
115
116     /// the span of that region_scope
117     region_scope_span: Span,
118
119     /// set of places to drop when exiting this scope. This starts
120     /// out empty but grows as variables are declared during the
121     /// building process. This is a stack, so we always drop from the
122     /// end of the vector (top of the stack) first.
123     drops: Vec<DropData>,
124
125     /// The drop index that will drop everything in and below this scope on an
126     /// unwind path.
127     cached_unwind_block: Option<DropIdx>,
128
129     /// The drop index that will drop everything in and below this scope on a
130     /// generator drop path.
131     cached_generator_drop_block: Option<DropIdx>,
132 }
133
134 #[derive(Clone, Copy, Debug)]
135 struct DropData {
136     /// The `Span` where drop obligation was incurred (typically where place was
137     /// declared)
138     source_info: SourceInfo,
139
140     /// local to drop
141     local: Local,
142
143     /// Whether this is a value Drop or a StorageDead.
144     kind: DropKind,
145 }
146
147 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
148 pub(crate) enum DropKind {
149     Value,
150     Storage,
151 }
152
153 #[derive(Debug)]
154 struct BreakableScope<'tcx> {
155     /// Region scope of the loop
156     region_scope: region::Scope,
157     /// The destination of the loop/block expression itself (i.e., where to put
158     /// the result of a `break` or `return` expression)
159     break_destination: Place<'tcx>,
160     /// The scope that the destination should have its drop scheduled in.
161     destination_scope: Option<region::Scope>,
162     /// Drops that happen on the `break`/`return` path.
163     break_drops: DropTree,
164     /// Drops that happen on the `continue` path.
165     continue_drops: Option<DropTree>,
166 }
167
168 /// The target of an expression that breaks out of a scope
169 #[derive(Clone, Copy, Debug)]
170 crate enum BreakableTarget {
171     Continue(region::Scope),
172     Break(region::Scope),
173     Return,
174 }
175
176 rustc_index::newtype_index! {
177     struct DropIdx { .. }
178 }
179
180 const ROOT_NODE: DropIdx = DropIdx::from_u32(0);
181
182 /// A tree of drops that we have deferred lowering. It's used for:
183 ///
184 /// * Drops on unwind paths
185 /// * Drops on generator drop paths (when a suspended generator is dropped)
186 /// * Drops on return and loop exit paths
187 ///
188 /// Once no more nodes could be added to the tree, we lower it to MIR in one go
189 /// in `build_mir`.
190 #[derive(Debug)]
191 struct DropTree {
192     /// Drops in the tree.
193     drops: IndexVec<DropIdx, (DropData, DropIdx)>,
194     /// Map for finding the inverse of the `next_drop` relation:
195     ///
196     /// `previous_drops[(drops[i].1, drops[i].0.local, drops[i].0.kind)] == i`
197     previous_drops: FxHashMap<(DropIdx, Local, DropKind), DropIdx>,
198     /// Edges into the `DropTree` that need to be added once it's lowered.
199     entry_points: Vec<(DropIdx, BasicBlock)>,
200 }
201
202 impl Scope {
203     /// Whether there's anything to do for the cleanup path, that is,
204     /// when unwinding through this scope. This includes destructors,
205     /// but not StorageDead statements, which don't get emitted at all
206     /// for unwinding, for several reasons:
207     ///  * clang doesn't emit llvm.lifetime.end for C++ unwinding
208     ///  * LLVM's memory dependency analysis can't handle it atm
209     ///  * polluting the cleanup MIR with StorageDead creates
210     ///    landing pads even though there's no actual destructors
211     ///  * freeing up stack space has no effect during unwinding
212     /// Note that for generators we do emit StorageDeads, for the
213     /// use of optimizations in the MIR generator transform.
214     fn needs_cleanup(&self) -> bool {
215         self.drops.iter().any(|drop| match drop.kind {
216             DropKind::Value => true,
217             DropKind::Storage => false,
218         })
219     }
220
221     fn invalidate_cache(&mut self) {
222         self.cached_unwind_block = None;
223         self.cached_generator_drop_block = None;
224     }
225 }
226
227 /// A trait that determined how [DropTree] creates its blocks and
228 /// links to any entry nodes.
229 trait DropTreeBuilder<'tcx> {
230     /// Create a new block for the tree. This should call either
231     /// `cfg.start_new_block()` or `cfg.start_new_cleanup_block()`.
232     fn make_block(cfg: &mut CFG<'tcx>) -> BasicBlock;
233
234     /// Links a block outside the drop tree, `from`, to the block `to` inside
235     /// the drop tree.
236     fn add_entry(cfg: &mut CFG<'tcx>, from: BasicBlock, to: BasicBlock);
237 }
238
239 impl DropTree {
240     fn new() -> Self {
241         // The root node of the tree doesn't represent a drop, but instead
242         // represents the block in the tree that should be jumped to once all
243         // of the required drops have been performed.
244         let fake_source_info = SourceInfo::outermost(DUMMY_SP);
245         let fake_data =
246             DropData { source_info: fake_source_info, local: Local::MAX, kind: DropKind::Storage };
247         let drop_idx = DropIdx::MAX;
248         let drops = IndexVec::from_elem_n((fake_data, drop_idx), 1);
249         Self { drops, entry_points: Vec::new(), previous_drops: FxHashMap::default() }
250     }
251
252     fn add_drop(&mut self, drop: DropData, next: DropIdx) -> DropIdx {
253         let drops = &mut self.drops;
254         *self
255             .previous_drops
256             .entry((next, drop.local, drop.kind))
257             .or_insert_with(|| drops.push((drop, next)))
258     }
259
260     fn add_entry(&mut self, from: BasicBlock, to: DropIdx) {
261         debug_assert!(to < self.drops.next_index());
262         self.entry_points.push((to, from));
263     }
264
265     /// Builds the MIR for a given drop tree.
266     ///
267     /// `blocks` should have the same length as `self.drops`, and may have its
268     /// first value set to some already existing block.
269     fn build_mir<'tcx, T: DropTreeBuilder<'tcx>>(
270         &mut self,
271         cfg: &mut CFG<'tcx>,
272         blocks: &mut IndexVec<DropIdx, Option<BasicBlock>>,
273     ) {
274         debug!("DropTree::build_mir(drops = {:#?})", self);
275         assert_eq!(blocks.len(), self.drops.len());
276
277         self.assign_blocks::<T>(cfg, blocks);
278         self.link_blocks(cfg, blocks)
279     }
280
281     /// Assign blocks for all of the drops in the drop tree that need them.
282     fn assign_blocks<'tcx, T: DropTreeBuilder<'tcx>>(
283         &mut self,
284         cfg: &mut CFG<'tcx>,
285         blocks: &mut IndexVec<DropIdx, Option<BasicBlock>>,
286     ) {
287         // StorageDead statements can share blocks with each other and also with
288         // a Drop terminator. We iterate through the drops to find which drops
289         // need their own block.
290         #[derive(Clone, Copy)]
291         enum Block {
292             // This drop is unreachable
293             None,
294             // This drop is only reachable through the `StorageDead` with the
295             // specified index.
296             Shares(DropIdx),
297             // This drop has more than one way of being reached, or it is
298             // branched to from outside the tree, or its predecessor is a
299             // `Value` drop.
300             Own,
301         }
302
303         let mut needs_block = IndexVec::from_elem(Block::None, &self.drops);
304         if blocks[ROOT_NODE].is_some() {
305             // In some cases (such as drops for `continue`) the root node
306             // already has a block. In this case, make sure that we don't
307             // override it.
308             needs_block[ROOT_NODE] = Block::Own;
309         }
310
311         // Sort so that we only need to check the last value.
312         let entry_points = &mut self.entry_points;
313         entry_points.sort();
314
315         for (drop_idx, drop_data) in self.drops.iter_enumerated().rev() {
316             if entry_points.last().map_or(false, |entry_point| entry_point.0 == drop_idx) {
317                 let block = *blocks[drop_idx].get_or_insert_with(|| T::make_block(cfg));
318                 needs_block[drop_idx] = Block::Own;
319                 while entry_points.last().map_or(false, |entry_point| entry_point.0 == drop_idx) {
320                     let entry_block = entry_points.pop().unwrap().1;
321                     T::add_entry(cfg, entry_block, block);
322                 }
323             }
324             match needs_block[drop_idx] {
325                 Block::None => continue,
326                 Block::Own => {
327                     blocks[drop_idx].get_or_insert_with(|| T::make_block(cfg));
328                 }
329                 Block::Shares(pred) => {
330                     blocks[drop_idx] = blocks[pred];
331                 }
332             }
333             if let DropKind::Value = drop_data.0.kind {
334                 needs_block[drop_data.1] = Block::Own;
335             } else if drop_idx != ROOT_NODE {
336                 match &mut needs_block[drop_data.1] {
337                     pred @ Block::None => *pred = Block::Shares(drop_idx),
338                     pred @ Block::Shares(_) => *pred = Block::Own,
339                     Block::Own => (),
340                 }
341             }
342         }
343
344         debug!("assign_blocks: blocks = {:#?}", blocks);
345         assert!(entry_points.is_empty());
346     }
347
348     fn link_blocks<'tcx>(
349         &self,
350         cfg: &mut CFG<'tcx>,
351         blocks: &IndexVec<DropIdx, Option<BasicBlock>>,
352     ) {
353         for (drop_idx, drop_data) in self.drops.iter_enumerated().rev() {
354             let block = if let Some(block) = blocks[drop_idx] {
355                 block
356             } else {
357                 continue;
358             };
359             match drop_data.0.kind {
360                 DropKind::Value => {
361                     let terminator = TerminatorKind::Drop {
362                         target: blocks[drop_data.1].unwrap(),
363                         // The caller will handle this if needed.
364                         unwind: None,
365                         place: drop_data.0.local.into(),
366                     };
367                     cfg.terminate(block, drop_data.0.source_info, terminator);
368                 }
369                 // Root nodes don't correspond to a drop.
370                 DropKind::Storage if drop_idx == ROOT_NODE => {}
371                 DropKind::Storage => {
372                     let stmt = Statement {
373                         source_info: drop_data.0.source_info,
374                         kind: StatementKind::StorageDead(drop_data.0.local),
375                     };
376                     cfg.push(block, stmt);
377                     let target = blocks[drop_data.1].unwrap();
378                     if target != block {
379                         // Diagnostics don't use this `Span` but debuginfo
380                         // might. Since we don't want breakpoints to be placed
381                         // here, especially when this is on an unwind path, we
382                         // use `DUMMY_SP`.
383                         let source_info = SourceInfo { span: DUMMY_SP, ..drop_data.0.source_info };
384                         let terminator = TerminatorKind::Goto { target };
385                         cfg.terminate(block, source_info, terminator);
386                     }
387                 }
388             }
389         }
390     }
391 }
392
393 impl<'tcx> Scopes<'tcx> {
394     pub(crate) fn new() -> Self {
395         Self {
396             scopes: Vec::new(),
397             breakable_scopes: Vec::new(),
398             unwind_drops: DropTree::new(),
399             generator_drops: DropTree::new(),
400         }
401     }
402
403     fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo), vis_scope: SourceScope) {
404         debug!("push_scope({:?})", region_scope);
405         self.scopes.push(Scope {
406             source_scope: vis_scope,
407             region_scope: region_scope.0,
408             region_scope_span: region_scope.1.span,
409             drops: vec![],
410             cached_unwind_block: None,
411             cached_generator_drop_block: None,
412         });
413     }
414
415     fn pop_scope(&mut self, region_scope: (region::Scope, SourceInfo)) -> Scope {
416         let scope = self.scopes.pop().unwrap();
417         assert_eq!(scope.region_scope, region_scope.0);
418         scope
419     }
420
421     fn scope_index(&self, region_scope: region::Scope, span: Span) -> usize {
422         self.scopes
423             .iter()
424             .rposition(|scope| scope.region_scope == region_scope)
425             .unwrap_or_else(|| span_bug!(span, "region_scope {:?} does not enclose", region_scope))
426     }
427
428     /// Returns the topmost active scope, which is known to be alive until
429     /// the next scope expression.
430     fn topmost(&self) -> region::Scope {
431         self.scopes.last().expect("topmost_scope: no scopes present").region_scope
432     }
433 }
434
435 impl<'a, 'tcx> Builder<'a, 'tcx> {
436     // Adding and removing scopes
437     // ==========================
438     //  Start a breakable scope, which tracks where `continue`, `break` and
439     //  `return` should branch to.
440     crate fn in_breakable_scope<F>(
441         &mut self,
442         loop_block: Option<BasicBlock>,
443         break_destination: Place<'tcx>,
444         destination_scope: Option<region::Scope>,
445         span: Span,
446         f: F,
447     ) -> BlockAnd<()>
448     where
449         F: FnOnce(&mut Builder<'a, 'tcx>) -> Option<BlockAnd<()>>,
450     {
451         let region_scope = self.scopes.topmost();
452         let scope = BreakableScope {
453             region_scope,
454             break_destination,
455             destination_scope,
456             break_drops: DropTree::new(),
457             continue_drops: loop_block.map(|_| DropTree::new()),
458         };
459         let continue_block = loop_block.map(|block| (block, self.diverge_cleanup()));
460         self.scopes.breakable_scopes.push(scope);
461         let normal_exit_block = f(self);
462         let breakable_scope = self.scopes.breakable_scopes.pop().unwrap();
463         assert!(breakable_scope.region_scope == region_scope);
464         if let Some(drops) = breakable_scope.continue_drops {
465             self.build_exit_tree(drops, continue_block);
466         }
467         let break_block = self.build_exit_tree(breakable_scope.break_drops, None);
468         match (normal_exit_block, break_block) {
469             (Some(block), None) | (None, Some(block)) => block,
470             (None, None) => self.cfg.start_new_block().unit(),
471             (Some(normal_block), Some(exit_block)) => {
472                 let target = self.cfg.start_new_block();
473                 let source_info = self.source_info(span);
474                 self.cfg.terminate(
475                     unpack!(normal_block),
476                     source_info,
477                     TerminatorKind::Goto { target },
478                 );
479                 self.cfg.terminate(
480                     unpack!(exit_block),
481                     source_info,
482                     TerminatorKind::Goto { target },
483                 );
484                 target.unit()
485             }
486         }
487     }
488
489     crate fn in_opt_scope<F, R>(
490         &mut self,
491         opt_scope: Option<(region::Scope, SourceInfo)>,
492         f: F,
493     ) -> BlockAnd<R>
494     where
495         F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
496     {
497         debug!("in_opt_scope(opt_scope={:?})", opt_scope);
498         if let Some(region_scope) = opt_scope {
499             self.push_scope(region_scope);
500         }
501         let mut block;
502         let rv = unpack!(block = f(self));
503         if let Some(region_scope) = opt_scope {
504             unpack!(block = self.pop_scope(region_scope, block));
505         }
506         debug!("in_scope: exiting opt_scope={:?} block={:?}", opt_scope, block);
507         block.and(rv)
508     }
509
510     /// Convenience wrapper that pushes a scope and then executes `f`
511     /// to build its contents, popping the scope afterwards.
512     crate fn in_scope<F, R>(
513         &mut self,
514         region_scope: (region::Scope, SourceInfo),
515         lint_level: LintLevel,
516         f: F,
517     ) -> BlockAnd<R>
518     where
519         F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>,
520     {
521         debug!("in_scope(region_scope={:?})", region_scope);
522         let source_scope = self.source_scope;
523         let tcx = self.hir.tcx();
524         if let LintLevel::Explicit(current_hir_id) = lint_level {
525             // Use `maybe_lint_level_root_bounded` with `root_lint_level` as a bound
526             // to avoid adding Hir dependences on our parents.
527             // We estimate the true lint roots here to avoid creating a lot of source scopes.
528
529             let parent_root = tcx.maybe_lint_level_root_bounded(
530                 self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root,
531                 self.hir.root_lint_level,
532             );
533             let current_root =
534                 tcx.maybe_lint_level_root_bounded(current_hir_id, self.hir.root_lint_level);
535
536             if parent_root != current_root {
537                 self.source_scope = self.new_source_scope(
538                     region_scope.1.span,
539                     LintLevel::Explicit(current_root),
540                     None,
541                 );
542             }
543         }
544         self.push_scope(region_scope);
545         let mut block;
546         let rv = unpack!(block = f(self));
547         unpack!(block = self.pop_scope(region_scope, block));
548         self.source_scope = source_scope;
549         debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block);
550         block.and(rv)
551     }
552
553     /// Push a scope onto the stack. You can then build code in this
554     /// scope and call `pop_scope` afterwards. Note that these two
555     /// calls must be paired; using `in_scope` as a convenience
556     /// wrapper maybe preferable.
557     crate fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo)) {
558         self.scopes.push_scope(region_scope, self.source_scope);
559     }
560
561     /// Pops a scope, which should have region scope `region_scope`,
562     /// adding any drops onto the end of `block` that are needed.
563     /// This must match 1-to-1 with `push_scope`.
564     crate fn pop_scope(
565         &mut self,
566         region_scope: (region::Scope, SourceInfo),
567         mut block: BasicBlock,
568     ) -> BlockAnd<()> {
569         debug!("pop_scope({:?}, {:?})", region_scope, block);
570
571         block = self.leave_top_scope(block);
572
573         self.scopes.pop_scope(region_scope);
574
575         block.unit()
576     }
577
578     /// Sets up the drops for breaking from `block` to `target`.
579     crate fn break_scope(
580         &mut self,
581         mut block: BasicBlock,
582         value: Option<ExprRef<'tcx>>,
583         target: BreakableTarget,
584         source_info: SourceInfo,
585     ) -> BlockAnd<()> {
586         let span = source_info.span;
587
588         let get_scope_index = |scope: region::Scope| {
589             // find the loop-scope by its `region::Scope`.
590             self.scopes
591                 .breakable_scopes
592                 .iter()
593                 .rposition(|breakable_scope| breakable_scope.region_scope == scope)
594                 .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found"))
595         };
596         let (break_index, destination, dest_scope) = match target {
597             BreakableTarget::Return => {
598                 let scope = &self.scopes.breakable_scopes[0];
599                 if scope.break_destination != Place::return_place() {
600                     span_bug!(span, "`return` in item with no return scope");
601                 }
602                 (0, Some(scope.break_destination), scope.destination_scope)
603             }
604             BreakableTarget::Break(scope) => {
605                 let break_index = get_scope_index(scope);
606                 let scope = &self.scopes.breakable_scopes[break_index];
607                 (break_index, Some(scope.break_destination), scope.destination_scope)
608             }
609             BreakableTarget::Continue(scope) => {
610                 let break_index = get_scope_index(scope);
611                 (break_index, None, None)
612             }
613         };
614
615         if let Some(destination) = destination {
616             if let Some(value) = value {
617                 debug!("stmt_expr Break val block_context.push(SubExpr)");
618                 self.block_context.push(BlockFrame::SubExpr);
619                 unpack!(block = self.into(destination, dest_scope, block, value));
620                 dest_scope
621                     .map(|scope| self.unschedule_drop(scope, destination.as_local().unwrap()));
622                 self.block_context.pop();
623             } else {
624                 self.cfg.push_assign_unit(block, source_info, destination, self.hir.tcx())
625             }
626         } else {
627             assert!(value.is_none(), "`return` and `break` should have a destination");
628         }
629
630         let region_scope = self.scopes.breakable_scopes[break_index].region_scope;
631         let scope_index = self.scopes.scope_index(region_scope, span);
632         let drops = if destination.is_some() {
633             &mut self.scopes.breakable_scopes[break_index].break_drops
634         } else {
635             self.scopes.breakable_scopes[break_index].continue_drops.as_mut().unwrap()
636         };
637         let mut drop_idx = ROOT_NODE;
638         for scope in &self.scopes.scopes[scope_index + 1..] {
639             for drop in &scope.drops {
640                 drop_idx = drops.add_drop(*drop, drop_idx);
641             }
642         }
643         drops.add_entry(block, drop_idx);
644
645         // `build_drop_tree` doesn't have access to our source_info, so we
646         // create a dummy terminator now. `TerminatorKind::Resume` is used
647         // because MIR type checking will panic if it hasn't been overwritten.
648         self.cfg.terminate(block, source_info, TerminatorKind::Resume);
649
650         self.cfg.start_new_block().unit()
651     }
652
653     crate fn exit_top_scope(
654         &mut self,
655         mut block: BasicBlock,
656         target: BasicBlock,
657         source_info: SourceInfo,
658     ) {
659         block = self.leave_top_scope(block);
660         self.cfg.terminate(block, source_info, TerminatorKind::Goto { target });
661     }
662
663     fn leave_top_scope(&mut self, block: BasicBlock) -> BasicBlock {
664         // If we are emitting a `drop` statement, we need to have the cached
665         // diverge cleanup pads ready in case that drop panics.
666         let needs_cleanup = self.scopes.scopes.last().map_or(false, |scope| scope.needs_cleanup());
667         let is_generator = self.generator_kind.is_some();
668         let unwind_to = if needs_cleanup { self.diverge_cleanup() } else { DropIdx::MAX };
669
670         let scope = self.scopes.scopes.last().expect("leave_top_scope called with no scopes");
671         unpack!(build_scope_drops(
672             &mut self.cfg,
673             &mut self.scopes.unwind_drops,
674             scope,
675             block,
676             unwind_to,
677             is_generator && needs_cleanup,
678             self.arg_count,
679         ))
680     }
681
682     /// Creates a new source scope, nested in the current one.
683     crate fn new_source_scope(
684         &mut self,
685         span: Span,
686         lint_level: LintLevel,
687         safety: Option<Safety>,
688     ) -> SourceScope {
689         let parent = self.source_scope;
690         debug!(
691             "new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}",
692             span,
693             lint_level,
694             safety,
695             parent,
696             self.source_scopes.get(parent)
697         );
698         let scope_local_data = SourceScopeLocalData {
699             lint_root: if let LintLevel::Explicit(lint_root) = lint_level {
700                 lint_root
701             } else {
702                 self.source_scopes[parent].local_data.as_ref().assert_crate_local().lint_root
703             },
704             safety: safety.unwrap_or_else(|| {
705                 self.source_scopes[parent].local_data.as_ref().assert_crate_local().safety
706             }),
707         };
708         self.source_scopes.push(SourceScopeData {
709             span,
710             parent_scope: Some(parent),
711             inlined: None,
712             inlined_parent_scope: None,
713             local_data: ClearCrossCrate::Set(scope_local_data),
714         })
715     }
716
717     /// Given a span and the current source scope, make a SourceInfo.
718     crate fn source_info(&self, span: Span) -> SourceInfo {
719         SourceInfo { span, scope: self.source_scope }
720     }
721
722     // Finding scopes
723     // ==============
724     /// Returns the scope that we should use as the lifetime of an
725     /// operand. Basically, an operand must live until it is consumed.
726     /// This is similar to, but not quite the same as, the temporary
727     /// scope (which can be larger or smaller).
728     ///
729     /// Consider:
730     ///
731     ///     let x = foo(bar(X, Y));
732     ///
733     /// We wish to pop the storage for X and Y after `bar()` is
734     /// called, not after the whole `let` is completed.
735     ///
736     /// As another example, if the second argument diverges:
737     ///
738     ///     foo(Box::new(2), panic!())
739     ///
740     /// We would allocate the box but then free it on the unwinding
741     /// path; we would also emit a free on the 'success' path from
742     /// panic, but that will turn out to be removed as dead-code.
743     ///
744     /// When building statics/constants, returns `None` since
745     /// intermediate values do not have to be dropped in that case.
746     crate fn local_scope(&self) -> Option<region::Scope> {
747         match self.hir.body_owner_kind {
748             hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) =>
749             // No need to free storage in this context.
750             {
751                 None
752             }
753             hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => Some(self.scopes.topmost()),
754         }
755     }
756
757     // Scheduling drops
758     // ================
759     crate fn schedule_drop_storage_and_value(
760         &mut self,
761         span: Span,
762         region_scope: region::Scope,
763         local: Local,
764     ) {
765         self.schedule_drop(span, region_scope, local, DropKind::Storage);
766         self.schedule_drop(span, region_scope, local, DropKind::Value);
767     }
768
769     /// Indicates that `place` should be dropped on exit from `region_scope`.
770     ///
771     /// When called with `DropKind::Storage`, `place` shouldn't be the return
772     /// place, or a function parameter.
773     crate fn schedule_drop(
774         &mut self,
775         span: Span,
776         region_scope: region::Scope,
777         local: Local,
778         drop_kind: DropKind,
779     ) {
780         let needs_drop = match drop_kind {
781             DropKind::Value => {
782                 if !self.hir.needs_drop(self.local_decls[local].ty) {
783                     return;
784                 }
785                 true
786             }
787             DropKind::Storage => {
788                 if local.index() <= self.arg_count {
789                     span_bug!(
790                         span,
791                         "`schedule_drop` called with local {:?} and arg_count {}",
792                         local,
793                         self.arg_count,
794                     )
795                 }
796                 false
797             }
798         };
799
800         // When building drops, we try to cache chains of drops to reduce the
801         // number of `DropTree::add_drop` calls. This, however, means that
802         // whenever we add a drop into a scope which already had some entries
803         // in the drop tree built (and thus, cached) for it, we must invalidate
804         // all caches which might branch into the scope which had a drop just
805         // added to it. This is necessary, because otherwise some other code
806         // might use the cache to branch into already built chain of drops,
807         // essentially ignoring the newly added drop.
808         //
809         // For example consider there’s two scopes with a drop in each. These
810         // are built and thus the caches are filled:
811         //
812         // +--------------------------------------------------------+
813         // | +---------------------------------+                    |
814         // | | +--------+     +-------------+  |  +---------------+ |
815         // | | | return | <-+ | drop(outer) | <-+ |  drop(middle) | |
816         // | | +--------+     +-------------+  |  +---------------+ |
817         // | +------------|outer_scope cache|--+                    |
818         // +------------------------------|middle_scope cache|------+
819         //
820         // Now, a new, inner-most scope is added along with a new drop into
821         // both inner-most and outer-most scopes:
822         //
823         // +------------------------------------------------------------+
824         // | +----------------------------------+                       |
825         // | | +--------+      +-------------+  |   +---------------+   | +-------------+
826         // | | | return | <+   | drop(new)   | <-+  |  drop(middle) | <--+| drop(inner) |
827         // | | +--------+  |   | drop(outer) |  |   +---------------+   | +-------------+
828         // | |             +-+ +-------------+  |                       |
829         // | +---|invalid outer_scope cache|----+                       |
830         // +----=----------------|invalid middle_scope cache|-----------+
831         //
832         // If, when adding `drop(new)` we do not invalidate the cached blocks for both
833         // outer_scope and middle_scope, then, when building drops for the inner (right-most)
834         // scope, the old, cached blocks, without `drop(new)` will get used, producing the
835         // wrong results.
836         //
837         // Note that this code iterates scopes from the inner-most to the outer-most,
838         // invalidating caches of each scope visited. This way bare minimum of the
839         // caches gets invalidated. i.e., if a new drop is added into the middle scope, the
840         // cache of outer scope stays intact.
841         //
842         // Since we only cache drops for the unwind path and the generator drop
843         // path, we only need to invalidate the cache for drops that happen on
844         // the unwind or generator drop paths. This means that for
845         // non-generators we don't need to invalidate caches for `DropKind::Storage`.
846         let invalidate_caches = needs_drop || self.generator_kind.is_some();
847         for scope in self.scopes.scopes.iter_mut().rev() {
848             if invalidate_caches {
849                 scope.invalidate_cache();
850             }
851
852             if scope.region_scope == region_scope {
853                 let region_scope_span =
854                     region_scope.span(self.hir.tcx(), &self.hir.region_scope_tree);
855                 // Attribute scope exit drops to scope's closing brace.
856                 let scope_end = self.hir.tcx().sess.source_map().end_point(region_scope_span);
857
858                 scope.drops.push(DropData {
859                     source_info: SourceInfo { span: scope_end, scope: scope.source_scope },
860                     local,
861                     kind: drop_kind,
862                 });
863
864                 return;
865             }
866         }
867
868         span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local);
869     }
870
871     /// Unschedule a drop. Used for `break`, `return` and `match` expressions,
872     /// where `record_operands_moved` is not powerful enough.
873     ///
874     /// The given local is expected to have a value drop scheduled in the given
875     /// scope and for that drop to be the most recent thing scheduled in that
876     /// scope.
877     fn unschedule_drop(&mut self, region_scope: region::Scope, local: Local) {
878         if !self.hir.needs_drop(self.local_decls[local].ty) {
879             return;
880         }
881         for scope in self.scopes.scopes.iter_mut().rev() {
882             scope.invalidate_cache();
883
884             if scope.region_scope == region_scope {
885                 let drop = scope.drops.pop();
886
887                 match drop {
888                     Some(DropData { local: removed_local, kind: DropKind::Value, .. })
889                         if removed_local == local =>
890                     {
891                         return;
892                     }
893                     _ => bug!(
894                         "found wrong drop, expected value drop of {:?}, found {:?}",
895                         local,
896                         drop,
897                     ),
898                 }
899             }
900         }
901
902         bug!("region scope {:?} not in scope to unschedule drop of {:?}", region_scope, local);
903     }
904
905     /// Indicates that the "local operands" stored in `local` is
906     /// *moved* at some point during execution (see `local_scope` for
907     /// more information about what a "local operand" is -- in short,
908     /// it's an intermediate operand created as part of preparing some
909     /// MIR instruction). We use this information to suppress
910     /// redundant drops. This results in less MIR, but also avoids spurious
911     /// borrow check errors (c.f. #64391).
912     ///
913     /// Example: when compiling the call to `foo` here:
914     ///
915     /// ```rust
916     /// foo(bar(), ...)
917     /// ```
918     ///
919     /// we would evaluate `bar()` to an operand `_X`. We would also
920     /// schedule `_X` to be dropped when the expression scope for
921     /// `foo(bar())` is exited. This is relevant, for example, if the
922     /// later arguments should unwind (it would ensure that `_X` gets
923     /// dropped). However, if no unwind occurs, then `_X` will be
924     /// unconditionally consumed by the `call`:
925     ///
926     /// ```
927     /// bb {
928     ///   ...
929     ///   _R = CALL(foo, _X, ...)
930     /// }
931     /// ```
932     ///
933     /// However, `_X` is still registered to be dropped, and so if we
934     /// do nothing else, we would generate a `DROP(_X)` that occurs
935     /// after the call. This will later be optimized out by the
936     /// drop-elaboation code, but in the meantime it can lead to
937     /// spurious borrow-check errors -- the problem, ironically, is
938     /// not the `DROP(_X)` itself, but the (spurious) unwind pathways
939     /// that it creates. See #64391 for an example.
940     crate fn record_operands_moved(&mut self, operands: &[Operand<'tcx>]) {
941         let scope = match self.local_scope() {
942             None => {
943                 // if there is no local scope, operands won't be dropped anyway
944                 return;
945             }
946
947             Some(local_scope) => {
948                 let top_scope = self.scopes.scopes.last_mut().unwrap();
949                 assert!(
950                     top_scope.region_scope == local_scope,
951                     "local scope ({:?}) is not the topmost scope!",
952                     local_scope
953                 );
954
955                 top_scope
956             }
957         };
958
959         // look for moves of a local variable, like `MOVE(_X)`
960         let locals_moved = operands
961             .iter()
962             .filter_map(|operand| match operand {
963                 Operand::Copy(_) | Operand::Constant(_) => None,
964                 Operand::Move(place) => place.as_local(),
965             })
966             .collect::<FxHashSet<_>>();
967
968         // Remove the drops for the moved operands.
969         scope
970             .drops
971             .retain(|drop| drop.kind == DropKind::Storage || !locals_moved.contains(&drop.local));
972         scope.invalidate_cache();
973     }
974
975     // Other
976     // =====
977     /// Branch based on a boolean condition.
978     ///
979     /// This is a special case because the temporary for the condition needs to
980     /// be dropped on both the true and the false arm.
981     crate fn test_bool(
982         &mut self,
983         mut block: BasicBlock,
984         condition: Expr<'tcx>,
985         source_info: SourceInfo,
986     ) -> (BasicBlock, BasicBlock) {
987         let cond = unpack!(block = self.as_local_operand(block, condition));
988         let true_block = self.cfg.start_new_block();
989         let false_block = self.cfg.start_new_block();
990         let term = TerminatorKind::if_(self.hir.tcx(), cond.clone(), true_block, false_block);
991         self.cfg.terminate(block, source_info, term);
992
993         match cond {
994             // Don't try to drop a constant
995             Operand::Constant(_) => (),
996             // If constants and statics, we don't generate StorageLive for this
997             // temporary, so don't try to generate StorageDead for it either.
998             _ if self.local_scope().is_none() => (),
999             Operand::Copy(place) | Operand::Move(place) => {
1000                 if let Some(cond_temp) = place.as_local() {
1001                     // Manually drop the condition on both branches.
1002                     let top_scope = self.scopes.scopes.last_mut().unwrap();
1003                     let top_drop_data = top_scope.drops.pop().unwrap();
1004                     if self.generator_kind.is_some() {
1005                         top_scope.invalidate_cache();
1006                     }
1007
1008                     match top_drop_data.kind {
1009                         DropKind::Value { .. } => {
1010                             bug!("Drop scheduled on top of condition variable")
1011                         }
1012                         DropKind::Storage => {
1013                             let source_info = top_drop_data.source_info;
1014                             let local = top_drop_data.local;
1015                             assert_eq!(local, cond_temp, "Drop scheduled on top of condition");
1016                             self.cfg.push(
1017                                 true_block,
1018                                 Statement { source_info, kind: StatementKind::StorageDead(local) },
1019                             );
1020                             self.cfg.push(
1021                                 false_block,
1022                                 Statement { source_info, kind: StatementKind::StorageDead(local) },
1023                             );
1024                         }
1025                     }
1026                 } else {
1027                     bug!("Expected as_local_operand to produce a temporary");
1028                 }
1029             }
1030         }
1031
1032         (true_block, false_block)
1033     }
1034
1035     /// Returns the [DropIdx] for the innermost drop if the function unwound at
1036     /// this point. The `DropIdx` will be created if it doesn't already exist.
1037     fn diverge_cleanup(&mut self) -> DropIdx {
1038         let is_generator = self.generator_kind.is_some();
1039         let (uncached_scope, mut cached_drop) = self
1040             .scopes
1041             .scopes
1042             .iter()
1043             .enumerate()
1044             .rev()
1045             .find_map(|(scope_idx, scope)| {
1046                 scope.cached_unwind_block.map(|cached_block| (scope_idx + 1, cached_block))
1047             })
1048             .unwrap_or((0, ROOT_NODE));
1049
1050         for scope in &mut self.scopes.scopes[uncached_scope..] {
1051             for drop in &scope.drops {
1052                 if is_generator || drop.kind == DropKind::Value {
1053                     cached_drop = self.scopes.unwind_drops.add_drop(*drop, cached_drop);
1054                 }
1055             }
1056             scope.cached_unwind_block = Some(cached_drop);
1057         }
1058
1059         cached_drop
1060     }
1061
1062     /// Prepares to create a path that performs all required cleanup for a
1063     /// terminator that can unwind at the given basic block.
1064     ///
1065     /// This path terminates in Resume. The path isn't created until after all
1066     /// of the non-unwind paths in this item have been lowered.
1067     crate fn diverge_from(&mut self, start: BasicBlock) {
1068         debug_assert!(
1069             matches!(
1070                 self.cfg.block_data(start).terminator().kind,
1071                 TerminatorKind::Assert { .. }
1072                 | TerminatorKind::Call {..}
1073                 | TerminatorKind::DropAndReplace { .. }
1074                 | TerminatorKind::FalseUnwind { .. }
1075             ),
1076             "diverge_from called on block with terminator that cannot unwind."
1077         );
1078
1079         let next_drop = self.diverge_cleanup();
1080         self.scopes.unwind_drops.add_entry(start, next_drop);
1081     }
1082
1083     /// Sets up a path that performs all required cleanup for dropping a
1084     /// generator, starting from the given block that ends in
1085     /// [TerminatorKind::Yield].
1086     ///
1087     /// This path terminates in GeneratorDrop.
1088     crate fn generator_drop_cleanup(&mut self, yield_block: BasicBlock) {
1089         debug_assert!(
1090             matches!(
1091                 self.cfg.block_data(yield_block).terminator().kind,
1092                 TerminatorKind::Yield { .. }
1093             ),
1094             "generator_drop_cleanup called on block with non-yield terminator."
1095         );
1096         let (uncached_scope, mut cached_drop) = self
1097             .scopes
1098             .scopes
1099             .iter()
1100             .enumerate()
1101             .rev()
1102             .find_map(|(scope_idx, scope)| {
1103                 scope.cached_generator_drop_block.map(|cached_block| (scope_idx + 1, cached_block))
1104             })
1105             .unwrap_or((0, ROOT_NODE));
1106
1107         for scope in &mut self.scopes.scopes[uncached_scope..] {
1108             for drop in &scope.drops {
1109                 cached_drop = self.scopes.generator_drops.add_drop(*drop, cached_drop);
1110             }
1111             scope.cached_generator_drop_block = Some(cached_drop);
1112         }
1113
1114         self.scopes.generator_drops.add_entry(yield_block, cached_drop);
1115     }
1116
1117     /// Utility function for *non*-scope code to build their own drops
1118     crate fn build_drop_and_replace(
1119         &mut self,
1120         block: BasicBlock,
1121         span: Span,
1122         place: Place<'tcx>,
1123         value: Operand<'tcx>,
1124     ) -> BlockAnd<()> {
1125         let source_info = self.source_info(span);
1126         let next_target = self.cfg.start_new_block();
1127
1128         self.cfg.terminate(
1129             block,
1130             source_info,
1131             TerminatorKind::DropAndReplace { place, value, target: next_target, unwind: None },
1132         );
1133         self.diverge_from(block);
1134
1135         next_target.unit()
1136     }
1137
1138     /// Creates an `Assert` terminator and return the success block.
1139     /// If the boolean condition operand is not the expected value,
1140     /// a runtime panic will be caused with the given message.
1141     crate fn assert(
1142         &mut self,
1143         block: BasicBlock,
1144         cond: Operand<'tcx>,
1145         expected: bool,
1146         msg: AssertMessage<'tcx>,
1147         span: Span,
1148     ) -> BasicBlock {
1149         let source_info = self.source_info(span);
1150         let success_block = self.cfg.start_new_block();
1151
1152         self.cfg.terminate(
1153             block,
1154             source_info,
1155             TerminatorKind::Assert { cond, expected, msg, target: success_block, cleanup: None },
1156         );
1157         self.diverge_from(block);
1158
1159         success_block
1160     }
1161
1162     /// Lower the arms and guards of a match.
1163     ///
1164     /// The decision tree should have already been created (by
1165     /// [Builder::lower_match_tree]).
1166     ///
1167     /// This is this module, and not in `build::matches` because we have to do
1168     /// some careful scope manipulation to have the drop of the destination be
1169     /// scheduled at the end of each arm and then cleared for the next arm.
1170     crate fn lower_match_arms(
1171         &mut self,
1172         destination: Place<'tcx>,
1173         destination_scope: Option<region::Scope>,
1174         scrutinee_place: Place<'tcx>,
1175         scrutinee_span: Span,
1176         arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
1177         outer_source_info: SourceInfo,
1178         fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
1179     ) -> BlockAnd<()> {
1180         if arm_candidates.is_empty() {
1181             // If there are no arms to schedule drops, then we have to do it
1182             // manually.
1183             if let Some(scope) = destination_scope {
1184                 self.schedule_drop(
1185                     outer_source_info.span,
1186                     scope,
1187                     destination.as_local().unwrap(),
1188                     DropKind::Value,
1189                 );
1190             }
1191             return self.cfg.start_new_block().unit();
1192         }
1193         let mut first_arm = true;
1194         let arm_end_blocks: Vec<_> = arm_candidates
1195             .into_iter()
1196             .map(|(arm, candidate)| {
1197                 debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate);
1198
1199                 if first_arm {
1200                     first_arm = false;
1201                 } else if let Some(scope) = destination_scope {
1202                     self.unschedule_drop(scope, destination.as_local().unwrap());
1203                 }
1204
1205                 let arm_source_info = self.source_info(arm.span);
1206                 let arm_scope = (arm.scope, arm_source_info);
1207                 self.in_scope(arm_scope, arm.lint_level, |this| {
1208                     let body = this.hir.mirror(arm.body.clone());
1209                     let scope = this.declare_bindings(
1210                         None,
1211                         arm.span,
1212                         &arm.pattern,
1213                         ArmHasGuard(arm.guard.is_some()),
1214                         Some((Some(&scrutinee_place), scrutinee_span)),
1215                     );
1216
1217                     let arm_block = this.bind_pattern(
1218                         outer_source_info,
1219                         candidate,
1220                         arm.guard.as_ref(),
1221                         &fake_borrow_temps,
1222                         scrutinee_span,
1223                         Some(arm.span),
1224                         Some(arm.scope),
1225                     );
1226
1227                     if let Some(source_scope) = scope {
1228                         this.source_scope = source_scope;
1229                     }
1230
1231                     this.into(destination, destination_scope, arm_block, body)
1232                 })
1233             })
1234             .collect();
1235
1236         // all the arm blocks will rejoin here
1237         let end_block = self.cfg.start_new_block();
1238
1239         for arm_block in arm_end_blocks {
1240             self.cfg.goto(unpack!(arm_block), outer_source_info, end_block);
1241         }
1242
1243         self.source_scope = outer_source_info.scope;
1244
1245         end_block.unit()
1246     }
1247
1248     /// Unschedules any drops in the top scope.
1249     ///
1250     /// This is only needed for `match` arm scopes, because they have one
1251     /// entrance per pattern, but only one exit.
1252     pub(super) fn clear_top_scope(&mut self, region_scope: region::Scope) {
1253         let top_scope = self.scopes.scopes.last_mut().unwrap();
1254
1255         assert_eq!(top_scope.region_scope, region_scope);
1256
1257         top_scope.drops.clear();
1258         top_scope.invalidate_cache();
1259     }
1260
1261     /// Unschedules the drop of the return place.
1262     ///
1263     /// If the return type of a function requires drop, then we schedule it
1264     /// in the outermost scope so that it's dropped if there's a panic while
1265     /// we drop any local variables. But we don't want to drop it if we
1266     /// return normally.
1267     crate fn unschedule_return_place_drop(&mut self) {
1268         assert_eq!(self.scopes.scopes.len(), 1);
1269         assert!(self.scopes.scopes[0].drops.len() <= 1);
1270         self.scopes.scopes[0].drops.clear();
1271     }
1272 }
1273
1274 /// Builds drops for `pop_scope` and `leave_top_scope`.
1275 fn build_scope_drops<'tcx>(
1276     cfg: &mut CFG<'tcx>,
1277     unwind_drops: &mut DropTree,
1278     scope: &Scope,
1279     mut block: BasicBlock,
1280     mut unwind_to: DropIdx,
1281     storage_dead_on_unwind: bool,
1282     arg_count: usize,
1283 ) -> BlockAnd<()> {
1284     debug!("build_scope_drops({:?} -> {:?})", block, scope);
1285
1286     // Build up the drops in evaluation order. The end result will
1287     // look like:
1288     //
1289     // [SDs, drops[n]] --..> [SDs, drop[1]] -> [SDs, drop[0]] -> [[SDs]]
1290     //               |                    |                 |
1291     //               :                    |                 |
1292     //                                    V                 V
1293     // [drop[n]] -...-> [drop[1]] ------> [drop[0]] ------> [last_unwind_to]
1294     //
1295     // The horizontal arrows represent the execution path when the drops return
1296     // successfully. The downwards arrows represent the execution path when the
1297     // drops panic (panicking while unwinding will abort, so there's no need for
1298     // another set of arrows).
1299     //
1300     // For generators, we unwind from a drop on a local to its StorageDead
1301     // statement. For other functions we don't worry about StorageDead. The
1302     // drops for the unwind path should have already been generated by
1303     // `diverge_cleanup_gen`.
1304
1305     for drop_data in scope.drops.iter().rev() {
1306         let source_info = drop_data.source_info;
1307         let local = drop_data.local;
1308
1309         match drop_data.kind {
1310             DropKind::Value => {
1311                 // `unwind_to` should drop the value that we're about to
1312                 // schedule. If dropping this value panics, then we continue
1313                 // with the *next* value on the unwind path.
1314                 debug_assert_eq!(unwind_drops.drops[unwind_to].0.local, drop_data.local);
1315                 debug_assert_eq!(unwind_drops.drops[unwind_to].0.kind, drop_data.kind);
1316                 unwind_to = unwind_drops.drops[unwind_to].1;
1317
1318                 unwind_drops.add_entry(block, unwind_to);
1319
1320                 let next = cfg.start_new_block();
1321                 cfg.terminate(
1322                     block,
1323                     source_info,
1324                     TerminatorKind::Drop { place: local.into(), target: next, unwind: None },
1325                 );
1326                 block = next;
1327             }
1328             DropKind::Storage => {
1329                 if storage_dead_on_unwind {
1330                     debug_assert_eq!(unwind_drops.drops[unwind_to].0.local, drop_data.local);
1331                     debug_assert_eq!(unwind_drops.drops[unwind_to].0.kind, drop_data.kind);
1332                     unwind_to = unwind_drops.drops[unwind_to].1;
1333                 }
1334                 // Only temps and vars need their storage dead.
1335                 assert!(local.index() > arg_count);
1336                 cfg.push(block, Statement { source_info, kind: StatementKind::StorageDead(local) });
1337             }
1338         }
1339     }
1340     block.unit()
1341 }
1342
1343 impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
1344     /// Build a drop tree for a breakable scope.
1345     ///
1346     /// If `continue_block` is `Some`, then the tree is for `continue` inside a
1347     /// loop. Otherwise this is for `break` or `return`. The `DropIdx` is the
1348     /// next drop in the case that the drop tree unwinds. This is needed
1349     /// because the drop of the break destination has already been scheduled
1350     /// but it hasn't been initialized on the `continue` paths.
1351     fn build_exit_tree(
1352         &mut self,
1353         mut drops: DropTree,
1354         continue_block: Option<(BasicBlock, DropIdx)>,
1355     ) -> Option<BlockAnd<()>> {
1356         let mut blocks = IndexVec::from_elem(None, &drops.drops);
1357         blocks[ROOT_NODE] = continue_block.map(|(block, _)| block);
1358
1359         drops.build_mir::<ExitScopes>(&mut self.cfg, &mut blocks);
1360
1361         // Link the exit drop tree to unwind drop tree.
1362         if drops.drops.iter().any(|(drop, _)| drop.kind == DropKind::Value) {
1363             let unwind_target = continue_block
1364                 .map_or_else(|| self.diverge_cleanup(), |(_, unwind_target)| unwind_target);
1365             let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1);
1366             for (drop_idx, drop_data) in drops.drops.iter_enumerated().skip(1) {
1367                 match drop_data.0.kind {
1368                     DropKind::Storage => {
1369                         if self.generator_kind.is_some() {
1370                             let unwind_drop = self
1371                                 .scopes
1372                                 .unwind_drops
1373                                 .add_drop(drop_data.0, unwind_indices[drop_data.1]);
1374                             unwind_indices.push(unwind_drop);
1375                         } else {
1376                             unwind_indices.push(unwind_indices[drop_data.1]);
1377                         }
1378                     }
1379                     DropKind::Value => {
1380                         let unwind_drop = self
1381                             .scopes
1382                             .unwind_drops
1383                             .add_drop(drop_data.0, unwind_indices[drop_data.1]);
1384                         self.scopes
1385                             .unwind_drops
1386                             .add_entry(blocks[drop_idx].unwrap(), unwind_indices[drop_data.1]);
1387                         unwind_indices.push(unwind_drop);
1388                     }
1389                 }
1390             }
1391         }
1392         blocks[ROOT_NODE].map(BasicBlock::unit)
1393     }
1394
1395     /// Build the unwind and generator drop trees.
1396     crate fn build_drop_trees(&mut self, should_abort: bool) {
1397         if self.generator_kind.is_some() {
1398             self.build_generator_drop_trees(should_abort);
1399         } else {
1400             Self::build_unwind_tree(
1401                 &mut self.cfg,
1402                 &mut self.scopes.unwind_drops,
1403                 self.fn_span,
1404                 should_abort,
1405                 &mut None,
1406             );
1407         }
1408     }
1409
1410     fn build_generator_drop_trees(&mut self, should_abort: bool) {
1411         // Build the drop tree for dropping the generator while it's suspended.
1412         let drops = &mut self.scopes.generator_drops;
1413         let cfg = &mut self.cfg;
1414         let fn_span = self.fn_span;
1415         let mut blocks = IndexVec::from_elem(None, &drops.drops);
1416         drops.build_mir::<GeneratorDrop>(cfg, &mut blocks);
1417         if let Some(root_block) = blocks[ROOT_NODE] {
1418             cfg.terminate(
1419                 root_block,
1420                 SourceInfo::outermost(fn_span),
1421                 TerminatorKind::GeneratorDrop,
1422             );
1423         }
1424
1425         // Build the drop tree for unwinding in the normal control flow paths.
1426         let resume_block = &mut None;
1427         let unwind_drops = &mut self.scopes.unwind_drops;
1428         Self::build_unwind_tree(cfg, unwind_drops, fn_span, should_abort, resume_block);
1429
1430         // Build the drop tree for unwinding when dropping a suspended
1431         // generator.
1432         //
1433         // This is a different tree to the standard unwind paths here to
1434         // prevent drop elaboration from creating drop flags that would have
1435         // to be captured by the generator. I'm not sure how important this
1436         // optimization is, but it is here.
1437         for (drop_idx, drop_data) in drops.drops.iter_enumerated() {
1438             if let DropKind::Value = drop_data.0.kind {
1439                 debug_assert!(drop_data.1 < drops.drops.next_index());
1440                 drops.entry_points.push((drop_data.1, blocks[drop_idx].unwrap()));
1441             }
1442         }
1443         Self::build_unwind_tree(cfg, drops, fn_span, should_abort, resume_block);
1444     }
1445
1446     fn build_unwind_tree(
1447         cfg: &mut CFG<'tcx>,
1448         drops: &mut DropTree,
1449         fn_span: Span,
1450         should_abort: bool,
1451         resume_block: &mut Option<BasicBlock>,
1452     ) {
1453         let mut blocks = IndexVec::from_elem(None, &drops.drops);
1454         blocks[ROOT_NODE] = *resume_block;
1455         drops.build_mir::<Unwind>(cfg, &mut blocks);
1456         if let (None, Some(resume)) = (*resume_block, blocks[ROOT_NODE]) {
1457             // `TerminatorKind::Abort` is used for `#[unwind(aborts)]`
1458             // functions.
1459             let terminator =
1460                 if should_abort { TerminatorKind::Abort } else { TerminatorKind::Resume };
1461
1462             cfg.terminate(resume, SourceInfo::outermost(fn_span), terminator);
1463
1464             *resume_block = blocks[ROOT_NODE];
1465         }
1466     }
1467 }
1468
1469 // DropTreeBuilder implementations.
1470
1471 struct ExitScopes;
1472
1473 impl<'tcx> DropTreeBuilder<'tcx> for ExitScopes {
1474     fn make_block(cfg: &mut CFG<'tcx>) -> BasicBlock {
1475         cfg.start_new_block()
1476     }
1477     fn add_entry(cfg: &mut CFG<'tcx>, from: BasicBlock, to: BasicBlock) {
1478         cfg.block_data_mut(from).terminator_mut().kind = TerminatorKind::Goto { target: to };
1479     }
1480 }
1481
1482 struct GeneratorDrop;
1483
1484 impl<'tcx> DropTreeBuilder<'tcx> for GeneratorDrop {
1485     fn make_block(cfg: &mut CFG<'tcx>) -> BasicBlock {
1486         cfg.start_new_block()
1487     }
1488     fn add_entry(cfg: &mut CFG<'tcx>, from: BasicBlock, to: BasicBlock) {
1489         let term = cfg.block_data_mut(from).terminator_mut();
1490         if let TerminatorKind::Yield { ref mut drop, .. } = term.kind {
1491             *drop = Some(to);
1492         } else {
1493             span_bug!(
1494                 term.source_info.span,
1495                 "cannot enter generator drop tree from {:?}",
1496                 term.kind
1497             )
1498         }
1499     }
1500 }
1501
1502 struct Unwind;
1503
1504 impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
1505     fn make_block(cfg: &mut CFG<'tcx>) -> BasicBlock {
1506         cfg.start_new_cleanup_block()
1507     }
1508     fn add_entry(cfg: &mut CFG<'tcx>, from: BasicBlock, to: BasicBlock) {
1509         let term = &mut cfg.block_data_mut(from).terminator_mut();
1510         match &mut term.kind {
1511             TerminatorKind::Drop { unwind, .. }
1512             | TerminatorKind::DropAndReplace { unwind, .. }
1513             | TerminatorKind::FalseUnwind { unwind, .. }
1514             | TerminatorKind::Call { cleanup: unwind, .. }
1515             | TerminatorKind::Assert { cleanup: unwind, .. } => {
1516                 *unwind = Some(to);
1517             }
1518             TerminatorKind::Goto { .. }
1519             | TerminatorKind::SwitchInt { .. }
1520             | TerminatorKind::Resume
1521             | TerminatorKind::Abort
1522             | TerminatorKind::Return
1523             | TerminatorKind::Unreachable
1524             | TerminatorKind::Yield { .. }
1525             | TerminatorKind::GeneratorDrop
1526             | TerminatorKind::FalseEdge { .. }
1527             | TerminatorKind::InlineAsm { .. } => {
1528                 span_bug!(term.source_info.span, "cannot unwind from {:?}", term.kind)
1529             }
1530         }
1531     }
1532 }