Auto merge of #40224 - nikomatsakis:issue-39808, r=eddyb

change the strategy for diverging types

The new strategy is as follows. First, the `!` type is assigned
in two cases:

- a block with a diverging statement and no tail expression (e.g.,
  `{return;}`);
- any expression with the type `!` is considered diverging.

Second, we track when we are in a diverging state, and we permit a value
of any type to be coerced **into** `!` if the expression that produced
it is diverging. This means that `fn foo() -> ! { panic!(); 22 }`
type-checks, even though the block has a type of `usize`.

Finally, coercions **from** the `!` type to any other are always
permitted.

Fixes #39808.
Fixes #39984.
This commit is contained in:
bors 2017-03-30 14:20:20 +00:00
commit 7ae95e5489
146 changed files with 2436 additions and 2595 deletions

View File

@ -74,11 +74,11 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
fn block(&mut self, blk: &hir::Block, pred: CFGIndex) -> CFGIndex {
if let Some(break_to_expr_id) = blk.break_to_expr_id {
if blk.targeted_by_break {
let expr_exit = self.add_ast_node(blk.id, &[]);
self.breakable_block_scopes.push(BlockScope {
block_expr_id: break_to_expr_id,
block_expr_id: blk.id,
break_index: expr_exit,
});
@ -195,7 +195,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
// [..expr..]
//
let cond_exit = self.expr(&cond, pred); // 1
let then_exit = self.block(&then, cond_exit); // 2
let then_exit = self.expr(&then, cond_exit); // 2
self.add_ast_node(expr.id, &[cond_exit, then_exit]) // 3,4
}
@ -215,7 +215,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
// [..expr..]
//
let cond_exit = self.expr(&cond, pred); // 1
let then_exit = self.block(&then, cond_exit); // 2
let then_exit = self.expr(&then, cond_exit); // 2
let else_exit = self.expr(&otherwise, cond_exit); // 3
self.add_ast_node(expr.id, &[then_exit, else_exit]) // 4, 5
}

View File

@ -960,7 +960,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
}
ExprIf(ref head_expression, ref if_block, ref optional_else) => {
visitor.visit_expr(head_expression);
visitor.visit_block(if_block);
visitor.visit_expr(if_block);
walk_list!(visitor, visit_expr, optional_else);
}
ExprWhile(ref subexpression, ref block, ref opt_sp_name) => {

View File

@ -1156,7 +1156,7 @@ impl<'a> LoweringContext<'a> {
bounds.iter().map(|bound| self.lower_ty_param_bound(bound)).collect()
}
fn lower_block(&mut self, b: &Block, break_to: Option<NodeId>) -> P<hir::Block> {
fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P<hir::Block> {
let mut expr = None;
let mut stmts = vec![];
@ -1179,7 +1179,7 @@ impl<'a> LoweringContext<'a> {
expr: expr,
rules: self.lower_block_check_mode(&b.rules),
span: b.span,
break_to_expr_id: break_to,
targeted_by_break: targeted_by_break,
})
}
@ -1274,7 +1274,7 @@ impl<'a> LoweringContext<'a> {
}
ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
self.with_new_scopes(|this| {
let body = this.lower_block(body, None);
let body = this.lower_block(body, false);
let body = this.expr_block(body, ThinVec::new());
let body_id = this.record_body(body, Some(decl));
hir::ItemFn(this.lower_fn_decl(decl),
@ -1368,7 +1368,7 @@ impl<'a> LoweringContext<'a> {
hir::TraitMethod::Required(names))
}
TraitItemKind::Method(ref sig, Some(ref body)) => {
let body = this.lower_block(body, None);
let body = this.lower_block(body, false);
let expr = this.expr_block(body, ThinVec::new());
let body_id = this.record_body(expr, Some(&sig.decl));
hir::TraitItemKind::Method(this.lower_method_sig(sig),
@ -1424,7 +1424,7 @@ impl<'a> LoweringContext<'a> {
hir::ImplItemKind::Const(this.lower_ty(ty), body_id)
}
ImplItemKind::Method(ref sig, ref body) => {
let body = this.lower_block(body, None);
let body = this.lower_block(body, false);
let expr = this.expr_block(body, ThinVec::new());
let body_id = this.record_body(expr, Some(&sig.decl));
hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id)
@ -1848,7 +1848,7 @@ impl<'a> LoweringContext<'a> {
id: id,
rules: hir::DefaultBlock,
span: span,
break_to_expr_id: None,
targeted_by_break: false,
});
P(self.expr_block(blk, ThinVec::new()))
}
@ -1856,24 +1856,27 @@ impl<'a> LoweringContext<'a> {
}
});
hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk, None), else_opt)
let then_blk = self.lower_block(blk, false);
let then_expr = self.expr_block(then_blk, ThinVec::new());
hir::ExprIf(P(self.lower_expr(cond)), P(then_expr), else_opt)
}
ExprKind::While(ref cond, ref body, opt_ident) => {
self.with_loop_scope(e.id, |this|
hir::ExprWhile(
this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
this.lower_block(body, None),
this.lower_block(body, false),
this.lower_opt_sp_ident(opt_ident)))
}
ExprKind::Loop(ref body, opt_ident) => {
self.with_loop_scope(e.id, |this|
hir::ExprLoop(this.lower_block(body, None),
hir::ExprLoop(this.lower_block(body, false),
this.lower_opt_sp_ident(opt_ident),
hir::LoopSource::Loop))
}
ExprKind::Catch(ref body) => {
self.with_catch_scope(e.id, |this|
hir::ExprBlock(this.lower_block(body, Some(e.id))))
self.with_catch_scope(body.id, |this|
hir::ExprBlock(this.lower_block(body, true)))
}
ExprKind::Match(ref expr, ref arms) => {
hir::ExprMatch(P(self.lower_expr(expr)),
@ -1891,7 +1894,7 @@ impl<'a> LoweringContext<'a> {
})
})
}
ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, None)),
ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, false)),
ExprKind::Assign(ref el, ref er) => {
hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er)))
}
@ -2037,7 +2040,7 @@ impl<'a> LoweringContext<'a> {
// `<pat> => <body>`
{
let body = self.lower_block(body, None);
let body = self.lower_block(body, false);
let body_expr = P(self.expr_block(body, ThinVec::new()));
let pat = self.lower_pat(pat);
arms.push(self.arm(hir_vec![pat], body_expr));
@ -2109,7 +2112,7 @@ impl<'a> LoweringContext<'a> {
let (guard, body) = if let ExprKind::If(ref cond,
ref then,
_) = else_expr.node {
let then = self.lower_block(then, None);
let then = self.lower_block(then, false);
(Some(cond),
self.expr_block(then, ThinVec::new()))
} else {
@ -2159,7 +2162,7 @@ impl<'a> LoweringContext<'a> {
// Note that the block AND the condition are evaluated in the loop scope.
// This is done to allow `break` from inside the condition of the loop.
let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| (
this.lower_block(body, None),
this.lower_block(body, false),
this.expr_break(e.span, ThinVec::new()),
this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
));
@ -2220,7 +2223,7 @@ impl<'a> LoweringContext<'a> {
// `::std::option::Option::Some(<pat>) => <body>`
let pat_arm = {
let body_block = self.with_loop_scope(e.id,
|this| this.lower_block(body, None));
|this| this.lower_block(body, false));
let body_expr = P(self.expr_block(body_block, ThinVec::new()));
let pat = self.lower_pat(pat);
let some_pat = self.pat_some(e.span, pat);
@ -2652,7 +2655,7 @@ impl<'a> LoweringContext<'a> {
id: self.next_id(),
rules: hir::DefaultBlock,
span: span,
break_to_expr_id: None,
targeted_by_break: false,
}
}
@ -2760,7 +2763,7 @@ impl<'a> LoweringContext<'a> {
id: id,
stmts: stmts,
expr: Some(expr),
break_to_expr_id: None,
targeted_by_break: false,
});
self.expr_block(block, attrs)
}

View File

@ -549,9 +549,11 @@ pub struct Block {
/// Distinguishes between `unsafe { ... }` and `{ ... }`
pub rules: BlockCheckMode,
pub span: Span,
/// The id of the expression that `break` breaks to if the block can be broken out of.
/// Currently only `Some(_)` for `catch {}` blocks
pub break_to_expr_id: Option<NodeId>,
/// If true, then there may exist `break 'a` values that aim to
/// break out of this block early. As of this writing, this is not
/// currently permitted in Rust itself, but it is generated as
/// part of `catch` statements.
pub targeted_by_break: bool,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
@ -993,8 +995,8 @@ pub enum Expr_ {
ExprType(P<Expr>, P<Ty>),
/// An `if` block, with an optional else block
///
/// `if expr { block } else { expr }`
ExprIf(P<Expr>, P<Block>, Option<P<Expr>>),
/// `if expr { expr } else { expr }`
ExprIf(P<Expr>, P<Expr>, Option<P<Expr>>),
/// A while loop, with an optional label
///
/// `'label: while expr { block }`

View File

@ -1036,7 +1036,7 @@ impl<'a> State<'a> {
word(&mut self.s, " else if ")?;
self.print_expr(&i)?;
space(&mut self.s)?;
self.print_block(&then)?;
self.print_expr(&then)?;
self.print_else(e.as_ref().map(|e| &**e))
}
// "final else"
@ -1058,13 +1058,13 @@ impl<'a> State<'a> {
pub fn print_if(&mut self,
test: &hir::Expr,
blk: &hir::Block,
blk: &hir::Expr,
elseopt: Option<&hir::Expr>)
-> io::Result<()> {
self.head("if")?;
self.print_expr(test)?;
space(&mut self.s)?;
self.print_block(blk)?;
self.print_expr(blk)?;
self.print_else(elseopt)
}

View File

@ -30,6 +30,7 @@ pub struct TypeVariableTable<'tcx> {
}
/// Reasons to create a type inference variable
#[derive(Debug)]
pub enum TypeVariableOrigin {
MiscVariable(Span),
NormalizeProjectionType(Span),
@ -41,6 +42,7 @@ pub enum TypeVariableOrigin {
AdjustmentType(Span),
DivergingStmt(Span),
DivergingBlockExpr(Span),
DivergingFn(Span),
LatticeVariable(Span),
}
@ -196,6 +198,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
diverging: bool,
origin: TypeVariableOrigin,
default: Option<Default<'tcx>>,) -> ty::TyVid {
debug!("new_var(diverging={:?}, origin={:?})", diverging, origin);
self.eq_relations.new_key(());
let index = self.values.push(TypeVariableData {
value: Bounded { relations: vec![], default: default },
@ -203,7 +206,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
diverging: diverging
});
let v = ty::TyVid { index: index as u32 };
debug!("new_var() -> {:?}", v);
debug!("new_var: diverging={:?} index={:?}", diverging, v);
v
}

View File

@ -414,9 +414,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
self.consume_exprs(exprs);
}
hir::ExprIf(ref cond_expr, ref then_blk, ref opt_else_expr) => {
hir::ExprIf(ref cond_expr, ref then_expr, ref opt_else_expr) => {
self.consume_expr(&cond_expr);
self.walk_block(&then_blk);
self.walk_expr(&then_expr);
if let Some(ref else_expr) = *opt_else_expr {
self.consume_expr(&else_expr);
}

View File

@ -821,8 +821,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode)
-> LiveNode {
if let Some(break_to_expr_id) = blk.break_to_expr_id {
self.breakable_block_ln.insert(break_to_expr_id, succ);
if blk.targeted_by_break {
self.breakable_block_ln.insert(blk.id, succ);
}
let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ);
blk.stmts.iter().rev().fold(succ, |succ, stmt| {
@ -951,7 +951,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// ( succ )
//
let else_ln = self.propagate_through_opt_expr(els.as_ref().map(|e| &**e), succ);
let then_ln = self.propagate_through_block(&then, succ);
let then_ln = self.propagate_through_expr(&then, succ);
let ln = self.live_node(expr.id, expr.span);
self.init_from_succ(ln, else_ln);
self.merge_from_succ(ln, then_ln, false);

View File

@ -904,6 +904,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ObligationCauseCode::StartFunctionType |
ObligationCauseCode::IntrinsicType |
ObligationCauseCode::MethodReceiver |
ObligationCauseCode::ReturnNoExpression |
ObligationCauseCode::MiscObligation => {
}
ObligationCauseCode::SliceOrArrayElem => {

View File

@ -173,6 +173,9 @@ pub enum ObligationCauseCode<'tcx> {
// method receiver
MethodReceiver,
// `return` with no expression
ReturnNoExpression,
}
#[derive(Clone, Debug, PartialEq, Eq)]

View File

@ -167,6 +167,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
type Lifted = traits::ObligationCauseCode<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
match *self {
super::ReturnNoExpression => Some(super::ReturnNoExpression),
super::MiscObligation => Some(super::MiscObligation),
super::SliceOrArrayElem => Some(super::SliceOrArrayElem),
super::TupleElem => Some(super::TupleElem),
@ -489,6 +490,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
super::StructInitializerSized |
super::VariableType(_) |
super::ReturnType |
super::ReturnNoExpression |
super::RepeatVec |
super::FieldSized |
super::ConstSized |
@ -533,6 +535,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
super::StructInitializerSized |
super::VariableType(_) |
super::ReturnType |
super::ReturnNoExpression |
super::RepeatVec |
super::FieldSized |
super::ConstSized |

View File

@ -12,90 +12,116 @@ use build::{BlockAnd, BlockAndExtension, Builder};
use hair::*;
use rustc::mir::*;
use rustc::hir;
use syntax_pos::Span;
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
pub fn ast_block(&mut self,
destination: &Lvalue<'tcx>,
mut block: BasicBlock,
ast_block: &'tcx hir::Block)
block: BasicBlock,
ast_block: &'tcx hir::Block,
source_info: SourceInfo)
-> BlockAnd<()> {
let Block { extent, span, stmts, expr } = self.hir.mirror(ast_block);
let Block { extent, span, stmts, expr, targeted_by_break } = self.hir.mirror(ast_block);
self.in_scope(extent, block, move |this| {
// This convoluted structure is to avoid using recursion as we walk down a list
// of statements. Basically, the structure we get back is something like:
//
// let x = <init> in {
// expr1;
// let y = <init> in {
// expr2;
// expr3;
// ...
// }
// }
//
// The let bindings are valid till the end of block so all we have to do is to pop all
// the let-scopes at the end.
//
// First we build all the statements in the block.
let mut let_extent_stack = Vec::with_capacity(8);
let outer_visibility_scope = this.visibility_scope;
for stmt in stmts {
let Stmt { span: _, kind } = this.hir.mirror(stmt);
match kind {
StmtKind::Expr { scope, expr } => {
unpack!(block = this.in_scope(scope, block, |this| {
let expr = this.hir.mirror(expr);
this.stmt_expr(block, expr)
if targeted_by_break {
// This is a `break`-able block (currently only `catch { ... }`)
let exit_block = this.cfg.start_new_block();
let block_exit = this.in_breakable_scope(None, exit_block,
destination.clone(), |this| {
this.ast_block_stmts(destination, block, span, stmts, expr)
});
this.cfg.terminate(unpack!(block_exit), source_info,
TerminatorKind::Goto { target: exit_block });
exit_block.unit()
} else {
this.ast_block_stmts(destination, block, span, stmts, expr)
}
})
}
fn ast_block_stmts(&mut self,
destination: &Lvalue<'tcx>,
mut block: BasicBlock,
span: Span,
stmts: Vec<StmtRef<'tcx>>,
expr: Option<ExprRef<'tcx>>)
-> BlockAnd<()> {
let this = self;
// This convoluted structure is to avoid using recursion as we walk down a list
// of statements. Basically, the structure we get back is something like:
//
// let x = <init> in {
// expr1;
// let y = <init> in {
// expr2;
// expr3;
// ...
// }
// }
//
// The let bindings are valid till the end of block so all we have to do is to pop all
// the let-scopes at the end.
//
// First we build all the statements in the block.
let mut let_extent_stack = Vec::with_capacity(8);
let outer_visibility_scope = this.visibility_scope;
for stmt in stmts {
let Stmt { span: _, kind } = this.hir.mirror(stmt);
match kind {
StmtKind::Expr { scope, expr } => {
unpack!(block = this.in_scope(scope, block, |this| {
let expr = this.hir.mirror(expr);
this.stmt_expr(block, expr)
}));
}
StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
let tcx = this.hir.tcx();
// Enter the remainder scope, i.e. the bindings' destruction scope.
this.push_scope(remainder_scope);
let_extent_stack.push(remainder_scope);
// Declare the bindings, which may create a visibility scope.
let remainder_span = remainder_scope.span(&tcx.region_maps, &tcx.hir);
let remainder_span = remainder_span.unwrap_or(span);
let scope = this.declare_bindings(None, remainder_span, &pattern);
// Evaluate the initializer, if present.
if let Some(init) = initializer {
unpack!(block = this.in_scope(init_scope, block, move |this| {
// FIXME #30046 ^~~~
this.expr_into_pattern(block, pattern, init)
}));
} else {
this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
this.storage_live_binding(block, node, span);
this.schedule_drop_for_binding(node, span);
})
}
StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
let tcx = this.hir.tcx();
// Enter the remainder scope, i.e. the bindings' destruction scope.
this.push_scope(remainder_scope);
let_extent_stack.push(remainder_scope);
// Declare the bindings, which may create a visibility scope.
let remainder_span = remainder_scope.span(&tcx.region_maps, &tcx.hir);
let remainder_span = remainder_span.unwrap_or(span);
let scope = this.declare_bindings(None, remainder_span, &pattern);
// Evaluate the initializer, if present.
if let Some(init) = initializer {
unpack!(block = this.in_scope(init_scope, block, move |this| {
// FIXME #30046 ^~~~
this.expr_into_pattern(block, pattern, init)
}));
} else {
this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| {
this.storage_live_binding(block, node, span);
this.schedule_drop_for_binding(node, span);
})
}
// Enter the visibility scope, after evaluating the initializer.
if let Some(visibility_scope) = scope {
this.visibility_scope = visibility_scope;
}
// Enter the visibility scope, after evaluating the initializer.
if let Some(visibility_scope) = scope {
this.visibility_scope = visibility_scope;
}
}
}
// Then, the block may have an optional trailing expression which is a “return” value
// of the block.
if let Some(expr) = expr {
unpack!(block = this.into(destination, block, expr));
} else {
let source_info = this.source_info(span);
this.cfg.push_assign_unit(block, source_info, destination);
}
// Finally, we pop all the let scopes before exiting out from the scope of block
// itself.
for extent in let_extent_stack.into_iter().rev() {
unpack!(block = this.pop_scope(extent, block));
}
// Restore the original visibility scope.
this.visibility_scope = outer_visibility_scope;
block.unit()
})
}
// Then, the block may have an optional trailing expression which is a “return” value
// of the block.
if let Some(expr) = expr {
unpack!(block = this.into(destination, block, expr));
} else {
let source_info = this.source_info(span);
this.cfg.push_assign_unit(block, source_info, destination);
}
// Finally, we pop all the let scopes before exiting out from the scope of block
// itself.
for extent in let_extent_stack.into_iter().rev() {
unpack!(block = this.pop_scope(extent, block));
}
// Restore the original visibility scope.
this.visibility_scope = outer_visibility_scope;
block.unit()
}
}

View File

@ -40,19 +40,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
this.in_scope(extent, block, |this| this.into(destination, block, value))
}
ExprKind::Block { body: ast_block } => {
if let Some(_) = ast_block.break_to_expr_id {
// This is a `break`-able block (currently only `catch { ... }`)
let exit_block = this.cfg.start_new_block();
let block_exit = this.in_breakable_scope(None, exit_block,
destination.clone(), |this| {
this.ast_block(destination, block, ast_block)
});
this.cfg.terminate(unpack!(block_exit), source_info,
TerminatorKind::Goto { target: exit_block });
exit_block.unit()
} else {
this.ast_block(destination, block, ast_block)
}
this.ast_block(destination, block, ast_block, source_info)
}
ExprKind::Match { discriminant, arms } => {
this.match_expr(destination, expr_span, block, discriminant, arms)

View File

@ -23,6 +23,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
// in order to get the lexical scoping correctly.
let stmts = mirror_stmts(cx, self.id, &*self.stmts);
Block {
targeted_by_break: self.targeted_by_break,
extent: cx.tcx.region_maps.node_extent(self.id),
span: self.span,
stmts: stmts,

View File

@ -636,7 +636,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
hir::ExprIf(ref cond, ref then, ref otherwise) => {
ExprKind::If {
condition: cond.to_ref(),
then: block::to_expr_ref(cx, then),
then: then.to_ref(),
otherwise: otherwise.to_ref(),
}
}

View File

@ -31,6 +31,7 @@ pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPatt
#[derive(Clone, Debug)]
pub struct Block<'tcx> {
pub targeted_by_break: bool,
pub extent: CodeExtent,
pub span: Span,
pub stmts: Vec<StmtRef<'tcx>>,

View File

@ -369,7 +369,7 @@ impl FnType {
match sig.inputs().last().unwrap().sty {
ty::TyTuple(ref tupled_arguments, _) => {
inputs = &sig.inputs()[0..sig.inputs().len() - 1];
&tupled_arguments
tupled_arguments
}
_ => {
bug!("argument to function with \"rust-call\" ABI \

View File

@ -16,6 +16,7 @@ use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::traits::ObligationCauseCode;
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
use check::{FnCtxt, Expectation, Diverges};
use check::coercion::CoerceMany;
use util::nodemap::FxHashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
@ -414,6 +415,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span));
self.check_expr_has_type(discrim, discrim_ty);
};
// If the discriminant diverges, the match is pointless (e.g.,
// `match (return) { }`).
self.warn_if_unreachable(expr.id, expr.span, "expression");
// If there are no arms, that is a diverging match; a special case.
if arms.is_empty() {
self.diverges.set(self.diverges.get() | Diverges::Always);
return tcx.types.never;
}
// Otherwise, we have to union together the types that the
// arms produce and so forth.
let discrim_diverges = self.diverges.get();
self.diverges.set(Diverges::Maybe);
@ -426,6 +441,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.check_pat(&p, discrim_ty);
all_pats_diverge &= self.diverges.get();
}
// As discussed with @eddyb, this is for disabling unreachable_code
// warnings on patterns (they're now subsumed by unreachable_patterns
// warnings).
@ -444,20 +460,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// on any empty type and is therefore unreachable; should the flow
// of execution reach it, we will panic, so bottom is an appropriate
// type in that case)
let expected = expected.adjust_for_branches(self);
let mut result_ty = self.next_diverging_ty_var(
TypeVariableOrigin::DivergingBlockExpr(expr.span));
let mut all_arms_diverge = Diverges::WarnedAlways;
let coerce_first = match expected {
// We don't coerce to `()` so that if the match expression is a
// statement it's branches can have any consistent type. That allows
// us to give better error messages (pointing to a usually better
// arm for inconsistent arms or to the whole match when a `()` type
// is required).
Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => {
ety
}
_ => result_ty
let expected = expected.adjust_for_branches(self);
let mut coercion = {
let coerce_first = match expected {
// We don't coerce to `()` so that if the match expression is a
// statement it's branches can have any consistent type. That allows
// us to give better error messages (pointing to a usually better
// arm for inconsistent arms or to the whole match when a `()` type
// is required).
Expectation::ExpectHasType(ety) if ety != self.tcx.mk_nil() => ety,
_ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)),
};
CoerceMany::with_coercion_sites(coerce_first, arms)
};
for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() {
@ -470,11 +487,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
all_arms_diverge &= self.diverges.get();
if result_ty.references_error() || arm_ty.references_error() {
result_ty = tcx.types.err;
continue;
}
// Handle the fallback arm of a desugared if-let like a missing else.
let is_if_let_fallback = match match_src {
hir::MatchSource::IfLetDesugar { contains_else_clause: false } => {
@ -483,47 +495,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
_ => false
};
let cause = if is_if_let_fallback {
self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse)
if is_if_let_fallback {
let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse);
assert!(arm_ty.is_nil());
coercion.coerce_forced_unit(self, &cause, &mut |_| ());
} else {
self.cause(expr.span, ObligationCauseCode::MatchExpressionArm {
let cause = self.cause(expr.span, ObligationCauseCode::MatchExpressionArm {
arm_span: arm.body.span,
source: match_src
})
};
let result = if is_if_let_fallback {
self.eq_types(true, &cause, arm_ty, result_ty)
.map(|infer_ok| {
self.register_infer_ok_obligations(infer_ok);
arm_ty
})
} else if i == 0 {
// Special-case the first arm, as it has no "previous expressions".
self.try_coerce(&arm.body, arm_ty, coerce_first)
} else {
let prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
self.try_find_coercion_lub(&cause, prev_arms, result_ty, &arm.body, arm_ty)
};
result_ty = match result {
Ok(ty) => ty,
Err(e) => {
let (expected, found) = if is_if_let_fallback {
(arm_ty, result_ty)
} else {
(result_ty, arm_ty)
};
self.report_mismatched_types(&cause, expected, found, e).emit();
self.tcx.types.err
}
};
});
coercion.coerce(self, &cause, &arm.body, arm_ty, self.diverges.get());
}
}
// We won't diverge unless the discriminant or all arms diverge.
self.diverges.set(discrim_diverges | all_arms_diverge);
result_ty
coercion.complete(self)
}
fn check_pat_struct(&self,

View File

@ -12,6 +12,7 @@ use astconv::AstConv;
use super::FnCtxt;
use check::coercion::AsCoercionSite;
use rustc::infer::InferOk;
use rustc::traits;
use rustc::ty::{self, Ty, TraitRef};
@ -148,16 +149,16 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
self.fcx.resolve_type_vars_if_possible(&self.cur_ty)
}
pub fn finalize<'b, I>(self, pref: LvaluePreference, exprs: I)
where I: IntoIterator<Item = &'b hir::Expr>
pub fn finalize<E>(self, pref: LvaluePreference, exprs: &[E])
where E: AsCoercionSite
{
let fcx = self.fcx;
fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, exprs));
}
pub fn finalize_as_infer_ok<'b, I>(self, pref: LvaluePreference, exprs: I)
-> InferOk<'tcx, ()>
where I: IntoIterator<Item = &'b hir::Expr>
pub fn finalize_as_infer_ok<E>(self, pref: LvaluePreference, exprs: &[E])
-> InferOk<'tcx, ()>
where E: AsCoercionSite
{
let methods: Vec<_> = self.steps
.iter()
@ -176,6 +177,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
self.obligations);
for expr in exprs {
let expr = expr.as_coercion_site();
debug!("finalize - finalizing #{} - {:?}", expr.id, expr);
for (n, method) in methods.iter().enumerate() {
if let &Some(method) = method {

View File

@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
})
.next();
let callee_ty = autoderef.unambiguous_final_ty();
autoderef.finalize(LvaluePreference::NoPreference, Some(callee_expr));
autoderef.finalize(LvaluePreference::NoPreference, &[callee_expr]);
let output = match result {
None => {

View File

@ -38,7 +38,7 @@
//! expression, `e as U2` is not necessarily so (in fact it will only be valid if
//! `U1` coerces to `U2`).
use super::FnCtxt;
use super::{Diverges, FnCtxt};
use lint;
use hir::def_id::DefId;
@ -56,6 +56,7 @@ use util::common::ErrorReported;
pub struct CastCheck<'tcx> {
expr: &'tcx hir::Expr,
expr_ty: Ty<'tcx>,
expr_diverges: Diverges,
cast_ty: Ty<'tcx>,
cast_span: Span,
span: Span,
@ -115,6 +116,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
pub fn new(fcx: &FnCtxt<'a, 'gcx, 'tcx>,
expr: &'tcx hir::Expr,
expr_ty: Ty<'tcx>,
expr_diverges: Diverges,
cast_ty: Ty<'tcx>,
cast_span: Span,
span: Span)
@ -122,6 +124,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
let check = CastCheck {
expr: expr,
expr_ty: expr_ty,
expr_diverges: expr_diverges,
cast_ty: cast_ty,
cast_span: cast_span,
span: span,
@ -376,7 +379,10 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
(None, Some(t_cast)) => {
if let ty::TyFnDef(.., f) = self.expr_ty.sty {
// Attempt a coercion to a fn pointer type.
let res = fcx.try_coerce(self.expr, self.expr_ty, fcx.tcx.mk_fn_ptr(f));
let res = fcx.try_coerce(self.expr,
self.expr_ty,
self.expr_diverges,
fcx.tcx.mk_fn_ptr(f));
if !res.is_ok() {
return Err(CastError::NonScalar);
}
@ -542,7 +548,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
}
fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok()
fcx.try_coerce(self.expr, self.expr_ty, self.expr_diverges, self.cast_ty).is_ok()
}
}

View File

@ -60,7 +60,7 @@
//! sort of a minor point so I've opted to leave it for later---after all
//! we may want to adjust precisely when coercions occur.
use check::FnCtxt;
use check::{Diverges, FnCtxt};
use rustc::hir;
use rustc::hir::def_id::DefId;
@ -74,8 +74,10 @@ use rustc::ty::fold::TypeFoldable;
use rustc::ty::error::TypeError;
use rustc::ty::relate::RelateResult;
use rustc::ty::subst::Subst;
use errors::DiagnosticBuilder;
use syntax::abi;
use syntax::feature_gate;
use syntax::ptr::P;
use std::collections::VecDeque;
use std::ops::Deref;
@ -155,11 +157,13 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
})
}
fn coerce<'a, E, I>(&self, exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx>
where E: Fn() -> I,
I: IntoIterator<Item = &'a hir::Expr>
fn coerce<E>(&self,
exprs: &[E],
a: Ty<'tcx>,
b: Ty<'tcx>)
-> CoerceResult<'tcx>
where E: AsCoercionSite
{
let a = self.shallow_resolve(a);
debug!("Coerce.tys({:?} => {:?})", a, b);
@ -169,7 +173,23 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
}
if a.is_never() {
return success(Adjust::NeverToAny, b, vec![]);
// Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
// type variable, we want `?T` to fallback to `!` if not
// otherwise constrained. An example where this arises:
//
// let _: Option<?T> = Some({ return; });
//
// here, we would coerce from `!` to `?T`.
let b = self.shallow_resolve(b);
return if self.shallow_resolve(b).is_ty_var() {
// micro-optimization: no need for this if `b` is
// already resolved in some way.
let diverging_ty = self.next_diverging_ty_var(
TypeVariableOrigin::AdjustmentType(self.cause.span));
self.unify_and(&b, &diverging_ty, Adjust::NeverToAny)
} else {
success(Adjust::NeverToAny, b, vec![])
};
}
// Consider coercing the subtype to a DST
@ -223,15 +243,14 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
/// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
/// To match `A` with `B`, autoderef will be performed,
/// calling `deref`/`deref_mut` where necessary.
fn coerce_borrowed_pointer<'a, E, I>(&self,
exprs: &E,
a: Ty<'tcx>,
b: Ty<'tcx>,
r_b: &'tcx ty::Region,
mt_b: TypeAndMut<'tcx>)
-> CoerceResult<'tcx>
where E: Fn() -> I,
I: IntoIterator<Item = &'a hir::Expr>
fn coerce_borrowed_pointer<E>(&self,
exprs: &[E],
a: Ty<'tcx>,
b: Ty<'tcx>,
r_b: &'tcx ty::Region,
mt_b: TypeAndMut<'tcx>)
-> CoerceResult<'tcx>
where E: AsCoercionSite
{
debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b);
@ -408,7 +427,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
autoref);
let pref = LvaluePreference::from_mutbl(mt_b.mutbl);
obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs()).obligations);
obligations.extend(autoderef.finalize_as_infer_ok(pref, exprs).obligations);
success(Adjust::DerefRef {
autoderefs: autoderefs,
@ -675,47 +694,66 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn try_coerce(&self,
expr: &hir::Expr,
expr_ty: Ty<'tcx>,
expr_diverges: Diverges,
target: Ty<'tcx>)
-> RelateResult<'tcx, Ty<'tcx>> {
let source = self.resolve_type_vars_with_obligations(expr_ty);
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
// Special-ish case: we can coerce any type `T` into the `!`
// type, but only if the source expression diverges.
if target.is_never() && expr_diverges.always() {
debug!("permit coercion to `!` because expr diverges");
return Ok(target);
}
let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
let coerce = Coerce::new(self, cause);
self.commit_if_ok(|_| {
let ok = coerce.coerce(&|| Some(expr), source, target)?;
let ok = coerce.coerce(&[expr], source, target)?;
let adjustment = self.register_infer_ok_obligations(ok);
if !adjustment.is_identity() {
debug!("Success, coerced with {:?}", adjustment);
match self.tables.borrow().adjustments.get(&expr.id) {
None |
Some(&Adjustment { kind: Adjust::NeverToAny, .. }) => (),
_ => bug!("expr already has an adjustment on it!"),
};
if self.tables.borrow().adjustments.get(&expr.id).is_some() {
bug!("expr already has an adjustment on it!");
}
self.write_adjustment(expr.id, adjustment);
}
Ok(adjustment.target)
// We should now have added sufficient adjustments etc to
// ensure that the type of expression, post-adjustment, is
// a subtype of target.
Ok(target)
})
}
/// Given some expressions, their known unified type and another expression,
/// tries to unify the types, potentially inserting coercions on any of the
/// provided expressions and returns their LUB (aka "common supertype").
pub fn try_find_coercion_lub<'b, E, I>(&self,
cause: &ObligationCause<'tcx>,
exprs: E,
prev_ty: Ty<'tcx>,
new: &'b hir::Expr,
new_ty: Ty<'tcx>)
-> RelateResult<'tcx, Ty<'tcx>>
where E: Fn() -> I,
I: IntoIterator<Item = &'b hir::Expr>
///
/// This is really an internal helper. From outside the coercion
/// module, you should instantiate a `CoerceMany` instance.
fn try_find_coercion_lub<E>(&self,
cause: &ObligationCause<'tcx>,
exprs: &[E],
prev_ty: Ty<'tcx>,
new: &hir::Expr,
new_ty: Ty<'tcx>,
new_diverges: Diverges)
-> RelateResult<'tcx, Ty<'tcx>>
where E: AsCoercionSite
{
let prev_ty = self.resolve_type_vars_with_obligations(prev_ty);
let new_ty = self.resolve_type_vars_with_obligations(new_ty);
debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);
// Special-ish case: we can coerce any type `T` into the `!`
// type, but only if the source expression diverges.
if prev_ty.is_never() && new_diverges.always() {
debug!("permit coercion to `!` because expr diverges");
return Ok(prev_ty);
}
let trace = TypeTrace::types(cause, true, prev_ty, new_ty);
// Special-case that coercion alone cannot handle:
@ -741,7 +779,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Reify both sides and return the reified fn pointer type.
let fn_ptr = self.tcx.mk_fn_ptr(fty);
for expr in exprs().into_iter().chain(Some(new)) {
for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) {
// No adjustments can produce a fn item, so this should never trip.
assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
self.write_adjustment(expr.id, Adjustment {
@ -761,7 +799,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// but only if the new expression has no coercion already applied to it.
let mut first_error = None;
if !self.tables.borrow().adjustments.contains_key(&new.id) {
let result = self.commit_if_ok(|_| coerce.coerce(&|| Some(new), new_ty, prev_ty));
let result = self.commit_if_ok(|_| coerce.coerce(&[new], new_ty, prev_ty));
match result {
Ok(ok) => {
let adjustment = self.register_infer_ok_obligations(ok);
@ -777,7 +815,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Then try to coerce the previous expressions to the type of the new one.
// This requires ensuring there are no coercions applied to *any* of the
// previous expressions, other than noop reborrows (ignoring lifetimes).
for expr in exprs() {
for expr in exprs {
let expr = expr.as_coercion_site();
let noop = match self.tables.borrow().adjustments.get(&expr.id).map(|adj| adj.kind) {
Some(Adjust::DerefRef {
autoderefs: 1,
@ -821,7 +860,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let adjustment = self.register_infer_ok_obligations(ok);
if !adjustment.is_identity() {
let mut tables = self.tables.borrow_mut();
for expr in exprs() {
for expr in exprs {
let expr = expr.as_coercion_site();
if let Some(&mut Adjustment {
kind: Adjust::NeverToAny,
ref mut target
@ -837,3 +877,337 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}
}
/// CoerceMany encapsulates the pattern you should use when you have
/// many expressions that are all getting coerced to a common
/// type. This arises, for example, when you have a match (the result
/// of each arm is coerced to a common type). It also arises in less
/// obvious places, such as when you have many `break foo` expressions
/// that target the same loop, or the various `return` expressions in
/// a function.
///
/// The basic protocol is as follows:
///
/// - Instantiate the `CoerceMany` with an initial `expected_ty`.
/// This will also serve as the "starting LUB". The expectation is
/// that this type is something which all of the expressions *must*
/// be coercible to. Use a fresh type variable if needed.
/// - For each expression whose result is to be coerced, invoke `coerce()` with.
/// - In some cases we wish to coerce "non-expressions" whose types are implicitly
/// unit. This happens for example if you have a `break` with no expression,
/// or an `if` with no `else`. In that case, invoke `coerce_forced_unit()`.
/// - `coerce()` and `coerce_forced_unit()` may report errors. They hide this
/// from you so that you don't have to worry your pretty head about it.
/// But if an error is reported, the final type will be `err`.
/// - Invoking `coerce()` may cause us to go and adjust the "adjustments" on
/// previously coerced expressions.
/// - When all done, invoke `complete()`. This will return the LUB of
/// all your expressions.
/// - WARNING: I don't believe this final type is guaranteed to be
/// related to your initial `expected_ty` in any particular way,
/// although it will typically be a subtype, so you should check it.
/// - Invoking `complete()` may cause us to go and adjust the "adjustments" on
/// previously coerced expressions.
///
/// Example:
///
/// ```
/// let mut coerce = CoerceMany::new(expected_ty);
/// for expr in exprs {
/// let expr_ty = fcx.check_expr_with_expectation(expr, expected);
/// coerce.coerce(fcx, &cause, expr, expr_ty);
/// }
/// let final_ty = coerce.complete(fcx);
/// ```
pub struct CoerceMany<'gcx, 'tcx, 'exprs, E>
where 'gcx: 'tcx, E: 'exprs + AsCoercionSite,
{
expected_ty: Ty<'tcx>,
final_ty: Option<Ty<'tcx>>,
expressions: Expressions<'gcx, 'exprs, E>,
pushed: usize,
}
/// The type of a `CoerceMany` that is storing up the expressions into
/// a buffer. We use this in `check/mod.rs` for things like `break`.
pub type DynamicCoerceMany<'gcx, 'tcx> = CoerceMany<'gcx, 'tcx, 'gcx, P<hir::Expr>>;
enum Expressions<'gcx, 'exprs, E>
where E: 'exprs + AsCoercionSite,
{
Dynamic(Vec<&'gcx hir::Expr>),
UpFront(&'exprs [E]),
}
impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
where 'gcx: 'tcx, E: 'exprs + AsCoercionSite,
{
/// The usual case; collect the set of expressions dynamically.
/// If the full set of coercion sites is known before hand,
/// consider `with_coercion_sites()` instead to avoid allocation.
pub fn new(expected_ty: Ty<'tcx>) -> Self {
Self::make(expected_ty, Expressions::Dynamic(vec![]))
}
/// As an optimization, you can create a `CoerceMany` with a
/// pre-existing slice of expressions. In this case, you are
/// expected to pass each element in the slice to `coerce(...)` in
/// order. This is used with arrays in particular to avoid
/// needlessly cloning the slice.
pub fn with_coercion_sites(expected_ty: Ty<'tcx>,
coercion_sites: &'exprs [E])
-> Self {
Self::make(expected_ty, Expressions::UpFront(coercion_sites))
}
fn make(expected_ty: Ty<'tcx>, expressions: Expressions<'gcx, 'exprs, E>) -> Self {
CoerceMany {
expected_ty,
final_ty: None,
expressions,
pushed: 0,
}
}
pub fn is_empty(&self) -> bool {
self.pushed == 0
}
/// Return the "expected type" with which this coercion was
/// constructed. This represents the "downward propagated" type
/// that was given to us at the start of typing whatever construct
/// we are typing (e.g., the match expression).
///
/// Typically, this is used as the expected type when
/// type-checking each of the alternative expressions whose types
/// we are trying to merge.
pub fn expected_ty(&self) -> Ty<'tcx> {
self.expected_ty
}
/// Returns the current "merged type", representing our best-guess
/// at the LUB of the expressions we've seen so far (if any). This
/// isn't *final* until you call `self.final()`, which will return
/// the merged type.
pub fn merged_ty(&self) -> Ty<'tcx> {
self.final_ty.unwrap_or(self.expected_ty)
}
/// Indicates that the value generated by `expression`, which is
/// of type `expression_ty`, is one of the possibility that we
/// could coerce from. This will record `expression` and later
/// calls to `coerce` may come back and add adjustments and things
/// if necessary.
pub fn coerce<'a>(&mut self,
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
cause: &ObligationCause<'tcx>,
expression: &'gcx hir::Expr,
expression_ty: Ty<'tcx>,
expression_diverges: Diverges)
{
self.coerce_inner(fcx, cause, Some(expression), expression_ty, expression_diverges, None)
}
/// Indicates that one of the inputs is a "forced unit". This
/// occurs in a case like `if foo { ... };`, where the issing else
/// generates a "forced unit". Another example is a `loop { break;
/// }`, where the `break` has no argument expression. We treat
/// these cases slightly differently for error-reporting
/// purposes. Note that these tend to correspond to cases where
/// the `()` expression is implicit in the source, and hence we do
/// not take an expression argument.
///
/// The `augment_error` gives you a chance to extend the error
/// message, in case any results (e.g., we use this to suggest
/// removing a `;`).
pub fn coerce_forced_unit<'a>(&mut self,
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
cause: &ObligationCause<'tcx>,
augment_error: &mut FnMut(&mut DiagnosticBuilder))
{
self.coerce_inner(fcx,
cause,
None,
fcx.tcx.mk_nil(),
Diverges::Maybe,
Some(augment_error))
}
/// The inner coercion "engine". If `expression` is `None`, this
/// is a forced-unit case, and hence `expression_ty` must be
/// `Nil`.
fn coerce_inner<'a>(&mut self,
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
cause: &ObligationCause<'tcx>,
expression: Option<&'gcx hir::Expr>,
mut expression_ty: Ty<'tcx>,
expression_diverges: Diverges,
augment_error: Option<&mut FnMut(&mut DiagnosticBuilder)>)
{
// Incorporate whatever type inference information we have
// until now; in principle we might also want to process
// pending obligations, but doing so should only improve
// compatibility (hopefully that is true) by helping us
// uncover never types better.
if expression_ty.is_ty_var() {
expression_ty = fcx.infcx.shallow_resolve(expression_ty);
}
// If we see any error types, just propagate that error
// upwards.
if expression_ty.references_error() || self.merged_ty().references_error() {
self.final_ty = Some(fcx.tcx.types.err);
return;
}
// Handle the actual type unification etc.
let result = if let Some(expression) = expression {
if self.pushed == 0 {
// Special-case the first expression we are coercing.
// To be honest, I'm not entirely sure why we do this.
fcx.try_coerce(expression, expression_ty, expression_diverges, self.expected_ty)
} else {
match self.expressions {
Expressions::Dynamic(ref exprs) =>
fcx.try_find_coercion_lub(cause,
exprs,
self.merged_ty(),
expression,
expression_ty,
expression_diverges),
Expressions::UpFront(ref coercion_sites) =>
fcx.try_find_coercion_lub(cause,
&coercion_sites[0..self.pushed],
self.merged_ty(),
expression,
expression_ty,
expression_diverges),
}
}
} else {
// this is a hack for cases where we default to `()` because
// the expression etc has been omitted from the source. An
// example is an `if let` without an else:
//
// if let Some(x) = ... { }
//
// we wind up with a second match arm that is like `_ =>
// ()`. That is the case we are considering here. We take
// a different path to get the right "expected, found"
// message and so forth (and because we know that
// `expression_ty` will be unit).
//
// Another example is `break` with no argument expression.
assert!(expression_ty.is_nil());
assert!(expression_ty.is_nil(), "if let hack without unit type");
fcx.eq_types(true, cause, expression_ty, self.merged_ty())
.map(|infer_ok| {
fcx.register_infer_ok_obligations(infer_ok);
expression_ty
})
};
match result {
Ok(v) => {
self.final_ty = Some(v);
if let Some(e) = expression {
match self.expressions {
Expressions::Dynamic(ref mut buffer) => buffer.push(e),
Expressions::UpFront(coercion_sites) => {
// if the user gave us an array to validate, check that we got
// the next expression in the list, as expected
assert_eq!(coercion_sites[self.pushed].as_coercion_site().id, e.id);
}
}
self.pushed += 1;
}
}
Err(err) => {
let (expected, found) = if expression.is_none() {
// In the case where this is a "forced unit", like
// `break`, we want to call the `()` "expected"
// since it is implied by the syntax.
assert!(expression_ty.is_nil());
(expression_ty, self.final_ty.unwrap_or(self.expected_ty))
} else {
// Otherwise, the "expected" type for error
// reporting is the current unification type,
// which is basically the LUB of the expressions
// we've seen so far (combined with the expected
// type)
(self.final_ty.unwrap_or(self.expected_ty), expression_ty)
};
let mut db;
match cause.code {
ObligationCauseCode::ReturnNoExpression => {
db = struct_span_err!(
fcx.tcx.sess, cause.span, E0069,
"`return;` in a function whose return type is not `()`");
db.span_label(cause.span, &format!("return type is not ()"));
}
_ => {
db = fcx.report_mismatched_types(cause, expected, found, err);
}
}
if let Some(mut augment_error) = augment_error {
augment_error(&mut db);
}
db.emit();
self.final_ty = Some(fcx.tcx.types.err);
}
}
}
pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
if let Some(final_ty) = self.final_ty {
final_ty
} else {
// If we only had inputs that were of type `!` (or no
// inputs at all), then the final type is `!`.
assert_eq!(self.pushed, 0);
fcx.tcx.types.never
}
}
}
/// Something that can be converted into an expression to which we can
/// apply a coercion.
pub trait AsCoercionSite {
fn as_coercion_site(&self) -> &hir::Expr;
}
impl AsCoercionSite for hir::Expr {
fn as_coercion_site(&self) -> &hir::Expr {
self
}
}
impl AsCoercionSite for P<hir::Expr> {
fn as_coercion_site(&self) -> &hir::Expr {
self
}
}
impl<'a, T> AsCoercionSite for &'a T
where T: AsCoercionSite
{
fn as_coercion_site(&self) -> &hir::Expr {
(**self).as_coercion_site()
}
}
impl AsCoercionSite for ! {
fn as_coercion_site(&self) -> &hir::Expr {
unreachable!()
}
}
impl AsCoercionSite for hir::Arm {
fn as_coercion_site(&self) -> &hir::Expr {
&self.body
}
}

View File

@ -362,7 +362,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
&infcx.parameter_environment.caller_bounds);
infcx.resolve_regions_and_report_errors(&free_regions, impl_m_body_id);
} else {
let fcx = FnCtxt::new(&inh, Some(tcx.types.err), impl_m_body_id);
let fcx = FnCtxt::new(&inh, impl_m_body_id);
fcx.regionck_item(impl_m_body_id, impl_m_span, &[]);
}

View File

@ -67,9 +67,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
// Checks that the type of `expr` can be coerced to `expected`.
pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
//
// NB: This code relies on `self.diverges` to be accurate. In
// particular, assignments to `!` will be permitted if the
// diverges flag is currently "always".
pub fn demand_coerce(&self,
expr: &hir::Expr,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>) {
let expected = self.resolve_type_vars_with_obligations(expected);
if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
if let Err(e) = self.try_coerce(expr, checked_ty, self.diverges.get(), expected) {
let cause = self.misc(expr.span);
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
let mode = probe::Mode::MethodCall;

View File

@ -137,7 +137,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
assert_eq!(n, pick.autoderefs);
autoderef.unambiguous_final_ty();
autoderef.finalize(LvaluePreference::NoPreference, Some(self.self_expr));
autoderef.finalize(LvaluePreference::NoPreference, &[self.self_expr]);
let target = pick.unsize.unwrap_or(autoderefd_ty);
let target = target.adjust_for_autoref(self.tcx, autoref);
@ -444,7 +444,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
"expr was deref-able {} times but now isn't?",
autoderefs);
});
autoderef.finalize(PreferMutLvalue, Some(expr));
autoderef.finalize(PreferMutLvalue, &[expr]);
}
}
Some(_) | None => {}

File diff suppressed because it is too large Load Diff

View File

@ -50,7 +50,7 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
let id = self.id;
let span = self.span;
self.inherited.enter(|inh| {
let fcx = FnCtxt::new(&inh, None, id);
let fcx = FnCtxt::new(&inh, id);
let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
tcx: fcx.tcx.global_tcx(),
code: code

View File

@ -79,6 +79,7 @@ This API is completely unstable and subject to change.
#![feature(conservative_impl_trait)]
#![cfg_attr(stage0,feature(field_init_shorthand))]
#![feature(loop_break_value)]
#![feature(never_type)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]

View File

@ -36,6 +36,7 @@ pub trait ParserObsoleteMethods {
impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
/// Reports an obsolete syntax non-fatal error.
#[allow(unused_variables)]
#[allow(unreachable_code)]
fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) {
let (kind_str, desc, error) = match kind {
// Nothing here at the moment

View File

@ -0,0 +1,23 @@
// Copyright 2016 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.
#![feature(never_type)]
fn foo(x: usize, y: !, z: usize) { }
fn cast_a() {
let y = {return; 22} as !;
}
fn cast_b() {
let y = 22 as !; //~ ERROR non-scalar cast
}
fn main() { }

View File

@ -0,0 +1,90 @@
// Copyright 2016 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.
#![feature(never_type)]
fn foo(x: usize, y: !, z: usize) { }
fn call_foo_a() {
// FIXME(#40800) -- accepted beacuse divergence happens **before**
// the coercion to `!`, but within same expression. Not clear that
// these are the rules we want.
foo(return, 22, 44);
}
fn call_foo_b() {
// Divergence happens in the argument itself, definitely ok.
foo(22, return, 44);
}
fn call_foo_c() {
// This test fails because the divergence happens **after** the
// coercion to `!`:
foo(22, 44, return); //~ ERROR mismatched types
}
fn call_foo_d() {
// This test passes because `a` has type `!`:
let a: ! = return;
let b = 22;
let c = 44;
foo(a, b, c); // ... and hence a reference to `a` is expected to diverge.
}
fn call_foo_e() {
// This test probably could pass but we don't *know* that `a`
// has type `!` so we don't let it work.
let a = return;
let b = 22;
let c = 44;
foo(a, b, c); //~ ERROR mismatched types
}
fn call_foo_f() {
// This fn fails because `a` has type `usize`, and hence a
// reference to is it **not** considered to diverge.
let a: usize = return;
let b = 22;
let c = 44;
foo(a, b, c); //~ ERROR mismatched types
}
fn array_a() {
// Accepted: return is coerced to `!` just fine, and then `22` can be
// because we already diverged.
let x: [!; 2] = [return, 22];
}
fn array_b() {
// Error: divergence has not yet occurred.
let x: [!; 2] = [22, return]; //~ ERROR mismatched types
}
fn tuple_a() {
// No divergence at all.
let x: (usize, !, usize) = (22, 44, 66); //~ ERROR mismatched types
}
fn tuple_b() {
// Divergence happens before coercion: OK
let x: (usize, !, usize) = (return, 44, 66);
}
fn tuple_c() {
// Divergence happens before coercion: OK
let x: (usize, !, usize) = (22, return, 66);
}
fn tuple_d() {
// Error: divergence happens too late
let x: (usize, !, usize) = (22, 44, return); //~ ERROR mismatched types
}
fn main() { }

View File

@ -22,16 +22,6 @@ impl Deserialize for () {
}
}
fn doit() -> Result<(), String> {
let _ = match Deserialize::deserialize() {
//~^ ERROR code relies on type
//~| WARNING previously accepted
Ok(x) => x,
Err(e) => return Err(e),
};
Ok(())
}
trait ImplementedForUnitButNotNever {}
impl ImplementedForUnitButNotNever for () {}
@ -46,6 +36,6 @@ fn smeg() {
}
fn main() {
let _ = doit();
smeg();
}

View File

@ -8,24 +8,18 @@
// 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;
// After #39485, this test used to pass, but that change was reverted
// due to numerous inference failures like #39808, so it now fails
// again. #39485 made it so that diverging types never propagate
// upward; but we now do propagate such types upward in many more
// cases.
while x > 0 {
x -= 1;
while y > 0 {
y -= 1;
while z > 0 { z -= 1; }
if x > 10 {
return;
"unreachable";
}
}
}
fn g() {
&panic!() //~ ERROR mismatched types
}
fn f() -> isize {
(return 1, return 2) //~ ERROR mismatched types
}
fn main() {}

View File

@ -9,5 +9,5 @@
// except according to those terms.
fn main() {
(return)[0]; //~ ERROR the type of this value must be known in this context
(return)[0]; //~ ERROR cannot index a value of type `!`
}

View File

@ -12,7 +12,7 @@ fn f() -> isize {
(return 1, return 2)
//~^ ERROR mismatched types
//~| expected type `isize`
//~| found type `(_, _)`
//~| found type `(!, !)`
//~| expected isize, found tuple
}

View File

@ -9,5 +9,5 @@
// except according to those terms.
fn main() {
return.is_failure //~ ERROR the type of this value must be known in this context
return.is_failure //~ ERROR no field `is_failure` on type `!`
}

View File

@ -10,7 +10,7 @@
fn main() {
loop {
break.push(1) //~ ERROR the type of this value must be known in this context
break.push(1) //~ ERROR no method named `push` found for type `!`
;
}
}

View File

@ -9,6 +9,6 @@
// except according to those terms.
fn main() {
*return //~ ERROR the type of this value must be known in this context
*return //~ ERROR type `!` cannot be dereferenced
;
}

View File

@ -13,6 +13,5 @@
// into it.
fn main() {
(return)((),());
//~^ ERROR the type of this value must be known
(return)((),()); //~ ERROR expected function, found `!`
}

View File

@ -21,5 +21,5 @@ impl<A> vec_monad<A> for Vec<A> {
}
fn main() {
["hi"].bind(|x| [x] );
//~^ ERROR no method named `bind` found for type `[&'static str; 1]` in the current scope
//~^ ERROR no method named `bind` found for type `[&str; 1]` in the current scope
}

View File

@ -12,14 +12,14 @@
fn main() {
let _: i32 =
'a: //~ ERROR mismatched types
loop { break };
'a: // in this case, the citation is just the `break`:
loop { break }; //~ ERROR mismatched types
let _: i32 =
'b: //~ ERROR mismatched types
while true { break };
while true { break }; // but here we cite the whole loop
let _: i32 =
'c: //~ ERROR mismatched types
for _ in None { break };
for _ in None { break }; // but here we cite the whole loop
let _: i32 =
'd: //~ ERROR mismatched types
while let Some(_) = None { break };

View File

@ -40,37 +40,40 @@ fn main() {
loop {
break 'while_loop 123;
//~^ ERROR `break` with value from a `while` loop
//~| ERROR mismatched types
break 456;
break 789;
};
}
'while_let_loop: while let Some(_) = Some(()) {
while let Some(_) = Some(()) {
if break () { //~ ERROR `break` with value from a `while let` loop
break;
break None;
//~^ ERROR `break` with value from a `while let` loop
//~| ERROR mismatched types
}
}
while let Some(_) = Some(()) {
break None;
//~^ ERROR `break` with value from a `while let` loop
}
'while_let_loop: while let Some(_) = Some(()) {
loop {
break 'while_let_loop "nope";
//~^ ERROR `break` with value from a `while let` loop
//~| ERROR mismatched types
break 33;
};
}
'for_loop: for _ in &[1,2,3] {
for _ in &[1,2,3] {
break (); //~ ERROR `break` with value from a `for` loop
break [()];
//~^ ERROR `break` with value from a `for` loop
//~| ERROR mismatched types
}
'for_loop: for _ in &[1,2,3] {
loop {
break Some(3);
break 'for_loop Some(17);
//~^ ERROR `break` with value from a `for` loop
//~| ERROR mismatched types
};
}

View File

@ -1,4 +1,4 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -8,6 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub fn lit_1() {
1;
#![allow(warnings)]
#![deny(unreachable_code)]
enum Void { }
fn foo(v: Void) {
match v { }
let x = 2; //~ ERROR unreachable
}
fn main() {
}

View File

@ -1,4 +1,4 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -8,10 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(slice_patterns)]
#![allow(unused_parens)]
#![deny(unreachable_code)]
pub fn pat_vec_7() {
match [7, 77, 777, 7777] {
[x, y, ..] => x + y
};
fn main() {
match (return) { } //~ ERROR unreachable expression
}

View File

@ -0,0 +1,17 @@
// Copyright 2016 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.
fn foo<T>() -> T { panic!("Rocks for my pillow") }
fn main() {
let x = match () { //~ ERROR type annotations needed
() => foo() // T here should be unresolved
};
}

View File

@ -16,5 +16,6 @@
fn main() {
let x: ! = panic!("aah"); //~ ERROR unused
drop(x); //~ ERROR unreachable
//~^ ERROR unreachable
}

View File

@ -11,6 +11,7 @@
// Test that we can't use another type in place of !
#![feature(never_type)]
#![deny(warnings)]
fn main() {
let x: ! = "hello"; //~ ERROR mismatched types

View File

@ -1,41 +0,0 @@
// Copyright 2015 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.
// Test that diverging types default to ! when feature(never_type) is enabled. This test is the
// same as run-pass/unit-fallback.rs except that ! is enabled.
#![feature(never_type)]
trait Balls: Sized {
fn smeg() -> Result<Self, ()>;
}
impl Balls for () {
fn smeg() -> Result<(), ()> { Ok(()) }
}
struct Flah;
impl Flah {
fn flah<T: Balls>(&self) -> Result<T, ()> {
T::smeg()
}
}
fn doit() -> Result<(), ()> {
// The type of _ is unconstrained here and should default to !
let _ = try!(Flah.flah()); //~ ERROR the trait bound
Ok(())
}
fn main() {
let _ = doit();
}

View File

@ -13,9 +13,6 @@
// over time, but this test used to exhibit some pretty bogus messages
// that were not remotely helpful.
// error-pattern:cannot infer
// error-pattern:cannot outlive the lifetime 'a
// error-pattern:must be valid for the static lifetime
// error-pattern:cannot infer
// error-pattern:cannot outlive the lifetime 'a
// error-pattern:must be valid for the static lifetime

View File

@ -16,17 +16,11 @@ struct an_enum<'a>(&'a isize);
struct a_class<'a> { x:&'a isize }
fn a_fn1<'a,'b>(e: an_enum<'a>) -> an_enum<'b> {
return e; //~ ERROR mismatched types
//~| expected type `an_enum<'b>`
//~| found type `an_enum<'a>`
//~| lifetime mismatch
return e; //~ ERROR mismatched types
}
fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> {
return e; //~ ERROR mismatched types
//~| expected type `a_class<'b>`
//~| found type `a_class<'a>`
//~| lifetime mismatch
return e; //~ ERROR mismatched types
}
fn main() { }

View File

@ -1,38 +0,0 @@
-include ../tools.mk
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 f23.rs \
f24.rs f25.rs
# all: $(patsubst %.rs,$(TMPDIR)/%.dot,$(FILES)) $(patsubst %.rs,$(TMPDIR)/%.pp,$(FILES))
all: $(patsubst %.rs,$(TMPDIR)/%.check,$(FILES))
RUSTC_LIB=$(RUSTC) --crate-type=lib
define FIND_LAST_BLOCK
LASTBLOCKNUM_$(1) := $(shell $(RUSTC_LIB) -Z unstable-options --pretty=expanded,identified $(1) \
| grep block
| tail -1
| sed -e 's@.*/\* block \([0-9]*\) \*/.*@\1@')
endef
ifeq ($(findstring rustc,$(RUSTC)),)
$(error Must set RUSTC)
endif
$(TMPDIR)/%.pp: %.rs
$(RUSTC_LIB) --pretty=expanded,identified $< -o $@
$(TMPDIR)/%.dot: %.rs
$(eval $(call FIND_LAST_BLOCK,$<))
$(RUSTC_LIB) -Z unstable-options --unpretty flowgraph,unlabelled=$(LASTBLOCKNUM_$<) $< -o $@.tmp
cat $@.tmp | sed -e 's@ (id=[0-9]*)@@g' \
-e 's@\[label=""\]@@' \
-e 's@digraph [a-zA-Z0-9_]* @digraph block @' \
> $@
$(TMPDIR)/%.check: %.rs $(TMPDIR)/%.dot
diff -u $(patsubst %.rs,$(TMPDIR)/%.dot,$<) $(patsubst %.rs,%.dot-expected.dot,$<)

View File

@ -1,9 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="block { }"];
N3[label="expr { }"];
N0 -> N2;
N2 -> N3;
N3 -> N1;
}

View File

@ -1,13 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 1"];
N3[label="stmt 1;"];
N4[label="block { 1; }"];
N5[label="expr { 1; }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N1;
}

View File

@ -1,13 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="local _x"];
N3[label="stmt let _x: isize;"];
N4[label="block { let _x: isize; }"];
N5[label="expr { let _x: isize; }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N1;
}

View File

@ -1,17 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 3"];
N3[label="expr 4"];
N4[label="expr 3 + 4"];
N5[label="stmt 3 + 4;"];
N6[label="block { 3 + 4; }"];
N7[label="expr { 3 + 4; }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N1;
}

View File

@ -1,13 +0,0 @@
// 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.
pub fn expr_add_3() {
3 + 4;
}

View File

@ -1,15 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 4"];
N3[label="local _x"];
N4[label="stmt let _x = 4;"];
N5[label="block { let _x = 4; }"];
N6[label="expr { let _x = 4; }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N1;
}

View File

@ -1,13 +0,0 @@
// 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.
pub fn pat_id_4() {
let _x = 4;
}

View File

@ -1,23 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 5"];
N3[label="expr 55"];
N4[label="expr (5, 55)"];
N5[label="local _x"];
N6[label="local _y"];
N7[label="pat (_x, _y)"];
N8[label="stmt let (_x, _y) = (5, 55);"];
N9[label="block { let (_x, _y) = (5, 55); }"];
N10[label="expr { let (_x, _y) = (5, 55); }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N9;
N9 -> N10;
N10 -> N1;
}

View File

@ -1,13 +0,0 @@
// 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.
pub fn pat_tup_5() {
let (_x, _y) = (5, 55);
}

View File

@ -1,19 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 6"];
N3[label="expr S6{val: 6,}"];
N4[label="local _x"];
N5[label="pat S6 { val: _x }"];
N6[label="stmt let S6 { val: _x } = S6{val: 6,};"];
N7[label="block { let S6 { val: _x } = S6{val: 6,}; }"];
N8[label="expr { let S6 { val: _x } = S6{val: 6,}; }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N1;
}

View File

@ -1,14 +0,0 @@
// 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.
struct S6 { val: isize }
pub fn pat_struct_6() {
let S6 { val: _x } = S6{ val: 6 };
}

View File

@ -1,39 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 7"];
N3[label="expr 77"];
N4[label="expr 777"];
N5[label="expr 7777"];
N6[label="expr [7, 77, 777, 7777]"];
N7[label="expr match [7, 77, 777, 7777] { [x, y, ..] => x + y, }"];
N8[label="(dummy_node)"];
N9[label="local x"];
N10[label="local y"];
N11[label="pat _"];
N12[label="pat [x, y, ..]"];
N13[label="expr x"];
N14[label="expr y"];
N15[label="expr x + y"];
N16[label="stmt match [7, 77, 777, 7777] { [x, y, ..] => x + y, };"];
N17[label="block { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"];
N18[label="expr { match [7, 77, 777, 7777] { [x, y, ..] => x + y, }; }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N9;
N9 -> N10;
N10 -> N11;
N11 -> N12;
N12 -> N8;
N8 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N7;
N7 -> N16;
N16 -> N17;
N17 -> N18;
N18 -> N1;
}

View File

@ -1,38 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 8"];
N3[label="local x"];
N4[label="stmt let x = 8;"];
N5[label="local _y"];
N6[label="stmt let _y;"];
N7[label="expr x"];
N8[label="expr 88"];
N9[label="expr x > 88"];
N10[label="expr 888"];
N11[label="expr _y"];
N12[label="expr _y = 888"];
N13[label="stmt _y = 888;"];
N14[label="block { _y = 888; }"];
N15[label="expr if x > 88 { _y = 888; }"];
N16[label="block { let x = 8; let _y; if x > 88 { _y = 888; } }"];
N17[label="expr { let x = 8; let _y; if x > 88 { _y = 888; } }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N9;
N9 -> N10;
N10 -> N11;
N11 -> N12;
N12 -> N13;
N13 -> N14;
N9 -> N15;
N14 -> N15;
N15 -> N16;
N16 -> N17;
N17 -> N1;
}

View File

@ -1,54 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 91"];
N3[label="local x"];
N4[label="stmt let x = 91;"];
N5[label="local _y"];
N6[label="stmt let _y;"];
N7[label="expr x"];
N8[label="expr 92"];
N9[label="expr x > 92"];
N10[label="expr 93"];
N11[label="expr _y"];
N12[label="expr _y = 93"];
N13[label="stmt _y = 93;"];
N14[label="block { _y = 93; }"];
N15[label="expr 94"];
N16[label="expr 95"];
N17[label="expr 94 + 95"];
N18[label="expr _y"];
N19[label="expr _y = 94 + 95"];
N20[label="stmt _y = 94 + 95;"];
N21[label="block { _y = 94 + 95; }"];
N22[label="expr { _y = 94 + 95; }"];
N23[label="expr if x > 92 { _y = 93; } else { _y = 94 + 95; }"];
N24[label="block { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"];
N25[label="expr { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N9;
N9 -> N10;
N10 -> N11;
N11 -> N12;
N12 -> N13;
N13 -> N14;
N9 -> N15;
N15 -> N16;
N16 -> N17;
N17 -> N18;
N18 -> N19;
N19 -> N20;
N20 -> N21;
N21 -> N22;
N14 -> N23;
N22 -> N23;
N23 -> N24;
N24 -> N25;
N25 -> N1;
}

View File

@ -1,18 +0,0 @@
// 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.
pub fn expr_if_twoarm_9() {
let x = 91; let _y;
if x > 92 {
_y = 93;
} else {
_y = 94+95;
}
}

View File

@ -1,36 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 10"];
N3[label="local mut x"];
N4[label="stmt let mut x = 10;"];
N5[label="(dummy_node)"];
N6[label="expr while x > 0 { x -= 1; }"];
N7[label="expr x"];
N8[label="expr 0"];
N9[label="expr x > 0"];
N10[label="expr 1"];
N11[label="expr x"];
N12[label="expr x -= 1"];
N13[label="stmt x -= 1;"];
N14[label="block { x -= 1; }"];
N15[label="block { let mut x = 10; while x > 0 { x -= 1; } }"];
N16[label="expr { let mut x = 10; while x > 0 { x -= 1; } }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N7;
N7 -> N8;
N8 -> N9;
N9 -> N6;
N9 -> N10;
N10 -> N11;
N11 -> N12;
N12 -> N13;
N13 -> N14;
N14 -> N5;
N6 -> N15;
N15 -> N16;
N16 -> N1;
}

View File

@ -1,35 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 11"];
N3[label="local mut _x"];
N4[label="stmt let mut _x = 11;"];
N5[label="(dummy_node)"];
N6[label="expr loop { _x -= 1; }"];
N7[label="expr 1"];
N8[label="expr _x"];
N9[label="expr _x -= 1"];
N10[label="stmt _x -= 1;"];
N11[label="block { _x -= 1; }"];
N12[label="stmt loop { _x -= 1; }"];
N13[label="expr \"unreachable\""];
N14[label="stmt \"unreachable\";"];
N15[label="block { let mut _x = 11; loop { _x -= 1; } \"unreachable\"; }"];
N16[label="expr { let mut _x = 11; loop { _x -= 1; } \"unreachable\"; }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N7;
N7 -> N8;
N8 -> N9;
N9 -> N10;
N10 -> N11;
N11 -> N5;
N6 -> N12;
N12 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N16;
N16 -> N1;
}

View File

@ -1,18 +0,0 @@
// 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_loop_11() {
let mut _x = 11;
loop {
_x -= 1;
}
"unreachable";
}

View File

@ -1,50 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 12"];
N3[label="local mut x"];
N4[label="stmt let mut x = 12;"];
N5[label="(dummy_node)"];
N6[label="expr loop { x -= 1; if x == 2 { break ; \"unreachable\"; } }"];
N7[label="expr 1"];
N8[label="expr x"];
N9[label="expr x -= 1"];
N10[label="stmt x -= 1;"];
N11[label="expr x"];
N12[label="expr 2"];
N13[label="expr x == 2"];
N14[label="expr break"];
N15[label="(dummy_node)"];
N16[label="stmt break ;"];
N17[label="expr \"unreachable\""];
N18[label="stmt \"unreachable\";"];
N19[label="block { break ; \"unreachable\"; }"];
N20[label="expr if x == 2 { break ; \"unreachable\"; }"];
N21[label="block { x -= 1; if x == 2 { break ; \"unreachable\"; } }"];
N22[label="block { let mut x = 12; loop { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"];
N23[label="expr { let mut x = 12; loop { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N7;
N7 -> N8;
N8 -> N9;
N9 -> N10;
N10 -> N11;
N11 -> N12;
N12 -> N13;
N13 -> N14;
N14 -> N6;
N15 -> N16;
N16 -> N17;
N17 -> N18;
N18 -> N19;
N13 -> N20;
N19 -> N20;
N20 -> N21;
N21 -> N5;
N6 -> N22;
N22 -> N23;
N23 -> N1;
}

View File

@ -1,18 +0,0 @@
// 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_loop_12() {
let mut x = 12;
loop {
x -= 1;
if x == 2 { break; "unreachable"; }
}
}

View File

@ -1,54 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr E13::E13b"];
N3[label="expr 13"];
N4[label="expr E13::E13b(13)"];
N5[label="local x"];
N6[label="stmt let x = E13::E13b(13);"];
N7[label="local _y"];
N8[label="stmt let _y;"];
N9[label="expr x"];
N10[label="expr match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }"];
N11[label="(dummy_node)"];
N12[label="pat E13::E13a"];
N13[label="expr 1"];
N14[label="expr _y"];
N15[label="expr _y = 1"];
N16[label="(dummy_node)"];
N17[label="local v"];
N18[label="pat E13::E13b(v)"];
N19[label="expr v"];
N20[label="expr 1"];
N21[label="expr v + 1"];
N22[label="expr _y"];
N23[label="expr _y = v + 1"];
N24[label="block {\l let x = E13::E13b(13);\l let _y;\l match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"];
N25[label="expr {\l let x = E13::E13b(13);\l let _y;\l match x { E13::E13a => _y = 1, E13::E13b(v) => _y = v + 1, }\l}\l"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N9;
N9 -> N12;
N12 -> N11;
N11 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N10;
N9 -> N17;
N17 -> N18;
N18 -> N16;
N16 -> N19;
N19 -> N20;
N20 -> N21;
N21 -> N22;
N22 -> N23;
N23 -> N10;
N10 -> N24;
N24 -> N25;
N25 -> N1;
}

View File

@ -1,18 +0,0 @@
// 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.
enum E13 { E13a, E13b(isize) }
pub fn expr_match_13() {
let x = E13::E13b(13); let _y;
match x {
E13::E13a => _y = 1,
E13::E13b(v) => _y = v + 1,
}
}

View File

@ -1,36 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 14"];
N3[label="local x"];
N4[label="stmt let x = 14;"];
N5[label="expr x"];
N6[label="expr 1"];
N7[label="expr x > 1"];
N8[label="expr return"];
N9[label="(dummy_node)"];
N10[label="stmt return;"];
N11[label="expr \"unreachable\""];
N12[label="stmt \"unreachable\";"];
N13[label="block { return; \"unreachable\"; }"];
N14[label="expr if x > 1 { return; \"unreachable\"; }"];
N15[label="block { let x = 14; if x > 1 { return; \"unreachable\"; } }"];
N16[label="expr { let x = 14; if x > 1 { return; \"unreachable\"; } }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N1;
N9 -> N10;
N10 -> N11;
N11 -> N12;
N12 -> N13;
N7 -> N14;
N13 -> N14;
N14 -> N15;
N15 -> N16;
N16 -> N1;
}

View File

@ -1,18 +0,0 @@
// 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_ret_14() {
let x = 14;
if x > 1 {
return;
"unreachable";
}
}

View File

@ -1,105 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 15"];
N3[label="local mut x"];
N4[label="stmt let mut x = 15;"];
N5[label="expr 151"];
N6[label="local mut y"];
N7[label="stmt let mut y = 151;"];
N8[label="(dummy_node)"];
N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l"];
N10[label="(dummy_node)"];
N11[label="expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l"];
N12[label="expr x"];
N13[label="expr 1"];
N14[label="expr x == 1"];
N15[label="expr break \'outer"];
N16[label="(dummy_node)"];
N17[label="stmt break \'outer ;"];
N18[label="expr \"unreachable\""];
N19[label="stmt \"unreachable\";"];
N20[label="block { break \'outer ; \"unreachable\"; }"];
N21[label="expr if x == 1 { break \'outer ; \"unreachable\"; }"];
N22[label="stmt if x == 1 { break \'outer ; \"unreachable\"; }"];
N23[label="expr y"];
N24[label="expr 2"];
N25[label="expr y >= 2"];
N26[label="expr break"];
N27[label="(dummy_node)"];
N28[label="stmt break ;"];
N29[label="expr \"unreachable\""];
N30[label="stmt \"unreachable\";"];
N31[label="block { break ; \"unreachable\"; }"];
N32[label="expr if y >= 2 { break ; \"unreachable\"; }"];
N33[label="stmt if y >= 2 { break ; \"unreachable\"; }"];
N34[label="expr 3"];
N35[label="expr y"];
N36[label="expr y -= 3"];
N37[label="stmt y -= 3;"];
N38[label="block {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l}\l"];
N39[label="stmt \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l"];
N40[label="expr 4"];
N41[label="expr y"];
N42[label="expr y -= 4"];
N43[label="stmt y -= 4;"];
N44[label="expr 5"];
N45[label="expr x"];
N46[label="expr x -= 5"];
N47[label="stmt x -= 5;"];
N48[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l}\l"];
N49[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l}\l"];
N50[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { break ; \"unreachable\"; }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l}\l"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N10;
N10 -> N12;
N12 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N9;
N16 -> N17;
N17 -> N18;
N18 -> N19;
N19 -> N20;
N14 -> N21;
N20 -> N21;
N21 -> N22;
N22 -> N23;
N23 -> N24;
N24 -> N25;
N25 -> N26;
N26 -> N11;
N27 -> N28;
N28 -> N29;
N29 -> N30;
N30 -> N31;
N25 -> N32;
N31 -> N32;
N32 -> N33;
N33 -> N34;
N34 -> N35;
N35 -> N36;
N36 -> N37;
N37 -> N38;
N38 -> N10;
N11 -> N39;
N39 -> N40;
N40 -> N41;
N41 -> N42;
N42 -> N43;
N43 -> N44;
N44 -> N45;
N45 -> N46;
N46 -> N47;
N47 -> N48;
N48 -> N8;
N9 -> N49;
N49 -> N50;
N50 -> N1;
}

View File

@ -1,30 +0,0 @@
// 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_break_label_15() {
let mut x = 15;
let mut y = 151;
'outer: loop {
'inner: loop {
if x == 1 {
break 'outer;
"unreachable";
}
if y >= 2 {
break;
"unreachable";
}
y -= 3;
}
y -= 4;
x -= 5;
}
}

View File

@ -1,111 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 16"];
N3[label="local mut x"];
N4[label="stmt let mut x = 16;"];
N5[label="expr 16"];
N6[label="local mut y"];
N7[label="stmt let mut y = 16;"];
N8[label="(dummy_node)"];
N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l"];
N10[label="(dummy_node)"];
N11[label="expr \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l"];
N12[label="expr x"];
N13[label="expr 1"];
N14[label="expr x == 1"];
N15[label="expr continue \'outer"];
N16[label="(dummy_node)"];
N17[label="stmt continue \'outer ;"];
N18[label="expr \"unreachable\""];
N19[label="stmt \"unreachable\";"];
N20[label="block { continue \'outer ; \"unreachable\"; }"];
N21[label="expr if x == 1 { continue \'outer ; \"unreachable\"; }"];
N22[label="stmt if x == 1 { continue \'outer ; \"unreachable\"; }"];
N23[label="expr y"];
N24[label="expr 1"];
N25[label="expr y >= 1"];
N26[label="expr break"];
N27[label="(dummy_node)"];
N28[label="stmt break ;"];
N29[label="expr \"unreachable\""];
N30[label="stmt \"unreachable\";"];
N31[label="block { break ; \"unreachable\"; }"];
N32[label="expr if y >= 1 { break ; \"unreachable\"; }"];
N33[label="stmt if y >= 1 { break ; \"unreachable\"; }"];
N34[label="expr 1"];
N35[label="expr y"];
N36[label="expr y -= 1"];
N37[label="stmt y -= 1;"];
N38[label="block {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l}\l"];
N39[label="stmt \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l"];
N40[label="expr 1"];
N41[label="expr y"];
N42[label="expr y -= 1"];
N43[label="stmt y -= 1;"];
N44[label="expr 1"];
N45[label="expr x"];
N46[label="expr x -= 1"];
N47[label="stmt x -= 1;"];
N48[label="block {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l}\l"];
N49[label="stmt \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l"];
N50[label="expr \"unreachable\""];
N51[label="stmt \"unreachable\";"];
N52[label="block {\l let mut x = 16;\l let mut y = 16;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l \"unreachable\";\l}\l"];
N53[label="expr {\l let mut x = 16;\l let mut y = 16;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 1 { break ; \"unreachable\"; }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l \"unreachable\";\l}\l"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N10;
N10 -> N12;
N12 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N8;
N16 -> N17;
N17 -> N18;
N18 -> N19;
N19 -> N20;
N14 -> N21;
N20 -> N21;
N21 -> N22;
N22 -> N23;
N23 -> N24;
N24 -> N25;
N25 -> N26;
N26 -> N11;
N27 -> N28;
N28 -> N29;
N29 -> N30;
N30 -> N31;
N25 -> N32;
N31 -> N32;
N32 -> N33;
N33 -> N34;
N34 -> N35;
N35 -> N36;
N36 -> N37;
N37 -> N38;
N38 -> N10;
N11 -> N39;
N39 -> N40;
N40 -> N41;
N41 -> N42;
N42 -> N43;
N43 -> N44;
N44 -> N45;
N45 -> N46;
N46 -> N47;
N47 -> N48;
N48 -> N8;
N9 -> N49;
N49 -> N50;
N50 -> N51;
N51 -> N52;
N52 -> N53;
N53 -> N1;
}

View File

@ -1,31 +0,0 @@
// 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_continue_label_16() {
let mut x = 16;
let mut y = 16;
'outer: loop {
'inner: loop {
if x == 1 {
continue 'outer;
"unreachable";
}
if y >= 1 {
break;
"unreachable";
}
y -= 1;
}
y -= 1;
x -= 1;
}
"unreachable";
}

View File

@ -1,21 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 1"];
N3[label="expr 7"];
N4[label="expr 17"];
N5[label="expr [1, 7, 17]"];
N6[label="local _v"];
N7[label="stmt let _v = [1, 7, 17];"];
N8[label="block { let _v = [1, 7, 17]; }"];
N9[label="expr { let _v = [1, 7, 17]; }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N9;
N9 -> N1;
}

View File

@ -1,13 +0,0 @@
// 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.
pub fn expr_vec_17() {
let _v = [1, 7, 17];
}

View File

@ -1,23 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="stmt fn inner(x: isize) -> isize { x + x }"];
N3[label="expr inner"];
N4[label="expr inner"];
N5[label="expr 18"];
N6[label="expr inner(18)"];
N7[label="expr inner(inner(18))"];
N8[label="stmt inner(inner(18));"];
N9[label="block {\l fn inner(x: isize) -> isize { x + x }\l inner(inner(18));\l}\l"];
N10[label="expr {\l fn inner(x: isize) -> isize { x + x }\l inner(inner(18));\l}\l"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N9;
N9 -> N10;
N10 -> N1;
}

View File

@ -1,14 +0,0 @@
// 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.
pub fn expr_call_18() {
fn inner(x:isize) -> isize { x + x }
inner(inner(18));
}

View File

@ -1,29 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="stmt struct S19 {\l x: isize,\l}\l"];
N3[label="stmt impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l}\l"];
N4[label="expr 19"];
N5[label="expr S19{x: 19,}"];
N6[label="local s"];
N7[label="stmt let s = S19{x: 19,};"];
N8[label="expr s"];
N9[label="expr s.inner()"];
N10[label="expr s.inner().inner()"];
N11[label="stmt s.inner().inner();"];
N12[label="block {\l struct S19 {\l x: isize,\l }\l impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"];
N13[label="expr {\l struct S19 {\l x: isize,\l }\l impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N9;
N9 -> N10;
N10 -> N11;
N11 -> N12;
N12 -> N13;
N13 -> N1;
}

View File

@ -1,16 +0,0 @@
// 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.
pub fn expr_method_call_19() {
struct S19 { x: isize }
impl S19 { fn inner(self) -> S19 { S19 { x: self.x + self.x } } }
let s = S19 { x: 19 };
s.inner().inner();
}

View File

@ -1,29 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 2"];
N3[label="expr 0"];
N4[label="expr 20"];
N5[label="expr [2, 0, 20]"];
N6[label="local v"];
N7[label="stmt let v = [2, 0, 20];"];
N8[label="expr v"];
N9[label="expr 20"];
N10[label="expr v[20]"];
N11[label="stmt v[20];"];
N12[label="block { let v = [2, 0, 20]; v[20]; }"];
N13[label="expr { let v = [2, 0, 20]; v[20]; }"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N9;
N9 -> N10;
N10 -> N11;
N11 -> N12;
N12 -> N13;
N13 -> N1;
}

View File

@ -1,14 +0,0 @@
// 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.
pub fn expr_index_20() {
let v = [2, 0, 20];
v[20];
}

View File

@ -1,101 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 15"];
N3[label="local mut x"];
N4[label="stmt let mut x = 15;"];
N5[label="expr 151"];
N6[label="local mut y"];
N7[label="stmt let mut y = 151;"];
N8[label="(dummy_node)"];
N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l"];
N10[label="(dummy_node)"];
N11[label="expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l"];
N12[label="expr x"];
N13[label="expr 1"];
N14[label="expr x == 1"];
N15[label="expr break \'outer"];
N16[label="(dummy_node)"];
N17[label="stmt break \'outer ;"];
N18[label="expr \"unreachable\""];
N19[label="stmt \"unreachable\";"];
N20[label="block { break \'outer ; \"unreachable\"; }"];
N21[label="expr if x == 1 { break \'outer ; \"unreachable\"; }"];
N22[label="stmt if x == 1 { break \'outer ; \"unreachable\"; }"];
N23[label="expr y"];
N24[label="expr 2"];
N25[label="expr y >= 2"];
N26[label="expr return"];
N27[label="(dummy_node)"];
N28[label="stmt return;"];
N29[label="expr \"unreachable\""];
N30[label="stmt \"unreachable\";"];
N31[label="block { return; \"unreachable\"; }"];
N32[label="expr if y >= 2 { return; \"unreachable\"; }"];
N33[label="stmt if y >= 2 { return; \"unreachable\"; }"];
N34[label="expr 3"];
N35[label="expr y"];
N36[label="expr y -= 3"];
N37[label="stmt y -= 3;"];
N38[label="expr 5"];
N39[label="expr x"];
N40[label="expr x -= 5"];
N41[label="stmt x -= 5;"];
N42[label="block {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l}\l"];
N43[label="stmt \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l"];
N44[label="expr \"unreachable\""];
N45[label="stmt \"unreachable\";"];
N46[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l}\l"];
N47[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l}\l"];
N48[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l}\l"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N10;
N10 -> N12;
N12 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N9;
N16 -> N17;
N17 -> N18;
N18 -> N19;
N19 -> N20;
N14 -> N21;
N20 -> N21;
N21 -> N22;
N22 -> N23;
N23 -> N24;
N24 -> N25;
N25 -> N26;
N26 -> N1;
N27 -> N28;
N28 -> N29;
N29 -> N30;
N30 -> N31;
N25 -> N32;
N31 -> N32;
N32 -> N33;
N33 -> N34;
N34 -> N35;
N35 -> N36;
N36 -> N37;
N37 -> N38;
N38 -> N39;
N39 -> N40;
N40 -> N41;
N41 -> N42;
N42 -> N10;
N11 -> N43;
N43 -> N44;
N44 -> N45;
N45 -> N46;
N46 -> N8;
N9 -> N47;
N47 -> N48;
N48 -> N1;
}

View File

@ -1,30 +0,0 @@
// 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_break_label_21() {
let mut x = 15;
let mut y = 151;
'outer: loop {
'inner: loop {
if x == 1 {
break 'outer;
"unreachable";
}
if y >= 2 {
return;
"unreachable";
}
y -= 3;
x -= 5;
}
"unreachable";
}
}

