auto merge of #14873 : pnkfelix/rust/fsk-dataflow-revisions, r=nikomatsakis
Fix #6298. Fix #13767. This also includes some drive by fixes for some other issues, noted in the commits. I still need to integrate regression tests for some cases that I noticed were missing from our unit test suite (i.e. things that compiling rustc exposes that should have been exposed when doing `make check-stage1`). So do not land this yet, until I get the chance to add those tests. I just wanted to get the review process started soon, since this has been long in the coming.
This commit is contained in:
commit
4416b32768
@ -242,7 +242,7 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
let mut loan_path = loan_path;
|
||||
loop {
|
||||
match *loan_path {
|
||||
LpVar(_) => {
|
||||
LpVar(_) | LpUpvar(_) => {
|
||||
break;
|
||||
}
|
||||
LpExtend(ref lp_base, _, _) => {
|
||||
@ -632,7 +632,7 @@ impl<'a> CheckLoanCtxt<'a> {
|
||||
*/
|
||||
|
||||
match **lp {
|
||||
LpVar(_) => {
|
||||
LpVar(_) | LpUpvar(_) => {
|
||||
// assigning to `x` does not require that `x` is initialized
|
||||
}
|
||||
LpExtend(ref lp_base, _, LpInterior(_)) => {
|
||||
|
@ -948,7 +948,7 @@ The borrow checker is also in charge of ensuring that:
|
||||
|
||||
These are two separate dataflow analyses built on the same
|
||||
framework. Let's look at checking that memory is initialized first;
|
||||
the checking of immutable local variabe assignments works in a very
|
||||
the checking of immutable local variable assignments works in a very
|
||||
similar way.
|
||||
|
||||
To track the initialization of memory, we actually track all the
|
||||
|
@ -395,7 +395,8 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
//! from a local variable, mark the mutability decl as necessary.
|
||||
|
||||
match *loan_path {
|
||||
LpVar(local_id) => {
|
||||
LpVar(local_id) |
|
||||
LpUpvar(ty::UpvarId{ var_id: local_id, closure_expr_id: _ }) => {
|
||||
self.tcx().used_mut_nodes.borrow_mut().insert(local_id);
|
||||
}
|
||||
LpExtend(ref base, mc::McInherited, _) => {
|
||||
@ -445,8 +446,8 @@ impl<'a> GatherLoanCtxt<'a> {
|
||||
//! with immutable `&` pointers, because borrows of such pointers
|
||||
//! do not require restrictions and hence do not cause a loan.
|
||||
|
||||
let lexical_scope = lp.kill_scope(self.bccx.tcx);
|
||||
let rm = &self.bccx.tcx.region_maps;
|
||||
let lexical_scope = rm.var_scope(lp.node_id());
|
||||
if rm.is_subscope_of(lexical_scope, loan_scope) {
|
||||
lexical_scope
|
||||
} else {
|
||||
|
@ -67,13 +67,23 @@ impl<'a> RestrictionsContext<'a> {
|
||||
}
|
||||
|
||||
mc::cat_local(local_id) |
|
||||
mc::cat_arg(local_id) |
|
||||
mc::cat_upvar(ty::UpvarId {var_id: local_id, ..}, _) => {
|
||||
// R-Variable
|
||||
mc::cat_arg(local_id) => {
|
||||
// R-Variable, locally declared
|
||||
let lp = Rc::new(LpVar(local_id));
|
||||
SafeIf(lp.clone(), vec!(lp))
|
||||
}
|
||||
|
||||
mc::cat_upvar(upvar_id, _) => {
|
||||
// R-Variable, captured into closure
|
||||
let lp = Rc::new(LpUpvar(upvar_id));
|
||||
SafeIf(lp.clone(), vec!(lp))
|
||||
}
|
||||
|
||||
mc::cat_copied_upvar(..) => {
|
||||
// FIXME(#2152) allow mutation of upvars
|
||||
Safe
|
||||
}
|
||||
|
||||
mc::cat_downcast(cmt_base) => {
|
||||
// When we borrow the interior of an enum, we have to
|
||||
// ensure the enum itself is not mutated, because that
|
||||
@ -107,7 +117,6 @@ impl<'a> RestrictionsContext<'a> {
|
||||
self.extend(result, cmt.mutbl, LpDeref(pk))
|
||||
}
|
||||
|
||||
mc::cat_copied_upvar(..) | // FIXME(#2152) allow mutation of upvars
|
||||
mc::cat_static_item(..) => {
|
||||
Safe
|
||||
}
|
||||
|
@ -12,7 +12,9 @@
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use middle::cfg;
|
||||
use middle::dataflow::DataFlowContext;
|
||||
use middle::dataflow::BitwiseOperator;
|
||||
use middle::dataflow::DataFlowOperator;
|
||||
use middle::def;
|
||||
use euv = middle::expr_use_visitor;
|
||||
@ -126,8 +128,13 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
|
||||
let id_range = ast_util::compute_id_range_for_fn_body(fk, decl, body, sp, id);
|
||||
let (all_loans, move_data) =
|
||||
gather_loans::gather_loans_in_fn(this, decl, body);
|
||||
let cfg = cfg::CFG::new(this.tcx, body);
|
||||
|
||||
let mut loan_dfcx =
|
||||
DataFlowContext::new(this.tcx,
|
||||
"borrowck",
|
||||
Some(decl),
|
||||
&cfg,
|
||||
LoanDataFlowOperator,
|
||||
id_range,
|
||||
all_loans.len());
|
||||
@ -135,11 +142,14 @@ fn borrowck_fn(this: &mut BorrowckCtxt,
|
||||
loan_dfcx.add_gen(loan.gen_scope, loan_idx);
|
||||
loan_dfcx.add_kill(loan.kill_scope, loan_idx);
|
||||
}
|
||||
loan_dfcx.propagate(body);
|
||||
loan_dfcx.add_kills_from_flow_exits(&cfg);
|
||||
loan_dfcx.propagate(&cfg, body);
|
||||
|
||||
let flowed_moves = move_data::FlowedMoveData::new(move_data,
|
||||
this.tcx,
|
||||
&cfg,
|
||||
id_range,
|
||||
decl,
|
||||
body);
|
||||
|
||||
check_loans::check_loans(this, &loan_dfcx, flowed_moves,
|
||||
@ -191,6 +201,7 @@ pub struct Loan {
|
||||
#[deriving(PartialEq, Eq, Hash)]
|
||||
pub enum LoanPath {
|
||||
LpVar(ast::NodeId), // `x` in doc.rs
|
||||
LpUpvar(ty::UpvarId), // `x` captured by-value into closure
|
||||
LpExtend(Rc<LoanPath>, mc::MutabilityCategory, LoanPathElem)
|
||||
}
|
||||
|
||||
@ -200,11 +211,25 @@ pub enum LoanPathElem {
|
||||
LpInterior(mc::InteriorKind) // `LV.f` in doc.rs
|
||||
}
|
||||
|
||||
pub fn closure_to_block(closure_id: ast::NodeId,
|
||||
tcx: &ty::ctxt) -> ast::NodeId {
|
||||
match tcx.map.get(closure_id) {
|
||||
ast_map::NodeExpr(expr) => match expr.node {
|
||||
ast::ExprProc(_decl, block) |
|
||||
ast::ExprFnBlock(_decl, block) => { block.id }
|
||||
_ => fail!("encountered non-closure id: {}", closure_id)
|
||||
},
|
||||
_ => fail!("encountered non-expr id: {}", closure_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl LoanPath {
|
||||
pub fn node_id(&self) -> ast::NodeId {
|
||||
pub fn kill_scope(&self, tcx: &ty::ctxt) -> ast::NodeId {
|
||||
match *self {
|
||||
LpVar(local_id) => local_id,
|
||||
LpExtend(ref base, _, _) => base.node_id()
|
||||
LpVar(local_id) => tcx.region_maps.var_scope(local_id),
|
||||
LpUpvar(upvar_id) =>
|
||||
closure_to_block(upvar_id.closure_expr_id, tcx),
|
||||
LpExtend(ref base, _, _) => base.kill_scope(tcx),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -224,12 +249,18 @@ pub fn opt_loan_path(cmt: &mc::cmt) -> Option<Rc<LoanPath>> {
|
||||
}
|
||||
|
||||
mc::cat_local(id) |
|
||||
mc::cat_arg(id) |
|
||||
mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id: id, .. }) |
|
||||
mc::cat_upvar(ty::UpvarId {var_id: id, ..}, _) => {
|
||||
mc::cat_arg(id) => {
|
||||
Some(Rc::new(LpVar(id)))
|
||||
}
|
||||
|
||||
mc::cat_upvar(ty::UpvarId {var_id: id, closure_expr_id: proc_id}, _) |
|
||||
mc::cat_copied_upvar(mc::CopiedUpvar { upvar_id: id,
|
||||
onceness: _,
|
||||
capturing_proc: proc_id }) => {
|
||||
let upvar_id = ty::UpvarId{ var_id: id, closure_expr_id: proc_id };
|
||||
Some(Rc::new(LpUpvar(upvar_id)))
|
||||
}
|
||||
|
||||
mc::cat_deref(ref cmt_base, _, pk) => {
|
||||
opt_loan_path(cmt_base).map(|lp| {
|
||||
Rc::new(LpExtend(lp, cmt.mutbl, LpDeref(pk)))
|
||||
@ -683,6 +714,7 @@ impl<'a> BorrowckCtxt<'a> {
|
||||
loan_path: &LoanPath,
|
||||
out: &mut String) {
|
||||
match *loan_path {
|
||||
LpUpvar(ty::UpvarId{ var_id: id, closure_expr_id: _ }) |
|
||||
LpVar(id) => {
|
||||
out.push_str(ty::local_var_name_str(self.tcx, id).get());
|
||||
}
|
||||
@ -724,7 +756,7 @@ impl<'a> BorrowckCtxt<'a> {
|
||||
self.append_autoderefd_loan_path_to_str(&**lp_base, out)
|
||||
}
|
||||
|
||||
LpVar(..) | LpExtend(_, _, LpInterior(..)) => {
|
||||
LpVar(..) | LpUpvar(..) | LpExtend(_, _, LpInterior(..)) => {
|
||||
self.append_loan_path_to_str(loan_path, out)
|
||||
}
|
||||
}
|
||||
@ -753,16 +785,18 @@ fn is_statement_scope(tcx: &ty::ctxt, region: ty::Region) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
impl BitwiseOperator for LoanDataFlowOperator {
|
||||
#[inline]
|
||||
fn join(&self, succ: uint, pred: uint) -> uint {
|
||||
succ | pred // loans from both preds are in scope
|
||||
}
|
||||
}
|
||||
|
||||
impl DataFlowOperator for LoanDataFlowOperator {
|
||||
#[inline]
|
||||
fn initial_value(&self) -> bool {
|
||||
false // no loans in scope by default
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn join(&self, succ: uint, pred: uint) -> uint {
|
||||
succ | pred // loans from both preds are in scope
|
||||
}
|
||||
}
|
||||
|
||||
impl Repr for Loan {
|
||||
@ -784,6 +818,12 @@ impl Repr for LoanPath {
|
||||
(format!("$({})", tcx.map.node_to_str(id))).to_string()
|
||||
}
|
||||
|
||||
&LpUpvar(ty::UpvarId{ var_id, closure_expr_id }) => {
|
||||
let s = tcx.map.node_to_str(var_id);
|
||||
let s = format!("$({} captured by id={})", s, closure_expr_id);
|
||||
s.to_string()
|
||||
}
|
||||
|
||||
&LpExtend(ref lp, _, LpDeref(_)) => {
|
||||
(format!("{}.*", lp.repr(tcx))).to_string()
|
||||
}
|
||||
|
@ -20,7 +20,9 @@ use std::rc::Rc;
|
||||
use std::uint;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use middle::borrowck::*;
|
||||
use middle::cfg;
|
||||
use middle::dataflow::DataFlowContext;
|
||||
use middle::dataflow::BitwiseOperator;
|
||||
use middle::dataflow::DataFlowOperator;
|
||||
use euv = middle::expr_use_visitor;
|
||||
use middle::ty;
|
||||
@ -229,7 +231,7 @@ impl MoveData {
|
||||
}
|
||||
|
||||
let index = match *lp {
|
||||
LpVar(..) => {
|
||||
LpVar(..) | LpUpvar(..) => {
|
||||
let index = MovePathIndex(self.paths.borrow().len());
|
||||
|
||||
self.paths.borrow_mut().push(MovePath {
|
||||
@ -300,7 +302,7 @@ impl MoveData {
|
||||
}
|
||||
None => {
|
||||
match **lp {
|
||||
LpVar(..) => { }
|
||||
LpVar(..) | LpUpvar(..) => { }
|
||||
LpExtend(ref b, _, _) => {
|
||||
self.add_existing_base_paths(b, result);
|
||||
}
|
||||
@ -416,6 +418,11 @@ impl MoveData {
|
||||
let path = *self.path_map.borrow().get(&path.loan_path);
|
||||
self.kill_moves(path, kill_id, dfcx_moves);
|
||||
}
|
||||
LpUpvar(ty::UpvarId { var_id: _, closure_expr_id }) => {
|
||||
let kill_id = closure_to_block(closure_expr_id, tcx);
|
||||
let path = *self.path_map.borrow().get(&path.loan_path);
|
||||
self.kill_moves(path, kill_id, dfcx_moves);
|
||||
}
|
||||
LpExtend(..) => {}
|
||||
}
|
||||
}
|
||||
@ -428,6 +435,10 @@ impl MoveData {
|
||||
let kill_id = tcx.region_maps.var_scope(id);
|
||||
dfcx_assign.add_kill(kill_id, assignment_index);
|
||||
}
|
||||
LpUpvar(ty::UpvarId { var_id: _, closure_expr_id }) => {
|
||||
let kill_id = closure_to_block(closure_expr_id, tcx);
|
||||
dfcx_assign.add_kill(kill_id, assignment_index);
|
||||
}
|
||||
LpExtend(..) => {
|
||||
tcx.sess.bug("var assignment for non var path");
|
||||
}
|
||||
@ -499,22 +510,33 @@ impl MoveData {
|
||||
impl<'a> FlowedMoveData<'a> {
|
||||
pub fn new(move_data: MoveData,
|
||||
tcx: &'a ty::ctxt,
|
||||
cfg: &'a cfg::CFG,
|
||||
id_range: ast_util::IdRange,
|
||||
decl: &ast::FnDecl,
|
||||
body: &ast::Block)
|
||||
-> FlowedMoveData<'a> {
|
||||
let mut dfcx_moves =
|
||||
DataFlowContext::new(tcx,
|
||||
"flowed_move_data_moves",
|
||||
Some(decl),
|
||||
cfg,
|
||||
MoveDataFlowOperator,
|
||||
id_range,
|
||||
move_data.moves.borrow().len());
|
||||
let mut dfcx_assign =
|
||||
DataFlowContext::new(tcx,
|
||||
"flowed_move_data_assigns",
|
||||
Some(decl),
|
||||
cfg,
|
||||
AssignDataFlowOperator,
|
||||
id_range,
|
||||
move_data.var_assignments.borrow().len());
|
||||
move_data.add_gen_kills(tcx, &mut dfcx_moves, &mut dfcx_assign);
|
||||
dfcx_moves.propagate(body);
|
||||
dfcx_assign.propagate(body);
|
||||
dfcx_moves.add_kills_from_flow_exits(cfg);
|
||||
dfcx_assign.add_kills_from_flow_exits(cfg);
|
||||
dfcx_moves.propagate(cfg, body);
|
||||
dfcx_assign.propagate(cfg, body);
|
||||
|
||||
FlowedMoveData {
|
||||
move_data: move_data,
|
||||
dfcx_moves: dfcx_moves,
|
||||
@ -659,12 +681,21 @@ impl<'a> FlowedMoveData<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl BitwiseOperator for MoveDataFlowOperator {
|
||||
#[inline]
|
||||
fn join(&self, succ: uint, pred: uint) -> uint {
|
||||
succ | pred // moves from both preds are in scope
|
||||
}
|
||||
}
|
||||
|
||||
impl DataFlowOperator for MoveDataFlowOperator {
|
||||
#[inline]
|
||||
fn initial_value(&self) -> bool {
|
||||
false // no loans in scope by default
|
||||
}
|
||||
}
|
||||
|
||||
impl BitwiseOperator for AssignDataFlowOperator {
|
||||
#[inline]
|
||||
fn join(&self, succ: uint, pred: uint) -> uint {
|
||||
succ | pred // moves from both preds are in scope
|
||||
@ -676,9 +707,4 @@ impl DataFlowOperator for AssignDataFlowOperator {
|
||||
fn initial_value(&self) -> bool {
|
||||
false // no assignments in scope by default
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn join(&self, succ: uint, pred: uint) -> uint {
|
||||
succ | pred // moves from both preds are in scope
|
||||
}
|
||||
}
|
||||
|
@ -254,6 +254,7 @@ impl<'a> CFGBuilder<'a> {
|
||||
});
|
||||
let body_exit = self.block(&**body, cond_exit); // 4
|
||||
self.add_contained_edge(body_exit, loopback); // 5
|
||||
self.loop_scopes.pop();
|
||||
expr_exit
|
||||
}
|
||||
|
||||
@ -427,8 +428,22 @@ impl<'a> CFGBuilder<'a> {
|
||||
self.straightline(expr, pred, [e])
|
||||
}
|
||||
|
||||
ast::ExprInlineAsm(ref inline_asm) => {
|
||||
let inputs = inline_asm.inputs.iter();
|
||||
let outputs = inline_asm.outputs.iter();
|
||||
fn extract_expr<A>(&(_, expr): &(A, Gc<ast::Expr>)) -> Gc<ast::Expr> { expr }
|
||||
let post_inputs = self.exprs(inputs.map(|a| {
|
||||
debug!("cfg::construct InlineAsm id:{} input:{:?}", expr.id, a);
|
||||
extract_expr(a)
|
||||
}), pred);
|
||||
let post_outputs = self.exprs(outputs.map(|a| {
|
||||
debug!("cfg::construct InlineAsm id:{} output:{:?}", expr.id, a);
|
||||
extract_expr(a)
|
||||
}), post_inputs);
|
||||
self.add_node(expr.id, [post_outputs])
|
||||
}
|
||||
|
||||
ast::ExprMac(..) |
|
||||
ast::ExprInlineAsm(..) |
|
||||
ast::ExprFnBlock(..) |
|
||||
ast::ExprProc(..) |
|
||||
ast::ExprLit(..) |
|
||||
@ -444,15 +459,22 @@ impl<'a> CFGBuilder<'a> {
|
||||
func_or_rcvr: Gc<ast::Expr>,
|
||||
args: &[Gc<ast::Expr>]) -> CFGIndex {
|
||||
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
|
||||
self.straightline(call_expr, func_or_rcvr_exit, args)
|
||||
let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
|
||||
|
||||
let return_ty = ty::node_id_to_type(self.tcx, call_expr.id);
|
||||
let fails = ty::type_is_bot(return_ty);
|
||||
if fails {
|
||||
self.add_node(ast::DUMMY_NODE_ID, [])
|
||||
} else {
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn exprs(&mut self,
|
||||
exprs: &[Gc<ast::Expr>],
|
||||
pred: CFGIndex) -> CFGIndex {
|
||||
fn exprs<I:Iterator<Gc<ast::Expr>>>(&mut self,
|
||||
mut exprs: I,
|
||||
pred: CFGIndex) -> CFGIndex {
|
||||
//! Constructs graph for `exprs` evaluated in order
|
||||
|
||||
exprs.iter().fold(pred, |p, &e| self.expr(e, p))
|
||||
exprs.fold(pred, |p, e| self.expr(e, p))
|
||||
}
|
||||
|
||||
fn opt_expr(&mut self,
|
||||
@ -469,7 +491,7 @@ impl<'a> CFGBuilder<'a> {
|
||||
subexprs: &[Gc<ast::Expr>]) -> CFGIndex {
|
||||
//! Handles case of an expression that evaluates `subexprs` in order
|
||||
|
||||
let subexprs_exit = self.exprs(subexprs, pred);
|
||||
let subexprs_exit = self.exprs(subexprs.iter().map(|&e|e), pred);
|
||||
self.add_node(expr.id, [subexprs_exit])
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,6 @@ Uses `Graph` as the underlying representation.
|
||||
|
||||
*/
|
||||
|
||||
#![allow(dead_code)] // still a WIP, #6298
|
||||
|
||||
use middle::graph;
|
||||
use middle::ty;
|
||||
use syntax::ast;
|
||||
@ -48,11 +46,6 @@ pub type CFGNode = graph::Node<CFGNodeData>;
|
||||
|
||||
pub type CFGEdge = graph::Edge<CFGEdgeData>;
|
||||
|
||||
pub struct CFGIndices {
|
||||
entry: CFGIndex,
|
||||
exit: CFGIndex,
|
||||
}
|
||||
|
||||
impl CFG {
|
||||
pub fn new(tcx: &ty::ctxt,
|
||||
blk: &ast::Block) -> CFG {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -186,24 +186,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
|
||||
|
||||
let cmt = return_if_err!(self.mc.cat_expr(expr));
|
||||
self.delegate_consume(expr.id, expr.span, cmt);
|
||||
|
||||
match expr.node {
|
||||
ast::ExprParen(ref subexpr) => {
|
||||
// Argh but is ExprParen horrible. So, if we consume
|
||||
// `(x)`, that generally is also consuming `x`, UNLESS
|
||||
// there are adjustments on the `(x)` expression
|
||||
// (e.g., autoderefs and autorefs).
|
||||
if self.typer.adjustments().borrow().contains_key(&expr.id) {
|
||||
self.walk_expr(expr);
|
||||
} else {
|
||||
self.consume_expr(&**subexpr);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
self.walk_expr(expr)
|
||||
}
|
||||
}
|
||||
self.walk_expr(expr);
|
||||
}
|
||||
|
||||
fn mutate_expr(&mut self,
|
||||
|
@ -55,7 +55,7 @@ pub struct Edge<E> {
|
||||
pub data: E,
|
||||
}
|
||||
|
||||
#[deriving(PartialEq)]
|
||||
#[deriving(Clone, PartialEq, Show)]
|
||||
pub struct NodeIndex(pub uint);
|
||||
pub static InvalidNodeIndex: NodeIndex = NodeIndex(uint::MAX);
|
||||
|
||||
|
@ -97,6 +97,7 @@ pub enum categorization {
|
||||
pub struct CopiedUpvar {
|
||||
pub upvar_id: ast::NodeId,
|
||||
pub onceness: ast::Onceness,
|
||||
pub capturing_proc: ast::NodeId,
|
||||
}
|
||||
|
||||
// different kinds of pointers:
|
||||
@ -559,7 +560,9 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
span:span,
|
||||
cat:cat_copied_upvar(CopiedUpvar {
|
||||
upvar_id: var_id,
|
||||
onceness: closure_ty.onceness}),
|
||||
onceness: closure_ty.onceness,
|
||||
capturing_proc: fn_node_id,
|
||||
}),
|
||||
mutbl:McImmutable,
|
||||
ty:expr_ty
|
||||
}))
|
||||
|
@ -12,7 +12,7 @@ fn a() {
|
||||
let mut v = vec!(1, 2, 3);
|
||||
let vb: &mut [int] = v.as_mut_slice();
|
||||
match vb {
|
||||
[_a, ..tail] => { //~ ERROR cannot use `vb[..]` because it was mutably borrowed
|
||||
[_a, ..tail] => {
|
||||
v.push(tail[0] + tail[1]); //~ ERROR cannot borrow
|
||||
}
|
||||
_ => {}
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
FILES=f00.rs f01.rs f02.rs f03.rs f04.rs f05.rs f06.rs f07.rs \
|
||||
f08.rs f09.rs f10.rs f11.rs f12.rs f13.rs f14.rs f15.rs \
|
||||
f16.rs f17.rs f18.rs f19.rs f20.rs f21.rs f22.rs
|
||||
f16.rs f17.rs f18.rs f19.rs f20.rs f21.rs f22.rs f23.rs \
|
||||
f24.rs f25.rs
|
||||
|
||||
|
||||
# all: $(patsubst %.rs,$(TMPDIR)/%.dot,$(FILES)) $(patsubst %.rs,$(TMPDIR)/%.pp,$(FILES))
|
||||
|
93
src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot
Normal file
93
src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot
Normal file
@ -0,0 +1,93 @@
|
||||
digraph block {
|
||||
N0[label="entry"];
|
||||
N1[label="exit"];
|
||||
N2[label="expr 23"];
|
||||
N3[label="local mut x"];
|
||||
N4[label="expr 23"];
|
||||
N5[label="local mut y"];
|
||||
N6[label="expr 23"];
|
||||
N7[label="local mut z"];
|
||||
N8[label="(dummy_node)"];
|
||||
N9[label="expr x"];
|
||||
N10[label="expr 0"];
|
||||
N11[label="expr x > 0"];
|
||||
N12[label="expr while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"];
|
||||
N13[label="expr 1"];
|
||||
N14[label="expr x"];
|
||||
N15[label="expr x -= 1"];
|
||||
N16[label="(dummy_node)"];
|
||||
N17[label="expr y"];
|
||||
N18[label="expr 0"];
|
||||
N19[label="expr y > 0"];
|
||||
N20[label="expr while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"];
|
||||
N21[label="expr 1"];
|
||||
N22[label="expr y"];
|
||||
N23[label="expr y -= 1"];
|
||||
N24[label="(dummy_node)"];
|
||||
N25[label="expr z"];
|
||||
N26[label="expr 0"];
|
||||
N27[label="expr z > 0"];
|
||||
N28[label="expr while z > 0 { z -= 1; }"];
|
||||
N29[label="expr 1"];
|
||||
N30[label="expr z"];
|
||||
N31[label="expr z -= 1"];
|
||||
N32[label="block { z -= 1; }"];
|
||||
N33[label="expr x"];
|
||||
N34[label="expr 10"];
|
||||
N35[label="expr x > 10"];
|
||||
N36[label="expr return"];
|
||||
N37[label="(dummy_node)"];
|
||||
N38[label="expr \"unreachable\""];
|
||||
N39[label="block { return; \"unreachable\"; }"];
|
||||
N40[label="expr if x > 10 { return; \"unreachable\"; }"];
|
||||
N41[label="block { y -= 1; while z > 0 { z -= 1; } if x > 10 { return; \"unreachable\"; } }"];
|
||||
N42[label="block {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"];
|
||||
N43[label="block {\l let mut x = 23;\l let mut y = 23;\l let mut z = 23;\l while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"];
|
||||
N0 -> N2;
|
||||
N2 -> N3;
|
||||
N3 -> N4;
|
||||
N4 -> N5;
|
||||
N5 -> N6;
|
||||
N6 -> N7;
|
||||
N7 -> N8;
|
||||
N8 -> N9;
|
||||
N9 -> N10;
|
||||
N10 -> N11;
|
||||
N11 -> N12;
|
||||
N11 -> N13;
|
||||
N13 -> N14;
|
||||
N14 -> N15;
|
||||
N15 -> N16;
|
||||
N16 -> N17;
|
||||
N17 -> N18;
|
||||
N18 -> N19;
|
||||
N19 -> N20;
|
||||
N19 -> N21;
|
||||
N21 -> N22;
|
||||
N22 -> N23;
|
||||
N23 -> N24;
|
||||
N24 -> N25;
|
||||
N25 -> N26;
|
||||
N26 -> N27;
|
||||
N27 -> N28;
|
||||
N27 -> N29;
|
||||
N29 -> N30;
|
||||
N30 -> N31;
|
||||
N31 -> N32;
|
||||
N32 -> N24;
|
||||
N28 -> N33;
|
||||
N33 -> N34;
|
||||
N34 -> N35;
|
||||
N35 -> N36;
|
||||
N36 -> N1[label="exiting scope_0 expr while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"];
|
||||
N37 -> N38;
|
||||
N38 -> N39;
|
||||
N35 -> N40;
|
||||
N39 -> N40;
|
||||
N40 -> N41;
|
||||
N41 -> N16;
|
||||
N20 -> N42;
|
||||
N42 -> N8;
|
||||
N12 -> N43;
|
||||
N43 -> N1;
|
||||
}
|
31
src/test/run-make/graphviz-flowgraph/f23.rs
Normal file
31
src/test/run-make/graphviz-flowgraph/f23.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
pub fn expr_while_23() {
|
||||
let mut x = 23;
|
||||
let mut y = 23;
|
||||
let mut z = 23;
|
||||
|
||||
while x > 0 {
|
||||
x -= 1;
|
||||
|
||||
while y > 0 {
|
||||
y -= 1;
|
||||
|
||||
while z > 0 { z -= 1; }
|
||||
|
||||
if x > 10 {
|
||||
return;
|
||||
"unreachable";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
123
src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot
Normal file
123
src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot
Normal file
@ -0,0 +1,123 @@
|
||||
digraph block {
|
||||
N0[label="entry"];
|
||||
N1[label="exit"];
|
||||
N2[label="expr 24"];
|
||||
N3[label="local mut x"];
|
||||
N4[label="expr 24"];
|
||||
N5[label="local mut y"];
|
||||
N6[label="expr 24"];
|
||||
N7[label="local mut z"];
|
||||
N8[label="(dummy_node)"];
|
||||
N9[label="expr loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"];
|
||||
N10[label="expr x"];
|
||||
N11[label="expr 0"];
|
||||
N12[label="expr x == 0"];
|
||||
N13[label="expr break"];
|
||||
N14[label="(dummy_node)"];
|
||||
N15[label="expr \"unreachable\""];
|
||||
N16[label="block { break ; \"unreachable\"; }"];
|
||||
N17[label="expr if x == 0 { break ; \"unreachable\"; }"];
|
||||
N18[label="expr 1"];
|
||||
N19[label="expr x"];
|
||||
N20[label="expr x -= 1"];
|
||||
N21[label="(dummy_node)"];
|
||||
N22[label="expr loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"];
|
||||
N23[label="expr y"];
|
||||
N24[label="expr 0"];
|
||||
N25[label="expr y == 0"];
|
||||
N26[label="expr break"];
|
||||
N27[label="(dummy_node)"];
|
||||
N28[label="expr \"unreachable\""];
|
||||
N29[label="block { break ; \"unreachable\"; }"];
|
||||
N30[label="expr if y == 0 { break ; \"unreachable\"; }"];
|
||||
N31[label="expr 1"];
|
||||
N32[label="expr y"];
|
||||
N33[label="expr y -= 1"];
|
||||
N34[label="(dummy_node)"];
|
||||
N35[label="expr loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"];
|
||||
N36[label="expr z"];
|
||||
N37[label="expr 0"];
|
||||
N38[label="expr z == 0"];
|
||||
N39[label="expr break"];
|
||||
N40[label="(dummy_node)"];
|
||||
N41[label="expr \"unreachable\""];
|
||||
N42[label="block { break ; \"unreachable\"; }"];
|
||||
N43[label="expr if z == 0 { break ; \"unreachable\"; }"];
|
||||
N44[label="expr 1"];
|
||||
N45[label="expr z"];
|
||||
N46[label="expr z -= 1"];
|
||||
N47[label="block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"];
|
||||
N48[label="expr x"];
|
||||
N49[label="expr 10"];
|
||||
N50[label="expr x > 10"];
|
||||
N51[label="expr return"];
|
||||
N52[label="(dummy_node)"];
|
||||
N53[label="expr \"unreachable\""];
|
||||
N54[label="block { return; \"unreachable\"; }"];
|
||||
N55[label="expr if x > 10 { return; \"unreachable\"; }"];
|
||||
N56[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"];
|
||||
N57[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"];
|
||||
N58[label="block {\l let mut x = 24;\l let mut y = 24;\l let mut z = 24;\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l }\l}\l"];
|
||||
N0 -> N2;
|
||||
N2 -> N3;
|
||||
N3 -> N4;
|
||||
N4 -> N5;
|
||||
N5 -> N6;
|
||||
N6 -> N7;
|
||||
N7 -> N8;
|
||||
N8 -> N10;
|
||||
N10 -> N11;
|
||||
N11 -> N12;
|
||||
N12 -> N13;
|
||||
N13 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0 { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0 { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"];
|
||||
N14 -> N15;
|
||||
N15 -> N16;
|
||||
N12 -> N17;
|
||||
N16 -> N17;
|
||||
N17 -> N18;
|
||||
N18 -> N19;
|
||||
N19 -> N20;
|
||||
N20 -> N21;
|
||||
N21 -> N23;
|
||||
N23 -> N24;
|
||||
N24 -> N25;
|
||||
N25 -> N26;
|
||||
N26 -> N22[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0 { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0 { break ; \"unreachable\"; },\lexiting scope_5 block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"];
|
||||
N27 -> N28;
|
||||
N28 -> N29;
|
||||
N25 -> N30;
|
||||
N29 -> N30;
|
||||
N30 -> N31;
|
||||
N31 -> N32;
|
||||
N32 -> N33;
|
||||
N33 -> N34;
|
||||
N34 -> N36;
|
||||
N36 -> N37;
|
||||
N37 -> N38;
|
||||
N38 -> N39;
|
||||
N39 -> N35[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0 { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0 { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"];
|
||||
N40 -> N41;
|
||||
N41 -> N42;
|
||||
N38 -> N43;
|
||||
N42 -> N43;
|
||||
N43 -> N44;
|
||||
N44 -> N45;
|
||||
N45 -> N46;
|
||||
N46 -> N47;
|
||||
N47 -> N34;
|
||||
N35 -> N48;
|
||||
N48 -> N49;
|
||||
N49 -> N50;
|
||||
N50 -> N51;
|
||||
N51 -> N1[label="exiting scope_0 expr loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l,\lexiting scope_1 expr loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"];
|
||||
N52 -> N53;
|
||||
N53 -> N54;
|
||||
N50 -> N55;
|
||||
N54 -> N55;
|
||||
N55 -> N56;
|
||||
N56 -> N21;
|
||||
N22 -> N57;
|
||||
N57 -> N8;
|
||||
N9 -> N58;
|
||||
N58 -> N1;
|
||||
}
|
36
src/test/run-make/graphviz-flowgraph/f24.rs
Normal file
36
src/test/run-make/graphviz-flowgraph/f24.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
pub fn expr_while_24() {
|
||||
let mut x = 24;
|
||||
let mut y = 24;
|
||||
let mut z = 24;
|
||||
|
||||
loop {
|
||||
if x == 0 { break; "unreachable"; }
|
||||
x -= 1;
|
||||
|
||||
loop {
|
||||
if y == 0 { break; "unreachable"; }
|
||||
y -= 1;
|
||||
|
||||
loop {
|
||||
if z == 0 { break; "unreachable"; }
|
||||
z -= 1;
|
||||
}
|
||||
|
||||
if x > 10 {
|
||||
return;
|
||||
"unreachable";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
123
src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot
Normal file
123
src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot
Normal file
@ -0,0 +1,123 @@
|
||||
digraph block {
|
||||
N0[label="entry"];
|
||||
N1[label="exit"];
|
||||
N2[label="expr 25"];
|
||||
N3[label="local mut x"];
|
||||
N4[label="expr 25"];
|
||||
N5[label="local mut y"];
|
||||
N6[label="expr 25"];
|
||||
N7[label="local mut z"];
|
||||
N8[label="(dummy_node)"];
|
||||
N9[label="expr \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l"];
|
||||
N10[label="expr x"];
|
||||
N11[label="expr 0"];
|
||||
N12[label="expr x == 0"];
|
||||
N13[label="expr break"];
|
||||
N14[label="(dummy_node)"];
|
||||
N15[label="expr \"unreachable\""];
|
||||
N16[label="block { break ; \"unreachable\"; }"];
|
||||
N17[label="expr if x == 0 { break ; \"unreachable\"; }"];
|
||||
N18[label="expr 1"];
|
||||
N19[label="expr x"];
|
||||
N20[label="expr x -= 1"];
|
||||
N21[label="(dummy_node)"];
|
||||
N22[label="expr \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l"];
|
||||
N23[label="expr y"];
|
||||
N24[label="expr 0"];
|
||||
N25[label="expr y == 0"];
|
||||
N26[label="expr break"];
|
||||
N27[label="(dummy_node)"];
|
||||
N28[label="expr \"unreachable\""];
|
||||
N29[label="block { break ; \"unreachable\"; }"];
|
||||
N30[label="expr if y == 0 { break ; \"unreachable\"; }"];
|
||||
N31[label="expr 1"];
|
||||
N32[label="expr y"];
|
||||
N33[label="expr y -= 1"];
|
||||
N34[label="(dummy_node)"];
|
||||
N35[label="expr \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"];
|
||||
N36[label="expr z"];
|
||||
N37[label="expr 0"];
|
||||
N38[label="expr z == 0"];
|
||||
N39[label="expr break"];
|
||||
N40[label="(dummy_node)"];
|
||||
N41[label="expr \"unreachable\""];
|
||||
N42[label="block { break ; \"unreachable\"; }"];
|
||||
N43[label="expr if z == 0 { break ; \"unreachable\"; }"];
|
||||
N44[label="expr 1"];
|
||||
N45[label="expr z"];
|
||||
N46[label="expr z -= 1"];
|
||||
N47[label="block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"];
|
||||
N48[label="expr x"];
|
||||
N49[label="expr 10"];
|
||||
N50[label="expr x > 10"];
|
||||
N51[label="expr continue \'a"];
|
||||
N52[label="(dummy_node)"];
|
||||
N53[label="expr \"unreachable\""];
|
||||
N54[label="block { continue \'a ; \"unreachable\"; }"];
|
||||
N55[label="expr if x > 10 { continue \'a ; \"unreachable\"; }"];
|
||||
N56[label="block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l}\l"];
|
||||
N57[label="block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l}\l"];
|
||||
N58[label="block {\l let mut x = 25;\l let mut y = 25;\l let mut z = 25;\l \'a:\l loop {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l }\l}\l"];
|
||||
N0 -> N2;
|
||||
N2 -> N3;
|
||||
N3 -> N4;
|
||||
N4 -> N5;
|
||||
N5 -> N6;
|
||||
N6 -> N7;
|
||||
N7 -> N8;
|
||||
N8 -> N10;
|
||||
N10 -> N11;
|
||||
N11 -> N12;
|
||||
N12 -> N13;
|
||||
N13 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0 { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0 { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 0 { break ; \"unreachable\"; }\l x -= 1;\l \'a:\l loop {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l }\l}\l"];
|
||||
N14 -> N15;
|
||||
N15 -> N16;
|
||||
N12 -> N17;
|
||||
N16 -> N17;
|
||||
N17 -> N18;
|
||||
N18 -> N19;
|
||||
N19 -> N20;
|
||||
N20 -> N21;
|
||||
N21 -> N23;
|
||||
N23 -> N24;
|
||||
N24 -> N25;
|
||||
N25 -> N26;
|
||||
N26 -> N22[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0 { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0 { break ; \"unreachable\"; },\lexiting scope_5 block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l}\l"];
|
||||
N27 -> N28;
|
||||
N28 -> N29;
|
||||
N25 -> N30;
|
||||
N29 -> N30;
|
||||
N30 -> N31;
|
||||
N31 -> N32;
|
||||
N32 -> N33;
|
||||
N33 -> N34;
|
||||
N34 -> N36;
|
||||
N36 -> N37;
|
||||
N37 -> N38;
|
||||
N38 -> N39;
|
||||
N39 -> N35[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0 { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0 { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"];
|
||||
N40 -> N41;
|
||||
N41 -> N42;
|
||||
N38 -> N43;
|
||||
N42 -> N43;
|
||||
N43 -> N44;
|
||||
N44 -> N45;
|
||||
N45 -> N46;
|
||||
N46 -> N47;
|
||||
N47 -> N34;
|
||||
N35 -> N48;
|
||||
N48 -> N49;
|
||||
N49 -> N50;
|
||||
N50 -> N51;
|
||||
N51 -> N21[label="exiting scope_0 expr continue \'a,\lexiting scope_1 stmt continue \'a ;,\lexiting scope_2 block { continue \'a ; \"unreachable\"; },\lexiting scope_3 expr if x > 10 { continue \'a ; \"unreachable\"; },\lexiting scope_4 block {\l if y == 0 { break ; \"unreachable\"; }\l y -= 1;\l \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }\l if x > 10 { continue \'a ; \"unreachable\"; }\l}\l"];
|
||||
N52 -> N53;
|
||||
N53 -> N54;
|
||||
N50 -> N55;
|
||||
N54 -> N55;
|
||||
N55 -> N56;
|
||||
N56 -> N21;
|
||||
N22 -> N57;
|
||||
N57 -> N8;
|
||||
N9 -> N58;
|
||||
N58 -> N1;
|
||||
}
|
36
src/test/run-make/graphviz-flowgraph/f25.rs
Normal file
36
src/test/run-make/graphviz-flowgraph/f25.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
pub fn expr_while_25() {
|
||||
let mut x = 25;
|
||||
let mut y = 25;
|
||||
let mut z = 25;
|
||||
|
||||
'a: loop {
|
||||
if x == 0 { break; "unreachable"; }
|
||||
x -= 1;
|
||||
|
||||
'a: loop {
|
||||
if y == 0 { break; "unreachable"; }
|
||||
y -= 1;
|
||||
|
||||
'a: loop {
|
||||
if z == 0 { break; "unreachable"; }
|
||||
z -= 1;
|
||||
}
|
||||
|
||||
if x > 10 {
|
||||
continue 'a;
|
||||
"unreachable";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
src/test/run-pass/loop-no-reinit-needed-post-bot.rs
Normal file
41
src/test/run-pass/loop-no-reinit-needed-post-bot.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct S;
|
||||
// Ensure S is moved, not copied, on assignment.
|
||||
impl Drop for S { fn drop(&mut self) { } }
|
||||
|
||||
// user-defined function "returning" bottom (i.e. no return at all).
|
||||
fn my_fail() -> ! { loop {} }
|
||||
|
||||
pub fn step(f: bool) {
|
||||
let mut g = S;
|
||||
let mut i = 0;
|
||||
loop
|
||||
{
|
||||
if i > 10 { break; } else { i += 1; }
|
||||
|
||||
let _g = g;
|
||||
|
||||
if f {
|
||||
// re-initialize g, but only before restarting loop.
|
||||
g = S;
|
||||
continue;
|
||||
}
|
||||
|
||||
my_fail();
|
||||
|
||||
// we never get here, so we do not need to re-initialize g.
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
step(true);
|
||||
}
|
30
src/test/run-pass/struct-partial-move-1.rs
Normal file
30
src/test/run-pass/struct-partial-move-1.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[deriving(PartialEq, Show)]
|
||||
struct Partial<T> { x: T, y: T }
|
||||
|
||||
#[deriving(PartialEq, Show)]
|
||||
struct S { val: int }
|
||||
impl S { fn new(v: int) -> S { S { val: v } } }
|
||||
impl Drop for S { fn drop(&mut self) { } }
|
||||
|
||||
pub fn f<T>((b1, b2): (T, T), f: |T| -> T) -> Partial<T> {
|
||||
let p = Partial { x: b1, y: b2 };
|
||||
|
||||
// Move of `p` is legal even though we are also moving `p.y`; the
|
||||
// `..p` moves all fields *except* `p.y` in this context.
|
||||
Partial { y: f(p.y), ..p }
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let p = f((S::new(3), S::new(4)), |S { val: z }| S::new(z+1));
|
||||
assert_eq!(p, Partial { x: S::new(3), y: S::new(5) });
|
||||
}
|
37
src/test/run-pass/struct-partial-move-2.rs
Normal file
37
src/test/run-pass/struct-partial-move-2.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[deriving(PartialEq, Show)]
|
||||
struct Partial<T> { x: T, y: T }
|
||||
|
||||
#[deriving(PartialEq, Show)]
|
||||
struct S { val: int }
|
||||
impl S { fn new(v: int) -> S { S { val: v } } }
|
||||
impl Drop for S { fn drop(&mut self) { } }
|
||||
|
||||
type Two<T> = (Partial<T>, Partial<T>);
|
||||
|
||||
pub fn f<T>((b1, b2): (T, T), (b3, b4): (T, T), f: |T| -> T) -> Two<T> {
|
||||
let p = Partial { x: b1, y: b2 };
|
||||
let q = Partial { x: b3, y: b4 };
|
||||
|
||||
// Move of `q` is legal even though we have already moved `q.y`;
|
||||
// the `..q` moves all fields *except* `q.y` in this context.
|
||||
// Likewise, the move of `p.x` is legal for similar reasons.
|
||||
(Partial { x: f(q.y), ..p }, Partial { y: f(p.x), ..q })
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let two = f((S::new(1), S::new(3)),
|
||||
(S::new(5), S::new(7)),
|
||||
|S { val: z }| S::new(z+1));
|
||||
assert_eq!(two, (Partial { x: S::new(8), y: S::new(3) },
|
||||
Partial { x: S::new(5), y: S::new(2) }));
|
||||
}
|
Loading…
Reference in New Issue
Block a user