]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/transform/clear_dead_blocks.rs
Imported Upstream version 1.8.0+dfsg1
[rustc.git] / src / librustc_mir / transform / clear_dead_blocks.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! A pass that erases the contents of dead blocks. This pass must
12 //! run before any analysis passes because some of the dead blocks
13 //! can be ill-typed.
14 //!
15 //! The main problem is that typeck lets most blocks whose end is not
16 //! reachable have an arbitrary return type, rather than having the
17 //! usual () return type (as a note, typeck's notion of reachability
18 //! is in fact slightly weaker than MIR CFG reachability - see #31617).
19 //!
20 //! A standard example of the situation is:
21 //! ```rust
22 //! fn example() {
23 //! let _a: char = { return; };
24 //! }
25 //! ```
26 //!
27 //! Here the block (`{ return; }`) has the return type `char`,
28 //! rather than `()`, but the MIR we naively generate still contains
29 //! the `_a = ()` write in the unreachable block "after" the return.
30 //!
31 //! As we have to run this pass even when we want to debug the MIR,
32 //! this pass just replaces the blocks with empty "return" blocks
33 //! and does not renumber anything.
34
35 use rustc::middle::infer;
36 use rustc::mir::repr::*;
37 use rustc::mir::transform::MirPass;
38
39 pub struct ClearDeadBlocks;
40
41 impl ClearDeadBlocks {
42 pub fn new() -> ClearDeadBlocks {
43 ClearDeadBlocks
44 }
45
46 fn clear_dead_blocks(&self, mir: &mut Mir) {
47 let mut seen = vec![false; mir.basic_blocks.len()];
48
49 // These blocks are always required.
50 seen[START_BLOCK.index()] = true;
51 seen[END_BLOCK.index()] = true;
52
53 let mut worklist = vec![START_BLOCK];
54 while let Some(bb) = worklist.pop() {
55 for succ in mir.basic_block_data(bb).terminator().successors().iter() {
56 if !seen[succ.index()] {
57 seen[succ.index()] = true;
58 worklist.push(*succ);
59 }
60 }
61 }
62
63 for (n, (block, seen)) in mir.basic_blocks.iter_mut().zip(seen).enumerate() {
64 if !seen {
65 info!("clearing block #{}: {:?}", n, block);
66 *block = BasicBlockData {
67 statements: vec![],
68 terminator: Some(Terminator::Return),
69 is_cleanup: false
70 };
71 }
72 }
73 }
74 }
75
76 impl MirPass for ClearDeadBlocks {
77 fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &infer::InferCtxt<'a, 'tcx>)
78 {
79 self.clear_dead_blocks(mir);
80 }
81 }