Skip to content

Commit 544b06d

Browse files
committed
Add a MIR visitor
1 parent e84829d commit 544b06d

File tree

2 files changed

+240
-0
lines changed

2 files changed

+240
-0
lines changed

src/librustc_mir/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,5 @@ mod hair;
3535
pub mod repr;
3636
mod graphviz;
3737
pub mod tcx;
38+
pub mod visit;
3839

src/librustc_mir/visit.rs

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
// Copyright 2012-2014 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+
use rustc::middle::ty::Region;
12+
use repr::*;
13+
14+
pub trait Visitor<'tcx> {
15+
// Override these, and call `self.super_xxx` to revert back to the
16+
// default behavior.
17+
18+
fn visit_mir(&mut self, mir: &Mir<'tcx>) {
19+
self.super_mir(mir);
20+
}
21+
22+
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
23+
self.super_basic_block_data(block, data);
24+
}
25+
26+
fn visit_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
27+
self.super_statement(block, statement);
28+
}
29+
30+
fn visit_assign(&mut self, block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) {
31+
self.super_assign(block, lvalue, rvalue);
32+
}
33+
34+
fn visit_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) {
35+
self.super_terminator(block, terminator);
36+
}
37+
38+
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
39+
self.super_rvalue(rvalue);
40+
}
41+
42+
fn visit_operand(&mut self, operand: &Operand<'tcx>) {
43+
self.super_operand(operand);
44+
}
45+
46+
fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
47+
self.super_lvalue(lvalue, context);
48+
}
49+
50+
fn visit_branch(&mut self, source: BasicBlock, target: BasicBlock) {
51+
self.super_branch(source, target);
52+
}
53+
54+
fn visit_constant(&mut self, constant: &Constant<'tcx>) {
55+
self.super_constant(constant);
56+
}
57+
58+
// The `super_xxx` methods comprise the default behavior and are
59+
// not meant to be overidden.
60+
61+
fn super_mir(&mut self, mir: &Mir<'tcx>) {
62+
for block in mir.all_basic_blocks() {
63+
let data = mir.basic_block_data(block);
64+
self.visit_basic_block_data(block, data);
65+
}
66+
}
67+
68+
fn super_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
69+
for statement in &data.statements {
70+
self.visit_statement(block, statement);
71+
}
72+
self.visit_terminator(block, &data.terminator);
73+
}
74+
75+
fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
76+
match statement.kind {
77+
StatementKind::Assign(ref lvalue, ref rvalue) => {
78+
self.visit_assign(block, lvalue, rvalue);
79+
}
80+
StatementKind::Drop(_, ref lvalue) => {
81+
self.visit_lvalue(lvalue, LvalueContext::Drop);
82+
}
83+
}
84+
}
85+
86+
fn super_assign(&mut self, _block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) {
87+
self.visit_lvalue(lvalue, LvalueContext::Store);
88+
self.visit_rvalue(rvalue);
89+
}
90+
91+
fn super_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) {
92+
match *terminator {
93+
Terminator::Goto { target } |
94+
Terminator::Panic { target } => {
95+
self.visit_branch(block, target);
96+
}
97+
98+
Terminator::If { ref cond, ref targets } => {
99+
self.visit_operand(cond);
100+
for &target in &targets[..] {
101+
self.visit_branch(block, target);
102+
}
103+
}
104+
105+
Terminator::Switch { ref discr, adt_def: _, ref targets } => {
106+
self.visit_lvalue(discr, LvalueContext::Inspect);
107+
for &target in targets {
108+
self.visit_branch(block, target);
109+
}
110+
}
111+
112+
Terminator::Diverge |
113+
Terminator::Return => {
114+
}
115+
116+
Terminator::Call { ref data, ref targets } => {
117+
self.visit_lvalue(&data.destination, LvalueContext::Store);
118+
self.visit_operand(&data.func);
119+
for arg in &data.args {
120+
self.visit_operand(arg);
121+
}
122+
for &target in &targets[..] {
123+
self.visit_branch(block, target);
124+
}
125+
}
126+
}
127+
}
128+
129+
fn super_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
130+
match *rvalue {
131+
Rvalue::Use(ref operand) => {
132+
self.visit_operand(operand);
133+
}
134+
135+
Rvalue::Repeat(ref value, ref len) => {
136+
self.visit_operand(value);
137+
self.visit_operand(len);
138+
}
139+
140+
Rvalue::Ref(r, bk, ref path) => {
141+
self.visit_lvalue(path, LvalueContext::Borrow {
142+
region: r,
143+
kind: bk
144+
});
145+
}
146+
147+
Rvalue::Len(ref path) => {
148+
self.visit_lvalue(path, LvalueContext::Inspect);
149+
}
150+
151+
Rvalue::Cast(_, ref operand, _) => {
152+
self.visit_operand(operand);
153+
}
154+
155+
Rvalue::BinaryOp(_, ref lhs, ref rhs) => {
156+
self.visit_operand(lhs);
157+
self.visit_operand(rhs);
158+
}
159+
160+
Rvalue::UnaryOp(_, ref op) => {
161+
self.visit_operand(op);
162+
}
163+
164+
Rvalue::Box(_) => {
165+
}
166+
167+
Rvalue::Aggregate(_, ref operands) => {
168+
for operand in operands {
169+
self.visit_operand(operand);
170+
}
171+
}
172+
173+
Rvalue::Slice { ref input, from_start, from_end } => {
174+
self.visit_lvalue(input, LvalueContext::Slice {
175+
from_start: from_start,
176+
from_end: from_end,
177+
});
178+
}
179+
180+
Rvalue::InlineAsm(_) => {
181+
}
182+
}
183+
}
184+
185+
fn super_operand(&mut self, operand: &Operand<'tcx>) {
186+
match *operand {
187+
Operand::Consume(ref lvalue) => {
188+
self.visit_lvalue(lvalue, LvalueContext::Consume);
189+
}
190+
Operand::Constant(ref constant) => {
191+
self.visit_constant(constant);
192+
}
193+
}
194+
}
195+
196+
fn super_lvalue(&mut self, lvalue: &Lvalue<'tcx>, _context: LvalueContext) {
197+
match *lvalue {
198+
Lvalue::Var(_) |
199+
Lvalue::Temp(_) |
200+
Lvalue::Arg(_) |
201+
Lvalue::Static(_) |
202+
Lvalue::ReturnPointer => {
203+
}
204+
Lvalue::Projection(ref proj) => {
205+
self.visit_lvalue(&proj.base, LvalueContext::Projection);
206+
}
207+
}
208+
}
209+
210+
fn super_branch(&mut self, _source: BasicBlock, _target: BasicBlock) {
211+
}
212+
213+
fn super_constant(&mut self, _constant: &Constant<'tcx>) {
214+
}
215+
}
216+
217+
#[derive(Copy, Clone, Debug)]
218+
pub enum LvalueContext {
219+
// Appears as LHS of an assignment or as dest of a call
220+
Store,
221+
222+
// Being dropped
223+
Drop,
224+
225+
// Being inspected in some way, like loading a len
226+
Inspect,
227+
228+
// Being borrowed
229+
Borrow { region: Region, kind: BorrowKind },
230+
231+
// Being sliced -- this should be same as being borrowed, probably
232+
Slice { from_start: usize, from_end: usize },
233+
234+
// Used as base for another lvalue, e.g. `x` in `x.y`
235+
Projection,
236+
237+
// Consumed as part of an operand
238+
Consume,
239+
}

0 commit comments

Comments
 (0)