blob: b4557021b69fc57949b7f5817dbbbc1051652550 [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::typeck;
16use middle::ty;
Niko Matsakis86b6e6e2013-05-10 17:10:3517use syntax::ast;
18use syntax::ast_util;
Eduard Burtescub0621282014-09-07 17:09:0619use syntax::ptr::P;
Alex Crichtonbec7b762014-02-28 22:34:2620use util::nodemap::NodeMap;
Niko Matsakis86b6e6e2013-05-10 17:10:3521
Eduard Burtescu28be6952014-04-22 12:56:3722struct CFGBuilder<'a, 'tcx: 'a> {
23 tcx: &'a ty::ctxt<'tcx>,
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 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
Eduard Burtescub0621282014-09-07 17:09:06153 fn pats_all<'a, I: Iterator<&'a P<ast::Pat>>>(&mut self,
154 pats: I,
155 pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35156 //! Handles case where all of the patterns must match.
157 let mut pats = pats;
Eduard Burtescub0621282014-09-07 17:09:06158 pats.fold(pred, |pred, pat| self.pat(&**pat, pred))
Niko Matsakis86b6e6e2013-05-10 17:10:35159 }
160
161 fn pats_any(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06162 pats: &[P<ast::Pat>],
Niko Matsakis86b6e6e2013-05-10 17:10:35163 pred: CFGIndex) -> CFGIndex {
164 //! Handles case where just one of the patterns must match.
165
166 if pats.len() == 1 {
Alex Crichton54c2a1e2014-05-16 17:15:33167 self.pat(&*pats[0], pred)
Niko Matsakis86b6e6e2013-05-10 17:10:35168 } else {
Nick Cameronca085402014-11-17 08:39:01169 let collect = self.add_dummy_node(&[]);
Eduard Burtescub0621282014-09-07 17:09:06170 for pat in pats.iter() {
171 let pat_exit = self.pat(&**pat, pred);
Niko Matsakis86b6e6e2013-05-10 17:10:35172 self.add_contained_edge(pat_exit, collect);
173 }
174 collect
175 }
176 }
177
Eduard Burtescub0621282014-09-07 17:09:06178 fn expr(&mut self, expr: &ast::Expr, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35179 match expr.node {
Alex Crichton54c2a1e2014-05-16 17:15:33180 ast::ExprBlock(ref blk) => {
181 let blk_exit = self.block(&**blk, pred);
Nick Cameronca085402014-11-17 08:39:01182 self.add_node(expr.id, &[blk_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35183 }
184
Alex Crichton54c2a1e2014-05-16 17:15:33185 ast::ExprIf(ref cond, ref then, None) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35186 //
187 // [pred]
188 // |
189 // v 1
190 // [cond]
191 // |
192 // / \
193 // / \
194 // v 2 *
195 // [then] |
196 // | |
197 // v 3 v 4
198 // [..expr..]
199 //
Eduard Burtescub0621282014-09-07 17:09:06200 let cond_exit = self.expr(&**cond, pred); // 1
Alex Crichton54c2a1e2014-05-16 17:15:33201 let then_exit = self.block(&**then, cond_exit); // 2
Nick Cameronca085402014-11-17 08:39:01202 self.add_node(expr.id, &[cond_exit, then_exit]) // 3,4
Niko Matsakis86b6e6e2013-05-10 17:10:35203 }
204
Alex Crichton54c2a1e2014-05-16 17:15:33205 ast::ExprIf(ref cond, ref then, Some(ref otherwise)) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35206 //
207 // [pred]
208 // |
209 // v 1
210 // [cond]
211 // |
212 // / \
213 // / \
214 // v 2 v 3
215 // [then][otherwise]
216 // | |
217 // v 4 v 5
218 // [..expr..]
219 //
Eduard Burtescub0621282014-09-07 17:09:06220 let cond_exit = self.expr(&**cond, pred); // 1
Alex Crichton54c2a1e2014-05-16 17:15:33221 let then_exit = self.block(&**then, cond_exit); // 2
Eduard Burtescub0621282014-09-07 17:09:06222 let else_exit = self.expr(&**otherwise, cond_exit); // 3
Nick Cameronca085402014-11-17 08:39:01223 self.add_node(expr.id, &[then_exit, else_exit]) // 4, 5
Niko Matsakis86b6e6e2013-05-10 17:10:35224 }
225
Kevin Ballard13e00e42014-08-28 04:34:03226 ast::ExprIfLet(..) => {
227 self.tcx.sess.span_bug(expr.span, "non-desugared ExprIfLet");
228 }
Kevin Ballard0e6ff432014-08-25 02:08:48229
Pythoner6373b9d62014-07-26 00:12:51230 ast::ExprWhile(ref cond, ref body, _) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35231 //
232 // [pred]
233 // |
234 // v 1
235 // [loopback] <--+ 5
236 // | |
237 // v 2 |
238 // +-----[cond] |
239 // | | |
240 // | v 4 |
241 // | [body] -----+
242 // v 3
243 // [expr]
244 //
Patrick Waltoncaa564b2014-07-22 03:54:28245 // Note that `break` and `continue` statements
Niko Matsakis86b6e6e2013-05-10 17:10:35246 // may cause additional edges.
247
Michael Sullivan7dbc5ae2013-07-30 23:47:22248 // Is the condition considered part of the loop?
Nick Cameronca085402014-11-17 08:39:01249 let loopback = self.add_dummy_node(&[pred]); // 1
250 let cond_exit = self.expr(&**cond, loopback); // 2
251 let expr_exit = self.add_node(expr.id, &[cond_exit]); // 3
Niko Matsakis86b6e6e2013-05-10 17:10:35252 self.loop_scopes.push(LoopScope {
253 loop_id: expr.id,
254 continue_index: loopback,
255 break_index: expr_exit
256 });
Alex Crichton54c2a1e2014-05-16 17:15:33257 let body_exit = self.block(&**body, cond_exit); // 4
258 self.add_contained_edge(body_exit, loopback); // 5
Felix S. Klock IIbe9c2d12014-05-20 16:49:19259 self.loop_scopes.pop();
Niko Matsakis86b6e6e2013-05-10 17:10:35260 expr_exit
261 }
262
John Gallagher45fd6232014-10-03 04:41:24263 ast::ExprWhileLet(..) => {
264 self.tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
265 }
266
Patrick Waltoncaa564b2014-07-22 03:54:28267 ast::ExprForLoop(ref pat, ref head, ref body, _) => {
268 //
269 // [pred]
270 // |
271 // v 1
272 // [head]
273 // |
274 // v 2
275 // [loopback] <--+ 7
276 // | |
277 // v 3 |
278 // +------[cond] |
279 // | | |
280 // | v 5 |
281 // | [pat] |
282 // | | |
283 // | v 6 |
284 // v 4 [body] -----+
285 // [expr]
286 //
287 // Note that `break` and `continue` statements
288 // may cause additional edges.
289
Nick Cameronca085402014-11-17 08:39:01290 let head = self.expr(&**head, pred); // 1
291 let loopback = self.add_dummy_node(&[head]); // 2
292 let cond = self.add_dummy_node(&[loopback]); // 3
293 let expr_exit = self.add_node(expr.id, &[cond]); // 4
Patrick Waltoncaa564b2014-07-22 03:54:28294 self.loop_scopes.push(LoopScope {
295 loop_id: expr.id,
296 continue_index: loopback,
297 break_index: expr_exit,
298 });
299 let pat = self.pat(&**pat, cond); // 5
300 let body = self.block(&**body, pat); // 6
301 self.add_contained_edge(body, loopback); // 7
302 self.loop_scopes.pop();
303 expr_exit
304 }
Graydon Hoarec29e9fb2013-07-30 00:25:00305
Alex Crichton54c2a1e2014-05-16 17:15:33306 ast::ExprLoop(ref body, _) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35307 //
308 // [pred]
309 // |
310 // v 1
311 // [loopback] <---+
312 // | 4 |
313 // v 3 |
314 // [body] ------+
315 //
316 // [expr] 2
317 //
318 // Note that `break` and `loop` statements
319 // may cause additional edges.
320
Nick Cameronca085402014-11-17 08:39:01321 let loopback = self.add_dummy_node(&[pred]); // 1
322 let expr_exit = self.add_node(expr.id, &[]); // 2
Niko Matsakis86b6e6e2013-05-10 17:10:35323 self.loop_scopes.push(LoopScope {
324 loop_id: expr.id,
325 continue_index: loopback,
326 break_index: expr_exit,
327 });
Alex Crichton54c2a1e2014-05-16 17:15:33328 let body_exit = self.block(&**body, loopback); // 3
329 self.add_contained_edge(body_exit, loopback); // 4
Niko Matsakis86b6e6e2013-05-10 17:10:35330 self.loop_scopes.pop();
331 expr_exit
332 }
333
Kevin Ballard976438f2014-08-25 21:55:00334 ast::ExprMatch(ref discr, ref arms, _) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35335 //
336 // [pred]
337 // |
338 // v 1
339 // [discr]
340 // |
341 // v 2
Patrick Waltonb2eb8882014-07-25 22:18:19342 // [cond1]
Niko Matsakis86b6e6e2013-05-10 17:10:35343 // / \
344 // | \
Patrick Waltonb2eb8882014-07-25 22:18:19345 // v 3 \
346 // [pat1] \
347 // | |
348 // v 4 |
349 // [guard1] |
350 // | |
351 // | |
352 // v 5 v
353 // [body1] [cond2]
354 // | / \
355 // | ... ...
356 // | | |
357 // v 6 v v
358 // [.....expr.....]
Niko Matsakis86b6e6e2013-05-10 17:10:35359 //
Eduard Burtescub0621282014-09-07 17:09:06360 let discr_exit = self.expr(&**discr, pred); // 1
Niko Matsakis86b6e6e2013-05-10 17:10:35361
Nick Cameronca085402014-11-17 08:39:01362 let expr_exit = self.add_node(expr.id, &[]);
Patrick Waltonb2eb8882014-07-25 22:18:19363 let mut cond_exit = discr_exit;
Daniel Micay100894552013-08-03 16:45:23364 for arm in arms.iter() {
Nick Cameronca085402014-11-17 08:39:01365 cond_exit = self.add_dummy_node(&[cond_exit]); // 2
Patrick Waltonc1ed4d72014-02-28 23:25:15366 let pats_exit = self.pats_any(arm.pats.as_slice(),
Patrick Waltonb2eb8882014-07-25 22:18:19367 cond_exit); // 3
Eduard Burtescub0621282014-09-07 17:09:06368 let guard_exit = self.opt_expr(&arm.guard,
Patrick Waltonb2eb8882014-07-25 22:18:19369 pats_exit); // 4
Eduard Burtescub0621282014-09-07 17:09:06370 let body_exit = self.expr(&*arm.body, guard_exit); // 5
Patrick Waltonb2eb8882014-07-25 22:18:19371 self.add_contained_edge(body_exit, expr_exit); // 6
Niko Matsakis86b6e6e2013-05-10 17:10:35372 }
373 expr_exit
374 }
375
Alex Crichton54c2a1e2014-05-16 17:15:33376 ast::ExprBinary(op, ref l, ref r) if ast_util::lazy_binop(op) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35377 //
378 // [pred]
379 // |
380 // v 1
381 // [l]
382 // |
383 // / \
384 // / \
385 // v 2 *
386 // [r] |
387 // | |
388 // v 3 v 4
389 // [..exit..]
390 //
Eduard Burtescub0621282014-09-07 17:09:06391 let l_exit = self.expr(&**l, pred); // 1
392 let r_exit = self.expr(&**r, l_exit); // 2
Nick Cameronca085402014-11-17 08:39:01393 self.add_node(expr.id, &[l_exit, r_exit]) // 3,4
Niko Matsakis86b6e6e2013-05-10 17:10:35394 }
395
Alex Crichton54c2a1e2014-05-16 17:15:33396 ast::ExprRet(ref v) => {
Eduard Burtescub0621282014-09-07 17:09:06397 let v_exit = self.opt_expr(v, pred);
Nick Cameronca085402014-11-17 08:39:01398 let b = self.add_node(expr.id, &[v_exit]);
Felix S. Klock II65b65fe2014-05-08 22:07:57399 self.add_returning_edge(expr, b);
Nick Cameronca085402014-11-17 08:39:01400 self.add_node(ast::DUMMY_NODE_ID, &[])
Niko Matsakis86b6e6e2013-05-10 17:10:35401 }
402
Marvin Löbel74190852013-09-02 01:45:37403 ast::ExprBreak(label) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35404 let loop_scope = self.find_scope(expr, label);
Nick Cameronca085402014-11-17 08:39:01405 let b = self.add_node(expr.id, &[pred]);
Felix S. Klock II65b65fe2014-05-08 22:07:57406 self.add_exiting_edge(expr, b,
Niko Matsakis86b6e6e2013-05-10 17:10:35407 loop_scope, loop_scope.break_index);
Nick Cameronca085402014-11-17 08:39:01408 self.add_node(ast::DUMMY_NODE_ID, &[])
Niko Matsakis86b6e6e2013-05-10 17:10:35409 }
410
Marvin Löbel74190852013-09-02 01:45:37411 ast::ExprAgain(label) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35412 let loop_scope = self.find_scope(expr, label);
Nick Cameronca085402014-11-17 08:39:01413 let a = self.add_node(expr.id, &[pred]);
Felix S. Klock II65b65fe2014-05-08 22:07:57414 self.add_exiting_edge(expr, a,
Niko Matsakis86b6e6e2013-05-10 17:10:35415 loop_scope, loop_scope.continue_index);
Nick Cameronca085402014-11-17 08:39:01416 self.add_node(ast::DUMMY_NODE_ID, &[])
Niko Matsakis86b6e6e2013-05-10 17:10:35417 }
418
Eduard Burtescu7c48e532014-04-04 10:12:18419 ast::ExprVec(ref elems) => {
Eduard Burtescub0621282014-09-07 17:09:06420 self.straightline(expr, pred, elems.iter().map(|e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35421 }
422
Alex Crichton54c2a1e2014-05-16 17:15:33423 ast::ExprCall(ref func, ref args) => {
Eduard Burtescub0621282014-09-07 17:09:06424 self.call(expr, pred, &**func, args.iter().map(|e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35425 }
426
Eduard Burtescu05e4d942014-02-26 14:06:45427 ast::ExprMethodCall(_, _, ref args) => {
Alex Crichton9d5d97b2014-10-15 06:05:01428 self.call(expr, pred, &*args[0], args.slice_from(1).iter().map(|e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35429 }
430
Alex Crichton54c2a1e2014-05-16 17:15:33431 ast::ExprIndex(ref l, ref r) |
Eduard Burtescub0621282014-09-07 17:09:06432 ast::ExprBinary(_, ref l, ref r) if self.is_method_call(expr) => {
Aaron Turonfc525ee2014-09-15 03:27:36433 self.call(expr, pred, &**l, Some(&**r).into_iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35434 }
435
Nick Cameron31a7e382014-09-15 08:48:58436 ast::ExprSlice(ref base, ref start, ref end, _) => {
437 self.call(expr,
438 pred,
439 &**base,
440 start.iter().chain(end.iter()).map(|x| &**x))
441 }
442
Eduard Burtescub0621282014-09-07 17:09:06443 ast::ExprUnary(_, ref e) if self.is_method_call(expr) => {
444 self.call(expr, pred, &**e, None::<ast::Expr>.iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35445 }
446
Marvin Löbel74190852013-09-02 01:45:37447 ast::ExprTup(ref exprs) => {
Eduard Burtescub0621282014-09-07 17:09:06448 self.straightline(expr, pred, exprs.iter().map(|e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35449 }
450
Eduard Burtescub0621282014-09-07 17:09:06451 ast::ExprStruct(_, ref fields, ref base) => {
Brandon Sandersond80a62d2014-11-05 23:05:01452 let field_cfg = self.straightline(expr, pred, fields.iter().map(|f| &*f.expr));
453 self.opt_expr(base, field_cfg)
Niko Matsakis86b6e6e2013-05-10 17:10:35454 }
455
Eduard Burtescub0621282014-09-07 17:09:06456 ast::ExprRepeat(ref elem, ref count) => {
457 self.straightline(expr, pred, [elem, count].iter().map(|&e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35458 }
459
Eduard Burtescub0621282014-09-07 17:09:06460 ast::ExprAssign(ref l, ref r) |
461 ast::ExprAssignOp(_, ref l, ref r) => {
462 self.straightline(expr, pred, [r, l].iter().map(|&e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35463 }
464
Eduard Burtescub0621282014-09-07 17:09:06465 ast::ExprIndex(ref l, ref r) |
466 ast::ExprBinary(_, ref l, ref r) => { // NB: && and || handled earlier
467 self.straightline(expr, pred, [l, r].iter().map(|&e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35468 }
469
Eduard Burtescub0621282014-09-07 17:09:06470 ast::ExprBox(ref p, ref e) => {
471 self.straightline(expr, pred, [p, e].iter().map(|&e| &**e))
Patrick Waltone1271152013-12-18 00:46:18472 }
473
Eduard Burtescub0621282014-09-07 17:09:06474 ast::ExprAddrOf(_, ref e) |
475 ast::ExprCast(ref e, _) |
476 ast::ExprUnary(_, ref e) |
477 ast::ExprParen(ref e) |
478 ast::ExprField(ref e, _, _) |
479 ast::ExprTupField(ref e, _, _) => {
Aaron Turonfc525ee2014-09-15 03:27:36480 self.straightline(expr, pred, Some(&**e).into_iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35481 }
482
Felix S. Klock IIbe9c2d12014-05-20 16:49:19483 ast::ExprInlineAsm(ref inline_asm) => {
484 let inputs = inline_asm.inputs.iter();
485 let outputs = inline_asm.outputs.iter();
Felix S. Klock IIbe9c2d12014-05-20 16:49:19486 let post_inputs = self.exprs(inputs.map(|a| {
Luqman Aden814586b2014-10-15 06:25:34487 debug!("cfg::construct InlineAsm id:{} input:{}", expr.id, a);
Eduard Burtescub0621282014-09-07 17:09:06488 let &(_, ref expr) = a;
489 &**expr
Felix S. Klock IIbe9c2d12014-05-20 16:49:19490 }), pred);
491 let post_outputs = self.exprs(outputs.map(|a| {
Luqman Aden814586b2014-10-15 06:25:34492 debug!("cfg::construct InlineAsm id:{} output:{}", expr.id, a);
Eduard Burtescub0621282014-09-07 17:09:06493 let &(_, ref expr, _) = a;
494 &**expr
Felix S. Klock IIbe9c2d12014-05-20 16:49:19495 }), post_inputs);
Nick Cameronca085402014-11-17 08:39:01496 self.add_node(expr.id, &[post_outputs])
Felix S. Klock IIbe9c2d12014-05-20 16:49:19497 }
498
Alex Crichtonab387a62013-11-28 20:22:53499 ast::ExprMac(..) |
Alex Crichtonab387a62013-11-28 20:22:53500 ast::ExprFnBlock(..) |
501 ast::ExprProc(..) |
Patrick Walton02adaca2014-05-29 05:26:56502 ast::ExprUnboxedFn(..) |
Alex Crichtonab387a62013-11-28 20:22:53503 ast::ExprLit(..) |
504 ast::ExprPath(..) => {
Eduard Burtescub0621282014-09-07 17:09:06505 self.straightline(expr, pred, None::<ast::Expr>.iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35506 }
507 }
508 }
509
Eduard Burtescub0621282014-09-07 17:09:06510 fn call<'a, I: Iterator<&'a ast::Expr>>(&mut self,
511 call_expr: &ast::Expr,
Niko Matsakis86b6e6e2013-05-10 17:10:35512 pred: CFGIndex,
Eduard Burtescub0621282014-09-07 17:09:06513 func_or_rcvr: &ast::Expr,
514 args: I) -> CFGIndex {
Jakub Bukajcca84e92014-10-24 19:14:37515 let method_call = typeck::MethodCall::expr(call_expr.id);
Alexis Beingessnereec145b2014-11-06 17:25:16516 let return_ty = ty::ty_fn_ret(match self.tcx.method_map.borrow().get(&method_call) {
Jakub Bukajcca84e92014-10-24 19:14:37517 Some(method) => method.ty,
518 None => ty::expr_ty(self.tcx, func_or_rcvr)
519 });
520
Niko Matsakis86b6e6e2013-05-10 17:10:35521 let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
Felix S. Klock IIbe9c2d12014-05-20 16:49:19522 let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
Jakub Bukajcca84e92014-10-24 19:14:37523 if return_ty == ty::FnDiverging {
Nick Cameronca085402014-11-17 08:39:01524 self.add_node(ast::DUMMY_NODE_ID, &[])
Felix S. Klock IIbe9c2d12014-05-20 16:49:19525 } else {
526 ret
527 }
Niko Matsakis86b6e6e2013-05-10 17:10:35528 }
529
Eduard Burtescub0621282014-09-07 17:09:06530 fn exprs<'a, I: Iterator<&'a ast::Expr>>(&mut self,
531 mut exprs: I,
532 pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35533 //! Constructs graph for `exprs` evaluated in order
Felix S. Klock IIbe9c2d12014-05-20 16:49:19534 exprs.fold(pred, |p, e| self.expr(e, p))
Niko Matsakis86b6e6e2013-05-10 17:10:35535 }
536
537 fn opt_expr(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06538 opt_expr: &Option<P<ast::Expr>>,
Niko Matsakis86b6e6e2013-05-10 17:10:35539 pred: CFGIndex) -> CFGIndex {
540 //! Constructs graph for `opt_expr` evaluated, if Some
Eduard Burtescub0621282014-09-07 17:09:06541 opt_expr.iter().fold(pred, |p, e| self.expr(&**e, p))
Niko Matsakis86b6e6e2013-05-10 17:10:35542 }
543
Eduard Burtescub0621282014-09-07 17:09:06544 fn straightline<'a, I: Iterator<&'a ast::Expr>>(&mut self,
545 expr: &ast::Expr,
Niko Matsakis86b6e6e2013-05-10 17:10:35546 pred: CFGIndex,
Eduard Burtescub0621282014-09-07 17:09:06547 subexprs: I) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35548 //! Handles case of an expression that evaluates `subexprs` in order
549
Eduard Burtescub0621282014-09-07 17:09:06550 let subexprs_exit = self.exprs(subexprs, pred);
Nick Cameronca085402014-11-17 08:39:01551 self.add_node(expr.id, &[subexprs_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35552 }
553
554 fn add_dummy_node(&mut self, preds: &[CFGIndex]) -> CFGIndex {
Felix S. Klock II65b65fe2014-05-08 22:07:57555 self.add_node(ast::DUMMY_NODE_ID, preds)
Niko Matsakis86b6e6e2013-05-10 17:10:35556 }
557
Michael Woerister8a329772013-07-27 08:25:59558 fn add_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35559 assert!(!self.exit_map.contains_key(&id));
560 let node = self.graph.add_node(CFGNodeData {id: id});
Felix S. Klock II65b65fe2014-05-08 22:07:57561 if id != ast::DUMMY_NODE_ID {
562 assert!(!self.exit_map.contains_key(&id));
563 self.exit_map.insert(id, node);
564 }
Daniel Micay100894552013-08-03 16:45:23565 for &pred in preds.iter() {
Niko Matsakis86b6e6e2013-05-10 17:10:35566 self.add_contained_edge(pred, node);
567 }
568 node
569 }
570
571 fn add_contained_edge(&mut self,
572 source: CFGIndex,
573 target: CFGIndex) {
Huon Wilson7785fe12014-03-19 12:16:56574 let data = CFGEdgeData {exiting_scopes: vec!() };
Niko Matsakis86b6e6e2013-05-10 17:10:35575 self.graph.add_edge(source, target, data);
576 }
577
578 fn add_exiting_edge(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06579 from_expr: &ast::Expr,
Niko Matsakis86b6e6e2013-05-10 17:10:35580 from_index: CFGIndex,
581 to_loop: LoopScope,
582 to_index: CFGIndex) {
Huon Wilson7785fe12014-03-19 12:16:56583 let mut data = CFGEdgeData {exiting_scopes: vec!() };
Felix S. Klock II5ff90872014-11-18 13:22:59584 let mut scope = CodeExtent::from_node_id(from_expr.id);
585 let target_scope = CodeExtent::from_node_id(to_loop.loop_id);
586 while scope != target_scope {
Huon Wilson7785fe12014-03-19 12:16:56587
Felix S. Klock II5ff90872014-11-18 13:22:59588 data.exiting_scopes.push(scope.node_id());
589 scope = self.tcx.region_maps.encl_scope(scope);
Niko Matsakis86b6e6e2013-05-10 17:10:35590 }
591 self.graph.add_edge(from_index, to_index, data);
592 }
593
Felix S. Klock II65b65fe2014-05-08 22:07:57594 fn add_returning_edge(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06595 _from_expr: &ast::Expr,
Felix S. Klock II65b65fe2014-05-08 22:07:57596 from_index: CFGIndex) {
Patrick Walton36195eb2014-05-16 17:45:16597 let mut data = CFGEdgeData {
598 exiting_scopes: vec!(),
599 };
Felix S. Klock II65b65fe2014-05-08 22:07:57600 for &LoopScope { loop_id: id, .. } in self.loop_scopes.iter().rev() {
601 data.exiting_scopes.push(id);
602 }
603 self.graph.add_edge(from_index, self.fn_exit, data);
604 }
605
Niko Matsakis86b6e6e2013-05-10 17:10:35606 fn find_scope(&self,
Eduard Burtescub0621282014-09-07 17:09:06607 expr: &ast::Expr,
Edward Wang386db052014-02-15 08:54:32608 label: Option<ast::Ident>) -> LoopScope {
Niko Matsakis86b6e6e2013-05-10 17:10:35609 match label {
610 None => {
Simon Sapinaa66b912013-12-23 14:08:23611 return *self.loop_scopes.last().unwrap();
Niko Matsakis86b6e6e2013-05-10 17:10:35612 }
613
614 Some(_) => {
Alexis Beingessnereec145b2014-11-06 17:25:16615 match self.tcx.def_map.borrow().get(&expr.id) {
Niko Matsakis0f03b562014-05-14 19:31:30616 Some(&def::DefLabel(loop_id)) => {
Daniel Micay100894552013-08-03 16:45:23617 for l in self.loop_scopes.iter() {
Niko Matsakis86b6e6e2013-05-10 17:10:35618 if l.loop_id == loop_id {
619 return *l;
620 }
621 }
622 self.tcx.sess.span_bug(
623 expr.span,
Luqman Aden814586b2014-10-15 06:25:34624 format!("no loop scope for id {}",
Patrick Walton36195eb2014-05-16 17:45:16625 loop_id).as_slice());
Niko Matsakis86b6e6e2013-05-10 17:10:35626 }
627
628 r => {
629 self.tcx.sess.span_bug(
630 expr.span,
Luqman Aden814586b2014-10-15 06:25:34631 format!("bad entry `{}` in def_map for label",
Patrick Walton36195eb2014-05-16 17:45:16632 r).as_slice());
Niko Matsakis86b6e6e2013-05-10 17:10:35633 }
634 }
635 }
636 }
637 }
638
Marvin Löbel74190852013-09-02 01:45:37639 fn is_method_call(&self, expr: &ast::Expr) -> bool {
Eduard Burtescu20b4e152014-03-06 17:24:11640 let method_call = typeck::MethodCall::expr(expr.id);
Felix S. Klock IIaaf398f2014-04-17 19:00:08641 self.tcx.method_map.borrow().contains_key(&method_call)
Niko Matsakis86b6e6e2013-05-10 17:10:35642 }
Patrick Walton99d44d22013-07-10 02:32:09643}