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:
commit
7ae95e5489
@ -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
|
||||
}
|
||||
|
@ -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) => {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 }`
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -904,6 +904,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
ObligationCauseCode::StartFunctionType |
|
||||
ObligationCauseCode::IntrinsicType |
|
||||
ObligationCauseCode::MethodReceiver |
|
||||
ObligationCauseCode::ReturnNoExpression |
|
||||
ObligationCauseCode::MiscObligation => {
|
||||
}
|
||||
ObligationCauseCode::SliceOrArrayElem => {
|
||||
|
@ -173,6 +173,9 @@ pub enum ObligationCauseCode<'tcx> {
|
||||
|
||||
// method receiver
|
||||
MethodReceiver,
|
||||
|
||||
// `return` with no expression
|
||||
ReturnNoExpression,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -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 |
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
@ -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>>,
|
||||
|
@ -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 \
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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 => {
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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, &[]);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
@ -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
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
|
23
src/test/compile-fail/coerce-to-bang-cast.rs
Normal file
23
src/test/compile-fail/coerce-to-bang-cast.rs
Normal 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() { }
|
90
src/test/compile-fail/coerce-to-bang.rs
Normal file
90
src/test/compile-fail/coerce-to-bang.rs
Normal 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() { }
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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() {}
|
@ -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 `!`
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 `!`
|
||||
}
|
||||
|
@ -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 `!`
|
||||
;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
;
|
||||
}
|
||||
|
@ -13,6 +13,5 @@
|
||||
// into it.
|
||||
|
||||
fn main() {
|
||||
(return)((),());
|
||||
//~^ ERROR the type of this value must be known
|
||||
(return)((),()); //~ ERROR expected function, found `!`
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 };
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
}
|
@ -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
|
||||
}
|
17
src/test/compile-fail/match-unresolved-one-arm.rs
Normal file
17
src/test/compile-fail/match-unresolved-one-arm.rs
Normal 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
|
||||
};
|
||||
}
|
@ -16,5 +16,6 @@
|
||||
fn main() {
|
||||
let x: ! = panic!("aah"); //~ ERROR unused
|
||||
drop(x); //~ ERROR unreachable
|
||||
//~^ ERROR unreachable
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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() { }
|
||||
|
@ -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,$<)
|
@ -1,9 +0,0 @@
|
||||
digraph block {
|
||||
N0[label="entry"];
|
||||
N1[label="exit"];
|
||||
N2[label="block { }"];
|
||||
N3[label="expr { }"];
|
||||
N0 -> N2;
|
||||
N2 -> N3;
|
||||
N3 -> N1;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
@ -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;
|
||||
}
|
@ -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 };
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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";
|
||||
}
|
@ -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;
|
||||
}
|
@ -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"; }
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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,
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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";
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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";
|
||||
}
|
@ -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;
|
||||
}
|
@ -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];
|
||||
}
|
@ -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;
|
||||
}
|
@ -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));
|
||||
}
|
@ -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;
|
||||
}
|
@ -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();
|
||||
}
|
@ -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;
|
||||
}
|
@ -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];
|
||||
}
|
@ -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;
|
||||
}
|
@ -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";
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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";
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
106
src/test/run-pass/diverging-fallback-control-flow.rs
Normal file
106
src/test/run-pass/diverging-fallback-control-flow.rs
Normal 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() { }
|
@ -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);
|
||||
}
|
||||
|
22
src/test/run-pass/diverging-fallback-option.rs
Normal file
22
src/test/run-pass/diverging-fallback-option.rs
Normal 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();
|
||||
}
|
26
src/test/run-pass/issue-39808.rs
Normal file
26
src/test/run-pass/issue-39808.rs
Normal 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
Loading…
x
Reference in New Issue
Block a user