]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/scope.rs
0d1d40a8af6333b42d3f9c73cebacf8c88e8ac7d
[rust.git] / src / librustc_mir / build / scope.rs
1 /*!
2 Managing the scope stack. The scopes are tied to lexical scopes, so as
3 we descend the HAIR, 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 keep a mapping from each `region::Scope` to its
17 corresponding SEME region for later reference (see caveat in next
18 paragraph). This is because region scopes are tied to
19 them. Eventually, when we shift to non-lexical lifetimes, there should
20 be no need to remember this mapping.
21
22 ### Not so SEME Regions
23
24 In the course of building matches, it sometimes happens that certain code
25 (namely guards) gets executed multiple times. This means that the scope lexical
26 scope may in fact correspond to multiple, disjoint SEME regions. So in fact our
27 mapping is from one scope to a vector of SEME regions.
28
29 Also in matches, the scopes assigned to arms are not even SEME regions! Each
30 arm has a single region with one entry for each pattern. We manually
31 manipulate the scheduled drops in this scope to avoid dropping things multiple
32 times, although drop elaboration would clean this up for value drops.
33
34 ### Drops
35
36 The primary purpose for scopes is to insert drops: while building
37 the contents, we also accumulate places that need to be dropped upon
38 exit from each scope. This is done by calling `schedule_drop`. Once a
39 drop is scheduled, whenever we branch out we will insert drops of all
40 those places onto the outgoing edge. Note that we don't know the full
41 set of scheduled drops up front, and so whenever we exit from the
42 scope we only drop the values scheduled thus far. For example, consider
43 the scope S corresponding to this loop:
44
45 ```
46 # let cond = true;
47 loop {
48     let x = ..;
49     if cond { break; }
50     let y = ..;
51 }
52 ```
53
54 When processing the `let x`, we will add one drop to the scope for
55 `x`.  The break will then insert a drop for `x`. When we process `let
56 y`, we will add another drop (in fact, to a subscope, but let's ignore
57 that for now); any later drops would also drop `y`.
58
59 ### Early exit
60
61 There are numerous "normal" ways to early exit a scope: `break`,
62 `continue`, `return` (panics are handled separately). Whenever an
63 early exit occurs, the method `exit_scope` is called. It is given the
64 current point in execution where the early exit occurs, as well as the
65 scope you want to branch to (note that all early exits from to some
66 other enclosing scope). `exit_scope` will record this exit point and
67 also add all drops.
68
69 Panics are handled in a similar fashion, except that a panic always
70 returns out to the `DIVERGE_BLOCK`. To trigger a panic, simply call
71 `panic(p)` with the current point `p`. Or else you can call
72 `diverge_cleanup`, which will produce a block that you can branch to
73 which does the appropriate cleanup and then diverges. `panic(p)`
74 simply calls `diverge_cleanup()` and adds an edge from `p` to the
75 result.
76
77 ### Loop scopes
78
79 In addition to the normal scope stack, we track a loop scope stack
80 that contains only loops. It tracks where a `break` and `continue`
81 should go to.
82
83 */
84
85 use crate::build::{BlockAnd, BlockAndExtension, Builder, CFG};
86 use crate::hair::LintLevel;
87 use rustc::middle::region;
88 use rustc::ty::Ty;
89 use rustc::hir;
90 use rustc::mir::*;
91 use syntax_pos::{Span};
92 use rustc_data_structures::fx::FxHashMap;
93 use std::collections::hash_map::Entry;
94
95 #[derive(Debug)]
96 pub struct Scope<'tcx> {
97     /// The source scope this scope was created in.
98     source_scope: SourceScope,
99
100     /// the region span of this scope within source code.
101     region_scope: region::Scope,
102
103     /// the span of that region_scope
104     region_scope_span: Span,
105
106     /// Whether there's anything to do for the cleanup path, that is,
107     /// when unwinding through this scope. This includes destructors,
108     /// but not StorageDead statements, which don't get emitted at all
109     /// for unwinding, for several reasons:
110     ///  * clang doesn't emit llvm.lifetime.end for C++ unwinding
111     ///  * LLVM's memory dependency analysis can't handle it atm
112     ///  * polluting the cleanup MIR with StorageDead creates
113     ///    landing pads even though there's no actual destructors
114     ///  * freeing up stack space has no effect during unwinding
115     needs_cleanup: bool,
116
117     /// set of places to drop when exiting this scope. This starts
118     /// out empty but grows as variables are declared during the
119     /// building process. This is a stack, so we always drop from the
120     /// end of the vector (top of the stack) first.
121     drops: Vec<DropData<'tcx>>,
122
123     /// The cache for drop chain on “normal” exit into a particular BasicBlock.
124     cached_exits: FxHashMap<(BasicBlock, region::Scope), BasicBlock>,
125
126     /// The cache for drop chain on "generator drop" exit.
127     cached_generator_drop: Option<BasicBlock>,
128
129     /// The cache for drop chain on "unwind" exit.
130     cached_unwind: CachedBlock,
131 }
132
133 #[derive(Debug)]
134 struct DropData<'tcx> {
135     /// span where drop obligation was incurred (typically where place was declared)
136     span: Span,
137
138     /// place to drop
139     location: Place<'tcx>,
140
141     /// Whether this is a value Drop or a StorageDead.
142     kind: DropKind,
143 }
144
145 #[derive(Debug, Default, Clone, Copy)]
146 pub(crate) struct CachedBlock {
147     /// The cached block for the cleanups-on-diverge path. This block
148     /// contains code to run the current drop and all the preceding
149     /// drops (i.e., those having lower index in Drop’s Scope drop
150     /// array)
151     unwind: Option<BasicBlock>,
152
153     /// The cached block for unwinds during cleanups-on-generator-drop path
154     ///
155     /// This is split from the standard unwind path here to prevent drop
156     /// elaboration from creating drop flags that would have to be captured
157     /// by the generator. I'm not sure how important this optimization is,
158     /// but it is here.
159     generator_drop: Option<BasicBlock>,
160 }
161
162 #[derive(Debug)]
163 pub(crate) enum DropKind {
164     Value {
165         cached_block: CachedBlock,
166     },
167     Storage
168 }
169
170 #[derive(Clone, Debug)]
171 pub struct BreakableScope<'tcx> {
172     /// Region scope of the loop
173     pub region_scope: region::Scope,
174     /// Where the body of the loop begins. `None` if block
175     pub continue_block: Option<BasicBlock>,
176     /// Block to branch into when the loop or block terminates (either by being `break`-en out
177     /// from, or by having its condition to become false)
178     pub break_block: BasicBlock,
179     /// The destination of the loop/block expression itself (i.e., where to put the result of a
180     /// `break` expression)
181     pub break_destination: Place<'tcx>,
182 }
183
184 impl CachedBlock {
185     fn invalidate(&mut self) {
186         self.generator_drop = None;
187         self.unwind = None;
188     }
189
190     fn get(&self, generator_drop: bool) -> Option<BasicBlock> {
191         if generator_drop {
192             self.generator_drop
193         } else {
194             self.unwind
195         }
196     }
197
198     fn ref_mut(&mut self, generator_drop: bool) -> &mut Option<BasicBlock> {
199         if generator_drop {
200             &mut self.generator_drop
201         } else {
202             &mut self.unwind
203         }
204     }
205 }
206
207 impl DropKind {
208     fn may_panic(&self) -> bool {
209         match *self {
210             DropKind::Value { .. } => true,
211             DropKind::Storage => false
212         }
213     }
214 }
215
216 impl<'tcx> Scope<'tcx> {
217     /// Invalidates all the cached blocks in the scope.
218     ///
219     /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a
220     /// larger extent of code.
221     ///
222     /// `storage_only` controls whether to invalidate only drop paths that run `StorageDead`.
223     /// `this_scope_only` controls whether to invalidate only drop paths that refer to the current
224     /// top-of-scope (as opposed to dependent scopes).
225     fn invalidate_cache(&mut self, storage_only: bool, this_scope_only: bool) {
226         // FIXME: maybe do shared caching of `cached_exits` etc. to handle functions
227         // with lots of `try!`?
228
229         // cached exits drop storage and refer to the top-of-scope
230         self.cached_exits.clear();
231
232         if !storage_only {
233             // the current generator drop and unwind ignore
234             // storage but refer to top-of-scope
235             self.cached_generator_drop = None;
236             self.cached_unwind.invalidate();
237         }
238
239         if !storage_only && !this_scope_only {
240             for drop_data in &mut self.drops {
241                 if let DropKind::Value { ref mut cached_block } = drop_data.kind {
242                     cached_block.invalidate();
243                 }
244             }
245         }
246     }
247
248     /// Given a span and this scope's source scope, make a SourceInfo.
249     fn source_info(&self, span: Span) -> SourceInfo {
250         SourceInfo {
251             span,
252             scope: self.source_scope
253         }
254     }
255 }
256
257 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
258     // Adding and removing scopes
259     // ==========================
260     /// Start a breakable scope, which tracks where `continue` and `break`
261     /// should branch to. See module comment for more details.
262     ///
263     /// Returns the might_break attribute of the BreakableScope used.
264     pub fn in_breakable_scope<F, R>(&mut self,
265                                     loop_block: Option<BasicBlock>,
266                                     break_block: BasicBlock,
267                                     break_destination: Place<'tcx>,
268                                     f: F) -> R
269         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> R
270     {
271         let region_scope = self.topmost_scope();
272         let scope = BreakableScope {
273             region_scope,
274             continue_block: loop_block,
275             break_block,
276             break_destination,
277         };
278         self.breakable_scopes.push(scope);
279         let res = f(self);
280         let breakable_scope = self.breakable_scopes.pop().unwrap();
281         assert!(breakable_scope.region_scope == region_scope);
282         res
283     }
284
285     pub fn in_opt_scope<F, R>(&mut self,
286                               opt_scope: Option<(region::Scope, SourceInfo)>,
287                               f: F)
288                               -> BlockAnd<R>
289         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd<R>
290     {
291         debug!("in_opt_scope(opt_scope={:?})", opt_scope);
292         if let Some(region_scope) = opt_scope { self.push_scope(region_scope); }
293         let mut block;
294         let rv = unpack!(block = f(self));
295         if let Some(region_scope) = opt_scope {
296             unpack!(block = self.pop_scope(region_scope, block));
297         }
298         debug!("in_scope: exiting opt_scope={:?} block={:?}", opt_scope, block);
299         block.and(rv)
300     }
301
302     /// Convenience wrapper that pushes a scope and then executes `f`
303     /// to build its contents, popping the scope afterwards.
304     pub fn in_scope<F, R>(&mut self,
305                           region_scope: (region::Scope, SourceInfo),
306                           lint_level: LintLevel,
307                           f: F)
308                           -> BlockAnd<R>
309         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd<R>
310     {
311         debug!("in_scope(region_scope={:?})", region_scope);
312         let source_scope = self.source_scope;
313         let tcx = self.hir.tcx();
314         if let LintLevel::Explicit(current_hir_id) = lint_level {
315             // Use `maybe_lint_level_root_bounded` with `root_lint_level` as a bound
316             // to avoid adding Hir dependences on our parents.
317             // We estimate the true lint roots here to avoid creating a lot of source scopes.
318
319             let parent_root = tcx.maybe_lint_level_root_bounded(
320                 self.source_scope_local_data[source_scope].lint_root,
321                 self.hir.root_lint_level,
322             );
323             let current_root = tcx.maybe_lint_level_root_bounded(
324                 current_hir_id,
325                 self.hir.root_lint_level
326             );
327
328             if parent_root != current_root {
329                 self.source_scope = self.new_source_scope(
330                     region_scope.1.span,
331                     LintLevel::Explicit(current_root),
332                     None
333                 );
334             }
335         }
336         self.push_scope(region_scope);
337         let mut block;
338         let rv = unpack!(block = f(self));
339         unpack!(block = self.pop_scope(region_scope, block));
340         self.source_scope = source_scope;
341         debug!("in_scope: exiting region_scope={:?} block={:?}", region_scope, block);
342         block.and(rv)
343     }
344
345     /// Push a scope onto the stack. You can then build code in this
346     /// scope and call `pop_scope` afterwards. Note that these two
347     /// calls must be paired; using `in_scope` as a convenience
348     /// wrapper maybe preferable.
349     pub fn push_scope(&mut self, region_scope: (region::Scope, SourceInfo)) {
350         debug!("push_scope({:?})", region_scope);
351         let vis_scope = self.source_scope;
352         self.scopes.push(Scope {
353             source_scope: vis_scope,
354             region_scope: region_scope.0,
355             region_scope_span: region_scope.1.span,
356             needs_cleanup: false,
357             drops: vec![],
358             cached_generator_drop: None,
359             cached_exits: Default::default(),
360             cached_unwind: CachedBlock::default(),
361         });
362     }
363
364     /// Pops a scope, which should have region scope `region_scope`,
365     /// adding any drops onto the end of `block` that are needed.
366     /// This must match 1-to-1 with `push_scope`.
367     pub fn pop_scope(&mut self,
368                      region_scope: (region::Scope, SourceInfo),
369                      mut block: BasicBlock)
370                      -> BlockAnd<()> {
371         debug!("pop_scope({:?}, {:?})", region_scope, block);
372         // If we are emitting a `drop` statement, we need to have the cached
373         // diverge cleanup pads ready in case that drop panics.
374         let may_panic =
375             self.scopes.last().unwrap().drops.iter().any(|s| s.kind.may_panic());
376         if may_panic {
377             self.diverge_cleanup();
378         }
379         let scope = self.scopes.pop().unwrap();
380         assert_eq!(scope.region_scope, region_scope.0);
381
382         let unwind_to = self.scopes.last().and_then(|next_scope| {
383             next_scope.cached_unwind.get(false)
384         }).unwrap_or_else(|| self.resume_block());
385
386         unpack!(block = build_scope_drops(
387             &mut self.cfg,
388             &scope,
389             block,
390             unwind_to,
391             self.arg_count,
392             false,
393         ));
394
395         block.unit()
396     }
397
398
399     /// Branch out of `block` to `target`, exiting all scopes up to
400     /// and including `region_scope`. This will insert whatever drops are
401     /// needed. See module comment for details.
402     pub fn exit_scope(&mut self,
403                       span: Span,
404                       region_scope: (region::Scope, SourceInfo),
405                       mut block: BasicBlock,
406                       target: BasicBlock) {
407         debug!("exit_scope(region_scope={:?}, block={:?}, target={:?})",
408                region_scope, block, target);
409         let scope_count = 1 + self.scopes.iter().rev()
410             .position(|scope| scope.region_scope == region_scope.0)
411             .unwrap_or_else(|| {
412                 span_bug!(span, "region_scope {:?} does not enclose", region_scope)
413             });
414         let len = self.scopes.len();
415         assert!(scope_count < len, "should not use `exit_scope` to pop ALL scopes");
416
417         // If we are emitting a `drop` statement, we need to have the cached
418         // diverge cleanup pads ready in case that drop panics.
419         let may_panic = self.scopes[(len - scope_count)..].iter().any(|s| s.needs_cleanup);
420         if may_panic {
421             self.diverge_cleanup();
422         }
423
424         let mut scopes = self.scopes[(len - scope_count - 1)..].iter_mut().rev();
425         let mut scope = scopes.next().unwrap();
426         for next_scope in scopes {
427             if scope.drops.is_empty() {
428                 scope = next_scope;
429                 continue;
430             }
431             let source_info = scope.source_info(span);
432             block = match scope.cached_exits.entry((target, region_scope.0)) {
433                 Entry::Occupied(e) => {
434                     self.cfg.terminate(block, source_info,
435                                     TerminatorKind::Goto { target: *e.get() });
436                     return;
437                 }
438                 Entry::Vacant(v) => {
439                     let b = self.cfg.start_new_block();
440                     self.cfg.terminate(block, source_info,
441                                     TerminatorKind::Goto { target: b });
442                     v.insert(b);
443                     b
444                 }
445             };
446
447             let unwind_to = next_scope.cached_unwind.get(false).unwrap_or_else(|| {
448                 debug_assert!(!may_panic, "cached block not present?");
449                 START_BLOCK
450             });
451
452             unpack!(block = build_scope_drops(
453                 &mut self.cfg,
454                 scope,
455                 block,
456                 unwind_to,
457                 self.arg_count,
458                 false,
459             ));
460
461             scope = next_scope;
462         }
463
464         let scope = &self.scopes[len - scope_count];
465         self.cfg.terminate(block, scope.source_info(span),
466                            TerminatorKind::Goto { target });
467     }
468
469     /// Creates a path that performs all required cleanup for dropping a generator.
470     ///
471     /// This path terminates in GeneratorDrop. Returns the start of the path.
472     /// None indicates there’s no cleanup to do at this point.
473     pub fn generator_drop_cleanup(&mut self) -> Option<BasicBlock> {
474         if !self.scopes.iter().any(|scope| scope.needs_cleanup) {
475             return None;
476         }
477
478         // Fill in the cache for unwinds
479         self.diverge_cleanup_gen(true);
480
481         let src_info = self.scopes[0].source_info(self.fn_span);
482         let resume_block = self.resume_block();
483         let mut scopes = self.scopes.iter_mut().rev().peekable();
484         let mut block = self.cfg.start_new_block();
485         let result = block;
486
487         while let Some(scope) = scopes.next() {
488             if !scope.needs_cleanup {
489                 continue;
490             }
491
492             block = if let Some(b) = scope.cached_generator_drop {
493                 self.cfg.terminate(block, src_info,
494                                    TerminatorKind::Goto { target: b });
495                 return Some(result);
496             } else {
497                 let b = self.cfg.start_new_block();
498                 scope.cached_generator_drop = Some(b);
499                 self.cfg.terminate(block, src_info,
500                                    TerminatorKind::Goto { target: b });
501                 b
502             };
503
504             let unwind_to = scopes.peek().as_ref().map(|scope| {
505                 scope.cached_unwind.get(true).unwrap_or_else(|| {
506                     span_bug!(src_info.span, "cached block not present?")
507                 })
508             }).unwrap_or(resume_block);
509
510             unpack!(block = build_scope_drops(
511                 &mut self.cfg,
512                 scope,
513                 block,
514                 unwind_to,
515                 self.arg_count,
516                 true,
517             ));
518         }
519
520         self.cfg.terminate(block, src_info, TerminatorKind::GeneratorDrop);
521
522         Some(result)
523     }
524
525     /// Creates a new source scope, nested in the current one.
526     pub fn new_source_scope(&mut self,
527                             span: Span,
528                             lint_level: LintLevel,
529                             safety: Option<Safety>) -> SourceScope {
530         let parent = self.source_scope;
531         debug!("new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}",
532                span, lint_level, safety,
533                parent, self.source_scope_local_data.get(parent));
534         let scope = self.source_scopes.push(SourceScopeData {
535             span,
536             parent_scope: Some(parent),
537         });
538         let scope_local_data = SourceScopeLocalData {
539             lint_root: if let LintLevel::Explicit(lint_root) = lint_level {
540                 lint_root
541             } else {
542                 self.source_scope_local_data[parent].lint_root
543             },
544             safety: safety.unwrap_or_else(|| {
545                 self.source_scope_local_data[parent].safety
546             })
547         };
548         self.source_scope_local_data.push(scope_local_data);
549         scope
550     }
551
552     // Finding scopes
553     // ==============
554     /// Finds the breakable scope for a given label. This is used for
555     /// resolving `break` and `continue`.
556     pub fn find_breakable_scope(&self,
557                                 span: Span,
558                                 label: region::Scope)
559                                 -> &BreakableScope<'tcx> {
560         // find the loop-scope with the correct id
561         self.breakable_scopes.iter()
562             .rev()
563             .filter(|breakable_scope| breakable_scope.region_scope == label)
564             .next()
565             .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found"))
566     }
567
568     /// Given a span and the current source scope, make a SourceInfo.
569     pub fn source_info(&self, span: Span) -> SourceInfo {
570         SourceInfo {
571             span,
572             scope: self.source_scope
573         }
574     }
575
576     /// Returns the `region::Scope` of the scope which should be exited by a
577     /// return.
578     pub fn region_scope_of_return_scope(&self) -> region::Scope {
579         // The outermost scope (`scopes[0]`) will be the `CallSiteScope`.
580         // We want `scopes[1]`, which is the `ParameterScope`.
581         assert!(self.scopes.len() >= 2);
582         assert!(match self.scopes[1].region_scope.data {
583             region::ScopeData::Arguments => true,
584             _ => false,
585         });
586         self.scopes[1].region_scope
587     }
588
589     /// Returns the topmost active scope, which is known to be alive until
590     /// the next scope expression.
591     pub fn topmost_scope(&self) -> region::Scope {
592         self.scopes.last().expect("topmost_scope: no scopes present").region_scope
593     }
594
595     /// Returns the scope that we should use as the lifetime of an
596     /// operand. Basically, an operand must live until it is consumed.
597     /// This is similar to, but not quite the same as, the temporary
598     /// scope (which can be larger or smaller).
599     ///
600     /// Consider:
601     ///
602     ///     let x = foo(bar(X, Y));
603     ///
604     /// We wish to pop the storage for X and Y after `bar()` is
605     /// called, not after the whole `let` is completed.
606     ///
607     /// As another example, if the second argument diverges:
608     ///
609     ///     foo(Box::new(2), panic!())
610     ///
611     /// We would allocate the box but then free it on the unwinding
612     /// path; we would also emit a free on the 'success' path from
613     /// panic, but that will turn out to be removed as dead-code.
614     ///
615     /// When building statics/constants, returns `None` since
616     /// intermediate values do not have to be dropped in that case.
617     pub fn local_scope(&self) -> Option<region::Scope> {
618         match self.hir.body_owner_kind {
619             hir::BodyOwnerKind::Const |
620             hir::BodyOwnerKind::Static(_) =>
621                 // No need to free storage in this context.
622                 None,
623             hir::BodyOwnerKind::Closure |
624             hir::BodyOwnerKind::Fn =>
625                 Some(self.topmost_scope()),
626         }
627     }
628
629     // Schedule an abort block - this is used for some ABIs that cannot unwind
630     pub fn schedule_abort(&mut self) -> BasicBlock {
631         self.scopes[0].needs_cleanup = true;
632         let abortblk = self.cfg.start_new_cleanup_block();
633         let source_info = self.scopes[0].source_info(self.fn_span);
634         self.cfg.terminate(abortblk, source_info, TerminatorKind::Abort);
635         self.cached_resume_block = Some(abortblk);
636         abortblk
637     }
638
639     pub fn schedule_drop_storage_and_value(
640         &mut self,
641         span: Span,
642         region_scope: region::Scope,
643         place: &Place<'tcx>,
644         place_ty: Ty<'tcx>,
645     ) {
646         self.schedule_drop(
647             span, region_scope, place, place_ty,
648             DropKind::Storage,
649         );
650         self.schedule_drop(
651             span, region_scope, place, place_ty,
652             DropKind::Value {
653                 cached_block: CachedBlock::default(),
654             },
655         );
656     }
657
658     // Scheduling drops
659     // ================
660     /// Indicates that `place` should be dropped on exit from
661     /// `region_scope`.
662     ///
663     /// When called with `DropKind::Storage`, `place` should be a local
664     /// with an index higher than the current `self.arg_count`.
665     pub fn schedule_drop(
666         &mut self,
667         span: Span,
668         region_scope: region::Scope,
669         place: &Place<'tcx>,
670         place_ty: Ty<'tcx>,
671         drop_kind: DropKind,
672     ) {
673         let needs_drop = self.hir.needs_drop(place_ty);
674         match drop_kind {
675             DropKind::Value { .. } => if !needs_drop { return },
676             DropKind::Storage => {
677                 match *place {
678                     Place::Base(PlaceBase::Local(index)) => if index.index() <= self.arg_count {
679                         span_bug!(
680                             span, "`schedule_drop` called with index {} and arg_count {}",
681                             index.index(),
682                             self.arg_count,
683                         )
684                     },
685                     _ => span_bug!(
686                         span, "`schedule_drop` called with non-`Local` place {:?}", place
687                     ),
688                 }
689             }
690         }
691
692         for scope in self.scopes.iter_mut().rev() {
693             let this_scope = scope.region_scope == region_scope;
694             // When building drops, we try to cache chains of drops in such a way so these drops
695             // could be reused by the drops which would branch into the cached (already built)
696             // blocks.  This, however, means that whenever we add a drop into a scope which already
697             // had some blocks built (and thus, cached) for it, we must invalidate all caches which
698             // might branch into the scope which had a drop just added to it. This is necessary,
699             // because otherwise some other code might use the cache to branch into already built
700             // chain of drops, essentially ignoring the newly added drop.
701             //
702             // For example consider there’s two scopes with a drop in each. These are built and
703             // thus the caches are filled:
704             //
705             // +--------------------------------------------------------+
706             // | +---------------------------------+                    |
707             // | | +--------+     +-------------+  |  +---------------+ |
708             // | | | return | <-+ | drop(outer) | <-+ |  drop(middle) | |
709             // | | +--------+     +-------------+  |  +---------------+ |
710             // | +------------|outer_scope cache|--+                    |
711             // +------------------------------|middle_scope cache|------+
712             //
713             // Now, a new, inner-most scope is added along with a new drop into both inner-most and
714             // outer-most scopes:
715             //
716             // +------------------------------------------------------------+
717             // | +----------------------------------+                       |
718             // | | +--------+      +-------------+  |   +---------------+   | +-------------+
719             // | | | return | <+   | drop(new)   | <-+  |  drop(middle) | <--+| drop(inner) |
720             // | | +--------+  |   | drop(outer) |  |   +---------------+   | +-------------+
721             // | |             +-+ +-------------+  |                       |
722             // | +---|invalid outer_scope cache|----+                       |
723             // +----=----------------|invalid middle_scope cache|-----------+
724             //
725             // If, when adding `drop(new)` we do not invalidate the cached blocks for both
726             // outer_scope and middle_scope, then, when building drops for the inner (right-most)
727             // scope, the old, cached blocks, without `drop(new)` will get used, producing the
728             // wrong results.
729             //
730             // The cache and its invalidation for unwind branch is somewhat special. The cache is
731             // per-drop, rather than per scope, which has a several different implications. Adding
732             // a new drop into a scope will not invalidate cached blocks of the prior drops in the
733             // scope. That is true, because none of the already existing drops will have an edge
734             // into a block with the newly added drop.
735             //
736             // Note that this code iterates scopes from the inner-most to the outer-most,
737             // invalidating caches of each scope visited. This way bare minimum of the
738             // caches gets invalidated. i.e., if a new drop is added into the middle scope, the
739             // cache of outer scope stays intact.
740             scope.invalidate_cache(!needs_drop, this_scope);
741             if this_scope {
742                 if let DropKind::Value { .. } = drop_kind {
743                     scope.needs_cleanup = true;
744                 }
745
746                 let region_scope_span = region_scope.span(self.hir.tcx(),
747                                                           &self.hir.region_scope_tree);
748                 // Attribute scope exit drops to scope's closing brace.
749                 let scope_end = self.hir.tcx().sess.source_map().end_point(region_scope_span);
750
751                 scope.drops.push(DropData {
752                     span: scope_end,
753                     location: place.clone(),
754                     kind: drop_kind
755                 });
756                 return;
757             }
758         }
759         span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, place);
760     }
761
762     // Other
763     // =====
764     /// Creates a path that performs all required cleanup for unwinding.
765     ///
766     /// This path terminates in Resume. Returns the start of the path.
767     /// See module comment for more details.
768     pub fn diverge_cleanup(&mut self) -> BasicBlock {
769         self.diverge_cleanup_gen(false)
770     }
771
772     fn resume_block(&mut self) -> BasicBlock {
773         if let Some(target) = self.cached_resume_block {
774             target
775         } else {
776             let resumeblk = self.cfg.start_new_cleanup_block();
777             self.cfg.terminate(resumeblk,
778                                SourceInfo {
779                                    scope: OUTERMOST_SOURCE_SCOPE,
780                                    span: self.fn_span
781                                },
782                                TerminatorKind::Resume);
783             self.cached_resume_block = Some(resumeblk);
784             resumeblk
785         }
786     }
787
788     fn diverge_cleanup_gen(&mut self, generator_drop: bool) -> BasicBlock {
789         // Build up the drops in **reverse** order. The end result will
790         // look like:
791         //
792         //    scopes[n] -> scopes[n-1] -> ... -> scopes[0]
793         //
794         // However, we build this in **reverse order**. That is, we
795         // process scopes[0], then scopes[1], etc, pointing each one at
796         // the result generates from the one before. Along the way, we
797         // store caches. If everything is cached, we'll just walk right
798         // to left reading the cached results but never created anything.
799
800         // Find the last cached block
801         let (mut target, first_uncached) = if let Some(cached_index) = self.scopes.iter()
802             .rposition(|scope| scope.cached_unwind.get(generator_drop).is_some()) {
803             (self.scopes[cached_index].cached_unwind.get(generator_drop).unwrap(), cached_index + 1)
804         } else {
805             (self.resume_block(), 0)
806         };
807
808         for scope in self.scopes[first_uncached..].iter_mut() {
809             target = build_diverge_scope(&mut self.cfg, scope.region_scope_span,
810                                          scope, target, generator_drop);
811         }
812
813         target
814     }
815
816     /// Utility function for *non*-scope code to build their own drops
817     pub fn build_drop(&mut self,
818                       block: BasicBlock,
819                       span: Span,
820                       location: Place<'tcx>,
821                       ty: Ty<'tcx>) -> BlockAnd<()> {
822         if !self.hir.needs_drop(ty) {
823             return block.unit();
824         }
825         let source_info = self.source_info(span);
826         let next_target = self.cfg.start_new_block();
827         let diverge_target = self.diverge_cleanup();
828         self.cfg.terminate(block, source_info,
829                            TerminatorKind::Drop {
830                                location,
831                                target: next_target,
832                                unwind: Some(diverge_target),
833                            });
834         next_target.unit()
835     }
836
837     /// Utility function for *non*-scope code to build their own drops
838     pub fn build_drop_and_replace(&mut self,
839                                   block: BasicBlock,
840                                   span: Span,
841                                   location: Place<'tcx>,
842                                   value: Operand<'tcx>) -> BlockAnd<()> {
843         let source_info = self.source_info(span);
844         let next_target = self.cfg.start_new_block();
845         let diverge_target = self.diverge_cleanup();
846         self.cfg.terminate(block, source_info,
847                            TerminatorKind::DropAndReplace {
848                                location,
849                                value,
850                                target: next_target,
851                                unwind: Some(diverge_target),
852                            });
853         next_target.unit()
854     }
855
856     /// Creates an Assert terminator and return the success block.
857     /// If the boolean condition operand is not the expected value,
858     /// a runtime panic will be caused with the given message.
859     pub fn assert(&mut self, block: BasicBlock,
860                   cond: Operand<'tcx>,
861                   expected: bool,
862                   msg: AssertMessage<'tcx>,
863                   span: Span)
864                   -> BasicBlock {
865         let source_info = self.source_info(span);
866
867         let success_block = self.cfg.start_new_block();
868         let cleanup = self.diverge_cleanup();
869
870         self.cfg.terminate(block, source_info,
871                            TerminatorKind::Assert {
872                                cond,
873                                expected,
874                                msg,
875                                target: success_block,
876                                cleanup: Some(cleanup),
877                            });
878
879         success_block
880     }
881
882     // `match` arm scopes
883     // ==================
884     /// Unschedules any drops in the top scope.
885     ///
886     /// This is only needed for `match` arm scopes, because they have one
887     /// entrance per pattern, but only one exit.
888     pub fn clear_top_scope(&mut self, region_scope: region::Scope) {
889         let top_scope = self.scopes.last_mut().unwrap();
890
891         assert_eq!(top_scope.region_scope, region_scope);
892
893         top_scope.drops.clear();
894         top_scope.invalidate_cache(false, true);
895     }
896
897     /// Drops the single variable provided
898     ///
899     /// * The scope must be the top scope.
900     /// * The variable must be in that scope.
901     /// * The variable must be at the top of that scope: it's the next thing
902     ///   scheduled to drop.
903     /// * The drop must be of DropKind::Storage.
904     ///
905     /// This is used for the boolean holding the result of the match guard. We
906     /// do this because:
907     ///
908     /// * The boolean is different for each pattern
909     /// * There is only one exit for the arm scope
910     /// * The guard expression scope is too short, it ends just before the
911     ///   boolean is tested.
912     pub fn pop_variable(
913         &mut self,
914         block: BasicBlock,
915         region_scope: region::Scope,
916         variable: Local,
917     ) {
918         let top_scope = self.scopes.last_mut().unwrap();
919
920         assert_eq!(top_scope.region_scope, region_scope);
921
922         let top_drop_data = top_scope.drops.pop().unwrap();
923
924         match top_drop_data.kind {
925             DropKind::Value { .. } => {
926                 bug!("Should not be calling pop_top_variable on non-copy type!")
927             }
928             DropKind::Storage => {
929                 // Drop the storage for both value and storage drops.
930                 // Only temps and vars need their storage dead.
931                 match top_drop_data.location {
932                     Place::Base(PlaceBase::Local(index)) => {
933                         let source_info = top_scope.source_info(top_drop_data.span);
934                         assert_eq!(index, variable);
935                         self.cfg.push(block, Statement {
936                             source_info,
937                             kind: StatementKind::StorageDead(index)
938                         });
939                     }
940                     _ => unreachable!(),
941                 }
942             }
943         }
944
945         top_scope.invalidate_cache(true, true);
946     }
947
948 }
949
950 /// Builds drops for pop_scope and exit_scope.
951 fn build_scope_drops<'tcx>(
952     cfg: &mut CFG<'tcx>,
953     scope: &Scope<'tcx>,
954     mut block: BasicBlock,
955     last_unwind_to: BasicBlock,
956     arg_count: usize,
957     generator_drop: bool,
958 ) -> BlockAnd<()> {
959     debug!("build_scope_drops({:?} -> {:?}", block, scope);
960
961     // Build up the drops in evaluation order. The end result will
962     // look like:
963     //
964     // [SDs, drops[n]] --..> [SDs, drop[1]] -> [SDs, drop[0]] -> [[SDs]]
965     //               |                    |                 |
966     //               :                    |                 |
967     //                                    V                 V
968     // [drop[n]] -...-> [drop[1]] ------> [drop[0]] ------> [last_unwind_to]
969     //
970     // The horizontal arrows represent the execution path when the drops return
971     // successfully. The downwards arrows represent the execution path when the
972     // drops panic (panicking while unwinding will abort, so there's no need for
973     // another set of arrows). The drops for the unwind path should have already
974     // been generated by `diverge_cleanup_gen`.
975     //
976     // The code in this function reads from right to left.
977     // Storage dead drops have to be done left to right (since we can only push
978     // to the end of a Vec). So, we find the next drop and then call
979     // push_storage_deads which will iterate backwards through them so that
980     // they are added in the correct order.
981
982     let mut unwind_blocks = scope.drops.iter().rev().filter_map(|drop_data| {
983         if let DropKind::Value { cached_block } = drop_data.kind {
984             Some(cached_block.get(generator_drop).unwrap_or_else(|| {
985                 span_bug!(drop_data.span, "cached block not present?")
986             }))
987         } else {
988             None
989         }
990     });
991
992     // When we unwind from a drop, we start cleaning up from the next one, so
993     // we don't need this block.
994     unwind_blocks.next();
995
996     for drop_data in scope.drops.iter().rev() {
997         let source_info = scope.source_info(drop_data.span);
998         match drop_data.kind {
999             DropKind::Value { .. } => {
1000                 let unwind_to = unwind_blocks.next().unwrap_or(last_unwind_to);
1001
1002                 let next = cfg.start_new_block();
1003                 cfg.terminate(block, source_info, TerminatorKind::Drop {
1004                     location: drop_data.location.clone(),
1005                     target: next,
1006                     unwind: Some(unwind_to)
1007                 });
1008                 block = next;
1009             }
1010             DropKind::Storage => {
1011                 // We do not need to emit StorageDead for generator drops
1012                 if generator_drop {
1013                     continue
1014                 }
1015
1016                 // Drop the storage for both value and storage drops.
1017                 // Only temps and vars need their storage dead.
1018                 match drop_data.location {
1019                     Place::Base(PlaceBase::Local(index)) if index.index() > arg_count => {
1020                         cfg.push(block, Statement {
1021                             source_info,
1022                             kind: StatementKind::StorageDead(index)
1023                         });
1024                     }
1025                     _ => unreachable!(),
1026                 }
1027             }
1028         }
1029     }
1030     block.unit()
1031 }
1032
1033 fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>,
1034                              span: Span,
1035                              scope: &mut Scope<'tcx>,
1036                              mut target: BasicBlock,
1037                              generator_drop: bool)
1038                              -> BasicBlock
1039 {
1040     // Build up the drops in **reverse** order. The end result will
1041     // look like:
1042     //
1043     //    [drops[n]] -...-> [drops[0]] -> [target]
1044     //
1045     // The code in this function reads from right to left. At each
1046     // point, we check for cached blocks representing the
1047     // remainder. If everything is cached, we'll just walk right to
1048     // left reading the cached results but never create anything.
1049
1050     let source_scope = scope.source_scope;
1051     let source_info = |span| SourceInfo {
1052         span,
1053         scope: source_scope
1054     };
1055
1056     // Next, build up the drops. Here we iterate the vector in
1057     // *forward* order, so that we generate drops[0] first (right to
1058     // left in diagram above).
1059     for (j, drop_data) in scope.drops.iter_mut().enumerate() {
1060         debug!("build_diverge_scope drop_data[{}]: {:?}", j, drop_data);
1061         // Only full value drops are emitted in the diverging path,
1062         // not StorageDead.
1063         //
1064         // Note: This may not actually be what we desire (are we
1065         // "freeing" stack storage as we unwind, or merely observing a
1066         // frozen stack)? In particular, the intent may have been to
1067         // match the behavior of clang, but on inspection eddyb says
1068         // this is not what clang does.
1069         let cached_block = match drop_data.kind {
1070             DropKind::Value { ref mut cached_block } => cached_block.ref_mut(generator_drop),
1071             DropKind::Storage => continue
1072         };
1073         target = if let Some(cached_block) = *cached_block {
1074             cached_block
1075         } else {
1076             let block = cfg.start_new_cleanup_block();
1077             cfg.terminate(block, source_info(drop_data.span),
1078                           TerminatorKind::Drop {
1079                               location: drop_data.location.clone(),
1080                               target,
1081                               unwind: None
1082                           });
1083             *cached_block = Some(block);
1084             block
1085         };
1086     }
1087
1088     *scope.cached_unwind.ref_mut(generator_drop) = Some(target);
1089
1090     debug!("build_diverge_scope({:?}, {:?}) = {:?}", scope, span, target);
1091
1092     target
1093 }