blob: 35afdd75cb8c4f47baf90f1a59af38cb8ecf41b9 [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
Niko Matsakis7ab0d1a2015-04-07 10:12:1311use rustc_data_structures::graph;
Eduard Burtescu5efdde02016-03-22 15:30:5712use cfg::*;
Eduard Burtescu5efdde02016-03-22 15:30:5713use ty::{self, TyCtxt};
Niko Matsakis86b6e6e2013-05-10 17:10:3514use syntax::ast;
Eduard Burtescub0621282014-09-07 17:09:0615use syntax::ptr::P;
Niko Matsakis86b6e6e2013-05-10 17:10:3516
Eduard Burtescu8b093722016-03-29 05:50:4417use hir::{self, PatKind};
Nick Cameronfacdf2e2015-07-31 07:04:0618
Eduard Burtescu28be6952014-04-22 12:56:3719struct CFGBuilder<'a, 'tcx: 'a> {
Eduard Burtescu76affa52016-05-03 02:23:2220 tcx: TyCtxt<'a, 'tcx, 'tcx>,
Eduard-Mihai Burtescu85a4a192017-01-06 19:54:2421 tables: &'a ty::Tables<'tcx>,
Niko Matsakis86b6e6e2013-05-10 17:10:3522 graph: CFGGraph,
Felix S. Klock II65b65fe2014-05-08 22:07:5723 fn_exit: CFGIndex,
24 loop_scopes: Vec<LoopScope>,
Niko Matsakis86b6e6e2013-05-10 17:10:3525}
26
Niko Matsakisd9530c02015-03-30 13:38:4427#[derive(Copy, Clone)]
Niko Matsakis86b6e6e2013-05-10 17:10:3528struct LoopScope {
Michael Woerister8a329772013-07-27 08:25:5929 loop_id: ast::NodeId, // id of loop/while node
Niko Matsakis86b6e6e2013-05-10 17:10:3530 continue_index: CFGIndex, // where to go on a `loop`
31 break_index: CFGIndex, // where to go on a `break
32}
33
Eduard Burtescu76affa52016-05-03 02:23:2234pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
Eduard Burtescuff0830d2016-10-25 23:27:1435 body: &hir::Expr) -> CFG {
Felix S. Klock II65b65fe2014-05-08 22:07:5736 let mut graph = graph::Graph::new();
James Miller97c17112015-02-19 14:27:2537 let entry = graph.add_node(CFGNodeData::Entry);
Felix S. Klock II65b65fe2014-05-08 22:07:5738
39 // `fn_exit` is target of return exprs, which lies somewhere
Eduard Burtescuff0830d2016-10-25 23:27:1440 // outside input `body`. (Distinguishing `fn_exit` and `body_exit`
Felix S. Klock II65b65fe2014-05-08 22:07:5741 // also resolves chicken-and-egg problem that arises if you try to
Eduard Burtescuff0830d2016-10-25 23:27:1442 // have return exprs jump to `body_exit` during construction.)
James Miller97c17112015-02-19 14:27:2543 let fn_exit = graph.add_node(CFGNodeData::Exit);
Eduard Burtescuff0830d2016-10-25 23:27:1444 let body_exit;
Felix S. Klock II65b65fe2014-05-08 22:07:5745
Eduard-Mihai Burtescu85a4a192017-01-06 19:54:2446 // Find the function this expression is from.
47 let mut node_id = body.id;
48 loop {
49 let node = tcx.map.get(node_id);
50 if hir::map::blocks::FnLikeNode::from_node(node).is_some() {
51 break;
52 }
53 let parent = tcx.map.get_parent_node(node_id);
54 assert!(node_id != parent);
55 node_id = parent;
56 }
57
Niko Matsakis86b6e6e2013-05-10 17:10:3558 let mut cfg_builder = CFGBuilder {
Eduard-Mihai Burtescu85a4a192017-01-06 19:54:2459 tcx: tcx,
60 tables: tcx.item_tables(tcx.map.local_def_id(node_id)),
Felix S. Klock II65b65fe2014-05-08 22:07:5761 graph: graph,
62 fn_exit: fn_exit,
Patrick Walton3b6e9d42014-03-04 18:02:4963 loop_scopes: Vec::new()
Niko Matsakis86b6e6e2013-05-10 17:10:3564 };
Eduard Burtescuff0830d2016-10-25 23:27:1465 body_exit = cfg_builder.expr(body, entry);
66 cfg_builder.add_contained_edge(body_exit, fn_exit);
James Millera0b7bad2015-02-19 14:33:5367 let CFGBuilder {graph, ..} = cfg_builder;
68 CFG {graph: graph,
Niko Matsakis86b6e6e2013-05-10 17:10:3569 entry: entry,
Felix S. Klock II65b65fe2014-05-08 22:07:5770 exit: fn_exit}
71}
72
Eduard Burtescu28be6952014-04-22 12:56:3773impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
Nick Cameronfacdf2e2015-07-31 07:04:0674 fn block(&mut self, blk: &hir::Block, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:3575 let mut stmts_exit = pred;
Jorge Apariciod5d7e652015-01-31 17:20:4676 for stmt in &blk.stmts {
Vadim Petrochenkovca88e9c2015-12-07 14:17:4177 stmts_exit = self.stmt(stmt, stmts_exit);
Niko Matsakis86b6e6e2013-05-10 17:10:3578 }
79
Eduard Burtescub0621282014-09-07 17:09:0680 let expr_exit = self.opt_expr(&blk.expr, stmts_exit);
Niko Matsakis86b6e6e2013-05-10 17:10:3581
James Miller97c17112015-02-19 14:27:2582 self.add_ast_node(blk.id, &[expr_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:3583 }
84
Nick Cameronfacdf2e2015-07-31 07:04:0685 fn stmt(&mut self, stmt: &hir::Stmt, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:3586 match stmt.node {
Nick Cameronfacdf2e2015-07-31 07:04:0687 hir::StmtDecl(ref decl, id) => {
Jonas Schievink559fca02016-02-09 21:00:2088 let exit = self.decl(&decl, pred);
James Miller97c17112015-02-19 14:27:2589 self.add_ast_node(id, &[exit])
Niko Matsakis86b6e6e2013-05-10 17:10:3590 }
91
Nick Cameronfacdf2e2015-07-31 07:04:0692 hir::StmtExpr(ref expr, id) | hir::StmtSemi(ref expr, id) => {
Jonas Schievink559fca02016-02-09 21:00:2093 let exit = self.expr(&expr, pred);
James Miller97c17112015-02-19 14:27:2594 self.add_ast_node(id, &[exit])
Niko Matsakis86b6e6e2013-05-10 17:10:3595 }
Niko Matsakis86b6e6e2013-05-10 17:10:3596 }
97 }
98
Nick Cameronfacdf2e2015-07-31 07:04:0699 fn decl(&mut self, decl: &hir::Decl, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35100 match decl.node {
Nick Cameronfacdf2e2015-07-31 07:04:06101 hir::DeclLocal(ref local) => {
Eduard Burtescub0621282014-09-07 17:09:06102 let init_exit = self.opt_expr(&local.init, pred);
Jonas Schievink559fca02016-02-09 21:00:20103 self.pat(&local.pat, init_exit)
Niko Matsakis86b6e6e2013-05-10 17:10:35104 }
105
Nick Cameronfacdf2e2015-07-31 07:04:06106 hir::DeclItem(_) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35107 pred
108 }
109 }
110 }
111
Nick Cameronfacdf2e2015-07-31 07:04:06112 fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35113 match pat.node {
Vadim Petrochenkove05e74a2016-08-26 16:23:42114 PatKind::Binding(.., None) |
Eduard Burtescu16b5c2c2016-10-27 02:17:42115 PatKind::Path(_) |
Vadim Petrochenkov9b40e1e2016-02-14 12:25:12116 PatKind::Lit(..) |
117 PatKind::Range(..) |
118 PatKind::Wild => {
James Miller97c17112015-02-19 14:27:25119 self.add_ast_node(pat.id, &[pred])
Niko Matsakis86b6e6e2013-05-10 17:10:35120 }
121
Vadim Petrochenkov9b40e1e2016-02-14 12:25:12122 PatKind::Box(ref subpat) |
123 PatKind::Ref(ref subpat, _) |
Vadim Petrochenkove05e74a2016-08-26 16:23:42124 PatKind::Binding(.., Some(ref subpat)) => {
Jonas Schievink559fca02016-02-09 21:00:20125 let subpat_exit = self.pat(&subpat, pred);
James Miller97c17112015-02-19 14:27:25126 self.add_ast_node(pat.id, &[subpat_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35127 }
128
Vadim Petrochenkovd69aeaf2016-03-06 12:54:44129 PatKind::TupleStruct(_, ref subpats, _) |
130 PatKind::Tuple(ref subpats, _) => {
Eduard Burtescub0621282014-09-07 17:09:06131 let pats_exit = self.pats_all(subpats.iter(), pred);
James Miller97c17112015-02-19 14:27:25132 self.add_ast_node(pat.id, &[pats_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35133 }
134
Vadim Petrochenkov9b40e1e2016-02-14 12:25:12135 PatKind::Struct(_, ref subpats, _) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35136 let pats_exit =
P1startead6c4b2014-10-06 00:36:53137 self.pats_all(subpats.iter().map(|f| &f.node.pat), pred);
James Miller97c17112015-02-19 14:27:25138 self.add_ast_node(pat.id, &[pats_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35139 }
140
Jonas Schievinkcf0b7bd2016-09-20 00:14:46141 PatKind::Slice(ref pre, ref vec, ref post) => {
Eduard Burtescub0621282014-09-07 17:09:06142 let pre_exit = self.pats_all(pre.iter(), pred);
143 let vec_exit = self.pats_all(vec.iter(), pre_exit);
144 let post_exit = self.pats_all(post.iter(), vec_exit);
James Miller97c17112015-02-19 14:27:25145 self.add_ast_node(pat.id, &[post_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35146 }
147 }
148 }
149
Nick Cameronfacdf2e2015-07-31 07:04:06150 fn pats_all<'b, I: Iterator<Item=&'b P<hir::Pat>>>(&mut self,
Eduard Burtescub0621282014-09-07 17:09:06151 pats: I,
152 pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35153 //! Handles case where all of the patterns must match.
Jonas Schievink559fca02016-02-09 21:00:20154 pats.fold(pred, |pred, pat| self.pat(&pat, pred))
Niko Matsakis86b6e6e2013-05-10 17:10:35155 }
156
Nick Cameronfacdf2e2015-07-31 07:04:06157 fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35158 match expr.node {
Nick Cameronfacdf2e2015-07-31 07:04:06159 hir::ExprBlock(ref blk) => {
Jonas Schievink559fca02016-02-09 21:00:20160 let blk_exit = self.block(&blk, pred);
James Miller97c17112015-02-19 14:27:25161 self.add_ast_node(expr.id, &[blk_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35162 }
163
Nick Cameronfacdf2e2015-07-31 07:04:06164 hir::ExprIf(ref cond, ref then, None) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35165 //
166 // [pred]
167 // |
168 // v 1
169 // [cond]
170 // |
171 // / \
172 // / \
173 // v 2 *
174 // [then] |
175 // | |
176 // v 3 v 4
177 // [..expr..]
178 //
Jonas Schievink559fca02016-02-09 21:00:20179 let cond_exit = self.expr(&cond, pred); // 1
180 let then_exit = self.block(&then, cond_exit); // 2
James Miller97c17112015-02-19 14:27:25181 self.add_ast_node(expr.id, &[cond_exit, then_exit]) // 3,4
Niko Matsakis86b6e6e2013-05-10 17:10:35182 }
183
Nick Cameronfacdf2e2015-07-31 07:04:06184 hir::ExprIf(ref cond, ref then, Some(ref otherwise)) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35185 //
186 // [pred]
187 // |
188 // v 1
189 // [cond]
190 // |
191 // / \
192 // / \
193 // v 2 v 3
194 // [then][otherwise]
195 // | |
196 // v 4 v 5
197 // [..expr..]
198 //
Jonas Schievink559fca02016-02-09 21:00:20199 let cond_exit = self.expr(&cond, pred); // 1
200 let then_exit = self.block(&then, cond_exit); // 2
201 let else_exit = self.expr(&otherwise, cond_exit); // 3
James Miller97c17112015-02-19 14:27:25202 self.add_ast_node(expr.id, &[then_exit, else_exit]) // 4, 5
Niko Matsakis86b6e6e2013-05-10 17:10:35203 }
204
Nick Cameronfacdf2e2015-07-31 07:04:06205 hir::ExprWhile(ref cond, ref body, _) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35206 //
207 // [pred]
208 // |
209 // v 1
210 // [loopback] <--+ 5
211 // | |
212 // v 2 |
213 // +-----[cond] |
214 // | | |
215 // | v 4 |
216 // | [body] -----+
217 // v 3
218 // [expr]
219 //
Patrick Waltoncaa564b2014-07-22 03:54:28220 // Note that `break` and `continue` statements
Niko Matsakis86b6e6e2013-05-10 17:10:35221 // may cause additional edges.
222
Michael Sullivan7dbc5ae2013-07-30 23:47:22223 // Is the condition considered part of the loop?
Nick Cameronca085402014-11-17 08:39:01224 let loopback = self.add_dummy_node(&[pred]); // 1
Jonas Schievink559fca02016-02-09 21:00:20225 let cond_exit = self.expr(&cond, loopback); // 2
James Miller97c17112015-02-19 14:27:25226 let expr_exit = self.add_ast_node(expr.id, &[cond_exit]); // 3
Niko Matsakis86b6e6e2013-05-10 17:10:35227 self.loop_scopes.push(LoopScope {
228 loop_id: expr.id,
229 continue_index: loopback,
230 break_index: expr_exit
231 });
Jonas Schievink559fca02016-02-09 21:00:20232 let body_exit = self.block(&body, cond_exit); // 4
Alex Crichton54c2a1e2014-05-16 17:15:33233 self.add_contained_edge(body_exit, loopback); // 5
Felix S. Klock IIbe9c2d12014-05-20 16:49:19234 self.loop_scopes.pop();
Niko Matsakis86b6e6e2013-05-10 17:10:35235 expr_exit
236 }
237
Geoffry Song9d425492016-10-29 22:15:06238 hir::ExprLoop(ref body, _, _) => {
Niko Matsakis86b6e6e2013-05-10 17:10:35239 //
240 // [pred]
241 // |
242 // v 1
243 // [loopback] <---+
244 // | 4 |
245 // v 3 |
246 // [body] ------+
247 //
248 // [expr] 2
249 //
250 // Note that `break` and `loop` statements
251 // may cause additional edges.
252
Nick Cameronca085402014-11-17 08:39:01253 let loopback = self.add_dummy_node(&[pred]); // 1
James Miller97c17112015-02-19 14:27:25254 let expr_exit = self.add_ast_node(expr.id, &[]); // 2
Niko Matsakis86b6e6e2013-05-10 17:10:35255 self.loop_scopes.push(LoopScope {
256 loop_id: expr.id,
257 continue_index: loopback,
258 break_index: expr_exit,
259 });
Jonas Schievink559fca02016-02-09 21:00:20260 let body_exit = self.block(&body, loopback); // 3
Alex Crichton54c2a1e2014-05-16 17:15:33261 self.add_contained_edge(body_exit, loopback); // 4
Niko Matsakis86b6e6e2013-05-10 17:10:35262 self.loop_scopes.pop();
263 expr_exit
264 }
265
Nick Cameronfacdf2e2015-07-31 07:04:06266 hir::ExprMatch(ref discr, ref arms, _) => {
James Miller4bae1332015-02-19 16:54:41267 self.match_(expr.id, &discr, &arms, pred)
Niko Matsakis86b6e6e2013-05-10 17:10:35268 }
269
Eduard Burtescuef4c7242016-03-29 06:32:58270 hir::ExprBinary(op, ref l, ref r) if op.node.is_lazy() => {
Niko Matsakis86b6e6e2013-05-10 17:10:35271 //
272 // [pred]
273 // |
274 // v 1
275 // [l]
276 // |
277 // / \
278 // / \
279 // v 2 *
280 // [r] |
281 // | |
282 // v 3 v 4
283 // [..exit..]
284 //
Jonas Schievink559fca02016-02-09 21:00:20285 let l_exit = self.expr(&l, pred); // 1
286 let r_exit = self.expr(&r, l_exit); // 2
James Miller97c17112015-02-19 14:27:25287 self.add_ast_node(expr.id, &[l_exit, r_exit]) // 3,4
Niko Matsakis86b6e6e2013-05-10 17:10:35288 }
289
Nick Cameronfacdf2e2015-07-31 07:04:06290 hir::ExprRet(ref v) => {
Eduard Burtescub0621282014-09-07 17:09:06291 let v_exit = self.opt_expr(v, pred);
James Miller97c17112015-02-19 14:27:25292 let b = self.add_ast_node(expr.id, &[v_exit]);
Felix S. Klock II65b65fe2014-05-08 22:07:57293 self.add_returning_edge(expr, b);
James Miller97c17112015-02-19 14:27:25294 self.add_unreachable_node()
Niko Matsakis86b6e6e2013-05-10 17:10:35295 }
296
Geoffry Song9d425492016-10-29 22:15:06297 hir::ExprBreak(label, ref opt_expr) => {
298 let v = self.opt_expr(opt_expr, pred);
Eduard-Mihai Burtescu962633c2016-11-25 11:21:19299 let loop_scope = self.find_scope(expr, label);
Geoffry Song9d425492016-10-29 22:15:06300 let b = self.add_ast_node(expr.id, &[v]);
Felix S. Klock II65b65fe2014-05-08 22:07:57301 self.add_exiting_edge(expr, b,
Niko Matsakis86b6e6e2013-05-10 17:10:35302 loop_scope, loop_scope.break_index);
James Miller97c17112015-02-19 14:27:25303 self.add_unreachable_node()
Niko Matsakis86b6e6e2013-05-10 17:10:35304 }
305
Nick Cameronfacdf2e2015-07-31 07:04:06306 hir::ExprAgain(label) => {
Eduard-Mihai Burtescu962633c2016-11-25 11:21:19307 let loop_scope = self.find_scope(expr, label);
James Miller97c17112015-02-19 14:27:25308 let a = self.add_ast_node(expr.id, &[pred]);
Felix S. Klock II65b65fe2014-05-08 22:07:57309 self.add_exiting_edge(expr, a,
Niko Matsakis86b6e6e2013-05-10 17:10:35310 loop_scope, loop_scope.continue_index);
James Miller97c17112015-02-19 14:27:25311 self.add_unreachable_node()
Niko Matsakis86b6e6e2013-05-10 17:10:35312 }
313
Jonas Schievinkcf0b7bd2016-09-20 00:14:46314 hir::ExprArray(ref elems) => {
Nicholas Nethercote382d3b02016-10-28 10:16:44315 self.straightline(expr, pred, elems.iter().map(|e| &*e))
Niko Matsakis86b6e6e2013-05-10 17:10:35316 }
317
Nick Cameronfacdf2e2015-07-31 07:04:06318 hir::ExprCall(ref func, ref args) => {
Nicholas Nethercote382d3b02016-10-28 10:16:44319 self.call(expr, pred, &func, args.iter().map(|e| &*e))
Niko Matsakis86b6e6e2013-05-10 17:10:35320 }
321
Vadim Petrochenkove05e74a2016-08-26 16:23:42322 hir::ExprMethodCall(.., ref args) => {
Nicholas Nethercote382d3b02016-10-28 10:16:44323 self.call(expr, pred, &args[0], args[1..].iter().map(|e| &*e))
Niko Matsakis86b6e6e2013-05-10 17:10:35324 }
325
Nick Cameronfacdf2e2015-07-31 07:04:06326 hir::ExprIndex(ref l, ref r) |
Eduard-Mihai Burtescu85a4a192017-01-06 19:54:24327 hir::ExprBinary(_, ref l, ref r) if self.tables.is_method_call(expr.id) => {
Jonas Schievink559fca02016-02-09 21:00:20328 self.call(expr, pred, &l, Some(&**r).into_iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35329 }
330
Eduard-Mihai Burtescu85a4a192017-01-06 19:54:24331 hir::ExprUnary(_, ref e) if self.tables.is_method_call(expr.id) => {
Jonas Schievink559fca02016-02-09 21:00:20332 self.call(expr, pred, &e, None::<hir::Expr>.iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35333 }
334
Nick Cameronfacdf2e2015-07-31 07:04:06335 hir::ExprTup(ref exprs) => {
Nicholas Nethercote382d3b02016-10-28 10:16:44336 self.straightline(expr, pred, exprs.iter().map(|e| &*e))
Niko Matsakis86b6e6e2013-05-10 17:10:35337 }
338
Nick Cameronfacdf2e2015-07-31 07:04:06339 hir::ExprStruct(_, ref fields, ref base) => {
Brandon Sandersond80a62d2014-11-05 23:05:01340 let field_cfg = self.straightline(expr, pred, fields.iter().map(|f| &*f.expr));
341 self.opt_expr(base, field_cfg)
Niko Matsakis86b6e6e2013-05-10 17:10:35342 }
343
Nick Cameronfacdf2e2015-07-31 07:04:06344 hir::ExprAssign(ref l, ref r) |
345 hir::ExprAssignOp(_, ref l, ref r) => {
Eduard Burtescub0621282014-09-07 17:09:06346 self.straightline(expr, pred, [r, l].iter().map(|&e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35347 }
348
Nick Cameronfacdf2e2015-07-31 07:04:06349 hir::ExprIndex(ref l, ref r) |
350 hir::ExprBinary(_, ref l, ref r) => { // NB: && and || handled earlier
Eduard Burtescub0621282014-09-07 17:09:06351 self.straightline(expr, pred, [l, r].iter().map(|&e| &**e))
Niko Matsakis86b6e6e2013-05-10 17:10:35352 }
353
Eduard Burtescuf293ea22015-09-24 15:00:08354 hir::ExprBox(ref e) |
Nick Cameronfacdf2e2015-07-31 07:04:06355 hir::ExprAddrOf(_, ref e) |
356 hir::ExprCast(ref e, _) |
Eduard Burtescub8157cc2015-02-01 07:59:46357 hir::ExprType(ref e, _) |
Nick Cameronfacdf2e2015-07-31 07:04:06358 hir::ExprUnary(_, ref e) |
Nick Cameronfacdf2e2015-07-31 07:04:06359 hir::ExprField(ref e, _) |
Eduard-Mihai Burtescue64f64a2016-12-21 10:32:59360 hir::ExprTupField(ref e, _) |
361 hir::ExprRepeat(ref e, _) => {
Aaron Turonfc525ee2014-09-15 03:27:36362 self.straightline(expr, pred, Some(&**e).into_iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35363 }
364
Eduard Burtescu856185d2016-03-09 20:17:02365 hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
Nicholas Nethercote382d3b02016-10-28 10:16:44366 let post_outputs = self.exprs(outputs.iter().map(|e| &*e), pred);
367 let post_inputs = self.exprs(inputs.iter().map(|e| &*e), post_outputs);
Eduard Burtescu856185d2016-03-09 20:17:02368 self.add_ast_node(expr.id, &[post_inputs])
Felix S. Klock IIbe9c2d12014-05-20 16:49:19369 }
370
Nick Cameronfacdf2e2015-07-31 07:04:06371 hir::ExprClosure(..) |
372 hir::ExprLit(..) |
Eduard Burtescu16b5c2c2016-10-27 02:17:42373 hir::ExprPath(_) => {
Nick Cameronfacdf2e2015-07-31 07:04:06374 self.straightline(expr, pred, None::<hir::Expr>.iter())
Niko Matsakis86b6e6e2013-05-10 17:10:35375 }
376 }
377 }
378
Nick Cameronfacdf2e2015-07-31 07:04:06379 fn call<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
380 call_expr: &hir::Expr,
Niko Matsakis86b6e6e2013-05-10 17:10:35381 pred: CFGIndex,
Nick Cameronfacdf2e2015-07-31 07:04:06382 func_or_rcvr: &hir::Expr,
Eduard Burtescub0621282014-09-07 17:09:06383 args: I) -> CFGIndex {
Niko Matsakis7c445612014-11-25 19:21:20384 let method_call = ty::MethodCall::expr(call_expr.id);
Eduard-Mihai Burtescu85a4a192017-01-06 19:54:24385 let fn_ty = match self.tables.method_map.get(&method_call) {
Jakub Bukajcca84e92014-10-24 19:14:37386 Some(method) => method.ty,
Eduard-Mihai Burtescu85a4a192017-01-06 19:54:24387 None => self.tables.expr_ty_adjusted(func_or_rcvr)
Eduard Burtescu59935f72015-06-24 05:24:13388 };
Jakub Bukajcca84e92014-10-24 19:14:37389
Niko Matsakis86b6e6e2013-05-10 17:10:35390 let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
Felix S. Klock IIbe9c2d12014-05-20 16:49:19391 let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
Andrew Cannfadabe02016-08-02 07:56:20392 // FIXME(canndrew): This is_never should probably be an is_uninhabited.
393 if fn_ty.fn_ret().0.is_never() {
James Miller97c17112015-02-19 14:27:25394 self.add_unreachable_node()
Felix S. Klock IIbe9c2d12014-05-20 16:49:19395 } else {
396 ret
397 }
Niko Matsakis86b6e6e2013-05-10 17:10:35398 }
399
Nick Cameronfacdf2e2015-07-31 07:04:06400 fn exprs<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
Aaron Turonb299c2b2014-11-06 17:32:37401 exprs: I,
Eduard Burtescub0621282014-09-07 17:09:06402 pred: CFGIndex) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35403 //! Constructs graph for `exprs` evaluated in order
Felix S. Klock IIbe9c2d12014-05-20 16:49:19404 exprs.fold(pred, |p, e| self.expr(e, p))
Niko Matsakis86b6e6e2013-05-10 17:10:35405 }
406
407 fn opt_expr(&mut self,
Nick Cameronfacdf2e2015-07-31 07:04:06408 opt_expr: &Option<P<hir::Expr>>,
Niko Matsakis86b6e6e2013-05-10 17:10:35409 pred: CFGIndex) -> CFGIndex {
410 //! Constructs graph for `opt_expr` evaluated, if Some
Jonas Schievink559fca02016-02-09 21:00:20411 opt_expr.iter().fold(pred, |p, e| self.expr(&e, p))
Niko Matsakis86b6e6e2013-05-10 17:10:35412 }
413
Nick Cameronfacdf2e2015-07-31 07:04:06414 fn straightline<'b, I: Iterator<Item=&'b hir::Expr>>(&mut self,
415 expr: &hir::Expr,
Niko Matsakis86b6e6e2013-05-10 17:10:35416 pred: CFGIndex,
Eduard Burtescub0621282014-09-07 17:09:06417 subexprs: I) -> CFGIndex {
Niko Matsakis86b6e6e2013-05-10 17:10:35418 //! Handles case of an expression that evaluates `subexprs` in order
419
Eduard Burtescub0621282014-09-07 17:09:06420 let subexprs_exit = self.exprs(subexprs, pred);
James Miller97c17112015-02-19 14:27:25421 self.add_ast_node(expr.id, &[subexprs_exit])
Niko Matsakis86b6e6e2013-05-10 17:10:35422 }
423
Nick Cameronfacdf2e2015-07-31 07:04:06424 fn match_(&mut self, id: ast::NodeId, discr: &hir::Expr,
425 arms: &[hir::Arm], pred: CFGIndex) -> CFGIndex {
James Miller4bae1332015-02-19 16:54:41426 // The CFG for match expression is quite complex, so no ASCII
427 // art for it (yet).
428 //
429 // The CFG generated below matches roughly what trans puts
430 // out. Each pattern and guard is visited in parallel, with
431 // arms containing multiple patterns generating multiple nodes
432 // for the same guard expression. The guard expressions chain
433 // into each other from top to bottom, with a specific
434 // exception to allow some additional valid programs
435 // (explained below). Trans differs slightly in that the
436 // pattern matching may continue after a guard but the visible
437 // behaviour should be the same.
438 //
439 // What is going on is explained in further comments.
440
441 // Visit the discriminant expression
442 let discr_exit = self.expr(discr, pred);
443
444 // Add a node for the exit of the match expression as a whole.
445 let expr_exit = self.add_ast_node(id, &[]);
446
447 // Keep track of the previous guard expressions
448 let mut prev_guards = Vec::new();
449 // Track if the previous pattern contained bindings or wildcards
450 let mut prev_has_bindings = false;
451
452 for arm in arms {
453 // Add an exit node for when we've visited all the
454 // patterns and the guard (if there is one) in the arm.
455 let arm_exit = self.add_dummy_node(&[]);
456
457 for pat in &arm.pats {
458 // Visit the pattern, coming from the discriminant exit
Jonas Schievink559fca02016-02-09 21:00:20459 let mut pat_exit = self.pat(&pat, discr_exit);
James Miller4bae1332015-02-19 16:54:41460
461 // If there is a guard expression, handle it here
462 if let Some(ref guard) = arm.guard {
463 // Add a dummy node for the previous guard
464 // expression to target
465 let guard_start = self.add_dummy_node(&[pat_exit]);
466 // Visit the guard expression
Jonas Schievink559fca02016-02-09 21:00:20467 let guard_exit = self.expr(&guard, guard_start);
James Miller4bae1332015-02-19 16:54:41468
Eduard-Mihai Burtescu962633c2016-11-25 11:21:19469 let this_has_bindings = pat.contains_bindings_or_wild();
James Miller4bae1332015-02-19 16:54:41470
471 // If both this pattern and the previous pattern
472 // were free of bindings, they must consist only
473 // of "constant" patterns. Note we cannot match an
474 // all-constant pattern, fail the guard, and then
475 // match *another* all-constant pattern. This is
476 // because if the previous pattern matches, then
477 // we *cannot* match this one, unless all the
478 // constants are the same (which is rejected by
479 // `check_match`).
480 //
481 // We can use this to be smarter about the flow
482 // along guards. If the previous pattern matched,
483 // then we know we will not visit the guard in
484 // this one (whether or not the guard succeeded),
485 // if the previous pattern failed, then we know
486 // the guard for that pattern will not have been
487 // visited. Thus, it is not possible to visit both
488 // the previous guard and the current one when
489 // both patterns consist only of constant
490 // sub-patterns.
491 //
492 // However, if the above does not hold, then all
493 // previous guards need to be wired to visit the
494 // current guard pattern.
495 if prev_has_bindings || this_has_bindings {
496 while let Some(prev) = prev_guards.pop() {
497 self.add_contained_edge(prev, guard_start);
498 }
499 }
500
501 prev_has_bindings = this_has_bindings;
502
503 // Push the guard onto the list of previous guards
504 prev_guards.push(guard_exit);
505
506 // Update the exit node for the pattern
507 pat_exit = guard_exit;
508 }
509
510 // Add an edge from the exit of this pattern to the
511 // exit of the arm
512 self.add_contained_edge(pat_exit, arm_exit);
513 }
514
515 // Visit the body of this arm
516 let body_exit = self.expr(&arm.body, arm_exit);
517
518 // Link the body to the exit of the expression
519 self.add_contained_edge(body_exit, expr_exit);
520 }
521
522 expr_exit
523 }
524
Niko Matsakis86b6e6e2013-05-10 17:10:35525 fn add_dummy_node(&mut self, preds: &[CFGIndex]) -> CFGIndex {
James Miller97c17112015-02-19 14:27:25526 self.add_node(CFGNodeData::Dummy, preds)
Niko Matsakis86b6e6e2013-05-10 17:10:35527 }
528
James Miller97c17112015-02-19 14:27:25529 fn add_ast_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex {
James Miller97c17112015-02-19 14:27:25530 assert!(id != ast::DUMMY_NODE_ID);
531 self.add_node(CFGNodeData::AST(id), preds)
532 }
533
534 fn add_unreachable_node(&mut self) -> CFGIndex {
535 self.add_node(CFGNodeData::Unreachable, &[])
536 }
537
538 fn add_node(&mut self, data: CFGNodeData, preds: &[CFGIndex]) -> CFGIndex {
539 let node = self.graph.add_node(data);
Jorge Apariciod5d7e652015-01-31 17:20:46540 for &pred in preds {
Niko Matsakis86b6e6e2013-05-10 17:10:35541 self.add_contained_edge(pred, node);
542 }
543 node
544 }
545
546 fn add_contained_edge(&mut self,
547 source: CFGIndex,
548 target: CFGIndex) {
iirelue593c3b2016-10-29 21:54:04549 let data = CFGEdgeData {exiting_scopes: vec![] };
Niko Matsakis86b6e6e2013-05-10 17:10:35550 self.graph.add_edge(source, target, data);
551 }
552
553 fn add_exiting_edge(&mut self,
Nick Cameronfacdf2e2015-07-31 07:04:06554 from_expr: &hir::Expr,
Niko Matsakis86b6e6e2013-05-10 17:10:35555 from_index: CFGIndex,
556 to_loop: LoopScope,
557 to_index: CFGIndex) {
iirelue593c3b2016-10-29 21:54:04558 let mut data = CFGEdgeData {exiting_scopes: vec![] };
Ariel Ben-Yehudafc304382015-08-19 22:46:28559 let mut scope = self.tcx.region_maps.node_extent(from_expr.id);
560 let target_scope = self.tcx.region_maps.node_extent(to_loop.loop_id);
Felix S. Klock II5ff90872014-11-18 13:22:59561 while scope != target_scope {
Ariel Ben-Yehudafc304382015-08-19 22:46:28562 data.exiting_scopes.push(scope.node_id(&self.tcx.region_maps));
Felix S. Klock II5ff90872014-11-18 13:22:59563 scope = self.tcx.region_maps.encl_scope(scope);
Niko Matsakis86b6e6e2013-05-10 17:10:35564 }
565 self.graph.add_edge(from_index, to_index, data);
566 }
567
Felix S. Klock II65b65fe2014-05-08 22:07:57568 fn add_returning_edge(&mut self,
Nick Cameronfacdf2e2015-07-31 07:04:06569 _from_expr: &hir::Expr,
Felix S. Klock II65b65fe2014-05-08 22:07:57570 from_index: CFGIndex) {
Patrick Walton36195eb2014-05-16 17:45:16571 let mut data = CFGEdgeData {
iirelue593c3b2016-10-29 21:54:04572 exiting_scopes: vec![],
Patrick Walton36195eb2014-05-16 17:45:16573 };
Felix S. Klock II65b65fe2014-05-08 22:07:57574 for &LoopScope { loop_id: id, .. } in self.loop_scopes.iter().rev() {
575 data.exiting_scopes.push(id);
576 }
577 self.graph.add_edge(from_index, self.fn_exit, data);
578 }
579
Niko Matsakis86b6e6e2013-05-10 17:10:35580 fn find_scope(&self,
Nick Cameronfacdf2e2015-07-31 07:04:06581 expr: &hir::Expr,
Eduard-Mihai Burtescu962633c2016-11-25 11:21:19582 label: Option<hir::Label>) -> LoopScope {
583 match label {
584 None => *self.loop_scopes.last().unwrap(),
585 Some(label) => {
Eduard Burtescu5a6a9ed2015-02-17 04:44:23586 for l in &self.loop_scopes {
Eduard-Mihai Burtescu962633c2016-11-25 11:21:19587 if l.loop_id == label.loop_id {
Eduard Burtescu5a6a9ed2015-02-17 04:44:23588 return *l;
Niko Matsakis86b6e6e2013-05-10 17:10:35589 }
590 }
Eduard-Mihai Burtescu962633c2016-11-25 11:21:19591 span_bug!(expr.span, "no loop scope for id {}", label.loop_id);
Niko Matsakis86b6e6e2013-05-10 17:10:35592 }
593 }
594 }
Patrick Walton99d44d22013-07-10 02:32:09595}