Skip to content

Commit eee209d

Browse files
committed
Only count nested returns when the outer return is reachable
This narrows the definition of nested returns such that only when the outer return has a chance of being executed (due to the inner return being conditional) do we mark the function as having nested returns. Fixes #19684
1 parent 22a9f25 commit eee209d

File tree

5 files changed

+99
-44
lines changed

5 files changed

+99
-44
lines changed

src/librustc/middle/cfg/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,11 @@ impl CFG {
4949
blk: &ast::Block) -> CFG {
5050
construct::construct(tcx, blk)
5151
}
52+
53+
pub fn node_is_reachable(&self, id: ast::NodeId) -> bool {
54+
for node in self.graph.depth_traverse(self.entry) {
55+
if node.id == id { return true }
56+
}
57+
return false;
58+
}
5259
}

src/librustc/middle/graph.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
use std::fmt::{Formatter, Error, Show};
3636
use std::uint;
37+
use std::collections::BitvSet;
3738

3839
pub struct Graph<N,E> {
3940
nodes: Vec<Node<N>> ,
@@ -294,6 +295,42 @@ impl<N,E> Graph<N,E> {
294295
}
295296
}
296297
}
298+
299+
pub fn depth_traverse<'a>(&'a self, start: NodeIndex) -> DepthFirstTraversal<'a, N, E> {
300+
DepthFirstTraversal {
301+
graph: self,
302+
stack: vec![start],
303+
visited: BitvSet::new()
304+
}
305+
}
306+
}
307+
308+
pub struct DepthFirstTraversal<'g, N:'g, E:'g> {
309+
graph: &'g Graph<N, E>,
310+
stack: Vec<NodeIndex>,
311+
visited: BitvSet
312+
}
313+
314+
impl<'g, N, E> Iterator<&'g N> for DepthFirstTraversal<'g, N, E> {
315+
fn next(&mut self) -> Option<&'g N> {
316+
while self.stack.len() > 0 {
317+
let idx = self.stack.pop().unwrap();
318+
if self.visited.contains(&idx.node_id()) {
319+
continue;
320+
}
321+
self.visited.insert(idx.node_id());
322+
self.graph.each_outgoing_edge(idx, |_, e| -> bool {
323+
if !self.visited.contains(&e.target().node_id()) {
324+
self.stack.push(e.target());
325+
}
326+
true
327+
});
328+
329+
return Some(self.graph.node_data(idx));
330+
}
331+
332+
return None;
333+
}
297334
}
298335

299336
pub fn each_edge_index<F>(max_edge_index: EdgeIndex, mut f: F) where

src/librustc_driver/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ pub fn list_metadata(sess: &Session, path: &Path,
472472
/// The diagnostic emitter yielded to the procedure should be used for reporting
473473
/// errors of the compiler.
474474
pub fn monitor<F:FnOnce()+Send>(f: F) {
475-
static STACK_SIZE: uint = 32000000; // 32MB
475+
static STACK_SIZE: uint = 8 * 1024 * 1024; // 8MB
476476

477477
let (tx, rx) = channel();
478478
let w = io::ChanWriter::new(tx);

src/librustc_trans/trans/base.rs

Lines changed: 51 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param};
3838
use llvm;
3939
use metadata::{csearch, encoder, loader};
4040
use middle::astencode;
41+
use middle::cfg;
4142
use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
4243
use middle::subst;
4344
use middle::weak_lang_items;
@@ -1305,47 +1306,33 @@ pub fn make_return_slot_pointer<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
13051306
}
13061307
}
13071308