View File

@ -1,107 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 15"];
N3[label="local mut x"];
N4[label="stmt let mut x = 15;"];
N5[label="expr 151"];
N6[label="local mut y"];
N7[label="stmt let mut y = 151;"];
N8[label="(dummy_node)"];
N9[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l"];
N10[label="(dummy_node)"];
N11[label="expr \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l"];
N12[label="expr x"];
N13[label="expr 1"];
N14[label="expr x == 1"];
N15[label="expr continue \'outer"];
N16[label="(dummy_node)"];
N17[label="stmt continue \'outer ;"];
N18[label="expr \"unreachable\""];
N19[label="stmt \"unreachable\";"];
N20[label="block { continue \'outer ; \"unreachable\"; }"];
N21[label="expr if x == 1 { continue \'outer ; \"unreachable\"; }"];
N22[label="stmt if x == 1 { continue \'outer ; \"unreachable\"; }"];
N23[label="expr y"];
N24[label="expr 2"];
N25[label="expr y >= 2"];
N26[label="expr return"];
N27[label="(dummy_node)"];
N28[label="stmt return;"];
N29[label="expr \"unreachable\""];
N30[label="stmt \"unreachable\";"];
N31[label="block { return; \"unreachable\"; }"];
N32[label="expr if y >= 2 { return; \"unreachable\"; }"];
N33[label="stmt if y >= 2 { return; \"unreachable\"; }"];
N34[label="expr 1"];
N35[label="expr x"];
N36[label="expr x -= 1"];
N37[label="stmt x -= 1;"];
N38[label="expr 3"];
N39[label="expr y"];
N40[label="expr y -= 3"];
N41[label="stmt y -= 3;"];
N42[label="block {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l}\l"];
N43[label="stmt \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l"];
N44[label="expr \"unreachable\""];
N45[label="stmt \"unreachable\";"];
N46[label="block {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l}\l"];
N47[label="stmt \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l"];
N48[label="expr \"unreachable\""];
N49[label="stmt \"unreachable\";"];
N50[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"];
N51[label="expr {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
N4 -> N5;
N5 -> N6;
N6 -> N7;
N7 -> N8;
N8 -> N10;
N10 -> N12;
N12 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N8;
N16 -> N17;
N17 -> N18;
N18 -> N19;
N19 -> N20;
N14 -> N21;
N20 -> N21;
N21 -> N22;
N22 -> N23;
N23 -> N24;
N24 -> N25;
N25 -> N26;
N26 -> N1;
N27 -> N28;
N28 -> N29;
N29 -> N30;
N30 -> N31;
N25 -> N32;
N31 -> N32;
N32 -> N33;
N33 -> N34;
N34 -> N35;
N35 -> N36;
N36 -> N37;
N37 -> N38;
N38 -> N39;
N39 -> N40;
N40 -> N41;
N41 -> N42;
N42 -> N10;
N11 -> N43;
N43 -> N44;
N44 -> N45;
N45 -> N46;
N46 -> N8;
N9 -> N47;
N47 -> N48;
N48 -> N49;
N49 -> N50;
N50 -> N51;
N51 -> N1;
}

View File

@ -1,31 +0,0 @@
// 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_break_label_21() {
let mut x = 15;
let mut y = 151;
'outer: loop {
'inner: loop {
if x == 1 {
continue 'outer;
"unreachable";
}
if y >= 2 {
return;
"unreachable";
}
x -= 1;
y -= 3;
}
"unreachable";
}
"unreachable";
}

