]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/scope.rs
fcd06835d98699d5606906c1063e74fd4d38d968
[rust.git] / src / librustc_mir / build / scope.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12 Managing the scope stack. The scopes are tied to lexical scopes, so as
13 we descend the HAIR, we push a scope on the stack, translate ite
14 contents, and then pop it off. Every scope is named by a
15 `CodeExtent`.
16
17 ### SEME Regions
18
19 When pushing a new scope, we record the current point in the graph (a
20 basic block); this marks the entry to the scope. We then generate more
21 stuff in the control-flow graph. Whenever the scope is exited, either
22 via a `break` or `return` or just by fallthrough, that marks an exit
23 from the scope. Each lexical scope thus corresponds to a single-entry,
24 multiple-exit (SEME) region in the control-flow graph.
25
26 For now, we keep a mapping from each `CodeExtent` to its
27 corresponding SEME region for later reference (see caveat in next
28 paragraph). This is because region scopes are tied to
29 them. Eventually, when we shift to non-lexical lifetimes, there should
30 be no need to remember this mapping.
31
32 There is one additional wrinkle, actually, that I wanted to hide from
33 you but duty compels me to mention. In the course of translating
34 matches, it sometimes happen that certain code (namely guards) gets
35 executed multiple times. This means that the scope lexical scope may
36 in fact correspond to multiple, disjoint SEME regions. So in fact our
37 mapping is from one scope to a vector of SEME regions.
38
39 ### Drops
40
41 The primary purpose for scopes is to insert drops: while translating
42 the contents, we also accumulate lvalues that need to be dropped upon
43 exit from each scope. This is done by calling `schedule_drop`. Once a
44 drop is scheduled, whenever we branch out we will insert drops of all
45 those lvalues onto the outgoing edge. Note that we don't know the full
46 set of scheduled drops up front, and so whenever we exit from the
47 scope we only drop the values scheduled thus far. For example, consider
48 the scope S corresponding to this loop:
49
50 ```rust,ignore
51 loop {
52     let x = ...;
53     if cond { break; }
54     let y = ...;
55 }
56 ```
57
58 When processing the `let x`, we will add one drop to the scope for
59 `x`.  The break will then insert a drop for `x`. When we process `let
60 y`, we will add another drop (in fact, to a subscope, but let's ignore
61 that for now); any later drops would also drop `y`.
62
63 ### Early exit
64
65 There are numerous "normal" ways to early exit a scope: `break`,
66 `continue`, `return` (panics are handled separately). Whenever an
67 early exit occurs, the method `exit_scope` is called. It is given the
68 current point in execution where the early exit occurs, as well as the
69 scope you want to branch to (note that all early exits from to some
70 other enclosing scope). `exit_scope` will record this exit point and
71 also add all drops.
72
73 Panics are handled in a similar fashion, except that a panic always
74 returns out to the `DIVERGE_BLOCK`. To trigger a panic, simply call
75 `panic(p)` with the current point `p`. Or else you can call
76 `diverge_cleanup`, which will produce a block that you can branch to
77 which does the appropriate cleanup and then diverges. `panic(p)`
78 simply calls `diverge_cleanup()` and adds an edge from `p` to the
79 result.
80
81 ### Loop scopes
82
83 In addition to the normal scope stack, we track a loop scope stack
84 that contains only loops. It tracks where a `break` and `continue`
85 should go to.
86
87 */
88
89 use build::{BlockAnd, BlockAndExtension, Builder, CFG};
90 use rustc::middle::region::{CodeExtent, CodeExtentData};
91 use rustc::middle::lang_items;
92 use rustc::middle::const_val::ConstVal;
93 use rustc::ty::subst::{Kind, Subst};
94 use rustc::ty::{Ty, TyCtxt};
95 use rustc::mir::*;
96 use syntax_pos::Span;
97 use rustc_data_structures::indexed_vec::Idx;
98 use rustc_data_structures::fx::FxHashMap;
99
100 pub struct Scope<'tcx> {
101     /// The visibility scope this scope was created in.
102     visibility_scope: VisibilityScope,
103
104     /// the extent of this scope within source code.
105     extent: CodeExtent<'tcx>,
106
107     /// Whether there's anything to do for the cleanup path, that is,
108     /// when unwinding through this scope. This includes destructors,
109     /// but not StorageDead statements, which don't get emitted at all
110     /// for unwinding, for several reasons:
111     ///  * clang doesn't emit llvm.lifetime.end for C++ unwinding
112     ///  * LLVM's memory dependency analysis can't handle it atm
113     ///  * pollutting the cleanup MIR with StorageDead creates
114     ///    landing pads even though there's no actual destructors
115     ///  * freeing up stack space has no effect during unwinding
116     needs_cleanup: bool,
117
118     /// set of lvalues to drop when exiting this scope. This starts
119     /// out empty but grows as variables are declared during the
120     /// building process. This is a stack, so we always drop from the
121     /// end of the vector (top of the stack) first.
122     drops: Vec<DropData<'tcx>>,
123
124     /// A scope may only have one associated free, because:
125     ///
126     /// 1. We require a `free` to only be scheduled in the scope of
127     ///    `EXPR` in `box EXPR`;
128     /// 2. It only makes sense to have it translated into the diverge-path.
129     ///
130     /// This kind of drop will be run *after* all the regular drops
131     /// scheduled onto this scope, because drops may have dependencies
132     /// on the allocated memory.
133     ///
134     /// This is expected to go away once `box EXPR` becomes a sugar
135     /// for placement protocol and gets desugared in some earlier
136     /// stage.
137     free: Option<FreeData<'tcx>>,
138
139     /// The cache for drop chain on “normal” exit into a particular BasicBlock.
140     cached_exits: FxHashMap<(BasicBlock, CodeExtent<'tcx>), BasicBlock>,
141 }
142
143 struct DropData<'tcx> {
144     /// span where drop obligation was incurred (typically where lvalue was declared)
145     span: Span,
146
147     /// lvalue to drop
148     location: Lvalue<'tcx>,
149
150     /// Whether this is a full value Drop, or just a StorageDead.
151     kind: DropKind
152 }
153
154 enum DropKind {
155     Value {
156         /// The cached block for the cleanups-on-diverge path. This block
157         /// contains code to run the current drop and all the preceding
158         /// drops (i.e. those having lower index in Drop’s Scope drop
159         /// array)
160         cached_block: Option<BasicBlock>
161     },
162     Storage
163 }
164
165 struct FreeData<'tcx> {
166     /// span where free obligation was incurred
167     span: Span,
168
169     /// Lvalue containing the allocated box.
170     value: Lvalue<'tcx>,
171
172     /// type of item for which the box was allocated for (i.e. the T in Box<T>).
173     item_ty: Ty<'tcx>,
174
175     /// The cached block containing code to run the free. The block will also execute all the drops
176     /// in the scope.
177     cached_block: Option<BasicBlock>
178 }
179
180 #[derive(Clone, Debug)]
181 pub struct BreakableScope<'tcx> {
182     /// Extent of the loop
183     pub extent: CodeExtent<'tcx>,
184     /// Where the body of the loop begins. `None` if block
185     pub continue_block: Option<BasicBlock>,
186     /// Block to branch into when the loop or block terminates (either by being `break`-en out
187     /// from, or by having its condition to become false)
188     pub break_block: BasicBlock,
189     /// The destination of the loop/block expression itself (i.e. where to put the result of a
190     /// `break` expression)
191     pub break_destination: Lvalue<'tcx>,
192 }
193
194 impl<'tcx> Scope<'tcx> {
195     /// Invalidate all the cached blocks in the scope.
196     ///
197     /// Should always be run for all inner scopes when a drop is pushed into some scope enclosing a
198     /// larger extent of code.
199     ///
200     /// `unwind` controls whether caches for the unwind branch are also invalidated.
201     fn invalidate_cache(&mut self, unwind: bool) {
202         self.cached_exits.clear();
203         if !unwind { return; }
204         for dropdata in &mut self.drops {
205             if let DropKind::Value { ref mut cached_block } = dropdata.kind {
206                 *cached_block = None;
207             }
208         }
209         if let Some(ref mut freedata) = self.free {
210             freedata.cached_block = None;
211         }
212     }
213
214     /// Returns the cached entrypoint for diverging exit from this scope.
215     ///
216     /// Precondition: the caches must be fully filled (i.e. diverge_cleanup is called) in order for
217     /// this method to work correctly.
218     fn cached_block(&self) -> Option<BasicBlock> {
219         let mut drops = self.drops.iter().rev().filter_map(|data| {
220             match data.kind {
221                 DropKind::Value { cached_block } => Some(cached_block),
222                 DropKind::Storage => None
223             }
224         });
225         if let Some(cached_block) = drops.next() {
226             Some(cached_block.expect("drop cache is not filled"))
227         } else if let Some(ref data) = self.free {
228             Some(data.cached_block.expect("free cache is not filled"))
229         } else {
230             None
231         }
232     }
233
234     /// Given a span and this scope's visibility scope, make a SourceInfo.
235     fn source_info(&self, span: Span) -> SourceInfo {
236         SourceInfo {
237             span: span,
238             scope: self.visibility_scope
239         }
240     }
241 }
242
243 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
244     // Adding and removing scopes
245     // ==========================
246     /// Start a breakable scope, which tracks where `continue` and `break`
247     /// should branch to. See module comment for more details.
248     ///
249     /// Returns the might_break attribute of the BreakableScope used.
250     pub fn in_breakable_scope<F, R>(&mut self,
251                                     loop_block: Option<BasicBlock>,
252                                     break_block: BasicBlock,
253                                     break_destination: Lvalue<'tcx>,
254                                     f: F) -> R
255         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> R
256     {
257         let extent = self.topmost_scope();
258         let scope = BreakableScope {
259             extent: extent,
260             continue_block: loop_block,
261             break_block: break_block,
262             break_destination: break_destination,
263         };
264         self.breakable_scopes.push(scope);
265         let res = f(self);
266         let breakable_scope = self.breakable_scopes.pop().unwrap();
267         assert!(breakable_scope.extent == extent);
268         res
269     }
270
271     /// Convenience wrapper that pushes a scope and then executes `f`
272     /// to build its contents, popping the scope afterwards.
273     pub fn in_scope<F, R>(&mut self, extent: CodeExtent<'tcx>, mut block: BasicBlock, f: F) -> BlockAnd<R>
274         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd<R>
275     {
276         debug!("in_scope(extent={:?}, block={:?})", extent, block);
277         self.push_scope(extent);
278         let rv = unpack!(block = f(self));
279         unpack!(block = self.pop_scope(extent, block));
280         debug!("in_scope: exiting extent={:?} block={:?}", extent, block);
281         block.and(rv)
282     }
283
284     /// Push a scope onto the stack. You can then build code in this
285     /// scope and call `pop_scope` afterwards. Note that these two
286     /// calls must be paired; using `in_scope` as a convenience
287     /// wrapper maybe preferable.
288     pub fn push_scope(&mut self, extent: CodeExtent<'tcx>) {
289         debug!("push_scope({:?})", extent);
290         let vis_scope = self.visibility_scope;
291         self.scopes.push(Scope {
292             visibility_scope: vis_scope,
293             extent: extent,
294             needs_cleanup: false,
295             drops: vec![],
296             free: None,
297             cached_exits: FxHashMap()
298         });
299     }
300
301     /// Pops a scope, which should have extent `extent`, adding any
302     /// drops onto the end of `block` that are needed.  This must
303     /// match 1-to-1 with `push_scope`.
304     pub fn pop_scope(&mut self,
305                      extent: CodeExtent<'tcx>,
306                      mut block: BasicBlock)
307                      -> BlockAnd<()> {
308         debug!("pop_scope({:?}, {:?})", extent, block);
309         // We need to have `cached_block`s available for all the drops, so we call diverge_cleanup
310         // to make sure all the `cached_block`s are filled in.
311         self.diverge_cleanup();
312         let scope = self.scopes.pop().unwrap();
313         assert_eq!(scope.extent, extent);
314         unpack!(block = build_scope_drops(&mut self.cfg,
315                                           &scope,
316                                           &self.scopes,
317                                           block,
318                                           self.arg_count));
319         block.unit()
320     }
321
322
323     /// Branch out of `block` to `target`, exiting all scopes up to
324     /// and including `extent`.  This will insert whatever drops are
325     /// needed, as well as tracking this exit for the SEME region. See
326     /// module comment for details.
327     pub fn exit_scope(&mut self,
328                       span: Span,
329                       extent: CodeExtent<'tcx>,
330                       mut block: BasicBlock,
331                       target: BasicBlock) {
332         debug!("exit_scope(extent={:?}, block={:?}, target={:?})", extent, block, target);
333         let scope_count = 1 + self.scopes.iter().rev().position(|scope| scope.extent == extent)
334                                                       .unwrap_or_else(||{
335             span_bug!(span, "extent {:?} does not enclose", extent)
336         });
337         let len = self.scopes.len();
338         assert!(scope_count < len, "should not use `exit_scope` to pop ALL scopes");
339         let tmp = self.get_unit_temp();
340         {
341         let mut rest = &mut self.scopes[(len - scope_count)..];
342         while let Some((scope, rest_)) = {rest}.split_last_mut() {
343             rest = rest_;
344             block = if let Some(&e) = scope.cached_exits.get(&(target, extent)) {
345                 self.cfg.terminate(block, scope.source_info(span),
346                                    TerminatorKind::Goto { target: e });
347                 return;
348             } else {
349                 let b = self.cfg.start_new_block();
350                 self.cfg.terminate(block, scope.source_info(span),
351                                    TerminatorKind::Goto { target: b });
352                 scope.cached_exits.insert((target, extent), b);
353                 b
354             };
355             unpack!(block = build_scope_drops(&mut self.cfg,
356                                               scope,
357                                               rest,
358                                               block,
359                                               self.arg_count));
360             if let Some(ref free_data) = scope.free {
361                 let next = self.cfg.start_new_block();
362                 let free = build_free(self.hir.tcx(), &tmp, free_data, next);
363                 self.cfg.terminate(block, scope.source_info(span), free);
364                 block = next;
365             }
366         }
367         }
368         let scope = &self.scopes[len - scope_count];
369         self.cfg.terminate(block, scope.source_info(span),
370                            TerminatorKind::Goto { target: target });
371     }
372
373     /// Creates a new visibility scope, nested in the current one.
374     pub fn new_visibility_scope(&mut self, span: Span) -> VisibilityScope {
375         let parent = self.visibility_scope;
376         let scope = VisibilityScope::new(self.visibility_scopes.len());
377         self.visibility_scopes.push(VisibilityScopeData {
378             span: span,
379             parent_scope: Some(parent),
380         });
381         scope
382     }
383
384     // Finding scopes
385     // ==============
386     /// Finds the breakable scope for a given label. This is used for
387     /// resolving `break` and `continue`.
388     pub fn find_breakable_scope(&mut self,
389                            span: Span,
390                            label: CodeExtent<'tcx>)
391                            -> &mut BreakableScope<'tcx> {
392         // find the loop-scope with the correct id
393         self.breakable_scopes.iter_mut()
394             .rev()
395             .filter(|breakable_scope| breakable_scope.extent == label)
396             .next()
397             .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found"))
398     }
399
400     /// Given a span and the current visibility scope, make a SourceInfo.
401     pub fn source_info(&self, span: Span) -> SourceInfo {
402         SourceInfo {
403             span: span,
404             scope: self.visibility_scope
405         }
406     }
407
408     /// Returns the extent of the scope which should be exited by a
409     /// return.
410     pub fn extent_of_return_scope(&self) -> CodeExtent<'tcx> {
411         // The outermost scope (`scopes[0]`) will be the `CallSiteScope`.
412         // We want `scopes[1]`, which is the `ParameterScope`.
413         assert!(self.scopes.len() >= 2);
414         assert!(match *self.scopes[1].extent {
415             CodeExtentData::ParameterScope { .. } => true,
416             _ => false,
417         });
418         self.scopes[1].extent
419     }
420
421     /// Returns the topmost active scope, which is known to be alive until
422     /// the next scope expression.
423     pub fn topmost_scope(&self) -> CodeExtent<'tcx> {
424         self.scopes.last().expect("topmost_scope: no scopes present").extent
425     }
426
427     // Scheduling drops
428     // ================
429     /// Indicates that `lvalue` should be dropped on exit from
430     /// `extent`.
431     pub fn schedule_drop(&mut self,
432                          span: Span,
433                          extent: CodeExtent<'tcx>,
434                          lvalue: &Lvalue<'tcx>,
435                          lvalue_ty: Ty<'tcx>) {
436         let needs_drop = self.hir.needs_drop(lvalue_ty);
437         let drop_kind = if needs_drop {
438             DropKind::Value { cached_block: None }
439         } else {
440             // Only temps and vars need their storage dead.
441             match *lvalue {
442                 Lvalue::Local(index) if index.index() > self.arg_count => DropKind::Storage,
443                 _ => return
444             }
445         };
446
447         for scope in self.scopes.iter_mut().rev() {
448             let this_scope = scope.extent == extent;
449             // When building drops, we try to cache chains of drops in such a way so these drops
450             // could be reused by the drops which would branch into the cached (already built)
451             // blocks.  This, however, means that whenever we add a drop into a scope which already
452             // had some blocks built (and thus, cached) for it, we must invalidate all caches which
453             // might branch into the scope which had a drop just added to it. This is necessary,
454             // because otherwise some other code might use the cache to branch into already built
455             // chain of drops, essentially ignoring the newly added drop.
456             //
457             // For example consider there’s two scopes with a drop in each. These are built and
458             // thus the caches are filled:
459             //
460             // +--------------------------------------------------------+
461             // | +---------------------------------+                    |
462             // | | +--------+     +-------------+  |  +---------------+ |
463             // | | | return | <-+ | drop(outer) | <-+ |  drop(middle) | |
464             // | | +--------+     +-------------+  |  +---------------+ |
465             // | +------------|outer_scope cache|--+                    |
466             // +------------------------------|middle_scope cache|------+
467             //
468             // Now, a new, inner-most scope is added along with a new drop into both inner-most and
469             // outer-most scopes:
470             //
471             // +------------------------------------------------------------+
472             // | +----------------------------------+                       |
473             // | | +--------+      +-------------+  |   +---------------+   | +-------------+
474             // | | | return | <+   | drop(new)   | <-+  |  drop(middle) | <--+| drop(inner) |
475             // | | +--------+  |   | drop(outer) |  |   +---------------+   | +-------------+
476             // | |             +-+ +-------------+  |                       |
477             // | +---|invalid outer_scope cache|----+                       |
478             // +----=----------------|invalid middle_scope cache|-----------+
479             //
480             // If, when adding `drop(new)` we do not invalidate the cached blocks for both
481             // outer_scope and middle_scope, then, when building drops for the inner (right-most)
482             // scope, the old, cached blocks, without `drop(new)` will get used, producing the
483             // wrong results.
484             //
485             // The cache and its invalidation for unwind branch is somewhat special. The cache is
486             // per-drop, rather than per scope, which has a several different implications. Adding
487             // a new drop into a scope will not invalidate cached blocks of the prior drops in the
488             // scope. That is true, because none of the already existing drops will have an edge
489             // into a block with the newly added drop.
490             //
491             // Note that this code iterates scopes from the inner-most to the outer-most,
492             // invalidating caches of each scope visited. This way bare minimum of the
493             // caches gets invalidated. i.e. if a new drop is added into the middle scope, the
494             // cache of outer scpoe stays intact.
495             let invalidate_unwind = needs_drop && !this_scope;
496             scope.invalidate_cache(invalidate_unwind);
497             if this_scope {
498                 if let DropKind::Value { .. } = drop_kind {
499                     scope.needs_cleanup = true;
500                 }
501                 let tcx = self.hir.tcx();
502                 let extent_span = extent.span(&tcx.hir).unwrap();
503                 // Attribute scope exit drops to scope's closing brace
504                 let scope_end = Span { lo: extent_span.hi, .. extent_span};
505                 scope.drops.push(DropData {
506                     span: scope_end,
507                     location: lvalue.clone(),
508                     kind: drop_kind
509                 });
510                 return;
511             }
512         }
513         span_bug!(span, "extent {:?} not in scope to drop {:?}", extent, lvalue);
514     }
515
516     /// Schedule dropping of a not-yet-fully-initialised box.
517     ///
518     /// This cleanup will only be translated into unwind branch.
519     /// The extent should be for the `EXPR` inside `box EXPR`.
520     /// There may only be one “free” scheduled in any given scope.
521     pub fn schedule_box_free(&mut self,
522                              span: Span,
523                              extent: CodeExtent<'tcx>,
524                              value: &Lvalue<'tcx>,
525                              item_ty: Ty<'tcx>) {
526         for scope in self.scopes.iter_mut().rev() {
527             // See the comment in schedule_drop above. The primary difference is that we invalidate
528             // the unwind blocks unconditionally. That’s because the box free may be considered
529             // outer-most cleanup within the scope.
530             scope.invalidate_cache(true);
531             if scope.extent == extent {
532                 assert!(scope.free.is_none(), "scope already has a scheduled free!");
533                 scope.needs_cleanup = true;
534                 scope.free = Some(FreeData {
535                     span: span,
536                     value: value.clone(),
537                     item_ty: item_ty,
538                     cached_block: None
539                 });
540                 return;
541             }
542         }
543         span_bug!(span, "extent {:?} not in scope to free {:?}", extent, value);
544     }
545
546     // Other
547     // =====
548     /// Creates a path that performs all required cleanup for unwinding.
549     ///
550     /// This path terminates in Resume. Returns the start of the path.
551     /// See module comment for more details. None indicates there’s no
552     /// cleanup to do at this point.
553     pub fn diverge_cleanup(&mut self) -> Option<BasicBlock> {
554         if !self.scopes.iter().any(|scope| scope.needs_cleanup) {
555             return None;
556         }
557         assert!(!self.scopes.is_empty()); // or `any` above would be false
558
559         let unit_temp = self.get_unit_temp();
560         let Builder { ref mut hir, ref mut cfg, ref mut scopes,
561                       ref mut cached_resume_block, .. } = *self;
562
563         // Build up the drops in **reverse** order. The end result will
564         // look like:
565         //
566         //    scopes[n] -> scopes[n-1] -> ... -> scopes[0]
567         //
568         // However, we build this in **reverse order**. That is, we
569         // process scopes[0], then scopes[1], etc, pointing each one at
570         // the result generates from the one before. Along the way, we
571         // store caches. If everything is cached, we'll just walk right
572         // to left reading the cached results but never created anything.
573
574         // To start, create the resume terminator.
575         let mut target = if let Some(target) = *cached_resume_block {
576             target
577         } else {
578             let resumeblk = cfg.start_new_cleanup_block();
579             cfg.terminate(resumeblk,
580                           scopes[0].source_info(self.fn_span),
581                           TerminatorKind::Resume);
582             *cached_resume_block = Some(resumeblk);
583             resumeblk
584         };
585
586         for scope in scopes.iter_mut().filter(|s| s.needs_cleanup) {
587             target = build_diverge_scope(hir.tcx(), cfg, &unit_temp, scope, target);
588         }
589         Some(target)
590     }
591
592     /// Utility function for *non*-scope code to build their own drops
593     pub fn build_drop(&mut self,
594                       block: BasicBlock,
595                       span: Span,
596                       location: Lvalue<'tcx>,
597                       ty: Ty<'tcx>) -> BlockAnd<()> {
598         if !self.hir.needs_drop(ty) {
599             return block.unit();
600         }
601         let source_info = self.source_info(span);
602         let next_target = self.cfg.start_new_block();
603         let diverge_target = self.diverge_cleanup();
604         self.cfg.terminate(block, source_info,
605                            TerminatorKind::Drop {
606                                location: location,
607                                target: next_target,
608                                unwind: diverge_target,
609                            });
610         next_target.unit()
611     }
612
613     /// Utility function for *non*-scope code to build their own drops
614     pub fn build_drop_and_replace(&mut self,
615                                   block: BasicBlock,
616                                   span: Span,
617                                   location: Lvalue<'tcx>,
618                                   value: Operand<'tcx>) -> BlockAnd<()> {
619         let source_info = self.source_info(span);
620         let next_target = self.cfg.start_new_block();
621         let diverge_target = self.diverge_cleanup();
622         self.cfg.terminate(block, source_info,
623                            TerminatorKind::DropAndReplace {
624                                location: location,
625                                value: value,
626                                target: next_target,
627                                unwind: diverge_target,
628                            });
629         next_target.unit()
630     }
631
632     /// Create an Assert terminator and return the success block.
633     /// If the boolean condition operand is not the expected value,
634     /// a runtime panic will be caused with the given message.
635     pub fn assert(&mut self, block: BasicBlock,
636                   cond: Operand<'tcx>,
637                   expected: bool,
638                   msg: AssertMessage<'tcx>,
639                   span: Span)
640                   -> BasicBlock {
641         let source_info = self.source_info(span);
642
643         let success_block = self.cfg.start_new_block();
644         let cleanup = self.diverge_cleanup();
645
646         self.cfg.terminate(block, source_info,
647                            TerminatorKind::Assert {
648                                cond: cond,
649                                expected: expected,
650                                msg: msg,
651                                target: success_block,
652                                cleanup: cleanup
653                            });
654
655         success_block
656     }
657 }
658
659 /// Builds drops for pop_scope and exit_scope.
660 fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
661                            scope: &Scope<'tcx>,
662                            earlier_scopes: &[Scope<'tcx>],
663                            mut block: BasicBlock,
664                            arg_count: usize)
665                            -> BlockAnd<()> {
666     let mut iter = scope.drops.iter().rev().peekable();
667     while let Some(drop_data) = iter.next() {
668         let source_info = scope.source_info(drop_data.span);
669         if let DropKind::Value { .. } = drop_data.kind {
670             // Try to find the next block with its cached block
671             // for us to diverge into in case the drop panics.
672             let on_diverge = iter.peek().iter().filter_map(|dd| {
673                 match dd.kind {
674                     DropKind::Value { cached_block } => cached_block,
675                     DropKind::Storage => None
676                 }
677             }).next();
678             // If there’s no `cached_block`s within current scope,
679             // we must look for one in the enclosing scope.
680             let on_diverge = on_diverge.or_else(||{
681                 earlier_scopes.iter().rev().flat_map(|s| s.cached_block()).next()
682             });
683             let next = cfg.start_new_block();
684             cfg.terminate(block, source_info, TerminatorKind::Drop {
685                 location: drop_data.location.clone(),
686                 target: next,
687                 unwind: on_diverge
688             });
689             block = next;
690         }
691         match drop_data.kind {
692             DropKind::Value { .. } |
693             DropKind::Storage => {
694                 // Only temps and vars need their storage dead.
695                 match drop_data.location {
696                     Lvalue::Local(index) if index.index() > arg_count => {}
697                     _ => continue
698                 }
699
700                 cfg.push(block, Statement {
701                     source_info: source_info,
702                     kind: StatementKind::StorageDead(drop_data.location.clone())
703                 });
704             }
705         }
706     }
707     block.unit()
708 }
709
710 fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
711                                        cfg: &mut CFG<'tcx>,
712                                        unit_temp: &Lvalue<'tcx>,
713                                        scope: &mut Scope<'tcx>,
714                                        mut target: BasicBlock)
715                                        -> BasicBlock
716 {
717     // Build up the drops in **reverse** order. The end result will
718     // look like:
719     //
720     //    [drops[n]] -...-> [drops[0]] -> [Free] -> [target]
721     //    |                                    |
722     //    +------------------------------------+
723     //     code for scope
724     //
725     // The code in this function reads from right to left. At each
726     // point, we check for cached blocks representing the
727     // remainder. If everything is cached, we'll just walk right to
728     // left reading the cached results but never created anything.
729
730     let visibility_scope = scope.visibility_scope;
731     let source_info = |span| SourceInfo {
732         span: span,
733         scope: visibility_scope
734     };
735
736     // Next, build up any free.
737     if let Some(ref mut free_data) = scope.free {
738         target = if let Some(cached_block) = free_data.cached_block {
739             cached_block
740         } else {
741             let into = cfg.start_new_cleanup_block();
742             cfg.terminate(into, source_info(free_data.span),
743                           build_free(tcx, unit_temp, free_data, target));
744             free_data.cached_block = Some(into);
745             into
746         };
747     }
748
749     // Next, build up the drops. Here we iterate the vector in
750     // *forward* order, so that we generate drops[0] first (right to
751     // left in diagram above).
752     for drop_data in &mut scope.drops {
753         // Only full value drops are emitted in the diverging path,
754         // not StorageDead.
755         let cached_block = match drop_data.kind {
756             DropKind::Value { ref mut cached_block } => cached_block,
757             DropKind::Storage => continue
758         };
759         target = if let Some(cached_block) = *cached_block {
760             cached_block
761         } else {
762             let block = cfg.start_new_cleanup_block();
763             cfg.terminate(block, source_info(drop_data.span),
764                           TerminatorKind::Drop {
765                               location: drop_data.location.clone(),
766                               target: target,
767                               unwind: None
768                           });
769             *cached_block = Some(block);
770             block
771         };
772     }
773
774     target
775 }
776
777 fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
778                               unit_temp: &Lvalue<'tcx>,
779                               data: &FreeData<'tcx>,
780                               target: BasicBlock)
781                               -> TerminatorKind<'tcx> {
782     let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem);
783     let substs = tcx.intern_substs(&[Kind::from(data.item_ty)]);
784     TerminatorKind::Call {
785         func: Operand::Constant(Constant {
786             span: data.span,
787             ty: tcx.type_of(free_func).subst(tcx, substs),
788             literal: Literal::Value {
789                 value: ConstVal::Function(free_func, substs),
790             }
791         }),
792         args: vec![Operand::Consume(data.value.clone())],
793         destination: Some((unit_temp.clone(), target)),
794         cleanup: None
795     }
796 }