Add some documentation

This commit is contained in:
James Miller 2014-12-16 12:35:59 +13:00
parent eee209d9e2
commit fb3e871734
3 changed files with 38 additions and 1 deletions

View file

@ -1393,6 +1393,16 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>)
(blk.id, Some(cfg::CFG::new(tcx, &**blk)))
}
// Checks for the presence of "nested returns" in a function.
// Nested returns are when the inner expression of a return expression
// (the 'expr' in 'return expr') contains a return expression. Only cases
// where the outer return is actually reachable are considered. Implicit
// returns from the end of blocks are considered as well.
//
// This check is needed to handle the case where the inner expression is
// part of a larger expression that may have already partially-filled the
// return slot alloca. This can cause errors related to clean-up due to
// the clobbering of the existing value in the return slot.
fn has_nested_returns(tcx: &ty::ctxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool {
for n in cfg.graph.depth_traverse(cfg.entry) {
match tcx.map.find(n.id) {

View file

@ -112,8 +112,17 @@ pub fn trans_block<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
if dest != expr::Ignore {
let block_ty = node_id_type(bcx, b.id);
if b.expr.is_none() || type_is_zero_size(bcx.ccx(), block_ty) {
dest = expr::Ignore;
} else if b.expr.is_some() {
// If the block has an expression, but that expression isn't reachable,
// don't save into the destination given, ignore it.
if let Some(ref cfg) = bcx.fcx.cfg {
if !cfg.node_is_reachable(b.expr.as_ref().unwrap().id) {
dest = expr::Ignore;
}
}
}
}

View file

@ -928,7 +928,25 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
controlflow::trans_cont(bcx, expr.id, label_opt)
}
ast::ExprRet(ref ex) => {
controlflow::trans_ret(bcx, ex.as_ref().map(|e| &**e))
// Check to see if the return expression itself is reachable.
// This can occur when the inner expression contains a return
let reachable = if let Some(ref cfg) = bcx.fcx.cfg {
cfg.node_is_reachable(expr.id)
} else {
true
};
if reachable {
controlflow::trans_ret(bcx, ex.as_ref().map(|e| &**e))
} else {
// If it's not reachable, just translate the inner expression
// directly. This avoids having to manage a return slot when
// it won't actually be used anyway.
if let &Some(ref x) = ex {
bcx = trans_into(bcx, &**x, Ignore);
}
bcx
}
}
ast::ExprWhile(ref cond, ref body, _) => {
controlflow::trans_while(bcx, expr.id, &**cond, &**body)