blob: 1419c48609b440ce378d7cb86e40b8ea89cb9229 [file] [log] [blame]
Pythoner6aec34d82014-07-27 11:50:461// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
Niko Matsakis86b6e6e2013-05-10 17:10:352// 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;
Eduard Burtescub0621282014-09-07 17:09:0618use syntax::ptr::P;
Alex Crichtonbec7b762014-02-28 22:34:2619use util::nodemap::NodeMap;
Niko Matsakis86b6e6e2013-05-10 17:10:3520
Eduard Burtescu28be6952014-04-22 12:56:3721struct CFGBuilder<'a, 'tcx: 'a> {
22 tcx: &'a ty::ctxt<'tcx>,
Alex Crichtonbec7b762014-02-28 22:34:2623 exit_map: NodeMap<CFGIndex>,
Niko Matsakis86b6e6e2013-05-10 17:10:3524 graph: CFGGraph,
Felix S. Klock II65b65fe2014-05-08 22:07:5725 fn_exit: CFGIndex,
26 loop_scopes: Vec<LoopScope>,
Niko Matsakis86b6e6e2013-05-10 17:10:3527}
28
29struct LoopScope {
Michael Woerister8a329772013-07-27 08:25:5930 loop_id: ast::NodeId, // id of loop/while node
Niko Matsakis86b6e6e2013-05-10 17:10:3531 continue_index: CFGIndex, // where to go on a `loop`
32 break_index: CFGIndex, // where to go on a `break
33}
34
Eduard Burtescu9b1fee82014-03-06 03:07:4735pub fn construct(tcx: &ty::ctxt,
Michael Woerister4bd14242013-07-19 05:38:5536 blk: &ast::Block) -> CFG {
Felix S. Klock II65b65fe2014-05-08 22:07:5737 let mut graph = graph::Graph::new();
38 let entry = add_initial_dummy_node(&mut graph);
39
40 // `fn_exit` is target of return exprs, which lies somewhere
41 // outside input `blk`. (Distinguishing `fn_exit` and `block_exit`
42 // also resolves chicken-and-egg problem that arises if you try to
43 // have return exprs jump to `block_exit` during construction.)
44 let fn_exit = add_initial_dummy_node(&mut graph);
45 let block_exit;
46
Niko Matsakis86b6e6e2013-05-10 17:10:3547 let mut cfg_builder = CFGBuilder {
Alex Crichtonbec7b762014-02-28 22:34:2648 exit_map: NodeMap::new(),
Felix S. Klock II65b65fe2014-05-08 22:07:5749 graph: graph,
50 fn_exit: fn_exit,
Niko Matsakis86b6e6e2013-05-10 17:10:3551 tcx: tcx,
Patrick Walton3b6e9d42014-03-04 18:02:4952 loop_scopes: Vec::new()
Niko Matsakis86b6e6e2013-05-10 17:10:3553 };
Felix S. Klock II65b65fe2014-05-08 22:07:5754 block_exit = cfg_builder.block(blk, entry);
55 cfg_builder.add_contained_edge(block_exit, fn_exit);
Alex Crichtonab387a62013-11-28 20:22:5356 let CFGBuilder {exit_map, graph, ..} = cfg_builder;
Niko Matsakis86b6e6e2013-05-10 17:10:3557 CFG {exit_map: exit_map,
58 graph: graph,
59 entry: entry,
Felix S. Klock II65b65fe2014-05-08 22:07:5760 exit: fn_exit}
61}
62
63fn add_initial_dummy_node(g: &mut CFGGraph) -> CFGIndex {
64 g.add_node(CFGNodeData { id: ast::DUMMY_NODE_ID })
Niko Matsakis86b6e6e2013-05-10 17:10:3565}
66
Eduard Burtescu28be6952014-04-22 12:56:3767impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
Michael Woerister4bd14242013-07-19 05:38:5568 fn block(&mut self, blk: &ast::Block, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:3569 let mut stmts_exit = pred;
Alex Crichton54c2a1e2014-05-16 17:15:3370 for stmt in blk.stmts.iter() {
Eduard Burtescub0621282014-09-07 17:09:0671 stmts_exit = self.stmt(&**stmt, stmts_exit);
Niko Matsakis86b6e6e2013-05-10 17:10:3572 }
73
Eduard Burtescub0621282014-09-07 17:09:0674 let expr_exit = self.opt_expr(&blk.expr, stmts_exit);
Niko Matsakis86b6e6e2013-05-10 17:10:3575
Michael Woerister0cc70742013-07-16 18:08:3576 self.add_node(blk.id, [expr_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:3577 }
78
Eduard Burtescub0621282014-09-07 17:09:0679 fn stmt(&mut self, stmt: &ast::Stmt, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:3580 match stmt.node {
Niko Matsakis1b487a82014-08-28 01:46:5281 ast::StmtDecl(ref decl, id) => {
82 let exit = self.decl(&**decl, pred);
83 self.add_node(id, [exit])
Niko Matsakis86b6e6e2013-05-10 17:10:3584 }
85
Niko Matsakis1b487a82014-08-28 01:46:5286 ast::StmtExpr(ref expr, id) | ast::StmtSemi(ref expr, id) => {
Eduard Burtescub0621282014-09-07 17:09:0687 let exit = self.expr(&**expr, pred);
Niko Matsakis1b487a82014-08-28 01:46:5288 self.add_node(id, [exit])
Niko Matsakis86b6e6e2013-05-10 17:10:3589 }
90
Alex Crichtonab387a62013-11-28 20:22:5391 ast::StmtMac(..) => {
Niko Matsakis86b6e6e2013-05-10 17:10:3592 self.tcx.sess.span_bug(stmt.span, "unexpanded macro");
93 }
94 }
95 }
96
Alex Crichton54c2a1e2014-05-16 17:15:3397 fn decl(&mut self, decl: &ast::Decl, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:3598 match decl.node {
Alex Crichton54c2a1e2014-05-16 17:15:3399 ast::DeclLocal(ref local) => {
Eduard Burtescub0621282014-09-07 17:09:06100 let init_exit = self.opt_expr(&local.init, pred);
Alex Crichton54c2a1e2014-05-16 17:15:33101 self.pat(&*local.pat, init_exit)
Niko Matsakis86b6e6e2013-05-10 17:10:35102 }
103
Marvin Löbel74190852013-09-02 01:45:37104 ast::DeclItem(_) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35105 pred
106 }
107 }
108 }
109
Alex Crichton54c2a1e2014-05-16 17:15:33110 fn pat(&mut self, pat: &ast::Pat, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35111 match pat.node {
Marvin Löbel74190852013-09-02 01:45:37112 ast::PatIdent(_, _, None) |
113 ast::PatEnum(_, None) |
Alex Crichtonab387a62013-11-28 20:22:53114 ast::PatLit(..) |
115 ast::PatRange(..) |
Felix S. Klock IId3202352014-08-06 15:04:44116 ast::PatWild(_) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35117 self.add_node(pat.id, [pred])
118 }
119
Alex Crichton54c2a1e2014-05-16 17:15:33120 ast::PatBox(ref subpat) |
121 ast::PatRegion(ref subpat) |
122 ast::PatIdent(_, _, Some(ref subpat)) => {
123 let subpat_exit = self.pat(&**subpat, pred);
Niko Matsakis86b6e6e2013-05-10 17:10:35124 self.add_node(pat.id, [subpat_exit])
125 }
126
Marvin Löbel74190852013-09-02 01:45:37127 ast::PatEnum(_, Some(ref subpats)) |
128 ast::PatTup(ref subpats) => {
Eduard Burtescub0621282014-09-07 17:09:06129 let pats_exit = self.pats_all(subpats.iter(), 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 =
P1startead6c4b2014-10-06 00:36:53135 self.pats_all(subpats.iter().map(|f| &f.node.pat), 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) => {
Eduard Burtescub0621282014-09-07 17:09:06140 let pre_exit = self.pats_all(pre.iter(), pred);
141 let vec_exit = self.pats_all(vec.iter(), pre_exit);
142 let post_exit = self.pats_all(post.iter(), vec_exit);
Niko Matsakis86b6e6e2013-05-10 17:10:35143 self.add_node(pat.id, [post_exit])
144 }
Keegan McAllister5fdd0e42014-05-19 20:29:41145
146 ast::PatMac(_) => {
147 self.tcx.sess.span_bug(pat.span, "unexpanded macro");
148 }
Niko Matsakis86b6e6e2013-05-10 17:10:35149 }
150 }
151
Eduard Burtescub0621282014-09-07 17:09:06152 fn pats_all<'a, I: Iterator<&'a P<ast::Pat>>>(&mut self,
153 pats: I,
154 pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35155 //! Handles case where all of the patterns must match.
156 let mut pats = pats;
Eduard Burtescub0621282014-09-07 17:09:06157 pats.fold(pred, |pred, pat| self.pat(&**pat, pred))
Niko Matsakis86b6e6e2013-05-10 17:10:35158 }
159
160 fn pats_any(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06161 pats: &[P<ast::Pat>],
Niko Matsakis86b6e6e2013-05-10 17:10:35162 pred: CFGIndex) -> CFGIndex {
163 //! Handles case where just one of the patterns must match.
164
165 if pats.len() == 1 {
Alex Crichton54c2a1e2014-05-16 17:15:33166 self.pat(&*pats[0], pred)
Niko Matsakis86b6e6e2013-05-10 17:10:35167 } else {
168 let collect = self.add_dummy_node([]);
Eduard Burtescub0621282014-09-07 17:09:06169 for pat in pats.iter() {
170 let pat_exit = self.pat(&**pat, pred);
Niko Matsakis86b6e6e2013-05-10 17:10:35171 self.add_contained_edge(pat_exit, collect);
172 }
173 collect
174 }
175 }
176
Eduard Burtescub0621282014-09-07 17:09:06177 fn expr(&mut self, expr: &ast::Expr, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35178 match expr.node {
Alex Crichton54c2a1e2014-05-16 17:15:33179 ast::ExprBlock(ref blk) => {
180 let blk_exit = self.block(&**blk, pred);
Niko Matsakis86b6e6e2013-05-10 17:10:35181 self.add_node(expr.id, [blk_exit])
182 }
183
Alex Crichton54c2a1e2014-05-16 17:15:33184 ast::ExprIf(ref cond, ref then, None) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35185 //
186 // [pred]
187 // |
188 // v 1
189 // [cond]
190 // |
191 // / \
192 // / \
193 // v 2 *
194 // [then] |
195 // | |
196 // v 3 v 4
197 // [..expr..]
198 //
Eduard Burtescub0621282014-09-07 17:09:06199 let cond_exit = self.expr(&**cond, pred); // 1
Alex Crichton54c2a1e2014-05-16 17:15:33200 let then_exit = self.block(&**then, cond_exit); // 2
201 self.add_node(expr.id, [cond_exit, then_exit]) // 3,4
Niko Matsakis86b6e6e2013-05-10 17:10:35202 }
203
Alex Crichton54c2a1e2014-05-16 17:15:33204 ast::ExprIf(ref cond, ref then, Some(ref otherwise)) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35205 //
206 // [pred]
207 // |
208 // v 1
209 // [cond]
210 // |
211 // / \
212 // / \
213 // v 2 v 3
214 // [then][otherwise]
215 // | |
216 // v 4 v 5
217 // [..expr..]
218 //
Eduard Burtescub0621282014-09-07 17:09:06219 let cond_exit = self.expr(&**cond, pred); // 1
Alex Crichton54c2a1e2014-05-16 17:15:33220 let then_exit = self.block(&**then, cond_exit); // 2
Eduard Burtescub0621282014-09-07 17:09:06221 let else_exit = self.expr(&**otherwise, cond_exit); // 3
Alex Crichton54c2a1e2014-05-16 17:15:33222 self.add_node(expr.id, [then_exit, else_exit]) // 4, 5
Niko Matsakis86b6e6e2013-05-10 17:10:35223 }
224
Kevin Ballard13e00e42014-08-28 04:34:03225 ast::ExprIfLet(..) => {
226 self.tcx.sess.span_bug(expr.span, "non-desugared ExprIfLet");
227 }
Kevin Ballard0e6ff432014-08-25 02:08:48228
Pythoner6373b9d62014-07-26 00:12:51229 ast::ExprWhile(ref cond, ref body, _) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35230 //
231 // [pred]
232 // |
233 // v 1
234 // [loopback] <--+ 5
235 // | |
236 // v 2 |
237 // +-----[cond] |
238 // | | |
239 // | v 4 |
240 // | [body] -----+
241 // v 3
242 // [expr]
243 //
Patrick Waltoncaa564b2014-07-22 03:54:28244 // Note that `break` and `continue` statements
Niko Matsakis86b6e6e2013-05-10 17:10:35245 // may cause additional edges.
246
Michael Sullivan7dbc5ae2013-07-30 23:47:22247 // Is the condition considered part of the loop?
Alex Crichton54c2a1e2014-05-16 17:15:33248 let loopback = self.add_dummy_node([pred]); // 1
Eduard Burtescub0621282014-09-07 17:09:06249 let cond_exit = self.expr(&**cond, loopback); // 2
Alex Crichton54c2a1e2014-05-16 17:15:33250 let expr_exit = self.add_node(expr.id, [cond_exit]); // 3
Niko Matsakis86b6e6e2013-05-10 17:10:35251 self.loop_scopes.push(LoopScope {
252 loop_id: expr.id,
253 continue_index: loopback,
254 break_index: expr_exit
255 });
Alex Crichton54c2a1e2014-05-16 17:15:33256 let body_exit = self.block(&**body, cond_exit); // 4
257 self.add_contained_edge(body_exit, loopback); // 5
Felix S. Klock IIbe9c2d12014-05-20 16:49:19258 self.loop_scopes.pop();
Niko Matsakis86b6e6e2013-05-10 17:10:35259 expr_exit
260 }
261
John Gallagher45fd6232014-10-03 04:41:24262 ast::ExprWhileLet(..) => {
263 self.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
264 }
265
Patrick Waltoncaa564b2014-07-22 03:54:28266 ast::ExprForLoop(ref pat, ref head, ref body, _) => {
267 //
268 // [pred]
269 // |
270 // v 1
271 // [head]
272 // |
273 // v 2
274 // [loopback] <--+ 7
275 // | |
276 // v 3 |
277 // +------[cond] |
278 // | | |
279 // | v 5 |
280 // | [pat] |
281 // | | |
282 // | v 6 |
283 // v 4 [body] -----+
284 // [expr]
285 //
286 // Note that `break` and `continue` statements
287 // may cause additional edges.
288
Eduard Burtescub0621282014-09-07 17:09:06289 let head = self.expr(&**head, pred); // 1
Patrick Waltoncaa564b2014-07-22 03:54:28290 let loopback = self.add_dummy_node([head]); // 2
291 let cond = self.add_dummy_node([loopback]); // 3
292 let expr_exit = self.add_node(expr.id, [cond]); // 4
293 self.loop_scopes.push(LoopScope {
294 loop_id: expr.id,
295 continue_index: loopback,
296 break_index: expr_exit,
297 });
298 let pat = self.pat(&**pat, cond); // 5
299 let body = self.block(&**body, pat); // 6
300 self.add_contained_edge(body, loopback); // 7
301 self.loop_scopes.pop();
302 expr_exit
303 }
Graydon Hoarec29e9fb2013-07-30 00:25:00304
Alex Crichton54c2a1e2014-05-16 17:15:33305 ast::ExprLoop(ref body, _) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35306 //
307 // [pred]
308 // |
309 // v 1
310 // [loopback] <---+
311 // | 4 |
312 // v 3 |
313 // [body] ------+
314 //
315 // [expr] 2
316 //
317 // Note that `break` and `loop` statements
318 // may cause additional edges.
319
Alex Crichton54c2a1e2014-05-16 17:15:33320 let loopback = self.add_dummy_node([pred]); // 1
321 let expr_exit = self.add_node(expr.id, []); // 2
Niko Matsakis86b6e6e2013-05-10 17:10:35322 self.loop_scopes.push(LoopScope {
323 loop_id: expr.id,
324 continue_index: loopback,
325 break_index: expr_exit,
326 });
Alex Crichton54c2a1e2014-05-16 17:15:33327 let body_exit = self.block(&**body, loopback); // 3
328 self.add_contained_edge(body_exit, loopback); // 4
Niko Matsakis86b6e6e2013-05-10 17:10:35329 self.loop_scopes.pop();
330 expr_exit
331 }
332
Kevin Ballard976438f2014-08-25 21:55:00333 ast::ExprMatch(ref discr, ref arms, _) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35334 //
335 // [pred]
336 // |
337 // v 1
338 // [discr]
339 // |
340 // v 2
Patrick Waltonb2eb8882014-07-25 22:18:19341 // [cond1]
Niko Matsakis86b6e6e2013-05-10 17:10:35342 // / \
343 // | \
Patrick Waltonb2eb8882014-07-25 22:18:19344 // v 3 \
345 // [pat1] \
346 // | |
347 // v 4 |
348 // [guard1] |
349 // | |
350 // | |
351 // v 5 v
352 // [body1] [cond2]
353 // | / \
354 // | ... ...
355 // | | |
356 // v 6 v v
357 // [.....expr.....]
Niko Matsakis86b6e6e2013-05-10 17:10:35358 //
Eduard Burtescub0621282014-09-07 17:09:06359 let discr_exit = self.expr(&**discr, pred); // 1
Niko Matsakis86b6e6e2013-05-10 17:10:35360
361 let expr_exit = self.add_node(expr.id, []);
Patrick Waltonb2eb8882014-07-25 22:18:19362 let mut cond_exit = discr_exit;
Daniel Micay100894552013-08-03 16:45:23363 for arm in arms.iter() {
Patrick Waltonb2eb8882014-07-25 22:18:19364 cond_exit = self.add_dummy_node([cond_exit]); // 2
Patrick Waltonc1ed4d72014-02-28 23:25:15365 let pats_exit = self.pats_any(arm.pats.as_slice(),
Patrick Waltonb2eb8882014-07-25 22:18:19366 cond_exit); // 3
Eduard Burtescub0621282014-09-07 17:09:06367 let guard_exit = self.opt_expr(&arm.guard,
Patrick Waltonb2eb8882014-07-25 22:18:19368 pats_exit); // 4
Eduard Burtescub0621282014-09-07 17:09:06369 let body_exit = self.expr(&*arm.body, guard_exit); // 5
Patrick Waltonb2eb8882014-07-25 22:18:19370 self.add_contained_edge(body_exit, expr_exit); // 6
Niko Matsakis86b6e6e2013-05-10 17:10:35371 }
372 expr_exit
373 }
374
Alex Crichton54c2a1e2014-05-16 17:15:33375 ast::ExprBinary(op, ref l, ref r) if ast_util::lazy_binop(op) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35376 //
377 // [pred]
378 // |
379 // v 1
380 // [l]
381 // |
382 // / \
383 // / \
384 // v 2 *
385 // [r] |
386 // | |
387 // v 3 v 4
388 // [..exit..]
389 //
Eduard Burtescub0621282014-09-07 17:09:06390 let l_exit = self.expr(&**l, pred); // 1
391 let r_exit = self.expr(&**r, l_exit); // 2
Niko Matsakis86b6e6e2013-05-10 17:10:35392 self.add_node(expr.id, [l_exit, r_exit]) // 3,4
393 }
394
Alex Crichton54c2a1e2014-05-16 17:15:33395 ast::ExprRet(ref v) => {
Eduard Burtescub0621282014-09-07 17:09:06396 let v_exit = self.opt_expr(v, pred);
Felix S. Klock II65b65fe2014-05-08 22:07:57397 let b = self.add_node(expr.id, [v_exit]);
398 self.add_returning_edge(expr, b);
399 self.add_node(ast::DUMMY_NODE_ID, [])
Niko Matsakis86b6e6e2013-05-10 17:10:35400 }
401
Marvin Löbel74190852013-09-02 01:45:37402 ast::ExprBreak(label) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35403 let loop_scope = self.find_scope(expr, label);
Felix S. Klock II65b65fe2014-05-08 22:07:57404 let b = self.add_node(expr.id, [pred]);
405 self.add_exiting_edge(expr, b,
Niko Matsakis86b6e6e2013-05-10 17:10:35406 loop_scope, loop_scope.break_index);
Felix S. Klock II65b65fe2014-05-08 22:07:57407 self.add_node(ast::DUMMY_NODE_ID, [])
Niko Matsakis86b6e6e2013-05-10 17:10:35408 }
409
Marvin Löbel74190852013-09-02 01:45:37410 ast::ExprAgain(label) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35411 let loop_scope = self.find_scope(expr, label);
Felix S. Klock II65b65fe2014-05-08 22:07:57412 let a = self.add_node(expr.id, [pred]);
413 self.add_exiting_edge(expr, a,
Niko Matsakis86b6e6e2013-05-10 17:10:35414 loop_scope, loop_scope.continue_index);
Felix S. Klock II65b65fe2014-05-08 22:07:57415 self.add_node(ast::DUMMY_NODE_ID, [])
Niko Matsakis86b6e6e2013-05-10 17:10:35416 }
417
Eduard Burtescu7c48e532014-04-04 10:12:18418 ast::ExprVec(ref elems) => {
Eduard Burtescub0621282014-09-07 17:09:06419 self.straightline(expr, pred, elems.iter().map(|e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35420 }
421
Alex Crichton54c2a1e2014-05-16 17:15:33422 ast::ExprCall(ref func, ref args) => {
Eduard Burtescub0621282014-09-07 17:09:06423 self.call(expr, pred, &**func, args.iter().map(|e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35424 }
425
Eduard Burtescu05e4d942014-02-26 14:06:45426 ast::ExprMethodCall(_, _, ref args) => {
Alex Crichton9d5d97b2014-10-15 06:05:01427 self.call(expr, pred, &*args[0], args.slice_from(1).iter().map(|e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35428 }
429
Alex Crichton54c2a1e2014-05-16 17:15:33430 ast::ExprIndex(ref l, ref r) |
Eduard Burtescub0621282014-09-07 17:09:06431 ast::ExprBinary(_, ref l, ref r) if self.is_method_call(expr) => {
Aaron Turonfc525ee2014-09-15 03:27:36432 self.call(expr, pred, &**l, Some(&**r).into_iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35433 }
434
Nick Cameron31a7e382014-09-15 08:48:58435 ast::ExprSlice(ref base, ref start, ref end, _) => {
436 self.call(expr,
437 pred,
438 &**base,
439 start.iter().chain(end.iter()).map(|x| &**x))
440 }
441
Eduard Burtescub0621282014-09-07 17:09:06442 ast::ExprUnary(_, ref e) if self.is_method_call(expr) => {
443 self.call(expr, pred, &**e, None::<ast::Expr>.iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35444 }
445
Marvin Löbel74190852013-09-02 01:45:37446 ast::ExprTup(ref exprs) => {
Eduard Burtescub0621282014-09-07 17:09:06447 self.straightline(expr, pred, exprs.iter().map(|e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35448 }
449
Eduard Burtescub0621282014-09-07 17:09:06450 ast::ExprStruct(_, ref fields, ref base) => {
Brandon Sandersond80a62d2014-11-05 23:05:01451 let field_cfg = self.straightline(expr, pred, fields.iter().map(|f| &*f.expr));
452 self.opt_expr(base, field_cfg)
Niko Matsakis86b6e6e2013-05-10 17:10:35453 }
454
Eduard Burtescub0621282014-09-07 17:09:06455 ast::ExprRepeat(ref elem, ref count) => {
456 self.straightline(expr, pred, [elem, count].iter().map(|&e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35457 }
458
Eduard Burtescub0621282014-09-07 17:09:06459 ast::ExprAssign(ref l, ref r) |
460 ast::ExprAssignOp(_, ref l, ref r) => {
461 self.straightline(expr, pred, [r, l].iter().map(|&e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35462 }
463
Eduard Burtescub0621282014-09-07 17:09:06464 ast::ExprIndex(ref l, ref r) |
465 ast::ExprBinary(_, ref l, ref r) => { // NB: && and || handled earlier
466 self.straightline(expr, pred, [l, r].iter().map(|&e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35467 }
468
Eduard Burtescub0621282014-09-07 17:09:06469 ast::ExprBox(ref p, ref e) => {
470 self.straightline(expr, pred, [p, e].iter().map(|&e| &**e))
Patrick Waltone1271152013-12-18 00:46:18471 }
472
Eduard Burtescub0621282014-09-07 17:09:06473 ast::ExprAddrOf(_, ref e) |
474 ast::ExprCast(ref e, _) |
475 ast::ExprUnary(_, ref e) |
476 ast::ExprParen(ref e) |
477 ast::ExprField(ref e, _, _) |
478 ast::ExprTupField(ref e, _, _) => {
Aaron Turonfc525ee2014-09-15 03:27:36479 self.straightline(expr, pred, Some(&**e).into_iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35480 }
481
Felix S. Klock IIbe9c2d12014-05-20 16:49:19482 ast::ExprInlineAsm(ref inline_asm) => {
483 let inputs = inline_asm.inputs.iter();
484 let outputs = inline_asm.outputs.iter();
Felix S. Klock IIbe9c2d12014-05-20 16:49:19485 let post_inputs = self.exprs(inputs.map(|a| {
Luqman Aden814586b2014-10-15 06:25:34486 debug!("cfg::construct InlineAsm id:{} input:{}", expr.id, a);
Eduard Burtescub0621282014-09-07 17:09:06487 let &(_, ref expr) = a;
488 &**expr
Felix S. Klock IIbe9c2d12014-05-20 16:49:19489 }), pred);
490 let post_outputs = self.exprs(outputs.map(|a| {
Luqman Aden814586b2014-10-15 06:25:34491 debug!("cfg::construct InlineAsm id:{} output:{}", expr.id, a);
Eduard Burtescub0621282014-09-07 17:09:06492 let &(_, ref expr, _) = a;
493 &**expr
Felix S. Klock IIbe9c2d12014-05-20 16:49:19494 }), post_inputs);
495 self.add_node(expr.id, [post_outputs])
496 }
497
Alex Crichtonab387a62013-11-28 20:22:53498 ast::ExprMac(..) |
Alex Crichtonab387a62013-11-28 20:22:53499 ast::ExprFnBlock(..) |
500 ast::ExprProc(..) |
Patrick Walton02adaca2014-05-29 05:26:56501 ast::ExprUnboxedFn(..) |
Alex Crichtonab387a62013-11-28 20:22:53502 ast::ExprLit(..) |
503 ast::ExprPath(..) => {
Eduard Burtescub0621282014-09-07 17:09:06504 self.straightline(expr, pred, None::<ast::Expr>.iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35505 }
506 }
507 }
508
Eduard Burtescub0621282014-09-07 17:09:06509 fn call<'a, I: Iterator<&'a ast::Expr>>(&mut self,
510 call_expr: &ast::Expr,
Niko Matsakis86b6e6e2013-05-10 17:10:35511 pred: CFGIndex,
Eduard Burtescub0621282014-09-07 17:09:06512 func_or_rcvr: &ast::Expr,
513 args: I) -> CFGIndex {
Jakub Bukajcca84e92014-10-24 19:14:37514 let method_call = typeck::MethodCall::expr(call_expr.id);
515 let return_ty = ty::ty_fn_ret(match self.tcx.method_map.borrow().find(&method_call) {
516 Some(method) => method.ty,
517 None => ty::expr_ty(self.tcx, func_or_rcvr)
518 });
519
Niko Matsakis86b6e6e2013-05-10 17:10:35520 let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
Felix S. Klock IIbe9c2d12014-05-20 16:49:19521 let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
Jakub Bukajcca84e92014-10-24 19:14:37522 if return_ty == ty::FnDiverging {
Felix S. Klock IIbe9c2d12014-05-20 16:49:19523 self.add_node(ast::DUMMY_NODE_ID, [])
524 } else {
525 ret
526 }
Niko Matsakis86b6e6e2013-05-10 17:10:35527 }
528
Eduard Burtescub0621282014-09-07 17:09:06529 fn exprs<'a, I: Iterator<&'a ast::Expr>>(&mut self,
530 mut exprs: I,
531 pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35532 //! Constructs graph for `exprs` evaluated in order
Felix S. Klock IIbe9c2d12014-05-20 16:49:19533 exprs.fold(pred, |p, e| self.expr(e, p))
Niko Matsakis86b6e6e2013-05-10 17:10:35534 }
535
536 fn opt_expr(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06537 opt_expr: &Option<P<ast::Expr>>,
Niko Matsakis86b6e6e2013-05-10 17:10:35538 pred: CFGIndex) -> CFGIndex {
539 //! Constructs graph for `opt_expr` evaluated, if Some
Eduard Burtescub0621282014-09-07 17:09:06540 opt_expr.iter().fold(pred, |p, e| self.expr(&**e, p))
Niko Matsakis86b6e6e2013-05-10 17:10:35541 }
542
Eduard Burtescub0621282014-09-07 17:09:06543 fn straightline<'a, I: Iterator<&'a ast::Expr>>(&mut self,
544 expr: &ast::Expr,
Niko Matsakis86b6e6e2013-05-10 17:10:35545 pred: CFGIndex,
Eduard Burtescub0621282014-09-07 17:09:06546 subexprs: I) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35547 //! Handles case of an expression that evaluates `subexprs` in order
548
Eduard Burtescub0621282014-09-07 17:09:06549 let subexprs_exit = self.exprs(subexprs, pred);
Niko Matsakis86b6e6e2013-05-10 17:10:35550 self.add_node(expr.id, [subexprs_exit])
551 }
552
553 fn add_dummy_node(&mut self, preds: &[CFGIndex]) -> CFGIndex {
Felix S. Klock II65b65fe2014-05-08 22:07:57554 self.add_node(ast::DUMMY_NODE_ID, preds)
Niko Matsakis86b6e6e2013-05-10 17:10:35555 }
556
Michael Woerister8a329772013-07-27 08:25:59557 fn add_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35558 assert!(!self.exit_map.contains_key(&id));
559 let node = self.graph.add_node(CFGNodeData {id: id});
Felix S. Klock II65b65fe2014-05-08 22:07:57560 if id != ast::DUMMY_NODE_ID {
561 assert!(!self.exit_map.contains_key(&id));
562 self.exit_map.insert(id, node);
563 }
Daniel Micay100894552013-08-03 16:45:23564 for &pred in preds.iter() {
Niko Matsakis86b6e6e2013-05-10 17:10:35565 self.add_contained_edge(pred, node);
566 }
567 node
568 }
569
570 fn add_contained_edge(&mut self,
571 source: CFGIndex,
572 target: CFGIndex) {
Huon Wilson7785fe12014-03-19 12:16:56573 let data = CFGEdgeData {exiting_scopes: vec!() };
Niko Matsakis86b6e6e2013-05-10 17:10:35574 self.graph.add_edge(source, target, data);
575 }
576
577 fn add_exiting_edge(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06578 from_expr: &ast::Expr,
Niko Matsakis86b6e6e2013-05-10 17:10:35579 from_index: CFGIndex,
580 to_loop: LoopScope,
581 to_index: CFGIndex) {
Huon Wilson7785fe12014-03-19 12:16:56582 let mut data = CFGEdgeData {exiting_scopes: vec!() };
Niko Matsakis86b6e6e2013-05-10 17:10:35583 let mut scope_id = from_expr.id;
584 while scope_id != to_loop.loop_id {
Huon Wilson7785fe12014-03-19 12:16:56585
Niko Matsakis86b6e6e2013-05-10 17:10:35586 data.exiting_scopes.push(scope_id);
587 scope_id = self.tcx.region_maps.encl_scope(scope_id);
588 }
589 self.graph.add_edge(from_index, to_index, data);
590 }
591
Felix S. Klock II65b65fe2014-05-08 22:07:57592 fn add_returning_edge(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06593 _from_expr: &ast::Expr,
Felix S. Klock II65b65fe2014-05-08 22:07:57594 from_index: CFGIndex) {
Patrick Walton36195eb2014-05-16 17:45:16595 let mut data = CFGEdgeData {
596 exiting_scopes: vec!(),
597 };
Felix S. Klock II65b65fe2014-05-08 22:07:57598 for &LoopScope { loop_id: id, .. } in self.loop_scopes.iter().rev() {
599 data.exiting_scopes.push(id);
600 }
601 self.graph.add_edge(from_index, self.fn_exit, data);
602 }
603
Niko Matsakis86b6e6e2013-05-10 17:10:35604 fn find_scope(&self,
Eduard Burtescub0621282014-09-07 17:09:06605 expr: &ast::Expr,
Edward Wang386db052014-02-15 08:54:32606 label: Option<ast::Ident>) -> LoopScope {
Niko Matsakis86b6e6e2013-05-10 17:10:35607 match label {
608 None => {
Simon Sapinaa66b912013-12-23 14:08:23609 return *self.loop_scopes.last().unwrap();
Niko Matsakis86b6e6e2013-05-10 17:10:35610 }
611
612 Some(_) => {
Alex Crichton0dbb9092014-03-21 02:49:20613 match self.tcx.def_map.borrow().find(&expr.id) {
Niko Matsakis0f03b562014-05-14 19:31:30614 Some(&def::DefLabel(loop_id)) => {
Daniel Micay100894552013-08-03 16:45:23615 for l in self.loop_scopes.iter() {
Niko Matsakis86b6e6e2013-05-10 17:10:35616 if l.loop_id == loop_id {
617 return *l;
618 }
619 }
620 self.tcx.sess.span_bug(
621 expr.span,
Luqman Aden814586b2014-10-15 06:25:34622 format!("no loop scope for id {}",
Patrick Walton36195eb2014-05-16 17:45:16623 loop_id).as_slice());
Niko Matsakis86b6e6e2013-05-10 17:10:35624 }
625
626 r => {
627 self.tcx.sess.span_bug(
628 expr.span,
Luqman Aden814586b2014-10-15 06:25:34629 format!("bad entry `{}` in def_map for label",
Patrick Walton36195eb2014-05-16 17:45:16630 r).as_slice());
Niko Matsakis86b6e6e2013-05-10 17:10:35631 }
632 }
633 }
634 }
635 }
636
Marvin Löbel74190852013-09-02 01:45:37637 fn is_method_call(&self, expr: &ast::Expr) -> bool {
Eduard Burtescu20b4e152014-03-06 17:24:11638 let method_call = typeck::MethodCall::expr(expr.id);
Felix S. Klock IIaaf398f2014-04-17 19:00:08639 self.tcx.method_map.borrow().contains_key(&method_call)
Niko Matsakis86b6e6e2013-05-10 17:10:35640 }
Patrick Walton99d44d22013-07-10 02:32:09641}