]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/build/scope.rs
pacify the mercilous tidy
[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,
274                           extent: CodeExtent<'tcx>,
275                           mut block: BasicBlock,
276                           f: F)
277                           -> BlockAnd<R>
278         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd<R>
279     {
280         debug!("in_scope(extent={:?}, block={:?})", extent, block);
281         self.push_scope(extent);
282         let rv = unpack!(block = f(self));
283         unpack!(block = self.pop_scope(extent, block));
284         debug!("in_scope: exiting extent={:?} block={:?}", extent, block);
285         block.and(rv)
286     }
287
288     /// Push a scope onto the stack. You can then build code in this
289     /// scope and call `pop_scope` afterwards. Note that these two
290     /// calls must be paired; using `in_scope` as a convenience
291     /// wrapper maybe preferable.
292     pub fn push_scope(&mut self, extent: CodeExtent<'tcx>) {
293         debug!("push_scope({:?})", extent);
294         let vis_scope = self.visibility_scope;
295         self.scopes.push(Scope {
296             visibility_scope: vis_scope,
297             extent: extent,
298             needs_cleanup: false,
299             drops: vec![],
300             free: None,
301             cached_exits: FxHashMap()
302         });
303     }
304
305     /// Pops a scope, which should have extent `extent`, adding any
306     /// drops onto the end of `block` that are needed.  This must
307     /// match 1-to-1 with `push_scope`.
308     pub fn pop_scope(&mut self,
309                      extent: CodeExtent<'tcx>,
310                      mut block: BasicBlock)
311                      -> BlockAnd<()> {
312         debug!("pop_scope({:?}, {:?})", extent, block);
313         // We need to have `cached_block`s available for all the drops, so we call diverge_cleanup
314         // to make sure all the `cached_block`s are filled in.
315         self.diverge_cleanup();
316         let scope = self.scopes.pop().unwrap();
317         assert_eq!(scope.extent, extent);
318         unpack!(block = build_scope_drops(&mut self.cfg,
319                                           &scope,
320                                           &self.scopes,
321                                           block,
322                                           self.arg_count));
323         block.unit()
324     }
325
326
327     /// Branch out of `block` to `target`, exiting all scopes up to
328     /// and including `extent`.  This will insert whatever drops are
329     /// needed, as well as tracking this exit for the SEME region. See
330     /// module comment for details.
331     pub fn exit_scope(&mut self,
332                       span: Span,
333                       extent: CodeExtent<'tcx>,
334                       mut block: BasicBlock,
335                       target: BasicBlock) {
336         debug!("exit_scope(extent={:?}, block={:?}, target={:?})", extent, block, target);
337         let scope_count = 1 + self.scopes.iter().rev().position(|scope| scope.extent == extent)
338                                                       .unwrap_or_else(||{
339             span_bug!(span, "extent {:?} does not enclose", extent)
340         });
341         let len = self.scopes.len();
342         assert!(scope_count < len, "should not use `exit_scope` to pop ALL scopes");
343         let tmp = self.get_unit_temp();
344         {
345         let mut rest = &mut self.scopes[(len - scope_count)..];
346         while let Some((scope, rest_)) = {rest}.split_last_mut() {
347             rest = rest_;
348             block = if let Some(&e) = scope.cached_exits.get(&(target, extent)) {
349                 self.cfg.terminate(block, scope.source_info(span),
350                                    TerminatorKind::Goto { target: e });
351                 return;
352             } else {
353                 let b = self.cfg.start_new_block();
354                 self.cfg.terminate(block, scope.source_info(span),
355                                    TerminatorKind::Goto { target: b });
356                 scope.cached_exits.insert((target, extent), b);
357                 b
358             };
359             unpack!(block = build_scope_drops(&mut self.cfg,
360                                               scope,
361                                               rest,
362                                               block,
363                                               self.arg_count));
364             if let Some(ref free_data) = scope.free {
365                 let next = self.cfg.start_new_block();
366                 let free = build_free(self.hir.tcx(), &tmp, free_data, next);
367                 self.cfg.terminate(block, scope.source_info(span), free);
368                 block = next;
369             }
370         }
371         }
372         let scope = &self.scopes[len - scope_count];
373         self.cfg.terminate(block, scope.source_info(span),
374                            TerminatorKind::Goto { target: target });
375     }
376
377     /// Creates a new visibility scope, nested in the current one.
378     pub fn new_visibility_scope(&mut self, span: Span) -> VisibilityScope {
379         let parent = self.visibility_scope;
380         let scope = VisibilityScope::new(self.visibility_scopes.len());
381         self.visibility_scopes.push(VisibilityScopeData {
382             span: span,
383             parent_scope: Some(parent),
384         });
385         scope
386     }
387
388     // Finding scopes
389     // ==============
390     /// Finds the breakable scope for a given label. This is used for
391     /// resolving `break` and `continue`.
392     pub fn find_breakable_scope(&mut self,
393                            span: Span,
394                            label: CodeExtent<'tcx>)
395                            -> &mut BreakableScope<'tcx> {
396         // find the loop-scope with the correct id
397         self.breakable_scopes.iter_mut()
398             .rev()
399             .filter(|breakable_scope| breakable_scope.extent == label)
400             .next()
401             .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found"))
402     }
403
404     /// Given a span and the current visibility scope, make a SourceInfo.
405     pub fn source_info(&self, span: Span) -> SourceInfo {
406         SourceInfo {
407             span: span,
408             scope: self.visibility_scope
409         }
410     }
411
412     /// Returns the extent of the scope which should be exited by a
413     /// return.
414     pub fn extent_of_return_scope(&self) -> CodeExtent<'tcx> {
415         // The outermost scope (`scopes[0]`) will be the `CallSiteScope`.
416         // We want `scopes[1]`, which is the `ParameterScope`.
417         assert!(self.scopes.len() >= 2);
418         assert!(match *self.scopes[1].extent {
419             CodeExtentData::ParameterScope { .. } => true,
420             _ => false,
421         });
422         self.scopes[1].extent
423     }
424
425     /// Returns the topmost active scope, which is known to be alive until
426     /// the next scope expression.
427     pub fn topmost_scope(&self) -> CodeExtent<'tcx> {
428         self.scopes.last().expect("topmost_scope: no scopes present").extent
429     }
430
431     // Scheduling drops
432     // ================
433     /// Indicates that `lvalue` should be dropped on exit from
434     /// `extent`.
435     pub fn schedule_drop(&mut self,
436                          span: Span,
437                          extent: CodeExtent<'tcx>,
438                          lvalue: &Lvalue<'tcx>,
439                          lvalue_ty: Ty<'tcx>) {
440         let needs_drop = self.hir.needs_drop(lvalue_ty);
441         let drop_kind = if needs_drop {
442             DropKind::Value { cached_block: None }
443         } else {
444             // Only temps and vars need their storage dead.
445             match *lvalue {
446                 Lvalue::Local(index) if index.index() > self.arg_count => DropKind::Storage,
447                 _ => return
448             }
449         };
450
451         for scope in self.scopes.iter_mut().rev() {
452             let this_scope = scope.extent == extent;
453             // When building drops, we try to cache chains of drops in such a way so these drops
454             // could be reused by the drops which would branch into the cached (already built)
455             // blocks.  This, however, means that whenever we add a drop into a scope which already
456             // had some blocks built (and thus, cached) for it, we must invalidate all caches which
457             // might branch into the scope which had a drop just added to it. This is necessary,
458             // because otherwise some other code might use the cache to branch into already built
459             // chain of drops, essentially ignoring the newly added drop.
460             //
461             // For example consider there’s two scopes with a drop in each. These are built and
462             // thus the caches are filled:
463             //
464             // +--------------------------------------------------------+
465             // | +---------------------------------+                    |
466             // | | +--------+     +-------------+  |  +---------------+ |
467             // | | | return | <-+ | drop(outer) | <-+ |  drop(middle) | |
468             // | | +--------+     +-------------+  |  +---------------+ |
469             // | +------------|outer_scope cache|--+                    |
470             // +------------------------------|middle_scope cache|------+
471             //
472             // Now, a new, inner-most scope is added along with a new drop into both inner-most and
473             // outer-most scopes:
474             //
475             // +------------------------------------------------------------+
476             // | +----------------------------------+                       |
477             // | | +--------+      +-------------+  |   +---------------+   | +-------------+
478             // | | | return | <+   | drop(new)   | <-+  |  drop(middle) | <--+| drop(inner) |
479             // | | +--------+  |   | drop(outer) |  |   +---------------+   | +-------------+
480             // | |             +-+ +-------------+  |                       |
481             // | +---|invalid outer_scope cache|----+                       |
482             // +----=----------------|invalid middle_scope cache|-----------+
483             //
484             // If, when adding `drop(new)` we do not invalidate the cached blocks for both
485             // outer_scope and middle_scope, then, when building drops for the inner (right-most)
486             // scope, the old, cached blocks, without `drop(new)` will get used, producing the
487             // wrong results.
488             //
489             // The cache and its invalidation for unwind branch is somewhat special. The cache is
490             // per-drop, rather than per scope, which has a several different implications. Adding
491             // a new drop into a scope will not invalidate cached blocks of the prior drops in the
492             // scope. That is true, because none of the already existing drops will have an edge
493             // into a block with the newly added drop.
494             //
495             // Note that this code iterates scopes from the inner-most to the outer-most,
496             // invalidating caches of each scope visited. This way bare minimum of the
497             // caches gets invalidated. i.e. if a new drop is added into the middle scope, the
498             // cache of outer scpoe stays intact.
499             let invalidate_unwind = needs_drop && !this_scope;
500             scope.invalidate_cache(invalidate_unwind);
501             if this_scope {
502                 if let DropKind::Value { .. } = drop_kind {
503                     scope.needs_cleanup = true;
504                 }
505                 let tcx = self.hir.tcx();
506                 let extent_span = extent.span(&tcx.hir).unwrap();
507                 // Attribute scope exit drops to scope's closing brace
508                 let scope_end = Span { lo: extent_span.hi, .. extent_span};
509                 scope.drops.push(DropData {
510                     span: scope_end,
511                     location: lvalue.clone(),
512                     kind: drop_kind
513                 });
514                 return;
515             }
516         }
517         span_bug!(span, "extent {:?} not in scope to drop {:?}", extent, lvalue);
518     }
519
520     /// Schedule dropping of a not-yet-fully-initialised box.
521     ///
522     /// This cleanup will only be translated into unwind branch.
523     /// The extent should be for the `EXPR` inside `box EXPR`.
524     /// There may only be one “free” scheduled in any given scope.
525     pub fn schedule_box_free(&mut self,
526                              span: Span,
527                              extent: CodeExtent<'tcx>,
528                              value: &Lvalue<'tcx>,
529                              item_ty: Ty<'tcx>) {
530         for scope in self.scopes.iter_mut().rev() {
531             // See the comment in schedule_drop above. The primary difference is that we invalidate
532             // the unwind blocks unconditionally. That’s because the box free may be considered
533             // outer-most cleanup within the scope.
534             scope.invalidate_cache(true);
535             if scope.extent == extent {
536                 assert!(scope.free.is_none(), "scope already has a scheduled free!");
537                 scope.needs_cleanup = true;
538                 scope.free = Some(FreeData {
539                     span: span,
540                     value: value.clone(),
541                     item_ty: item_ty,
542                     cached_block: None
543                 });
544                 return;
545             }
546         }
547         span_bug!(span, "extent {:?} not in scope to free {:?}", extent, value);
548     }
549
550     // Other
551     // =====
552     /// Creates a path that performs all required cleanup for unwinding.
553     ///
554     /// This path terminates in Resume. Returns the start of the path.
555     /// See module comment for more details. None indicates there’s no
556     /// cleanup to do at this point.
557     pub fn diverge_cleanup(&mut self) -> Option<BasicBlock> {
558         if !self.scopes.iter().any(|scope| scope.needs_cleanup) {
559             return None;
560         }
561         assert!(!self.scopes.is_empty()); // or `any` above would be false
562
563         let unit_temp = self.get_unit_temp();
564         let Builder { ref mut hir, ref mut cfg, ref mut scopes,
565                       ref mut cached_resume_block, .. } = *self;
566
567         // Build up the drops in **reverse** order. The end result will
568         // look like:
569         //
570         //    scopes[n] -> scopes[n-1] -> ... -> scopes[0]
571         //
572         // However, we build this in **reverse order**. That is, we
573         // process scopes[0], then scopes[1], etc, pointing each one at
574         // the result generates from the one before. Along the way, we
575         // store caches. If everything is cached, we'll just walk right
576         // to left reading the cached results but never created anything.
577
578         // To start, create the resume terminator.
579         let mut target = if let Some(target) = *cached_resume_block {
580             target
581         } else {
582             let resumeblk = cfg.start_new_cleanup_block();
583             cfg.terminate(resumeblk,
584                           scopes[0].source_info(self.fn_span),
585                           TerminatorKind::Resume);
586             *cached_resume_block = Some(resumeblk);
587             resumeblk
588         };
589
590         for scope in scopes.iter_mut().filter(|s| s.needs_cleanup) {
591             target = build_diverge_scope(hir.tcx(), cfg, &unit_temp, scope, target);
592         }
593         Some(target)
594     }
595
596     /// Utility function for *non*-scope code to build their own drops
597     pub fn build_drop(&mut self,
598                       block: BasicBlock,
599                       span: Span,
600                       location: Lvalue<'tcx>,
601                       ty: Ty<'tcx>) -> BlockAnd<()> {
602         if !self.hir.needs_drop(ty) {
603             return block.unit();
604         }
605         let source_info = self.source_info(span);
606         let next_target = self.cfg.start_new_block();
607         let diverge_target = self.diverge_cleanup();
608         self.cfg.terminate(block, source_info,
609                            TerminatorKind::Drop {
610                                location: location,
611                                target: next_target,
612                                unwind: diverge_target,
613                            });
614         next_target.unit()
615     }
616
617     /// Utility function for *non*-scope code to build their own drops
618     pub fn build_drop_and_replace(&mut self,
619                                   block: BasicBlock,
620                                   span: Span,
621                                   location: Lvalue<'tcx>,
622                                   value: Operand<'tcx>) -> BlockAnd<()> {
623         let source_info = self.source_info(span);
624         let next_target = self.cfg.start_new_block();
625         let diverge_target = self.diverge_cleanup();
626         self.cfg.terminate(block, source_info,
627                            TerminatorKind::DropAndReplace {
628                                location: location,
629                                value: value,
630                                target: next_target,
631                                unwind: diverge_target,
632                            });
633         next_target.unit()
634     }
635
636     /// Create an Assert terminator and return the success block.
637     /// If the boolean condition operand is not the expected value,
638     /// a runtime panic will be caused with the given message.
639     pub fn assert(&mut self, block: BasicBlock,
640                   cond: Operand<'tcx>,
641                   expected: bool,
642                   msg: AssertMessage<'tcx>,
643                   span: Span)
644                   -> BasicBlock {
645         let source_info = self.source_info(span);
646
647         let success_block = self.cfg.start_new_block();
648         let cleanup = self.diverge_cleanup();
649
650         self.cfg.terminate(block, source_info,
651                            TerminatorKind::Assert {
652                                cond: cond,
653                                expected: expected,
654                                msg: msg,
655                                target: success_block,
656                                cleanup: cleanup
657                            });
658
659         success_block
660     }
661 }
662
663 /// Builds drops for pop_scope and exit_scope.
664 fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
665                            scope: &Scope<'tcx>,
666                            earlier_scopes: &[Scope<'tcx>],
667                            mut block: BasicBlock,
668                            arg_count: usize)
669                            -> BlockAnd<()> {
670     let mut iter = scope.drops.iter().rev().peekable();
671     while let Some(drop_data) = iter.next() {
672         let source_info = scope.source_info(drop_data.span);
673         if let DropKind::Value { .. } = drop_data.kind {
674             // Try to find the next block with its cached block
675             // for us to diverge into in case the drop panics.
676             let on_diverge = iter.peek().iter().filter_map(|dd| {
677                 match dd.kind {
678                     DropKind::Value { cached_block } => cached_block,
679                     DropKind::Storage => None
680                 }
681             }).next();
682             // If there’s no `cached_block`s within current scope,
683             // we must look for one in the enclosing scope.
684             let on_diverge = on_diverge.or_else(||{
685                 earlier_scopes.iter().rev().flat_map(|s| s.cached_block()).next()
686             });
687             let next = cfg.start_new_block();
688             cfg.terminate(block, source_info, TerminatorKind::Drop {
689                 location: drop_data.location.clone(),
690                 target: next,
691                 unwind: on_diverge
692             });
693             block = next;
694         }
695         match drop_data.kind {
696             DropKind::Value { .. } |
697             DropKind::Storage => {
698                 // Only temps and vars need their storage dead.
699                 match drop_data.location {
700                     Lvalue::Local(index) if index.index() > arg_count => {}
701                     _ => continue
702                 }
703
704                 cfg.push(block, Statement {
705                     source_info: source_info,
706                     kind: StatementKind::StorageDead(drop_data.location.clone())
707                 });
708             }
709         }
710     }
711     block.unit()
712 }
713
714 fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
715                                        cfg: &mut CFG<'tcx>,
716                                        unit_temp: &Lvalue<'tcx>,
717                                        scope: &mut Scope<'tcx>,
718                                        mut target: BasicBlock)
719                                        -> BasicBlock
720 {
721     // Build up the drops in **reverse** order. The end result will
722     // look like:
723     //
724     //    [drops[n]] -...-> [drops[0]] -> [Free] -> [target]
725     //    |                                    |
726     //    +------------------------------------+
727     //     code for scope
728     //
729     // The code in this function reads from right to left. At each
730     // point, we check for cached blocks representing the
731     // remainder. If everything is cached, we'll just walk right to
732     // left reading the cached results but never created anything.
733
734     let visibility_scope = scope.visibility_scope;
735     let source_info = |span| SourceInfo {
736         span: span,
737         scope: visibility_scope
738     };
739
740     // Next, build up any free.
741     if let Some(ref mut free_data) = scope.free {
742         target = if let Some(cached_block) = free_data.cached_block {
743             cached_block
744         } else {
745             let into = cfg.start_new_cleanup_block();
746             cfg.terminate(into, source_info(free_data.span),
747                           build_free(tcx, unit_temp, free_data, target));
748             free_data.cached_block = Some(into);
749             into
750         };
751     }
752
753     // Next, build up the drops. Here we iterate the vector in
754     // *forward* order, so that we generate drops[0] first (right to
755     // left in diagram above).
756     for drop_data in &mut scope.drops {
757         // Only full value drops are emitted in the diverging path,
758         // not StorageDead.
759         let cached_block = match drop_data.kind {
760             DropKind::Value { ref mut cached_block } => cached_block,
761             DropKind::Storage => continue
762         };
763         target = if let Some(cached_block) = *cached_block {
764             cached_block
765         } else {
766             let block = cfg.start_new_cleanup_block();
767             cfg.terminate(block, source_info(drop_data.span),
768                           TerminatorKind::Drop {
769                               location: drop_data.location.clone(),
770                               target: target,
771                               unwind: None
772                           });
773             *cached_block = Some(block);
774             block
775         };
776     }
777
778     target
779 }
780
781 fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
782                               unit_temp: &Lvalue<'tcx>,
783                               data: &FreeData<'tcx>,
784                               target: BasicBlock)
785                               -> TerminatorKind<'tcx> {
786     let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem);
787     let substs = tcx.intern_substs(&[Kind::from(data.item_ty)]);
788     TerminatorKind::Call {
789         func: Operand::Constant(Constant {
790             span: data.span,
791             ty: tcx.type_of(free_func).subst(tcx, substs),
792             literal: Literal::Value {
793                 value: ConstVal::Function(free_func, substs),
794             }
795         }),
796         args: vec![Operand::Consume(data.value.clone())],
797         destination: Some((unit_temp.clone(), target)),
798         cleanup: None
799     }
800 }