1308-
struct CheckForNestedReturnsVisitor {
1309+
struct FindNestedReturn {
13091310
found: bool,
1310-
in_return: bool
13111311
}
13121312

1313-
impl CheckForNestedReturnsVisitor {
1314-
fn explicit() -> CheckForNestedReturnsVisitor {
1315-
CheckForNestedReturnsVisitor { found: false, in_return: false }
1316-
}
1317-
fn implicit() -> CheckForNestedReturnsVisitor {
1318-
CheckForNestedReturnsVisitor { found: false, in_return: true }
1313+
impl FindNestedReturn {
1314+
fn new() -> FindNestedReturn {
1315+
FindNestedReturn { found: false }
13191316
}
13201317
}
13211318

1322-
impl<'v> Visitor<'v> for CheckForNestedReturnsVisitor {
1319+
impl<'v> Visitor<'v> for FindNestedReturn {
13231320
fn visit_expr(&mut self, e: &ast::Expr) {
13241321
match e.node {
13251322
ast::ExprRet(..) => {
1326-
if self.in_return {
1327-
self.found = true;
1328-
} else {
1329-
self.in_return = true;
1330-
visit::walk_expr(self, e);
1331-
self.in_return = false;
1332-
}
1323+
self.found = true;
13331324
}
13341325
_ => visit::walk_expr(self, e)
13351326
}
13361327
}
13371328
}
13381329

1339-
fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
1340-
match tcx.map.find(id) {
1330+
fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>) {
1331+
let blk = match tcx.map.find(id) {
13411332
Some(ast_map::NodeItem(i)) => {
13421333
match i.node {
13431334
ast::ItemFn(_, _, _, _, ref blk) => {
1344-
let mut explicit = CheckForNestedReturnsVisitor::explicit();
1345-
let mut implicit = CheckForNestedReturnsVisitor::implicit();
1346-
visit::walk_item(&mut explicit, &*i);
1347-
visit::walk_expr_opt(&mut implicit, &blk.expr);
1348-
explicit.found || implicit.found
1335+
blk
13491336
}
13501337
_ => tcx.sess.bug("unexpected item variant in has_nested_returns")
13511338
}
@@ -1355,11 +1342,7 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
13551342
ast::ProvidedMethod(ref m) => {
13561343
match m.node {
13571344
ast::MethDecl(_, _, _, _, _, _, ref blk, _) => {
1358-
let mut explicit = CheckForNestedReturnsVisitor::explicit();
1359-
let mut implicit = CheckForNestedReturnsVisitor::implicit();
1360-
visit::walk_method_helper(&mut explicit, &**m);
1361-
visit::walk_expr_opt(&mut implicit, &blk.expr);
1362-
explicit.found || implicit.found
1345+
blk
13631346
}
13641347
ast::MethMac(_) => tcx.sess.bug("unexpanded macro")
13651348
}
@@ -1379,11 +1362,7 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
13791362
ast::MethodImplItem(ref m) => {
13801363
match m.node {
13811364
ast::MethDecl(_, _, _, _, _, _, ref blk, _) => {
1382-
let mut explicit = CheckForNestedReturnsVisitor::explicit();
1383-
let mut implicit = CheckForNestedReturnsVisitor::implicit();
1384-
visit::walk_method_helper(&mut explicit, &**m);
1385-
visit::walk_expr_opt(&mut implicit, &blk.expr);
1386-
explicit.found || implicit.found
1365+
blk
13871366
}
13881367
ast::MethMac(_) => tcx.sess.bug("unexpanded macro")
13891368
}
@@ -1397,24 +1376,47 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool {
13971376
Some(ast_map::NodeExpr(e)) => {
13981377
match e.node {
13991378
ast::ExprClosure(_, _, _, ref blk) => {
1400-
let mut explicit = CheckForNestedReturnsVisitor::explicit();
1401-
let mut implicit = CheckForNestedReturnsVisitor::implicit();
1402-
visit::walk_expr(&mut explicit, e);
1403-
visit::walk_expr_opt(&mut implicit, &blk.expr);
1404-
explicit.found || implicit.found
1379+
blk
14051380
}
14061381
_ => tcx.sess.bug("unexpected expr variant in has_nested_returns")
14071382
}
14081383
}
1409-
1410-
Some(ast_map::NodeVariant(..)) | Some(ast_map::NodeStructCtor(..)) => false,
1384+
Some(ast_map::NodeVariant(..)) | Some(ast_map::NodeStructCtor(..)) => return (ast::DUMMY_NODE_ID, None),
14111385

14121386
// glue, shims, etc
1413-
None if id == ast::DUMMY_NODE_ID => false,
1387+
None if id == ast::DUMMY_NODE_ID => return (ast::DUMMY_NODE_ID, None),
14141388

14151389
_ => tcx.sess.bug(format!("unexpected variant in has_nested_returns: {}",
14161390
tcx.map.path_to_string(id)).as_slice())
1391+
};
1392+
1393+
(blk.id, Some(cfg::CFG::new(tcx, &**blk)))
1394+
}
1395+
1396+
fn has_nested_returns(tcx: &ty::ctxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool {
1397+
for n in cfg.graph.depth_traverse(cfg.entry) {
1398+
match tcx.map.find(n.id) {
1399+
Some(ast_map::NodeExpr(ex)) => {
1400+
if let ast::ExprRet(Some(ref ret_expr)) = ex.node {
1401+
let mut visitor = FindNestedReturn::new();
1402+
visit::walk_expr(&mut visitor, &**ret_expr);
1403+
if visitor.found {
1404+
return true;
1405+
}
1406+
}
1407+
}
1408+
Some(ast_map::NodeBlock(blk)) if blk.id == blk_id => {
1409+
let mut visitor = FindNestedReturn::new();
1410+
visit::walk_expr_opt(&mut visitor, &blk.expr);
1411+
if visitor.found {
1412+
return true;
1413+
}
1414+
}
1415+
_ => {}
1416+
}
14171417
}
1418+
1419+
return false;
14181420
}
14191421

14201422
// NB: must keep 4 fns in sync:
@@ -1453,7 +1455,12 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
14531455
ty::FnDiverging => false
14541456
};
14551457
let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl);
1456-
let nested_returns = has_nested_returns(ccx.tcx(), id);
1458+
let (blk_id, cfg) = build_cfg(ccx.tcx(), id);
1459+
let nested_returns = if let Some(ref cfg) = cfg {
1460+
has_nested_returns(ccx.tcx(), cfg, blk_id)
1461+
} else {
1462+
false
1463+
};
14571464

14581465
let mut fcx = FunctionContext {
14591466
llfn: llfndecl,
@@ -1472,7 +1479,8 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
14721479
block_arena: block_arena,
14731480
ccx: ccx,
14741481
debug_context: debug_context,
1475-
scopes: RefCell::new(Vec::new())
1482+
scopes: RefCell::new(Vec::new()),
1483+
cfg: cfg
14761484
};
14771485

14781486
if has_env {

src/librustc_trans/trans/common.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use session::Session;
1818
use llvm;
1919
use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef};
2020
use llvm::{True, False, Bool};
21+
use middle::cfg;
2122
use middle::def;
2223
use middle::infer;
2324
use middle::lang_items::LangItem;
@@ -264,6 +265,8 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
264265

265266
// Cleanup scopes.
266267
pub scopes: RefCell<Vec<cleanup::CleanupScope<'a, 'tcx>>>,
268+
269+
pub cfg: Option<cfg::CFG>,
267270
}
268271

269272
impl<'a, 'tcx> FunctionContext<'a, 'tcx> {

0 commit comments

Comments
 (0)