blob: 9cd46067c107b3b5a7eafa140a7a75e16f26f03e [file] [log] [blame]
Niko Matsakis86b6e6e2013-05-10 17:10:351// Copyright 2012 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
11use middle::cfg::*;
Niko Matsakis0f03b562014-05-14 19:31:3012use middle::def;
Niko Matsakis86b6e6e2013-05-10 17:10:3513use middle::graph;
14use middle::typeck;
15use middle::ty;
Niko Matsakis86b6e6e2013-05-10 17:10:3516use syntax::ast;
17use syntax::ast_util;
Alex Crichtonbec7b762014-02-28 22:34:2618use util::nodemap::NodeMap;
Niko Matsakis86b6e6e2013-05-10 17:10:3519
Alex Crichton54c2a1e2014-05-16 17:15:3320use std::gc::Gc;
21
Eduard Burtescu9b1fee82014-03-06 03:07:4722struct CFGBuilder<'a> {
23 tcx: &'a ty::ctxt,
Alex Crichtonbec7b762014-02-28 22:34:2624 exit_map: NodeMap<CFGIndex>,
Niko Matsakis86b6e6e2013-05-10 17:10:3525 graph: CFGGraph,
Felix S. Klock II65b65fe2014-05-08 22:07:5726 fn_exit: CFGIndex,
27 loop_scopes: Vec<LoopScope>,
Niko Matsakis86b6e6e2013-05-10 17:10:3528}
29
30struct LoopScope {
Michael Woerister8a329772013-07-27 08:25:5931 loop_id: ast::NodeId, // id of loop/while node
Niko Matsakis86b6e6e2013-05-10 17:10:3532 continue_index: CFGIndex, // where to go on a `loop`
33 break_index: CFGIndex, // where to go on a `break
34}
35
Eduard Burtescu9b1fee82014-03-06 03:07:4736pub fn construct(tcx: &ty::ctxt,
Michael Woerister4bd14242013-07-19 05:38:5537 blk: &ast::Block) -> CFG {
Felix S. Klock II65b65fe2014-05-08 22:07:5738 let mut graph = graph::Graph::new();
39 let entry = add_initial_dummy_node(&mut graph);
40
41 // `fn_exit` is target of return exprs, which lies somewhere
42 // outside input `blk`. (Distinguishing `fn_exit` and `block_exit`
43 // also resolves chicken-and-egg problem that arises if you try to
44 // have return exprs jump to `block_exit` during construction.)
45 let fn_exit = add_initial_dummy_node(&mut graph);
46 let block_exit;
47
Niko Matsakis86b6e6e2013-05-10 17:10:3548 let mut cfg_builder = CFGBuilder {
Alex Crichtonbec7b762014-02-28 22:34:2649 exit_map: NodeMap::new(),
Felix S. Klock II65b65fe2014-05-08 22:07:5750 graph: graph,
51 fn_exit: fn_exit,
Niko Matsakis86b6e6e2013-05-10 17:10:3552 tcx: tcx,
Patrick Walton3b6e9d42014-03-04 18:02:4953 loop_scopes: Vec::new()
Niko Matsakis86b6e6e2013-05-10 17:10:3554 };
Felix S. Klock II65b65fe2014-05-08 22:07:5755 block_exit = cfg_builder.block(blk, entry);
56 cfg_builder.add_contained_edge(block_exit, fn_exit);
Alex Crichtonab387a62013-11-28 20:22:5357 let CFGBuilder {exit_map, graph, ..} = cfg_builder;
Niko Matsakis86b6e6e2013-05-10 17:10:3558 CFG {exit_map: exit_map,
59 graph: graph,
60 entry: entry,
Felix S. Klock II65b65fe2014-05-08 22:07:5761 exit: fn_exit}
62}
63
64fn add_initial_dummy_node(g: &mut CFGGraph) -> CFGIndex {
65 g.add_node(CFGNodeData { id: ast::DUMMY_NODE_ID })
Niko Matsakis86b6e6e2013-05-10 17:10:3566}
67
Eduard Burtescu9b1fee82014-03-06 03:07:4768impl<'a> CFGBuilder<'a> {
Michael Woerister4bd14242013-07-19 05:38:5569 fn block(&mut self, blk: &ast::Block, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:3570 let mut stmts_exit = pred;
Alex Crichton54c2a1e2014-05-16 17:15:3371 for stmt in blk.stmts.iter() {
72 stmts_exit = self.stmt(stmt.clone(), stmts_exit);
Niko Matsakis86b6e6e2013-05-10 17:10:3573 }
74
Alex Crichton54c2a1e2014-05-16 17:15:3375 let expr_exit = self.opt_expr(blk.expr.clone(), stmts_exit);
Niko Matsakis86b6e6e2013-05-10 17:10:3576
Michael Woerister0cc70742013-07-16 18:08:3577 self.add_node(blk.id, [expr_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:3578 }
79
Alex Crichton54c2a1e2014-05-16 17:15:3380 fn stmt(&mut self, stmt: Gc<ast::Stmt>, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:3581 match stmt.node {
Alex Crichton54c2a1e2014-05-16 17:15:3382 ast::StmtDecl(ref decl, _) => {
83 self.decl(&**decl, pred)
Niko Matsakis86b6e6e2013-05-10 17:10:3584 }
85
Alex Crichton54c2a1e2014-05-16 17:15:3386 ast::StmtExpr(ref expr, _) | ast::StmtSemi(ref expr, _) => {
87 self.expr(expr.clone(), pred)
Niko Matsakis86b6e6e2013-05-10 17:10:3588 }
89
Alex Crichtonab387a62013-11-28 20:22:5390 ast::StmtMac(..) => {
Niko Matsakis86b6e6e2013-05-10 17:10:3591 self.tcx.sess.span_bug(stmt.span, "unexpanded macro");
92 }
93 }
94 }
95
Alex Crichton54c2a1e2014-05-16 17:15:3396 fn decl(&mut self, decl: &ast::Decl, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:3597 match decl.node {
Alex Crichton54c2a1e2014-05-16 17:15:3398 ast::DeclLocal(ref local) => {
99 let init_exit = self.opt_expr(local.init.clone(), pred);
100 self.pat(&*local.pat, init_exit)
Niko Matsakis86b6e6e2013-05-10 17:10:35101 }
102
Marvin Löbel74190852013-09-02 01:45:37103 ast::DeclItem(_) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35104 pred
105 }
106 }
107 }
108
Alex Crichton54c2a1e2014-05-16 17:15:33109 fn pat(&mut self, pat: &ast::Pat, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35110 match pat.node {
Marvin Löbel74190852013-09-02 01:45:37111 ast::PatIdent(_, _, None) |
112 ast::PatEnum(_, None) |
Alex Crichtonab387a62013-11-28 20:22:53113 ast::PatLit(..) |
114 ast::PatRange(..) |
Brian Anderson85f107d2013-11-08 03:25:39115 ast::PatWild | ast::PatWildMulti => {
Niko Matsakis86b6e6e2013-05-10 17:10:35116 self.add_node(pat.id, [pred])
117 }
118
Alex Crichton54c2a1e2014-05-16 17:15:33119 ast::PatBox(ref subpat) |
120 ast::PatRegion(ref subpat) |
121 ast::PatIdent(_, _, Some(ref subpat)) => {
122 let subpat_exit = self.pat(&**subpat, pred);
Niko Matsakis86b6e6e2013-05-10 17:10:35123 self.add_node(pat.id, [subpat_exit])
124 }
125
Marvin Löbel74190852013-09-02 01:45:37126 ast::PatEnum(_, Some(ref subpats)) |
127 ast::PatTup(ref subpats) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35128 let pats_exit =
Alex Crichton54c2a1e2014-05-16 17:15:33129 self.pats_all(subpats.iter().map(|p| p.clone()), pred);
Niko Matsakis86b6e6e2013-05-10 17:10:35130 self.add_node(pat.id, [pats_exit])
131 }
132
Marvin Löbel74190852013-09-02 01:45:37133 ast::PatStruct(_, ref subpats, _) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35134 let pats_exit =
Alex Crichton54c2a1e2014-05-16 17:15:33135 self.pats_all(subpats.iter().map(|f| f.pat.clone()), pred);
Niko Matsakis86b6e6e2013-05-10 17:10:35136 self.add_node(pat.id, [pats_exit])
137 }
138
Marvin Löbel74190852013-09-02 01:45:37139 ast::PatVec(ref pre, ref vec, ref post) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35140 let pre_exit =
Erick Tryzelaar68f40d22013-08-10 03:09:47141 self.pats_all(pre.iter().map(|p| *p), pred);
Niko Matsakis86b6e6e2013-05-10 17:10:35142 let vec_exit =
Erick Tryzelaar68f40d22013-08-10 03:09:47143 self.pats_all(vec.iter().map(|p| *p), pre_exit);
Niko Matsakis86b6e6e2013-05-10 17:10:35144 let post_exit =
Erick Tryzelaar68f40d22013-08-10 03:09:47145 self.pats_all(post.iter().map(|p| *p), vec_exit);
Niko Matsakis86b6e6e2013-05-10 17:10:35146 self.add_node(pat.id, [post_exit])
147 }
Keegan McAllister5fdd0e42014-05-19 20:29:41148
149 ast::PatMac(_) => {
150 self.tcx.sess.span_bug(pat.span, "unexpanded macro");
151 }
Niko Matsakis86b6e6e2013-05-10 17:10:35152 }
153 }
154
Alex Crichton54c2a1e2014-05-16 17:15:33155 fn pats_all<I: Iterator<Gc<ast::Pat>>>(&mut self,
Niko Matsakis86b6e6e2013-05-10 17:10:35156 pats: I,
157 pred: CFGIndex) -> CFGIndex {
158 //! Handles case where all of the patterns must match.
159 let mut pats = pats;
Alex Crichton54c2a1e2014-05-16 17:15:33160 pats.fold(pred, |pred, pat| self.pat(&*pat, pred))
Niko Matsakis86b6e6e2013-05-10 17:10:35161 }
162
163 fn pats_any(&mut self,
Alex Crichton54c2a1e2014-05-16 17:15:33164 pats: &[Gc<ast::Pat>],
Niko Matsakis86b6e6e2013-05-10 17:10:35165 pred: CFGIndex) -> CFGIndex {
166 //! Handles case where just one of the patterns must match.
167
168 if pats.len() == 1 {
Alex Crichton54c2a1e2014-05-16 17:15:33169 self.pat(&*pats[0], pred)
Niko Matsakis86b6e6e2013-05-10 17:10:35170 } else {
171 let collect = self.add_dummy_node([]);
Daniel Micay100894552013-08-03 16:45:23172 for &pat in pats.iter() {
Alex Crichton54c2a1e2014-05-16 17:15:33173 let pat_exit = self.pat(&*pat, pred);
Niko Matsakis86b6e6e2013-05-10 17:10:35174 self.add_contained_edge(pat_exit, collect);
175 }
176 collect
177 }
178 }
179
Alex Crichton54c2a1e2014-05-16 17:15:33180 fn expr(&mut self, expr: Gc<ast::Expr>, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35181 match expr.node {
Alex Crichton54c2a1e2014-05-16 17:15:33182 ast::ExprBlock(ref blk) => {
183 let blk_exit = self.block(&**blk, pred);
Niko Matsakis86b6e6e2013-05-10 17:10:35184 self.add_node(expr.id, [blk_exit])
185 }
186
Alex Crichton54c2a1e2014-05-16 17:15:33187 ast::ExprIf(ref cond, ref then, None) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35188 //
189 // [pred]
190 // |
191 // v 1
192 // [cond]
193 // |
194 // / \
195 // / \
196 // v 2 *
197 // [then] |
198 // | |
199 // v 3 v 4
200 // [..expr..]
201 //
Alex Crichton54c2a1e2014-05-16 17:15:33202 let cond_exit = self.expr(cond.clone(), pred); // 1
203 let then_exit = self.block(&**then, cond_exit); // 2
204 self.add_node(expr.id, [cond_exit, then_exit]) // 3,4
Niko Matsakis86b6e6e2013-05-10 17:10:35205 }
206
Alex Crichton54c2a1e2014-05-16 17:15:33207 ast::ExprIf(ref cond, ref then, Some(ref otherwise)) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35208 //
209 // [pred]
210 // |
211 // v 1
212 // [cond]
213 // |
214 // / \
215 // / \
216 // v 2 v 3
217 // [then][otherwise]
218 // | |
219 // v 4 v 5
220 // [..expr..]
221 //
Alex Crichton54c2a1e2014-05-16 17:15:33222 let cond_exit = self.expr(cond.clone(), pred); // 1
223 let then_exit = self.block(&**then, cond_exit); // 2
224 let else_exit = self.expr(otherwise.clone(), cond_exit); // 3
225 self.add_node(expr.id, [then_exit, else_exit]) // 4, 5
Niko Matsakis86b6e6e2013-05-10 17:10:35226 }
227
Alex Crichton54c2a1e2014-05-16 17:15:33228 ast::ExprWhile(ref cond, ref body) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35229 //
230 // [pred]
231 // |
232 // v 1
233 // [loopback] <--+ 5
234 // | |
235 // v 2 |
236 // +-----[cond] |
237 // | | |
238 // | v 4 |
239 // | [body] -----+
240 // v 3
241 // [expr]
242 //
Patrick Waltoncaa564b2014-07-22 03:54:28243 // Note that `break` and `continue` statements
Niko Matsakis86b6e6e2013-05-10 17:10:35244 // may cause additional edges.
245
Michael Sullivan7dbc5ae2013-07-30 23:47:22246 // Is the condition considered part of the loop?
Alex Crichton54c2a1e2014-05-16 17:15:33247 let loopback = self.add_dummy_node([pred]); // 1
248 let cond_exit = self.expr(cond.clone(), loopback); // 2
249 let expr_exit = self.add_node(expr.id, [cond_exit]); // 3
Niko Matsakis86b6e6e2013-05-10 17:10:35250 self.loop_scopes.push(LoopScope {
251 loop_id: expr.id,
252 continue_index: loopback,
253 break_index: expr_exit
254 });
Alex Crichton54c2a1e2014-05-16 17:15:33255 let body_exit = self.block(&**body, cond_exit); // 4
256 self.add_contained_edge(body_exit, loopback); // 5
Felix S. Klock IIbe9c2d12014-05-20 16:49:19257 self.loop_scopes.pop();
Niko Matsakis86b6e6e2013-05-10 17:10:35258 expr_exit
259 }
260
Patrick Waltoncaa564b2014-07-22 03:54:28261 ast::ExprForLoop(ref pat, ref head, ref body, _) => {
262 //
263 // [pred]
264 // |
265 // v 1
266 // [head]
267 // |
268 // v 2
269 // [loopback] <--+ 7
270 // | |
271 // v 3 |
272 // +------[cond] |
273 // | | |
274 // | v 5 |
275 // | [pat] |
276 // | | |
277 // | v 6 |
278 // v 4 [body] -----+
279 // [expr]
280 //
281 // Note that `break` and `continue` statements
282 // may cause additional edges.
283
284 let head = self.expr(head.clone(), pred); // 1
285 let loopback = self.add_dummy_node([head]); // 2
286 let cond = self.add_dummy_node([loopback]); // 3
287 let expr_exit = self.add_node(expr.id, [cond]); // 4
288 self.loop_scopes.push(LoopScope {
289 loop_id: expr.id,
290 continue_index: loopback,
291 break_index: expr_exit,
292 });
293 let pat = self.pat(&**pat, cond); // 5
294 let body = self.block(&**body, pat); // 6
295 self.add_contained_edge(body, loopback); // 7
296 self.loop_scopes.pop();
297 expr_exit
298 }
Graydon Hoarec29e9fb2013-07-30 00:25:00299
Alex Crichton54c2a1e2014-05-16 17:15:33300 ast::ExprLoop(ref body, _) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35301 //
302 // [pred]
303 // |
304 // v 1
305 // [loopback] <---+
306 // | 4 |
307 // v 3 |
308 // [body] ------+
309 //
310 // [expr] 2
311 //
312 // Note that `break` and `loop` statements
313 // may cause additional edges.
314
Alex Crichton54c2a1e2014-05-16 17:15:33315 let loopback = self.add_dummy_node([pred]); // 1
316 let expr_exit = self.add_node(expr.id, []); // 2
Niko Matsakis86b6e6e2013-05-10 17:10:35317 self.loop_scopes.push(LoopScope {
318 loop_id: expr.id,
319 continue_index: loopback,
320 break_index: expr_exit,
321 });
Alex Crichton54c2a1e2014-05-16 17:15:33322 let body_exit = self.block(&**body, loopback); // 3
323 self.add_contained_edge(body_exit, loopback); // 4
Niko Matsakis86b6e6e2013-05-10 17:10:35324 self.loop_scopes.pop();
325 expr_exit
326 }
327
Alex Crichton54c2a1e2014-05-16 17:15:33328 ast::ExprMatch(ref discr, ref arms) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35329 //
330 // [pred]
331 // |
332 // v 1
333 // [discr]
334 // |
335 // v 2
Patrick Waltonb2eb8882014-07-25 22:18:19336 // [cond1]
Niko Matsakis86b6e6e2013-05-10 17:10:35337 // / \
338 // | \
Patrick Waltonb2eb8882014-07-25 22:18:19339 // v 3 \
340 // [pat1] \
341 // | |
342 // v 4 |
343 // [guard1] |
344 // | |
345 // | |
346 // v 5 v
347 // [body1] [cond2]
348 // | / \
349 // | ... ...
350 // | | |
351 // v 6 v v
352 // [.....expr.....]
Niko Matsakis86b6e6e2013-05-10 17:10:35353 //
Alex Crichton54c2a1e2014-05-16 17:15:33354 let discr_exit = self.expr(discr.clone(), pred); // 1
Niko Matsakis86b6e6e2013-05-10 17:10:35355
356 let expr_exit = self.add_node(expr.id, []);
Patrick Waltonb2eb8882014-07-25 22:18:19357 let mut cond_exit = discr_exit;
Daniel Micay100894552013-08-03 16:45:23358 for arm in arms.iter() {
Patrick Waltonb2eb8882014-07-25 22:18:19359 cond_exit = self.add_dummy_node([cond_exit]); // 2
Patrick Waltonc1ed4d72014-02-28 23:25:15360 let pats_exit = self.pats_any(arm.pats.as_slice(),
Patrick Waltonb2eb8882014-07-25 22:18:19361 cond_exit); // 3
362 let guard_exit = self.opt_expr(arm.guard,
363 pats_exit); // 4
364 let body_exit = self.expr(arm.body.clone(),
365 guard_exit); // 5
366 self.add_contained_edge(body_exit, expr_exit); // 6
Niko Matsakis86b6e6e2013-05-10 17:10:35367 }
368 expr_exit
369 }
370
Alex Crichton54c2a1e2014-05-16 17:15:33371 ast::ExprBinary(op, ref l, ref r) if ast_util::lazy_binop(op) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35372 //
373 // [pred]
374 // |
375 // v 1
376 // [l]
377 // |
378 // / \
379 // / \
380 // v 2 *
381 // [r] |
382 // | |
383 // v 3 v 4
384 // [..exit..]
385 //
Alex Crichton54c2a1e2014-05-16 17:15:33386 let l_exit = self.expr(l.clone(), pred); // 1
387 let r_exit = self.expr(r.clone(), l_exit); // 2
Niko Matsakis86b6e6e2013-05-10 17:10:35388 self.add_node(expr.id, [l_exit, r_exit]) // 3,4
389 }
390
Alex Crichton54c2a1e2014-05-16 17:15:33391 ast::ExprRet(ref v) => {
392 let v_exit = self.opt_expr(v.clone(), pred);
Felix S. Klock II65b65fe2014-05-08 22:07:57393 let b = self.add_node(expr.id, [v_exit]);
394 self.add_returning_edge(expr, b);
395 self.add_node(ast::DUMMY_NODE_ID, [])
Niko Matsakis86b6e6e2013-05-10 17:10:35396 }
397
Marvin Löbel74190852013-09-02 01:45:37398 ast::ExprBreak(label) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35399 let loop_scope = self.find_scope(expr, label);
Felix S. Klock II65b65fe2014-05-08 22:07:57400 let b = self.add_node(expr.id, [pred]);
401 self.add_exiting_edge(expr, b,
Niko Matsakis86b6e6e2013-05-10 17:10:35402 loop_scope, loop_scope.break_index);
Felix S. Klock II65b65fe2014-05-08 22:07:57403 self.add_node(ast::DUMMY_NODE_ID, [])
Niko Matsakis86b6e6e2013-05-10 17:10:35404 }
405
Marvin Löbel74190852013-09-02 01:45:37406 ast::ExprAgain(label) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35407 let loop_scope = self.find_scope(expr, label);
Felix S. Klock II65b65fe2014-05-08 22:07:57408 let a = self.add_node(expr.id, [pred]);
409 self.add_exiting_edge(expr, a,
Niko Matsakis86b6e6e2013-05-10 17:10:35410 loop_scope, loop_scope.continue_index);
Felix S. Klock II65b65fe2014-05-08 22:07:57411 self.add_node(ast::DUMMY_NODE_ID, [])
Niko Matsakis86b6e6e2013-05-10 17:10:35412 }
413
Eduard Burtescu7c48e532014-04-04 10:12:18414 ast::ExprVec(ref elems) => {
Patrick Waltonc1ed4d72014-02-28 23:25:15415 self.straightline(expr, pred, elems.as_slice())
Niko Matsakis86b6e6e2013-05-10 17:10:35416 }
417
Alex Crichton54c2a1e2014-05-16 17:15:33418 ast::ExprCall(ref func, ref args) => {
419 self.call(expr, pred, func.clone(), args.as_slice())
Niko Matsakis86b6e6e2013-05-10 17:10:35420 }
421
Eduard Burtescu05e4d942014-02-26 14:06:45422 ast::ExprMethodCall(_, _, ref args) => {
Patrick Waltonc1ed4d72014-02-28 23:25:15423 self.call(expr, pred, *args.get(0), args.slice_from(1))
Niko Matsakis86b6e6e2013-05-10 17:10:35424 }
425
Alex Crichton54c2a1e2014-05-16 17:15:33426 ast::ExprIndex(ref l, ref r) |
427 ast::ExprBinary(_, ref l, ref r) if self.is_method_call(&*expr) => {
428 self.call(expr, pred, l.clone(), [r.clone()])
Niko Matsakis86b6e6e2013-05-10 17:10:35429 }
430
Alex Crichton54c2a1e2014-05-16 17:15:33431 ast::ExprUnary(_, ref e) if self.is_method_call(&*expr) => {
432 self.call(expr, pred, e.clone(), [])
Niko Matsakis86b6e6e2013-05-10 17:10:35433 }
434
Marvin Löbel74190852013-09-02 01:45:37435 ast::ExprTup(ref exprs) => {
Patrick Waltonc1ed4d72014-02-28 23:25:15436 self.straightline(expr, pred, exprs.as_slice())
Niko Matsakis86b6e6e2013-05-10 17:10:35437 }
438
Marvin Löbel74190852013-09-02 01:45:37439 ast::ExprStruct(_, ref fields, base) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35440 let base_exit = self.opt_expr(base, pred);
Alex Crichton54c2a1e2014-05-16 17:15:33441 let field_exprs: Vec<Gc<ast::Expr>> =
Erick Tryzelaar68f40d22013-08-10 03:09:47442 fields.iter().map(|f| f.expr).collect();
Felix S. Klock II43c07242014-03-08 20:36:22443 self.straightline(expr, base_exit, field_exprs.as_slice())
Niko Matsakis86b6e6e2013-05-10 17:10:35444 }
445
Eduard Burtescu7c48e532014-04-04 10:12:18446 ast::ExprRepeat(elem, count) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35447 self.straightline(expr, pred, [elem, count])
448 }
449
Marvin Löbel74190852013-09-02 01:45:37450 ast::ExprAssign(l, r) |
Eduard Burtescu05e4d942014-02-26 14:06:45451 ast::ExprAssignOp(_, l, r) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35452 self.straightline(expr, pred, [r, l])
453 }
454
Eduard Burtescu05e4d942014-02-26 14:06:45455 ast::ExprIndex(l, r) |
456 ast::ExprBinary(_, l, r) => { // NB: && and || handled earlier
Niko Matsakis86b6e6e2013-05-10 17:10:35457 self.straightline(expr, pred, [l, r])
458 }
459
Patrick Waltone1271152013-12-18 00:46:18460 ast::ExprBox(p, e) => {
461 self.straightline(expr, pred, [p, e])
462 }
463
Marvin Löbel74190852013-09-02 01:45:37464 ast::ExprAddrOf(_, e) |
Marvin Löbel74190852013-09-02 01:45:37465 ast::ExprCast(e, _) |
Eduard Burtescu05e4d942014-02-26 14:06:45466 ast::ExprUnary(_, e) |
Marvin Löbel74190852013-09-02 01:45:37467 ast::ExprParen(e) |
468 ast::ExprVstore(e, _) |
469 ast::ExprField(e, _, _) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35470 self.straightline(expr, pred, [e])
471 }
472
Felix S. Klock IIbe9c2d12014-05-20 16:49:19473 ast::ExprInlineAsm(ref inline_asm) => {
474 let inputs = inline_asm.inputs.iter();
475 let outputs = inline_asm.outputs.iter();
476 fn extract_expr<A>(&(_, expr): &(A, Gc<ast::Expr>)) -> Gc<ast::Expr> { expr }
477 let post_inputs = self.exprs(inputs.map(|a| {
478 debug!("cfg::construct InlineAsm id:{} input:{:?}", expr.id, a);
479 extract_expr(a)
480 }), pred);
481 let post_outputs = self.exprs(outputs.map(|a| {
482 debug!("cfg::construct InlineAsm id:{} output:{:?}", expr.id, a);
483 extract_expr(a)
484 }), post_inputs);
485 self.add_node(expr.id, [post_outputs])
486 }
487
Alex Crichtonab387a62013-11-28 20:22:53488 ast::ExprMac(..) |
Alex Crichtonab387a62013-11-28 20:22:53489 ast::ExprFnBlock(..) |
490 ast::ExprProc(..) |
Patrick Walton02adaca2014-05-29 05:26:56491 ast::ExprUnboxedFn(..) |
Alex Crichtonab387a62013-11-28 20:22:53492 ast::ExprLit(..) |
493 ast::ExprPath(..) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35494 self.straightline(expr, pred, [])
495 }
496 }
497 }
498
499 fn call(&mut self,
Alex Crichton54c2a1e2014-05-16 17:15:33500 call_expr: Gc<ast::Expr>,
Niko Matsakis86b6e6e2013-05-10 17:10:35501 pred: CFGIndex,
Alex Crichton54c2a1e2014-05-16 17:15:33502 func_or_rcvr: Gc<ast::Expr>,
503 args: &[Gc<ast::Expr>]) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35504 let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
Felix S. Klock IIbe9c2d12014-05-20 16:49:19505 let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
506
507 let return_ty = ty::node_id_to_type(self.tcx, call_expr.id);
508 let fails = ty::type_is_bot(return_ty);
509 if fails {
510 self.add_node(ast::DUMMY_NODE_ID, [])
511 } else {
512 ret
513 }
Niko Matsakis86b6e6e2013-05-10 17:10:35514 }
515
Felix S. Klock IIbe9c2d12014-05-20 16:49:19516 fn exprs<I:Iterator<Gc<ast::Expr>>>(&mut self,
517 mut exprs: I,
518 pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35519 //! Constructs graph for `exprs` evaluated in order
Felix S. Klock IIbe9c2d12014-05-20 16:49:19520 exprs.fold(pred, |p, e| self.expr(e, p))
Niko Matsakis86b6e6e2013-05-10 17:10:35521 }
522
523 fn opt_expr(&mut self,
Alex Crichton54c2a1e2014-05-16 17:15:33524 opt_expr: Option<Gc<ast::Expr>>,
Niko Matsakis86b6e6e2013-05-10 17:10:35525 pred: CFGIndex) -> CFGIndex {
526 //! Constructs graph for `opt_expr` evaluated, if Some
527
528 opt_expr.iter().fold(pred, |p, &e| self.expr(e, p))
529 }
530
531 fn straightline(&mut self,
Alex Crichton54c2a1e2014-05-16 17:15:33532 expr: Gc<ast::Expr>,
Niko Matsakis86b6e6e2013-05-10 17:10:35533 pred: CFGIndex,
Alex Crichton54c2a1e2014-05-16 17:15:33534 subexprs: &[Gc<ast::Expr>]) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35535 //! Handles case of an expression that evaluates `subexprs` in order
536
Felix S. Klock IIbe9c2d12014-05-20 16:49:19537 let subexprs_exit = self.exprs(subexprs.iter().map(|&e|e), pred);
Niko Matsakis86b6e6e2013-05-10 17:10:35538 self.add_node(expr.id, [subexprs_exit])
539 }
540
541 fn add_dummy_node(&mut self, preds: &[CFGIndex]) -> CFGIndex {
Felix S. Klock II65b65fe2014-05-08 22:07:57542 self.add_node(ast::DUMMY_NODE_ID, preds)
Niko Matsakis86b6e6e2013-05-10 17:10:35543 }
544
Michael Woerister8a329772013-07-27 08:25:59545 fn add_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35546 assert!(!self.exit_map.contains_key(&id));
547 let node = self.graph.add_node(CFGNodeData {id: id});
Felix S. Klock II65b65fe2014-05-08 22:07:57548 if id != ast::DUMMY_NODE_ID {
549 assert!(!self.exit_map.contains_key(&id));
550 self.exit_map.insert(id, node);
551 }
Daniel Micay100894552013-08-03 16:45:23552 for &pred in preds.iter() {
Niko Matsakis86b6e6e2013-05-10 17:10:35553 self.add_contained_edge(pred, node);
554 }
555 node
556 }
557
558 fn add_contained_edge(&mut self,
559 source: CFGIndex,
560 target: CFGIndex) {
Huon Wilson7785fe12014-03-19 12:16:56561 let data = CFGEdgeData {exiting_scopes: vec!() };
Niko Matsakis86b6e6e2013-05-10 17:10:35562 self.graph.add_edge(source, target, data);
563 }
564
565 fn add_exiting_edge(&mut self,
Alex Crichton54c2a1e2014-05-16 17:15:33566 from_expr: Gc<ast::Expr>,
Niko Matsakis86b6e6e2013-05-10 17:10:35567 from_index: CFGIndex,
568 to_loop: LoopScope,
569 to_index: CFGIndex) {
Huon Wilson7785fe12014-03-19 12:16:56570 let mut data = CFGEdgeData {exiting_scopes: vec!() };
Niko Matsakis86b6e6e2013-05-10 17:10:35571 let mut scope_id = from_expr.id;
572 while scope_id != to_loop.loop_id {
Huon Wilson7785fe12014-03-19 12:16:56573
Niko Matsakis86b6e6e2013-05-10 17:10:35574 data.exiting_scopes.push(scope_id);
575 scope_id = self.tcx.region_maps.encl_scope(scope_id);
576 }
577 self.graph.add_edge(from_index, to_index, data);
578 }
579
Felix S. Klock II65b65fe2014-05-08 22:07:57580 fn add_returning_edge(&mut self,
Alex Crichton54c2a1e2014-05-16 17:15:33581 _from_expr: Gc<ast::Expr>,
Felix S. Klock II65b65fe2014-05-08 22:07:57582 from_index: CFGIndex) {
Patrick Walton36195eb2014-05-16 17:45:16583 let mut data = CFGEdgeData {
584 exiting_scopes: vec!(),
585 };
Felix S. Klock II65b65fe2014-05-08 22:07:57586 for &LoopScope { loop_id: id, .. } in self.loop_scopes.iter().rev() {
587 data.exiting_scopes.push(id);
588 }
589 self.graph.add_edge(from_index, self.fn_exit, data);
590 }
591
Niko Matsakis86b6e6e2013-05-10 17:10:35592 fn find_scope(&self,
Alex Crichton54c2a1e2014-05-16 17:15:33593 expr: Gc<ast::Expr>,
Edward Wang386db052014-02-15 08:54:32594 label: Option<ast::Ident>) -> LoopScope {
Niko Matsakis86b6e6e2013-05-10 17:10:35595 match label {
596 None => {
Simon Sapinaa66b912013-12-23 14:08:23597 return *self.loop_scopes.last().unwrap();
Niko Matsakis86b6e6e2013-05-10 17:10:35598 }
599
600 Some(_) => {
Alex Crichton0dbb9092014-03-21 02:49:20601 match self.tcx.def_map.borrow().find(&expr.id) {
Niko Matsakis0f03b562014-05-14 19:31:30602 Some(&def::DefLabel(loop_id)) => {
Daniel Micay100894552013-08-03 16:45:23603 for l in self.loop_scopes.iter() {
Niko Matsakis86b6e6e2013-05-10 17:10:35604 if l.loop_id == loop_id {
605 return *l;
606 }
607 }
608 self.tcx.sess.span_bug(
609 expr.span,
Patrick Walton36195eb2014-05-16 17:45:16610 format!("no loop scope for id {:?}",
611 loop_id).as_slice());
Niko Matsakis86b6e6e2013-05-10 17:10:35612 }
613
614 r => {
615 self.tcx.sess.span_bug(
616 expr.span,
Patrick Walton36195eb2014-05-16 17:45:16617 format!("bad entry `{:?}` in def_map for label",
618 r).as_slice());
Niko Matsakis86b6e6e2013-05-10 17:10:35619 }
620 }
621 }
622 }
623 }
624
Marvin Löbel74190852013-09-02 01:45:37625 fn is_method_call(&self, expr: &ast::Expr) -> bool {
Eduard Burtescu20b4e152014-03-06 17:24:11626 let method_call = typeck::MethodCall::expr(expr.id);
Felix S. Klock IIaaf398f2014-04-17 19:00:08627 self.tcx.method_map.borrow().contains_key(&method_call)
Niko Matsakis86b6e6e2013-05-10 17:10:35628 }
Patrick Walton99d44d22013-07-10 02:32:09629}