]> git.proxmox.com Git - rustc.git/blame - 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
CommitLineData
7453a54e
SL
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
35use rustc::middle::infer;
36use rustc::mir::repr::*;
37use rustc::mir::transform::MirPass;
38
39pub struct ClearDeadBlocks;
40
41impl 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
76impl 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}