View File

@ -1,113 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 23"];
N3[label="local mut x"];
N4[label="stmt let mut x = 23;"];
N5[label="expr 23"];
N6[label="local mut y"];
N7[label="stmt let mut y = 23;"];
N8[label="expr 23"];
N9[label="local mut z"];
N10[label="stmt let mut z = 23;"];
N11[label="(dummy_node)"];
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 x"];
N14[label="expr 0"];
N15[label="expr x > 0"];
N16[label="expr 1"];
N17[label="expr x"];
N18[label="expr x -= 1"];
N19[label="stmt x -= 1;"];
N20[label="(dummy_node)"];
N21[label="expr while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"];
N22[label="expr y"];
N23[label="expr 0"];
N24[label="expr y > 0"];
N25[label="expr 1"];
N26[label="expr y"];
N27[label="expr y -= 1"];
N28[label="stmt y -= 1;"];
N29[label="(dummy_node)"];
N30[label="expr while z > 0 { z -= 1; }"];
N31[label="expr z"];
N32[label="expr 0"];
N33[label="expr z > 0"];
N34[label="expr 1"];
N35[label="expr z"];
N36[label="expr z -= 1"];
N37[label="stmt z -= 1;"];
N38[label="block { z -= 1; }"];
N39[label="stmt while z > 0 { z -= 1; }"];
N40[label="expr x"];
N41[label="expr 10"];
N42[label="expr x > 10"];
N43[label="expr return"];
N44[label="(dummy_node)"];
N45[label="stmt return;"];
N46[label="expr \"unreachable\""];
N47[label="stmt \"unreachable\";"];
N48[label="block { return; \"unreachable\"; }"];
N49[label="expr if x > 10 { return; \"unreachable\"; }"];
N50[label="block { y -= 1; while z > 0 { z -= 1; } if x > 10 { return; \"unreachable\"; } }"];
N51[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"];
N52[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"];
N53[label="expr {\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 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N12;
N15 -> N16;
N16 -> N17;
N17 -> N18;
N18 -> N19;
N19 -> N20;
N20 -> N22;
N22 -> N23;
N23 -> N24;
N24 -> N21;
N24 -> N25;
N25 -> N26;
N26 -> N27;
N27 -> N28;
N28 -> N29;
N29 -> N31;
N31 -> N32;
N32 -> N33;
N33 -> N30;
N33 -> N34;
N34 -> N35;
N35 -> N36;
N36 -> N37;
N37 -> N38;
N38 -> N29;
N30 -> N39;
N39 -> N40;
N40 -> N41;
N41 -> N42;
N42 -> N43;
N43 -> N1;
N44 -> N45;
N45 -> N46;
N46 -> N47;
N47 -> N48;
N42 -> N49;
N48 -> N49;
N49 -> N50;
N50 -> N20;
N21 -> N51;
N51 -> N11;
N12 -> N52;
N52 -> N53;
N53 -> N1;
}

View File

@ -1,161 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 24"];
N3[label="local mut x"];
N4[label="stmt let mut x = 24;"];
N5[label="expr 24"];
N6[label="local mut y"];
N7[label="stmt let mut y = 24;"];
N8[label="expr 24"];
N9[label="local mut z"];
N10[label="stmt let mut z = 24;"];
N11[label="(dummy_node)"];
N12[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"];
N13[label="expr x"];
N14[label="expr 0"];
N15[label="expr x == 0"];
N16[label="expr break"];
N17[label="(dummy_node)"];
N18[label="stmt break ;"];
N19[label="expr \"unreachable\""];
N20[label="stmt \"unreachable\";"];
N21[label="block { break ; \"unreachable\"; }"];
N22[label="expr if x == 0 { break ; \"unreachable\"; }"];
N23[label="stmt if x == 0 { break ; \"unreachable\"; }"];
N24[label="expr 1"];
N25[label="expr x"];
N26[label="expr x -= 1"];
N27[label="stmt x -= 1;"];
N28[label="(dummy_node)"];
N29[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"];
N30[label="expr y"];
N31[label="expr 0"];
N32[label="expr y == 0"];
N33[label="expr break"];
N34[label="(dummy_node)"];
N35[label="stmt break ;"];
N36[label="expr \"unreachable\""];
N37[label="stmt \"unreachable\";"];
N38[label="block { break ; \"unreachable\"; }"];
N39[label="expr if y == 0 { break ; \"unreachable\"; }"];
N40[label="stmt if y == 0 { break ; \"unreachable\"; }"];
N41[label="expr 1"];
N42[label="expr y"];
N43[label="expr y -= 1"];
N44[label="stmt y -= 1;"];
N45[label="(dummy_node)"];
N46[label="expr loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"];
N47[label="expr z"];
N48[label="expr 0"];
N49[label="expr z == 0"];
N50[label="expr break"];
N51[label="(dummy_node)"];
N52[label="stmt break ;"];
N53[label="expr \"unreachable\""];
N54[label="stmt \"unreachable\";"];
N55[label="block { break ; \"unreachable\"; }"];
N56[label="expr if z == 0 { break ; \"unreachable\"; }"];
N57[label="stmt if z == 0 { break ; \"unreachable\"; }"];
N58[label="expr 1"];
N59[label="expr z"];
N60[label="expr z -= 1"];
N61[label="stmt z -= 1;"];
N62[label="block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"];
N63[label="stmt loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"];
N64[label="expr x"];
N65[label="expr 10"];
N66[label="expr x > 10"];
N67[label="expr return"];
N68[label="(dummy_node)"];
N69[label="stmt return;"];
N70[label="expr \"unreachable\""];
N71[label="stmt \"unreachable\";"];
N72[label="block { return; \"unreachable\"; }"];
N73[label="expr if x > 10 { return; \"unreachable\"; }"];
N74[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"];
N75[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"];
N76[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"];
N77[label="expr {\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 -> N9;
N9 -> N10;
N10 -> N11;
N11 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N16;
N16 -> N12;
N17 -> N18;
N18 -> N19;
N19 -> N20;
N20 -> N21;
N15 -> N22;
N21 -> N22;
N22 -> N23;
N23 -> N24;
N24 -> N25;
N25 -> N26;
N26 -> N27;
N27 -> N28;
N28 -> N30;
N30 -> N31;
N31 -> N32;
N32 -> N33;
N33 -> N29;
N34 -> N35;
N35 -> N36;
N36 -> N37;
N37 -> N38;
N32 -> N39;
N38 -> N39;
N39 -> N40;
N40 -> N41;
N41 -> N42;
N42 -> N43;
N43 -> N44;
N44 -> N45;
N45 -> N47;
N47 -> N48;
N48 -> N49;
N49 -> N50;
N50 -> N46;
N51 -> N52;
N52 -> N53;
N53 -> N54;
N54 -> N55;
N49 -> N56;
N55 -> N56;
N56 -> N57;
N57 -> N58;
N58 -> N59;
N59 -> N60;
N60 -> N61;
N61 -> N62;
N62 -> N45;
N46 -> N63;
N63 -> N64;
N64 -> N65;
N65 -> N66;
N66 -> N67;
N67 -> N1;
N68 -> N69;
N69 -> N70;
N70 -> N71;
N71 -> N72;
N66 -> N73;
N72 -> N73;
N73 -> N74;
N74 -> N28;
N29 -> N75;
N75 -> N11;
N12 -> N76;
N76 -> N77;
N77 -> N1;
}

View File

@ -1,36 +0,0 @@
// 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";
}
}
}
}

View File

@ -1,161 +0,0 @@
digraph block {
N0[label="entry"];
N1[label="exit"];
N2[label="expr 25"];
N3[label="local mut x"];
N4[label="stmt let mut x = 25;"];
N5[label="expr 25"];
N6[label="local mut y"];
N7[label="stmt let mut y = 25;"];
N8[label="expr 25"];
N9[label="local mut z"];
N10[label="stmt let mut z = 25;"];
N11[label="(dummy_node)"];
N12[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"];
N13[label="expr x"];
N14[label="expr 0"];
N15[label="expr x == 0"];
N16[label="expr break"];
N17[label="(dummy_node)"];
N18[label="stmt break ;"];
N19[label="expr \"unreachable\""];
N20[label="stmt \"unreachable\";"];
N21[label="block { break ; \"unreachable\"; }"];
N22[label="expr if x == 0 { break ; \"unreachable\"; }"];
N23[label="stmt if x == 0 { break ; \"unreachable\"; }"];
N24[label="expr 1"];
N25[label="expr x"];
N26[label="expr x -= 1"];
N27[label="stmt x -= 1;"];
N28[label="(dummy_node)"];
N29[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"];
N30[label="expr y"];
N31[label="expr 0"];
N32[label="expr y == 0"];
N33[label="expr break"];
N34[label="(dummy_node)"];
N35[label="stmt break ;"];
N36[label="expr \"unreachable\""];
N37[label="stmt \"unreachable\";"];
N38[label="block { break ; \"unreachable\"; }"];
N39[label="expr if y == 0 { break ; \"unreachable\"; }"];
N40[label="stmt if y == 0 { break ; \"unreachable\"; }"];
N41[label="expr 1"];
N42[label="expr y"];
N43[label="expr y -= 1"];
N44[label="stmt y -= 1;"];
N45[label="(dummy_node)"];
N46[label="expr \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"];
N47[label="expr z"];
N48[label="expr 0"];
N49[label="expr z == 0"];
N50[label="expr break"];
N51[label="(dummy_node)"];
N52[label="stmt break ;"];
N53[label="expr \"unreachable\""];
N54[label="stmt \"unreachable\";"];
N55[label="block { break ; \"unreachable\"; }"];
N56[label="expr if z == 0 { break ; \"unreachable\"; }"];
N57[label="stmt if z == 0 { break ; \"unreachable\"; }"];
N58[label="expr 1"];
N59[label="expr z"];
N60[label="expr z -= 1"];
N61[label="stmt z -= 1;"];
N62[label="block { if z == 0 { break ; \"unreachable\"; } z -= 1; }"];
N63[label="stmt \'a: loop { if z == 0 { break ; \"unreachable\"; } z -= 1; }"];
N64[label="expr x"];
N65[label="expr 10"];
N66[label="expr x > 10"];
N67[label="expr continue \'a"];
N68[label="(dummy_node)"];
N69[label="stmt continue \'a ;"];
N70[label="expr \"unreachable\""];
N71[label="stmt \"unreachable\";"];
N72[label="block { continue \'a ; \"unreachable\"; }"];
N73[label="expr if x > 10 { continue \'a ; \"unreachable\"; }"];
N74[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"];
N75[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"];
N76[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"];
N77[label="expr {\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 -> N9;
N9 -> N10;
N10 -> N11;
N11 -> N13;
N13 -> N14;
N14 -> N15;
N15 -> N16;
N16 -> N12;
N17 -> N18;
N18 -> N19;
N19 -> N20;
N20 -> N21;
N15 -> N22;
N21 -> N22;
N22 -> N23;
N23 -> N24;
N24 -> N25;
N25 -> N26;
N26 -> N27;
N27 -> N28;
N28 -> N30;
N30 -> N31;
N31 -> N32;
N32 -> N33;
N33 -> N29;
N34 -> N35;
N35 -> N36;
N36 -> N37;
N37 -> N38;
N32 -> N39;
N38 -> N39;
N39 -> N40;
N40 -> N41;
N41 -> N42;
N42 -> N43;
N43 -> N44;
N44 -> N45;
N45 -> N47;
N47 -> N48;
N48 -> N49;
N49 -> N50;
N50 -> N46;
N51 -> N52;
N52 -> N53;
N53 -> N54;
N54 -> N55;
N49 -> N56;
N55 -> N56;
N56 -> N57;
N57 -> N58;
N58 -> N59;
N59 -> N60;
N60 -> N61;
N61 -> N62;
N62 -> N45;
N46 -> N63;
N63 -> N64;
N64 -> N65;
N65 -> N66;
N66 -> N67;
N67 -> N28;
N68 -> N69;
N69 -> N70;
N70 -> N71;
N71 -> N72;
N66 -> N73;
N72 -> N73;
N73 -> N74;
N74 -> N28;
N29 -> N75;
N75 -> N11;
N12 -> N76;
N76 -> N77;
N77 -> N1;
}

View File

@ -1,36 +0,0 @@
// 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";
}
}
}
}

View File

@ -0,0 +1,106 @@
// Copyright 2015 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.
// Test various cases where we permit an unconstrained variable
// to fallback based on control-flow.
//
// These represent current behavior, but are pretty dubious. I would
// like to revisit these and potentially change them. --nmatsakis
#![feature(never_type)]
#![feature(loop_break_value)]
trait BadDefault {
fn default() -> Self;
}
impl BadDefault for u32 {
fn default() -> Self {
0
}
}
impl BadDefault for ! {
fn default() -> ! {
panic!()
}
}
fn assignment() {
let x;
if true {
x = BadDefault::default();
} else {
x = return;
}
}
fn assignment_rev() {
let x;
if true {
x = return;
} else {
x = BadDefault::default();
}
}
fn if_then_else() {
let _x = if true {
BadDefault::default()
} else {
return;
};
}
fn if_then_else_rev() {
let _x = if true {
return;
} else {
BadDefault::default()
};
}
fn match_arm() {
let _x = match Ok(BadDefault::default()) {
Ok(v) => v,
Err(()) => return,
};
}
fn match_arm_rev() {
let _x = match Ok(BadDefault::default()) {
Err(()) => return,
Ok(v) => v,
};
}
fn loop_break() {
let _x = loop {
if false {
break return;
} else {
break BadDefault::default();
}
};
}
fn loop_break_rev() {
let _x = loop {
if false {
break return;
} else {
break BadDefault::default();
}
};
}
fn main() { }

View File

@ -8,31 +8,20 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that diverging types default to () (with feature(never_type) disabled).
// Test a regression found when building compiler. The `produce()`
// error type `T` winds up getting unified with result of `x.parse()`;
// the type of the closure given to `unwrap_or_else` needs to be
// inferred to `usize`.
trait Balls: Sized {
fn smeg() -> Result<Self, ()>;
}
use std::num::ParseIntError;
impl Balls for () {
fn smeg() -> Result<(), ()> { Ok(()) }
}
struct Flah;
impl Flah {
fn flah<T: Balls>(&self) -> Result<T, ()> {
T::smeg()
}
}
fn doit() -> Result<(), ()> {
// The type of _ is unconstrained here and should default to ()
let _ = try!(Flah.flah());
Ok(())
fn produce<T>() -> Result<&'static str, T> {
Ok("22")
}
fn main() {
let _ = doit();
let x: usize = produce()
.and_then(|x| x.parse())
.unwrap_or_else(|_| panic!());
println!("{}", x);
}

View File

@ -0,0 +1,22 @@
// 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.
#![allow(warnings)]
// Here the type of `c` is `Option<?T>`, where `?T` is unconstrained.
// Because there is data-flow from the `{ return; }` block, which
// diverges and hence has type `!`, into `c`, we will default `?T` to
// `!`, and hence this code compiles rather than failing and requiring
// a type annotation.
fn main() {
let c = Some({ return; });
c.unwrap();
}

View File

@ -0,0 +1,26 @@
// Copyright 2016 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)]
// Regression test for #39808. The type parameter of `Owned` was
// considered to be "unconstrained" because the type resulting from
// `format!` (`String`) was not being propagated upward, owing to the
// fact that the expression diverges.
use std::borrow::Cow;
fn main() {
let _ = if false {
Cow::Owned(format!("{:?}", panic!()))
} else {
Cow::Borrowed("")
};
}

Some files were not shown because too many files have changed in this diff Show More