blob: a7b28a6323eaff7e09d43f18e6180bbad77b1003 [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;
Felix S. Klock II5ff90872014-11-18 13:22:5914use middle::region::CodeExtent;
Niko Matsakis86b6e6e2013-05-10 17:10:3515use 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
Jorge Aparicioe64a0072014-12-15 04:03:3429#[deriving(Copy)]
Niko Matsakis86b6e6e2013-05-10 17:10:3530struct 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 Burtescu28be6952014-04-22 12:56:3768impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
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() {
Eduard Burtescub0621282014-09-07 17:09:0672 stmts_exit = self.stmt(&**stmt, stmts_exit);
Niko Matsakis86b6e6e2013-05-10 17:10:3573 }
74
Eduard Burtescub0621282014-09-07 17:09:0675 let expr_exit = self.opt_expr(&blk.expr, stmts_exit);
Niko Matsakis86b6e6e2013-05-10 17:10:3576
Nick Cameronca085402014-11-17 08:39:0177 self.add_node(blk.id, &[expr_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:3578 }
79
Eduard Burtescub0621282014-09-07 17:09:0680 fn stmt(&mut self, stmt: &ast::Stmt, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:3581 match stmt.node {
Niko Matsakis1b487a82014-08-28 01:46:5282 ast::StmtDecl(ref decl, id) => {
83 let exit = self.decl(&**decl, pred);
Nick Cameronca085402014-11-17 08:39:0184 self.add_node(id, &[exit])
Niko Matsakis86b6e6e2013-05-10 17:10:3585 }
86
Niko Matsakis1b487a82014-08-28 01:46:5287 ast::StmtExpr(ref expr, id) | ast::StmtSemi(ref expr, id) => {
Eduard Burtescub0621282014-09-07 17:09:0688 let exit = self.expr(&**expr, pred);
Nick Cameronca085402014-11-17 08:39:0189 self.add_node(id, &[exit])
Niko Matsakis86b6e6e2013-05-10 17:10:3590 }
91
Alex Crichtonab387a62013-11-28 20:22:5392 ast::StmtMac(..) => {
Niko Matsakis86b6e6e2013-05-10 17:10:3593 self.tcx.sess.span_bug(stmt.span, "unexpanded macro");
94 }
95 }
96 }
97
Alex Crichton54c2a1e2014-05-16 17:15:3398 fn decl(&mut self, decl: &ast::Decl, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:3599 match decl.node {
Alex Crichton54c2a1e2014-05-16 17:15:33100 ast::DeclLocal(ref local) => {
Eduard Burtescub0621282014-09-07 17:09:06101 let init_exit = self.opt_expr(&local.init, pred);
Alex Crichton54c2a1e2014-05-16 17:15:33102 self.pat(&*local.pat, init_exit)
Niko Matsakis86b6e6e2013-05-10 17:10:35103 }
104
Marvin Löbel74190852013-09-02 01:45:37105 ast::DeclItem(_) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35106 pred
107 }
108 }
109 }
110
Alex Crichton54c2a1e2014-05-16 17:15:33111 fn pat(&mut self, pat: &ast::Pat, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35112 match pat.node {
Marvin Löbel74190852013-09-02 01:45:37113 ast::PatIdent(_, _, None) |
114 ast::PatEnum(_, None) |
Alex Crichtonab387a62013-11-28 20:22:53115 ast::PatLit(..) |
116 ast::PatRange(..) |
Felix S. Klock IId3202352014-08-06 15:04:44117 ast::PatWild(_) => {
Nick Cameronca085402014-11-17 08:39:01118 self.add_node(pat.id, &[pred])
Niko Matsakis86b6e6e2013-05-10 17:10:35119 }
120
Alex Crichton54c2a1e2014-05-16 17:15:33121 ast::PatBox(ref subpat) |
122 ast::PatRegion(ref subpat) |
123 ast::PatIdent(_, _, Some(ref subpat)) => {
124 let subpat_exit = self.pat(&**subpat, pred);
Nick Cameronca085402014-11-17 08:39:01125 self.add_node(pat.id, &[subpat_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35126 }
127
Marvin Löbel74190852013-09-02 01:45:37128 ast::PatEnum(_, Some(ref subpats)) |
129 ast::PatTup(ref subpats) => {
Eduard Burtescub0621282014-09-07 17:09:06130 let pats_exit = self.pats_all(subpats.iter(), pred);
Nick Cameronca085402014-11-17 08:39:01131 self.add_node(pat.id, &[pats_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35132 }
133
Marvin Löbel74190852013-09-02 01:45:37134 ast::PatStruct(_, ref subpats, _) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35135 let pats_exit =
P1startead6c4b2014-10-06 00:36:53136 self.pats_all(subpats.iter().map(|f| &f.node.pat), pred);
Nick Cameronca085402014-11-17 08:39:01137 self.add_node(pat.id, &[pats_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35138 }
139
Marvin Löbel74190852013-09-02 01:45:37140 ast::PatVec(ref pre, ref vec, ref post) => {
Eduard Burtescub0621282014-09-07 17:09:06141 let pre_exit = self.pats_all(pre.iter(), pred);
142 let vec_exit = self.pats_all(vec.iter(), pre_exit);
143 let post_exit = self.pats_all(post.iter(), vec_exit);
Nick Cameronca085402014-11-17 08:39:01144 self.add_node(pat.id, &[post_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35145 }
Keegan McAllister5fdd0e42014-05-19 20:29:41146
147 ast::PatMac(_) => {
148 self.tcx.sess.span_bug(pat.span, "unexpanded macro");
149 }
Niko Matsakis86b6e6e2013-05-10 17:10:35150 }
151 }
152
Jorge Aparicio62ee3f12015-01-02 04:26:38153 fn pats_all<'b, I: Iterator<Item=&'b P<ast::Pat>>>(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06154 pats: I,
155 pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35156 //! Handles case where all of the patterns must match.
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 {
Nick Cameronca085402014-11-17 08:39:01168 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);
Nick Cameronca085402014-11-17 08:39:01181 self.add_node(expr.id, &[blk_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35182 }
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
Nick Cameronca085402014-11-17 08:39:01201 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
Nick Cameronca085402014-11-17 08:39:01222 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?
Nick Cameronca085402014-11-17 08:39:01248 let loopback = self.add_dummy_node(&[pred]); // 1
249 let cond_exit = self.expr(&**cond, loopback); // 2
250 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
Nick Cameronca085402014-11-17 08:39:01289 let head = self.expr(&**head, pred); // 1
290 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
Patrick Waltoncaa564b2014-07-22 03:54:28293 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
Nick Cameronca085402014-11-17 08:39:01320 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
Nick Cameronca085402014-11-17 08:39:01361 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() {
Nick Cameronca085402014-11-17 08:39:01364 cond_exit = self.add_dummy_node(&[cond_exit]); // 2
Alex Crichton082bfde2014-12-11 03:46:38365 let pats_exit = self.pats_any(arm.pats[],
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
Nick Cameronca085402014-11-17 08:39:01392 self.add_node(expr.id, &[l_exit, r_exit]) // 3,4
Niko Matsakis86b6e6e2013-05-10 17:10:35393 }
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);
Nick Cameronca085402014-11-17 08:39:01397 let b = self.add_node(expr.id, &[v_exit]);
Felix S. Klock II65b65fe2014-05-08 22:07:57398 self.add_returning_edge(expr, b);
Nick Cameronca085402014-11-17 08:39:01399 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);
Nick Cameronca085402014-11-17 08:39:01404 let b = self.add_node(expr.id, &[pred]);
Felix S. Klock II65b65fe2014-05-08 22:07:57405 self.add_exiting_edge(expr, b,
Niko Matsakis86b6e6e2013-05-10 17:10:35406 loop_scope, loop_scope.break_index);
Nick Cameronca085402014-11-17 08:39:01407 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);
Nick Cameronca085402014-11-17 08:39:01412 let a = self.add_node(expr.id, &[pred]);
Felix S. Klock II65b65fe2014-05-08 22:07:57413 self.add_exiting_edge(expr, a,
Niko Matsakis86b6e6e2013-05-10 17:10:35414 loop_scope, loop_scope.continue_index);
Nick Cameronca085402014-11-17 08:39:01415 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 Cameron17826e12014-12-15 00:17:11435 ast::ExprRange(ref start, ref end) => {
Nick Cameroned8f5032014-12-18 04:55:04436 let fields = start.as_ref().map(|e| &**e).into_iter()
Nick Cameron17826e12014-12-15 00:17:11437 .chain(end.as_ref().map(|e| &**e).into_iter());
438 self.straightline(expr, pred, fields)
Nick Cameron8a357e12014-12-13 05:41:02439 }
440
Eduard Burtescub0621282014-09-07 17:09:06441 ast::ExprUnary(_, ref e) if self.is_method_call(expr) => {
442 self.call(expr, pred, &**e, None::<ast::Expr>.iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35443 }
444
Marvin Löbel74190852013-09-02 01:45:37445 ast::ExprTup(ref exprs) => {
Eduard Burtescub0621282014-09-07 17:09:06446 self.straightline(expr, pred, exprs.iter().map(|e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35447 }
448
Eduard Burtescub0621282014-09-07 17:09:06449 ast::ExprStruct(_, ref fields, ref base) => {
Brandon Sandersond80a62d2014-11-05 23:05:01450 let field_cfg = self.straightline(expr, pred, fields.iter().map(|f| &*f.expr));
451 self.opt_expr(base, field_cfg)
Niko Matsakis86b6e6e2013-05-10 17:10:35452 }
453
Eduard Burtescub0621282014-09-07 17:09:06454 ast::ExprRepeat(ref elem, ref count) => {
455 self.straightline(expr, pred, [elem, count].iter().map(|&e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35456 }
457
Eduard Burtescub0621282014-09-07 17:09:06458 ast::ExprAssign(ref l, ref r) |
459 ast::ExprAssignOp(_, ref l, ref r) => {
460 self.straightline(expr, pred, [r, l].iter().map(|&e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35461 }
462
Felix S. Klock II7d4e7f02014-12-16 13:30:30463 ast::ExprBox(Some(ref l), ref r) |
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
Felix S. Klock II7d4e7f02014-12-16 13:30:30469 ast::ExprBox(None, ref e) |
Eduard Burtescub0621282014-09-07 17:09:06470 ast::ExprAddrOf(_, ref e) |
471 ast::ExprCast(ref e, _) |
472 ast::ExprUnary(_, ref e) |
473 ast::ExprParen(ref e) |
Adolfo OchagavĂ­a35316972014-11-23 11:14:35474 ast::ExprField(ref e, _) |
475 ast::ExprTupField(ref e, _) => {
Aaron Turonfc525ee2014-09-15 03:27:36476 self.straightline(expr, pred, Some(&**e).into_iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35477 }
478
Felix S. Klock IIbe9c2d12014-05-20 16:49:19479 ast::ExprInlineAsm(ref inline_asm) => {
480 let inputs = inline_asm.inputs.iter();
481 let outputs = inline_asm.outputs.iter();
Felix S. Klock IIbe9c2d12014-05-20 16:49:19482 let post_inputs = self.exprs(inputs.map(|a| {
Luqman Aden814586b2014-10-15 06:25:34483 debug!("cfg::construct InlineAsm id:{} input:{}", expr.id, a);
Eduard Burtescub0621282014-09-07 17:09:06484 let &(_, ref expr) = a;
485 &**expr
Felix S. Klock IIbe9c2d12014-05-20 16:49:19486 }), pred);
487 let post_outputs = self.exprs(outputs.map(|a| {
Luqman Aden814586b2014-10-15 06:25:34488 debug!("cfg::construct InlineAsm id:{} output:{}", expr.id, a);
Eduard Burtescub0621282014-09-07 17:09:06489 let &(_, ref expr, _) = a;
490 &**expr
Felix S. Klock IIbe9c2d12014-05-20 16:49:19491 }), post_inputs);
Nick Cameronca085402014-11-17 08:39:01492 self.add_node(expr.id, &[post_outputs])
Felix S. Klock IIbe9c2d12014-05-20 16:49:19493 }
494
Alex Crichtonab387a62013-11-28 20:22:53495 ast::ExprMac(..) |
Niko Matsakis3e2929d2014-11-19 16:18:17496 ast::ExprClosure(..) |
Alex Crichtonab387a62013-11-28 20:22:53497 ast::ExprLit(..) |
498 ast::ExprPath(..) => {
Eduard Burtescub0621282014-09-07 17:09:06499 self.straightline(expr, pred, None::<ast::Expr>.iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35500 }
501 }
502 }
503
Jorge Aparicio62ee3f12015-01-02 04:26:38504 fn call<'b, I: Iterator<Item=&'b ast::Expr>>(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06505 call_expr: &ast::Expr,
Niko Matsakis86b6e6e2013-05-10 17:10:35506 pred: CFGIndex,
Eduard Burtescub0621282014-09-07 17:09:06507 func_or_rcvr: &ast::Expr,
508 args: I) -> CFGIndex {
Niko Matsakis7c445612014-11-25 19:21:20509 let method_call = ty::MethodCall::expr(call_expr.id);
Alexis Beingessnereec145b2014-11-06 17:25:16510 let return_ty = ty::ty_fn_ret(match self.tcx.method_map.borrow().get(&method_call) {
Jakub Bukajcca84e92014-10-24 19:14:37511 Some(method) => method.ty,
512 None => ty::expr_ty(self.tcx, func_or_rcvr)
513 });
514
Niko Matsakis86b6e6e2013-05-10 17:10:35515 let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
Felix S. Klock IIbe9c2d12014-05-20 16:49:19516 let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
Jakub Bukajcca84e92014-10-24 19:14:37517 if return_ty == ty::FnDiverging {
Nick Cameronca085402014-11-17 08:39:01518 self.add_node(ast::DUMMY_NODE_ID, &[])
Felix S. Klock IIbe9c2d12014-05-20 16:49:19519 } else {
520 ret
521 }
Niko Matsakis86b6e6e2013-05-10 17:10:35522 }
523
Jorge Aparicio62ee3f12015-01-02 04:26:38524 fn exprs<'b, I: Iterator<Item=&'b ast::Expr>>(&mut self,
Aaron Turonb299c2b2014-11-06 17:32:37525 exprs: I,
Eduard Burtescub0621282014-09-07 17:09:06526 pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35527 //! Constructs graph for `exprs` evaluated in order
Felix S. Klock IIbe9c2d12014-05-20 16:49:19528 exprs.fold(pred, |p, e| self.expr(e, p))
Niko Matsakis86b6e6e2013-05-10 17:10:35529 }
530
531 fn opt_expr(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06532 opt_expr: &Option<P<ast::Expr>>,
Niko Matsakis86b6e6e2013-05-10 17:10:35533 pred: CFGIndex) -> CFGIndex {
534 //! Constructs graph for `opt_expr` evaluated, if Some
Eduard Burtescub0621282014-09-07 17:09:06535 opt_expr.iter().fold(pred, |p, e| self.expr(&**e, p))
Niko Matsakis86b6e6e2013-05-10 17:10:35536 }
537
Jorge Aparicio62ee3f12015-01-02 04:26:38538 fn straightline<'b, I: Iterator<Item=&'b ast::Expr>>(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06539 expr: &ast::Expr,
Niko Matsakis86b6e6e2013-05-10 17:10:35540 pred: CFGIndex,
Eduard Burtescub0621282014-09-07 17:09:06541 subexprs: I) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35542 //! Handles case of an expression that evaluates `subexprs` in order
543
Eduard Burtescub0621282014-09-07 17:09:06544 let subexprs_exit = self.exprs(subexprs, pred);
Nick Cameronca085402014-11-17 08:39:01545 self.add_node(expr.id, &[subexprs_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35546 }
547
548 fn add_dummy_node(&mut self, preds: &[CFGIndex]) -> CFGIndex {
Felix S. Klock II65b65fe2014-05-08 22:07:57549 self.add_node(ast::DUMMY_NODE_ID, preds)
Niko Matsakis86b6e6e2013-05-10 17:10:35550 }
551
Michael Woerister8a329772013-07-27 08:25:59552 fn add_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35553 assert!(!self.exit_map.contains_key(&id));
554 let node = self.graph.add_node(CFGNodeData {id: id});
Felix S. Klock II65b65fe2014-05-08 22:07:57555 if id != ast::DUMMY_NODE_ID {
556 assert!(!self.exit_map.contains_key(&id));
557 self.exit_map.insert(id, node);
558 }
Daniel Micay100894552013-08-03 16:45:23559 for &pred in preds.iter() {
Niko Matsakis86b6e6e2013-05-10 17:10:35560 self.add_contained_edge(pred, node);
561 }
562 node
563 }
564
565 fn add_contained_edge(&mut self,
566 source: CFGIndex,
567 target: CFGIndex) {
Huon Wilson7785fe12014-03-19 12:16:56568 let data = CFGEdgeData {exiting_scopes: vec!() };
Niko Matsakis86b6e6e2013-05-10 17:10:35569 self.graph.add_edge(source, target, data);
570 }
571
572 fn add_exiting_edge(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06573 from_expr: &ast::Expr,
Niko Matsakis86b6e6e2013-05-10 17:10:35574 from_index: CFGIndex,
575 to_loop: LoopScope,
576 to_index: CFGIndex) {
Huon Wilson7785fe12014-03-19 12:16:56577 let mut data = CFGEdgeData {exiting_scopes: vec!() };
Felix S. Klock II5ff90872014-11-18 13:22:59578 let mut scope = CodeExtent::from_node_id(from_expr.id);
579 let target_scope = CodeExtent::from_node_id(to_loop.loop_id);
580 while scope != target_scope {
Huon Wilson7785fe12014-03-19 12:16:56581
Felix S. Klock II5ff90872014-11-18 13:22:59582 data.exiting_scopes.push(scope.node_id());
583 scope = self.tcx.region_maps.encl_scope(scope);
Niko Matsakis86b6e6e2013-05-10 17:10:35584 }
585 self.graph.add_edge(from_index, to_index, data);
586 }
587
Felix S. Klock II65b65fe2014-05-08 22:07:57588 fn add_returning_edge(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06589 _from_expr: &ast::Expr,
Felix S. Klock II65b65fe2014-05-08 22:07:57590 from_index: CFGIndex) {
Patrick Walton36195eb2014-05-16 17:45:16591 let mut data = CFGEdgeData {
592 exiting_scopes: vec!(),
593 };
Felix S. Klock II65b65fe2014-05-08 22:07:57594 for &LoopScope { loop_id: id, .. } in self.loop_scopes.iter().rev() {
595 data.exiting_scopes.push(id);
596 }
597 self.graph.add_edge(from_index, self.fn_exit, data);
598 }
599
Niko Matsakis86b6e6e2013-05-10 17:10:35600 fn find_scope(&self,
Eduard Burtescub0621282014-09-07 17:09:06601 expr: &ast::Expr,
Edward Wang386db052014-02-15 08:54:32602 label: Option<ast::Ident>) -> LoopScope {
Niko Matsakis86b6e6e2013-05-10 17:10:35603 match label {
604 None => {
Simon Sapinaa66b912013-12-23 14:08:23605 return *self.loop_scopes.last().unwrap();
Niko Matsakis86b6e6e2013-05-10 17:10:35606 }
607
608 Some(_) => {
Alexis Beingessnereec145b2014-11-06 17:25:16609 match self.tcx.def_map.borrow().get(&expr.id) {
Niko Matsakis0f03b562014-05-14 19:31:30610 Some(&def::DefLabel(loop_id)) => {
Daniel Micay100894552013-08-03 16:45:23611 for l in self.loop_scopes.iter() {
Niko Matsakis86b6e6e2013-05-10 17:10:35612 if l.loop_id == loop_id {
613 return *l;
614 }
615 }
616 self.tcx.sess.span_bug(
617 expr.span,
Luqman Aden814586b2014-10-15 06:25:34618 format!("no loop scope for id {}",
Alex Crichton082bfde2014-12-11 03:46:38619 loop_id)[]);
Niko Matsakis86b6e6e2013-05-10 17:10:35620 }
621
622 r => {
623 self.tcx.sess.span_bug(
624 expr.span,
Luqman Aden814586b2014-10-15 06:25:34625 format!("bad entry `{}` in def_map for label",
Alex Crichton082bfde2014-12-11 03:46:38626 r)[]);
Niko Matsakis86b6e6e2013-05-10 17:10:35627 }
628 }
629 }
630 }
631 }
632
Marvin Löbel74190852013-09-02 01:45:37633 fn is_method_call(&self, expr: &ast::Expr) -> bool {
Niko Matsakis7c445612014-11-25 19:21:20634 let method_call = ty::MethodCall::expr(expr.id);
Felix S. Klock IIaaf398f2014-04-17 19:00:08635 self.tcx.method_map.borrow().contains_key(&method_call)
Niko Matsakis86b6e6e2013-05-10 17:10:35636 }
Patrick Walton99d44d22013-07-10 02:32:09637}