diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index b87160dd75d04..853f81ceaa9b8 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -53,7 +53,7 @@ pub unsafe extern fn __rust_maybe_catch_panic(f: fn(*mut u8), // now hopefully. #[no_mangle] pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 { - return abort(); + abort(); #[cfg(unix)] unsafe fn abort() -> ! { diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index a2fc6e044e74c..22c7d14be29d2 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -33,16 +33,16 @@ struct LoopScope { } pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - blk: &hir::Block) -> CFG { + body: &hir::Expr) -> CFG { let mut graph = graph::Graph::new(); let entry = graph.add_node(CFGNodeData::Entry); // `fn_exit` is target of return exprs, which lies somewhere - // outside input `blk`. (Distinguishing `fn_exit` and `block_exit` + // outside input `body`. (Distinguishing `fn_exit` and `body_exit` // also resolves chicken-and-egg problem that arises if you try to - // have return exprs jump to `block_exit` during construction.) + // have return exprs jump to `body_exit` during construction.) let fn_exit = graph.add_node(CFGNodeData::Exit); - let block_exit; + let body_exit; let mut cfg_builder = CFGBuilder { graph: graph, @@ -50,8 +50,8 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: tcx, loop_scopes: Vec::new() }; - block_exit = cfg_builder.block(blk, entry); - cfg_builder.add_contained_edge(block_exit, fn_exit); + body_exit = cfg_builder.expr(body, entry); + cfg_builder.add_contained_edge(body_exit, fn_exit); let CFGBuilder {graph, ..} = cfg_builder; CFG {graph: graph, entry: entry, diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs index d06f51073df06..43434b884c8d4 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc/cfg/mod.rs @@ -59,8 +59,8 @@ pub type CFGEdge = graph::Edge; impl CFG { pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - blk: &hir::Block) -> CFG { - construct::construct(tcx, blk) + body: &hir::Expr) -> CFG { + construct::construct(tcx, body) } pub fn node_is_reachable(&self, id: ast::NodeId) -> bool { diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 465a09505e4a7..ec09877ae121c 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -672,120 +672,6 @@ extern "C" { ``` "##, -E0269: r##" -A returned value was expected but not all control paths return one. - -Erroneous code example: - -```compile_fail,E0269 -fn abracada_FAIL() -> String { - "this won't work".to_string(); - // error: not all control paths return a value -} -``` - -In the previous code, the function is supposed to return a `String`, however, -the code returns nothing (because of the ';'). Another erroneous code would be: - -```compile_fail -fn abracada_FAIL(b: bool) -> u32 { - if b { - 0 - } else { - "a" // It fails because an `u32` was expected and something else is - // returned. - } -} -``` - -It is advisable to find out what the unhandled cases are and check for them, -returning an appropriate value or panicking if necessary. Check if you need -to remove a semicolon from the last expression, like in the first erroneous -code example. -"##, - -E0270: r##" -Rust lets you define functions which are known to never return, i.e. are -'diverging', by marking its return type as `!`. - -For example, the following functions never return: - -```no_run -fn foo() -> ! { - loop {} -} - -fn bar() -> ! { - foo() // foo() is diverging, so this will diverge too -} - -fn baz() -> ! { - panic!(); // this macro internally expands to a call to a diverging function -} -``` - -Such functions can be used in a place where a value is expected without -returning a value of that type, for instance: - -```no_run -fn foo() -> ! { - loop {} -} - -let x = 3; - -let y = match x { - 1 => 1, - 2 => 4, - _ => foo() // diverging function called here -}; - -println!("{}", y) -``` - -If the third arm of the match block is reached, since `foo()` doesn't ever -return control to the match block, it is fine to use it in a place where an -integer was expected. The `match` block will never finish executing, and any -point where `y` (like the print statement) is needed will not be reached. - -However, if we had a diverging function that actually does finish execution: - -```ignore -fn foo() -> ! { - loop {break;} -} -``` - -Then we would have an unknown value for `y` in the following code: - -```no_run -fn foo() -> ! { - loop {} -} - -let x = 3; - -let y = match x { - 1 => 1, - 2 => 4, - _ => foo() -}; - -println!("{}", y); -``` - -In the previous example, the print statement was never reached when the -wildcard match arm was hit, so we were okay with `foo()` not returning an -integer that we could set to `y`. But in this example, `foo()` actually does -return control, so the print statement will be executed with an uninitialized -value. - -Obviously we cannot have functions which are allowed to be used in such -positions and yet can return control. So, if you are defining a function that -returns `!`, make sure that there is no way for it to actually finish -executing. -"##, - E0271: r##" This is because of a type mismatch between the associated type of some trait (e.g. `T::Bar`, where `T` implements `trait Quux { type Bar; }`) diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index b1771f52da2c6..9932e5fe68623 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -138,7 +138,7 @@ pub trait Visitor<'v> : Sized { fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) { walk_where_predicate(self, predicate) } - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, id: NodeId) { + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Expr, s: Span, id: NodeId) { walk_fn(self, fk, fd, b, s, id) } fn visit_trait_item(&mut self, ti: &'v TraitItem) { @@ -635,13 +635,13 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<' pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>, function_declaration: &'v FnDecl, - function_body: &'v Block, + function_body: &'v Expr, _span: Span, id: NodeId) { visitor.visit_id(id); walk_fn_decl(visitor, function_declaration); walk_fn_kind(visitor, function_kind); - visitor.visit_block(function_body) + visitor.visit_expr(function_body) } pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) { @@ -925,7 +925,7 @@ impl<'v> Visitor<'v> for IdRangeComputingVisitor { /// Computes the id range for a single fn body, ignoring nested items. pub fn compute_id_range_for_fn_body(fk: FnKind, decl: &FnDecl, - body: &Block, + body: &Expr, sp: Span, id: NodeId) -> IdRange { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e1fec898e41e4..b985298e47cc2 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -595,12 +595,13 @@ impl<'a> LoweringContext<'a> { hir::ItemConst(self.lower_ty(t), self.lower_expr(e)) } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { + let body = self.lower_block(body); hir::ItemFn(self.lower_fn_decl(decl), self.lower_unsafety(unsafety), self.lower_constness(constness), abi, self.lower_generics(generics), - self.lower_block(body)) + self.expr_block(body, ThinVec::new())) } ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)), ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)), @@ -665,7 +666,10 @@ impl<'a> LoweringContext<'a> { } TraitItemKind::Method(ref sig, ref body) => { hir::MethodTraitItem(this.lower_method_sig(sig), - body.as_ref().map(|x| this.lower_block(x))) + body.as_ref().map(|x| { + let body = this.lower_block(x); + this.expr_block(body, ThinVec::new()) + })) } TraitItemKind::Type(ref bounds, ref default) => { hir::TypeTraitItem(this.lower_bounds(bounds), @@ -691,8 +695,9 @@ impl<'a> LoweringContext<'a> { hir::ImplItemKind::Const(this.lower_ty(ty), this.lower_expr(expr)) } ImplItemKind::Method(ref sig, ref body) => { + let body = this.lower_block(body); hir::ImplItemKind::Method(this.lower_method_sig(sig), - this.lower_block(body)) + this.expr_block(body, ThinVec::new())) } ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)), ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"), @@ -1110,7 +1115,7 @@ impl<'a> LoweringContext<'a> { self.with_parent_def(e.id, |this| { hir::ExprClosure(this.lower_capture_clause(capture_clause), this.lower_fn_decl(decl), - this.lower_block(body), + this.lower_expr(body), fn_decl_span) }) } diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 4487234885692..325a90ea91e0e 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -21,11 +21,9 @@ //! nested within a uniquely determined `FnLike`), and users can ask //! for the `Code` associated with a particular NodeId. -pub use self::Code::*; - use hir as ast; use hir::map::{self, Node}; -use hir::{Block, FnDecl}; +use hir::{Expr, FnDecl}; use hir::intravisit::FnKind; use syntax::abi; use syntax::ast::{Attribute, Name, NodeId}; @@ -50,7 +48,7 @@ pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; } /// Components shared by fn-like things (fn items, methods, closures). pub struct FnParts<'a> { pub decl: &'a FnDecl, - pub body: &'a Block, + pub body: &'a Expr, pub kind: FnKind<'a>, pub span: Span, pub id: NodeId, @@ -77,29 +75,32 @@ impl MaybeFnLike for ast::Expr { } } -/// Carries either an FnLikeNode or a Block, as these are the two +/// Carries either an FnLikeNode or a Expr, as these are the two /// constructs that correspond to "code" (as in, something from which /// we can construct a control-flow graph). #[derive(Copy, Clone)] pub enum Code<'a> { - FnLikeCode(FnLikeNode<'a>), - BlockCode(&'a Block), + FnLike(FnLikeNode<'a>), + Expr(&'a Expr), } impl<'a> Code<'a> { pub fn id(&self) -> NodeId { match *self { - FnLikeCode(node) => node.id(), - BlockCode(block) => block.id, + Code::FnLike(node) => node.id(), + Code::Expr(block) => block.id, } } - /// Attempts to construct a Code from presumed FnLike or Block node input. - pub fn from_node(node: Node) -> Option { - if let map::NodeBlock(block) = node { - Some(BlockCode(block)) - } else { - FnLikeNode::from_node(node).map(|fn_like| FnLikeCode(fn_like)) + /// Attempts to construct a Code from presumed FnLike or Expr node input. + pub fn from_node(map: &map::Map<'a>, id: NodeId) -> Option> { + match map.get(id) { + map::NodeBlock(_) => { + // Use the parent, hopefully an expression node. + Code::from_node(map, map.get_parent_node(id)) + } + map::NodeExpr(expr) => Some(Code::Expr(expr)), + node => FnLikeNode::from_node(node).map(Code::FnLike) } } } @@ -114,7 +115,7 @@ struct ItemFnParts<'a> { abi: abi::Abi, vis: &'a ast::Visibility, generics: &'a ast::Generics, - body: &'a Block, + body: &'a Expr, id: NodeId, span: Span, attrs: &'a [Attribute], @@ -124,14 +125,14 @@ struct ItemFnParts<'a> { /// for use when implementing FnLikeNode operations. struct ClosureParts<'a> { decl: &'a FnDecl, - body: &'a Block, + body: &'a Expr, id: NodeId, span: Span, attrs: &'a [Attribute], } impl<'a> ClosureParts<'a> { - fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self { + fn new(d: &'a FnDecl, b: &'a Expr, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self { ClosureParts { decl: d, body: b, @@ -171,9 +172,9 @@ impl<'a> FnLikeNode<'a> { } } - pub fn body(self) -> &'a Block { + pub fn body(self) -> &'a Expr { self.handle(|i: ItemFnParts<'a>| &*i.body, - |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _, _| body, + |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Expr, _, _| body, |c: ClosureParts<'a>| c.body) } @@ -214,7 +215,7 @@ impl<'a> FnLikeNode<'a> { Name, &'a ast::MethodSig, Option<&'a ast::Visibility>, - &'a ast::Block, + &'a ast::Expr, Span, &'a [Attribute]) -> A, diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 3d9031a136e28..e23a721da08a6 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -211,7 +211,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { } fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl, - b: &'ast Block, s: Span, id: NodeId) { + b: &'ast Expr, s: Span, id: NodeId) { assert_eq!(self.parent_node, id); intravisit::walk_fn(self, fk, fd, b, s, id); } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index cbd3e39f8703a..6b5b8101a146c 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -904,7 +904,7 @@ pub enum Expr_ { /// A closure (for example, `move |a, b, c| {a + b + c}`). /// /// The final span is the span of the argument block `|...|` - ExprClosure(CaptureClause, P, P, Span), + ExprClosure(CaptureClause, P, P, Span), /// A block (`{ ... }`) ExprBlock(P), @@ -1035,7 +1035,7 @@ pub enum TraitItem_ { /// must contain a value) ConstTraitItem(P, Option>), /// A method with an optional body - MethodTraitItem(MethodSig, Option>), + MethodTraitItem(MethodSig, Option>), /// An associated type with (possibly empty) bounds and optional concrete /// type TypeTraitItem(TyParamBounds, Option>), @@ -1060,7 +1060,7 @@ pub enum ImplItemKind { /// of the expression Const(P, P), /// A method implementation with the given signature and body - Method(MethodSig, P), + Method(MethodSig, P), /// An associated type Type(P), } @@ -1501,7 +1501,7 @@ pub enum Item_ { /// A `const` item ItemConst(P, P), /// A function declaration - ItemFn(P, Unsafety, Constness, Abi, Generics, P), + ItemFn(P, Unsafety, Constness, Abi, Generics, P), /// A module ItemMod(Mod), /// An external module diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 657c10bab12eb..2c4ffb853c1f3 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -713,7 +713,9 @@ impl<'a> State<'a> { typarams, &item.vis)?; word(&mut self.s, " ")?; - self.print_block_with_attrs(&body, &item.attrs)?; + self.end()?; // need to close a box + self.end()?; // need to close a box + self.print_expr(&body)?; } hir::ItemMod(ref _mod) => { self.head(&visibility_qualified(&item.vis, "mod"))?; @@ -1002,7 +1004,9 @@ impl<'a> State<'a> { self.print_method_sig(ti.name, sig, &hir::Inherited)?; if let Some(ref body) = *body { self.nbsp()?; - self.print_block_with_attrs(body, &ti.attrs)?; + self.end()?; // need to close a box + self.end()?; // need to close a box + self.print_expr(body)?; } else { word(&mut self.s, ";")?; } @@ -1034,7 +1038,9 @@ impl<'a> State<'a> { self.head("")?; self.print_method_sig(ii.name, sig, &ii.vis)?; self.nbsp()?; - self.print_block_with_attrs(body, &ii.attrs)?; + self.end()?; // need to close a box + self.end()?; // need to close a box + self.print_expr(body)?; } hir::ImplItemKind::Type(ref ty) => { self.print_associated_type(ii.name, None, Some(ty))?; @@ -1402,26 +1408,10 @@ impl<'a> State<'a> { self.print_fn_block_args(&decl)?; space(&mut self.s)?; - let default_return = match decl.output { - hir::DefaultReturn(..) => true, - _ => false, - }; + // this is a bare expression + self.print_expr(body)?; + self.end()?; // need to close a box - if !default_return || !body.stmts.is_empty() || body.expr.is_none() { - self.print_block_unclosed(&body)?; - } else { - // we extract the block, so as not to create another set of boxes - match body.expr.as_ref().unwrap().node { - hir::ExprBlock(ref blk) => { - self.print_block_unclosed(&blk)?; - } - _ => { - // this is a bare expression - self.print_expr(body.expr.as_ref().map(|e| &**e).unwrap())?; - self.end()?; // need to close a box - } - } - } // a box will be closed by print_expr, but we didn't want an overall // wrapper so we closed the corresponding opening. so create an // empty box to satisfy the close. diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 9cc2337e3dd1e..f44f82860077e 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -838,7 +838,7 @@ impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> { } fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl, - body: &'v hir::Block, span: Span, id: ast::NodeId) { + body: &'v hir::Expr, span: Span, id: ast::NodeId) { run_lints!(self, check_fn, late_passes, fk, decl, body, span, id); hir_visit::walk_fn(self, fk, decl, body, span, id); run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id); @@ -994,10 +994,10 @@ impl<'a> ast_visit::Visitor for EarlyContext<'a> { } fn visit_fn(&mut self, fk: ast_visit::FnKind, decl: &ast::FnDecl, - body: &ast::Block, span: Span, id: ast::NodeId) { - run_lints!(self, check_fn, early_passes, fk, decl, body, span, id); - ast_visit::walk_fn(self, fk, decl, body, span); - run_lints!(self, check_fn_post, early_passes, fk, decl, body, span, id); + span: Span, id: ast::NodeId) { + run_lints!(self, check_fn, early_passes, fk, decl, span, id); + ast_visit::walk_fn(self, fk, decl, span); + run_lints!(self, check_fn_post, early_passes, fk, decl, span, id); } fn visit_variant_data(&mut self, diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 34e0ce7da1461..6f7102229f8d6 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -151,9 +151,9 @@ pub trait LateLintPass: LintPass { fn check_ty(&mut self, _: &LateContext, _: &hir::Ty) { } fn check_generics(&mut self, _: &LateContext, _: &hir::Generics) { } fn check_fn(&mut self, _: &LateContext, - _: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { } + _: FnKind, _: &hir::FnDecl, _: &hir::Expr, _: Span, _: ast::NodeId) { } fn check_fn_post(&mut self, _: &LateContext, - _: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { } + _: FnKind, _: &hir::FnDecl, _: &hir::Expr, _: Span, _: ast::NodeId) { } fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { } fn check_trait_item_post(&mut self, _: &LateContext, _: &hir::TraitItem) { } fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { } @@ -200,9 +200,9 @@ pub trait EarlyLintPass: LintPass { fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { } fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { } fn check_fn(&mut self, _: &EarlyContext, - _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { } + _: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { } fn check_fn_post(&mut self, _: &EarlyContext, - _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { } + _: ast_visit::FnKind, _: &ast::FnDecl, _: Span, _: ast::NodeId) { } fn check_trait_item(&mut self, _: &EarlyContext, _: &ast::TraitItem) { } fn check_trait_item_post(&mut self, _: &EarlyContext, _: &ast::TraitItem) { } fn check_impl_item(&mut self, _: &EarlyContext, _: &ast::ImplItem) { } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 7f3a58808c225..1ec3d0db8e0aa 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -498,7 +498,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> { // ^^^^^^^^^^^^^ only needed for pretty printing - pub fn propagate(&mut self, cfg: &cfg::CFG, blk: &hir::Block) { + pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Expr) { //! Performs the data flow analysis. if self.bits_per_id == 0 { @@ -524,17 +524,17 @@ impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> { debug!("Dataflow result for {}:", self.analysis_name); debug!("{}", { let mut v = Vec::new(); - self.pretty_print_to(box &mut v, blk).unwrap(); + self.pretty_print_to(box &mut v, body).unwrap(); String::from_utf8(v).unwrap() }); } fn pretty_print_to<'b>(&self, wr: Box, - blk: &hir::Block) -> io::Result<()> { + body: &hir::Expr) -> io::Result<()> { let mut ps = pprust::rust_printer_annotated(wr, self, None); ps.cbox(pprust::indent_unit)?; ps.ibox(0)?; - ps.print_block(blk)?; + ps.print_expr(body)?; pp::eof(&mut ps.s) } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 7fc698fdbebf5..a32d5542a79e2 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -567,7 +567,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { self.warn_dead_code(impl_item.id, impl_item.span, impl_item.name, "method"); } - intravisit::walk_block(self, body) + intravisit::walk_expr(self, body) } hir::ImplItemKind::Type(..) => {} } @@ -576,11 +576,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { // Overwrite so that we don't warn the trait item itself. fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) { match trait_item.node { - hir::ConstTraitItem(_, Some(ref expr)) => { - intravisit::walk_expr(self, expr) - } + hir::ConstTraitItem(_, Some(ref body))| hir::MethodTraitItem(_, Some(ref body)) => { - intravisit::walk_block(self, body) + intravisit::walk_expr(self, body) } hir::ConstTraitItem(_, None) | hir::MethodTraitItem(_, None) | diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 8ca3c75eaa4b1..5634e2012c971 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -94,7 +94,7 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { fn visit_fn(&mut self, fn_kind: FnKind<'v>, fn_decl: &'v hir::FnDecl, - block: &'v hir::Block, span: Span, id: ast::NodeId) { + block: &'v hir::Expr, span: Span, id: ast::NodeId) { let (is_item_fn, is_unsafe_fn) = match fn_kind { FnKind::ItemFn(_, _, unsafety, ..) => diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 0543d1303a5f1..711a131a68e17 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -290,14 +290,14 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn walk_fn(&mut self, decl: &hir::FnDecl, - body: &hir::Block) { + body: &hir::Expr) { self.walk_arg_patterns(decl, body); - self.walk_block(body); + self.consume_expr(body); } fn walk_arg_patterns(&mut self, decl: &hir::FnDecl, - body: &hir::Block) { + body: &hir::Expr) { for arg in &decl.inputs { let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id)); diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 57503398cfe57..7dbf9aa74144d 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ItemVisitor<'a, 'tcx> { } fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, id: ast::NodeId) { + b: &'v hir::Expr, s: Span, id: ast::NodeId) { if let FnKind::Closure(..) = fk { span_bug!(s, "intrinsicck: closure outside of function") } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 46bea00cca3cb..a654d65bc6796 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -123,10 +123,9 @@ use std::io::prelude::*; use std::io; use std::rc::Rc; use syntax::ast::{self, NodeId}; -use syntax::codemap::original_sp; use syntax::parse::token::keywords; use syntax::ptr::P; -use syntax_pos::{BytePos, Span}; +use syntax_pos::Span; use hir::Expr; use hir; @@ -187,7 +186,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt) -> String { impl<'a, 'tcx, 'v> Visitor<'v> for IrMaps<'a, 'tcx> { fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, id: NodeId) { + b: &'v hir::Expr, s: Span, id: NodeId) { visit_fn(self, fk, fd, b, s, id); } fn visit_local(&mut self, l: &hir::Local) { visit_local(self, l); } @@ -352,9 +351,9 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> { } impl<'a, 'tcx, 'v> Visitor<'v> for Liveness<'a, 'tcx> { - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, n: NodeId) { - check_fn(self, fk, fd, b, s, n); + fn visit_fn(&mut self, _: FnKind<'v>, _: &'v hir::FnDecl, + _: &'v hir::Expr, _: Span, _: NodeId) { + // do not check contents of nested fns } fn visit_local(&mut self, l: &hir::Local) { check_local(self, l); @@ -370,7 +369,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Liveness<'a, 'tcx> { fn visit_fn(ir: &mut IrMaps, fk: FnKind, decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, sp: Span, id: ast::NodeId) { debug!("visit_fn"); @@ -405,10 +404,10 @@ fn visit_fn(ir: &mut IrMaps, // compute liveness let mut lsets = Liveness::new(&mut fn_maps, specials); - let entry_ln = lsets.compute(decl, body); + let entry_ln = lsets.compute(body); // check for various error conditions - lsets.visit_block(body); + lsets.visit_expr(body); lsets.check_ret(id, sp, fk, entry_ln, body); lsets.warn_about_unused_args(decl, entry_ln); } @@ -821,17 +820,23 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // _______________________________________________________________________ - fn compute(&mut self, decl: &hir::FnDecl, body: &hir::Block) -> LiveNode { + fn compute(&mut self, body: &hir::Expr) -> LiveNode { // if there is a `break` or `again` at the top level, then it's // effectively a return---this only occurs in `for` loops, // where the body is really a closure. - debug!("compute: using id for block, {}", block_to_string(body)); + debug!("compute: using id for body, {}", expr_to_string(body)); let exit_ln = self.s.exit_ln; - let entry_ln: LiveNode = - self.with_loop_nodes(body.id, exit_ln, exit_ln, - |this| this.propagate_through_fn_block(decl, body)); + let entry_ln: LiveNode = self.with_loop_nodes(body.id, exit_ln, exit_ln, |this| { + // the fallthrough exit is only for those cases where we do not + // explicitly return: + let s = this.s; + this.init_from_succ(s.fallthrough_ln, s.exit_ln); + this.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ); + + this.propagate_through_expr(body, s.fallthrough_ln) + }); // hack to skip the loop unless debug! is enabled: debug!("^^ liveness computation results for body {} (entry={:?})", @@ -846,20 +851,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { entry_ln } - fn propagate_through_fn_block(&mut self, _: &hir::FnDecl, blk: &hir::Block) - -> LiveNode { - // the fallthrough exit is only for those cases where we do not - // explicitly return: - let s = self.s; - self.init_from_succ(s.fallthrough_ln, s.exit_ln); - if blk.expr.is_none() { - self.acc(s.fallthrough_ln, s.no_ret_var, ACC_READ) - } - self.acc(s.fallthrough_ln, s.clean_exit_var, ACC_READ); - - self.propagate_through_block(blk, s.fallthrough_ln) - } - fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode) -> LiveNode { let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ); @@ -1448,15 +1439,6 @@ fn check_expr(this: &mut Liveness, expr: &Expr) { } } -fn check_fn(_v: &Liveness, - _fk: FnKind, - _decl: &hir::FnDecl, - _body: &hir::Block, - _sp: Span, - _id: NodeId) { - // do not check contents of nested fns -} - impl<'a, 'tcx> Liveness<'a, 'tcx> { fn fn_ret(&self, id: NodeId) -> ty::Binder> { let fn_ty = self.ir.tcx.tables().node_id_to_type(id); @@ -1472,7 +1454,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { sp: Span, _fk: FnKind, entry_ln: LiveNode, - body: &hir::Block) + body: &hir::Expr) { // within the fn body, late-bound regions are liberated // and must outlive the *call-site* of the function. @@ -1481,13 +1463,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.ir.tcx.region_maps.call_site_extent(id, body.id), &self.fn_ret(id)); - if fn_ret.is_never() { - // FIXME(durka) this rejects code like `fn foo(x: !) -> ! { x }` - if self.live_on_entry(entry_ln, self.s.clean_exit_var).is_some() { - span_err!(self.ir.tcx.sess, sp, E0270, - "computation may converge in a function marked as diverging"); - } - } else if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { + if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { let param_env = ParameterEnvironment::for_item(self.ir.tcx, id); let t_ret_subst = fn_ret.subst(self.ir.tcx, ¶m_env.free_substs); let is_nil = self.ir.tcx.infer_ctxt(None, Some(param_env), @@ -1498,32 +1474,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // for nil return types, it is ok to not return a value expl. if !is_nil { - let ends_with_stmt = match body.expr { - None if !body.stmts.is_empty() => - match body.stmts.last().unwrap().node { - hir::StmtSemi(ref e, _) => { - self.ir.tcx.tables().expr_ty(&e) == fn_ret - }, - _ => false - }, - _ => false - }; - let mut err = struct_span_err!(self.ir.tcx.sess, - sp, - E0269, - "not all control paths return a value"); - if ends_with_stmt { - let last_stmt = body.stmts.last().unwrap(); - let original_span = original_sp(self.ir.tcx.sess.codemap(), - last_stmt.span, sp); - let span_semicolon = Span { - lo: original_span.hi - BytePos(1), - hi: original_span.hi, - expn_id: original_span.expn_id - }; - err.span_help(span_semicolon, "consider removing this semicolon:"); - } - err.emit(); + span_bug!(sp, "not all control paths return a value"); } } } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 9898ec7597d90..7868e700f2701 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -248,9 +248,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match *node { ast_map::NodeItem(item) => { match item.node { - hir::ItemFn(.., ref search_block) => { + hir::ItemFn(.., ref body) => { if item_might_be_inlined(&item) { - intravisit::walk_block(self, &search_block) + self.visit_expr(body); } } @@ -278,11 +278,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::MethodTraitItem(_, None) => { // Keep going, nothing to get exported } - hir::ConstTraitItem(_, Some(ref expr)) => { - self.visit_expr(&expr); - } + hir::ConstTraitItem(_, Some(ref body)) | hir::MethodTraitItem(_, Some(ref body)) => { - intravisit::walk_block(self, body); + self.visit_expr(body); } hir::TypeTraitItem(..) => {} } @@ -295,7 +293,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ImplItemKind::Method(ref sig, ref body) => { let did = self.tcx.map.get_parent_did(search_item); if method_might_be_inlined(self.tcx, sig, impl_item, did) { - intravisit::walk_block(self, body) + self.visit_expr(body) } } hir::ImplItemKind::Type(_) => {} diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 8d51fda0cf2b1..34a6a547d9440 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -490,12 +490,7 @@ impl RegionMaps { // if there's one. Static items, for instance, won't // have an enclosing scope, hence no scope will be // returned. - let expr_extent = self.node_extent(expr_id); - // For some reason, the expr's scope itself is skipped here. - let mut id = match scope_map[expr_extent.0 as usize].into_option() { - Some(i) => i, - _ => return None - }; + let mut id = self.node_extent(expr_id); while let Some(p) = scope_map[id.0 as usize].into_option() { match code_extents[p.0 as usize] { @@ -1086,7 +1081,7 @@ fn resolve_item(visitor: &mut RegionResolutionVisitor, item: &hir::Item) { fn resolve_fn(visitor: &mut RegionResolutionVisitor, kind: FnKind, decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, sp: Span, id: ast::NodeId) { debug!("region::resolve_fn(id={:?}, \ @@ -1128,7 +1123,7 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, parent: fn_decl_scope, var_parent: fn_decl_scope }; - visitor.visit_block(body); + visitor.visit_expr(body); // Restore context we had at the start. visitor.cx = outer_cx; @@ -1191,7 +1186,7 @@ impl<'a, 'v> Visitor<'v> for RegionResolutionVisitor<'a> { } fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, - b: &'v Block, s: Span, n: NodeId) { + b: &'v Expr, s: Span, n: NodeId) { resolve_fn(self, fk, fd, b, s, n); } fn visit_arm(&mut self, a: &Arm) { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index e6d960735299c..292d9592ceb0c 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -202,7 +202,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { } fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, fn_id: ast::NodeId) { + b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) { match fk { FnKind::ItemFn(_, generics, ..) => { self.visit_early_late(fn_id,decl, generics, |this| { @@ -403,7 +403,7 @@ fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, sha // Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning // if one of the label shadows a lifetime or another label. -fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) { +fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Expr) { struct GatherLabels<'a> { sess: &'a Session, scope: Scope<'a>, @@ -415,7 +415,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) { scope: ctxt.scope, labels_in_fn: &mut ctxt.labels_in_fn, }; - gather.visit_block(b); + gather.visit_expr(b); return; impl<'v, 'a> Visitor<'v> for GatherLabels<'a> { @@ -493,7 +493,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn add_scope_and_walk_fn<'b>(&mut self, fk: FnKind, fd: &hir::FnDecl, - fb: &'b hir::Block, + fb: &'b hir::Expr, _span: Span, fn_id: ast::NodeId) { @@ -516,7 +516,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { extract_labels(self, fb); self.with(FnScope { fn_id: fn_id, body_id: fb.id, s: self.scope }, - |_old_scope, this| this.visit_block(fb)) + |_old_scope, this| this.visit_expr(fb)) } fn with(&mut self, wrap_scope: ScopeChain, f: F) where diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index b2032e6a1bf9f..5ed628d7dcae5 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -190,7 +190,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, all_loans: &[Loan<'tcx>], fn_id: ast::NodeId, decl: &hir::FnDecl, - body: &hir::Block) { + body: &hir::Expr) { debug!("check_loans(body id={})", body.id); let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id); diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 763c012a8f8ab..8f2afa7f80822 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -42,7 +42,7 @@ mod move_error; pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, fn_id: NodeId, decl: &hir::FnDecl, - body: &hir::Block) + body: &hir::Expr) -> (Vec>, move_data::MoveData<'tcx>) { let mut glcx = GatherLoanCtxt { diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index cea9170da9ffd..836832de5b9c4 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -58,7 +58,7 @@ pub struct MoveDataParamEnv<'tcx> { pub fn borrowck_mir(bcx: &mut BorrowckCtxt, fk: FnKind, _decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, _sp: Span, id: ast::NodeId, attributes: &[ast::Attribute]) { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 2f74ea3e475b5..fb842f70a54a1 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -47,9 +47,7 @@ use syntax_pos::{MultiSpan, Span}; use errors::DiagnosticBuilder; use rustc::hir; -use rustc::hir::{FnDecl, Block}; -use rustc::hir::intravisit; -use rustc::hir::intravisit::{Visitor, FnKind}; +use rustc::hir::intravisit::{self, Visitor, FnKind}; pub mod check_loans; @@ -65,8 +63,8 @@ pub struct LoanDataFlowOperator; pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> { - fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, - b: &'v Block, s: Span, id: ast::NodeId) { + fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, + b: &'v hir::Expr, s: Span, id: ast::NodeId) { match fk { FnKind::ItemFn(..) | FnKind::Method(..) => { @@ -159,7 +157,7 @@ pub struct AnalysisData<'a, 'tcx: 'a> { fn borrowck_fn(this: &mut BorrowckCtxt, fk: FnKind, decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, sp: Span, id: ast::NodeId, attributes: &[ast::Attribute]) { @@ -200,7 +198,7 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, fk: FnKind, decl: &hir::FnDecl, cfg: &cfg::CFG, - body: &hir::Block, + body: &hir::Expr, sp: Span, id: ast::NodeId) -> AnalysisData<'a, 'tcx> diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index afc4ccef0cc0f..32bda5e11620a 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -656,7 +656,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> { cfg: &cfg::CFG, id_range: IdRange, decl: &hir::FnDecl, - body: &hir::Block) + body: &hir::Expr) -> FlowedMoveData<'a, 'tcx> { let mut dfcx_moves = DataFlowContext::new(tcx, diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 615aca90db8bf..e0e8a21591921 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -65,7 +65,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> { } fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, id: ast::NodeId) { + b: &'v hir::Expr, s: Span, id: ast::NodeId) { if let FnKind::Closure(..) = fk { span_bug!(s, "check_match: closure outside of function") } @@ -113,7 +113,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchVisitor<'a, 'tcx> { } fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, s: Span, n: ast::NodeId) { + b: &'v hir::Expr, s: Span, n: ast::NodeId) { intravisit::walk_fn(self, fk, fd, b, s, n); for input in &fd.inputs { diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 57a5400ecadf8..ee6c27655d68c 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -857,11 +857,10 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callee => signal!(e, CallOn(callee)), }; let (decl, result) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) { - (fn_like.decl(), &fn_like.body().expr) + (fn_like.decl(), fn_like.body()) } else { signal!(e, NonConstPath) }; - let result = result.as_ref().expect("const fn has no result expression"); assert_eq!(decl.inputs.len(), args.len()); let mut call_args = DefIdMap(); diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6551bad3bc92e..7e60c40220f84 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -455,8 +455,6 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { 1 => panic!("make_input should have provided valid inputs"), _ => early_error(sopts.error_format, "multiple input filenames provided"), } - - None } fn late_callback(&mut self, diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index b4ab9da92e9d0..ecbf28c1082f9 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -701,8 +701,8 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, mut out: W) -> io::Result<()> { let cfg = match code { - blocks::BlockCode(block) => cfg::CFG::new(tcx, &block), - blocks::FnLikeCode(fn_like) => cfg::CFG::new(tcx, &fn_like.body()), + blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr), + blocks::Code::FnLike(fn_like) => cfg::CFG::new(tcx, fn_like.body()), }; let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; let lcfg = LabelledCFG { @@ -717,12 +717,12 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, let r = dot::render(&lcfg, &mut out); return expand_err_details(r); } - blocks::BlockCode(_) => { + blocks::Code::Expr(_) => { tcx.sess.err("--pretty flowgraph with -Z flowgraph-print annotations requires \ fn-like node id."); return Ok(()); } - blocks::FnLikeCode(fn_like) => { + blocks::Code::FnLike(fn_like) => { let (bccx, analysis_data) = borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_like.to_fn_parts(), &cfg); @@ -990,8 +990,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) }); - let code = blocks::Code::from_node(node); - match code { + match blocks::Code::from_node(&tcx.map, nodeid) { Some(code) => { let variants = gather_flowgraph_variants(tcx.sess); diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index fea3de59520ca..e095bde18fd85 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -250,7 +250,7 @@ impl LateLintPass for NonSnakeCase { cx: &LateContext, fk: FnKind, _: &hir::FnDecl, - _: &hir::Block, + _: &hir::Expr, span: Span, id: ast::NodeId) { match fk { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 28dc71fd59bae..192d7be6774af 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -222,7 +222,7 @@ impl LateLintPass for UnsafeCode { cx: &LateContext, fk: FnKind, _: &hir::FnDecl, - _: &hir::Block, + _: &hir::Expr, span: Span, _: ast::NodeId) { match fk { @@ -812,7 +812,7 @@ impl LateLintPass for UnconditionalRecursion { cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl, - blk: &hir::Block, + blk: &hir::Expr, sp: Span, id: ast::NodeId) { let method = match fn_kind { diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index d3fd638d6b5ff..0668d362037dd 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -99,7 +99,7 @@ impl LateLintPass for UnusedMut { cx: &LateContext, _: FnKind, decl: &hir::FnDecl, - _: &hir::Block, + _: &hir::Expr, _: Span, _: ast::NodeId) { for a in &decl.inputs { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index b37dd8dd0a907..902798ec98006 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -156,7 +156,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, fn_id: ast::NodeId, arguments: A, return_ty: Ty<'gcx>, - ast_block: &'gcx hir::Block) + ast_body: &'gcx hir::Expr) -> (Mir<'tcx>, ScopeAuxiliaryVec) where A: Iterator, Option<&'gcx hir::Pat>)> { @@ -166,7 +166,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let span = tcx.map.span(fn_id); let mut builder = Builder::new(hir, span, arguments.len(), return_ty); - let body_id = ast_block.id; + let body_id = ast_body.id; let call_site_extent = tcx.region_maps.lookup_code_extent( CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id }); @@ -176,7 +176,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let mut block = START_BLOCK; unpack!(block = builder.in_scope(call_site_extent, block, |builder| { unpack!(block = builder.in_scope(arg_extent, block, |builder| { - builder.args_and_body(block, return_ty, &arguments, arg_extent, ast_block) + builder.args_and_body(block, &arguments, arg_extent, ast_body) })); // Attribute epilogue to function's closing brace let fn_end = Span { lo: span.hi, ..span }; @@ -310,10 +310,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn args_and_body(&mut self, mut block: BasicBlock, - return_ty: Ty<'tcx>, arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)], argument_extent: CodeExtent, - ast_block: &'gcx hir::Block) + ast_body: &'gcx hir::Expr) -> BlockAnd<()> { // Allocate locals for the function arguments @@ -342,12 +341,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(pattern) = pattern { let pattern = Pattern::from_hir(self.hir.tcx(), pattern); - scope = self.declare_bindings(scope, ast_block.span, &pattern); + scope = self.declare_bindings(scope, ast_body.span, &pattern); unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue)); } // Make sure we drop (parts of) the argument even when not matched on. - self.schedule_drop(pattern.as_ref().map_or(ast_block.span, |pat| pat.span), + self.schedule_drop(pattern.as_ref().map_or(ast_body.span, |pat| pat.span), argument_extent, &lvalue, ty); } @@ -357,13 +356,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.visibility_scope = visibility_scope; } - // FIXME(#32959): temporary hack for the issue at hand - let return_is_unit = return_ty.is_nil(); - // start the first basic block and translate the body - unpack!(block = self.ast_block(&Lvalue::Local(RETURN_POINTER), - return_is_unit, block, ast_block)); - - block.unit() + let body = self.hir.mirror(ast_body); + self.into(&Lvalue::Local(RETURN_POINTER), block, body) } fn get_unit_temp(&mut self) -> Lvalue<'tcx> { diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 0ffc59fe6bf45..af2f9adfc9a8c 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -209,7 +209,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> { fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl, - body: &'tcx hir::Block, + body: &'tcx hir::Expr, span: Span, id: ast::NodeId) { // fetch the fully liberated fn signature (that is, all bound diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index f23539e88f78d..7a93d4594ee99 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -134,7 +134,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { fn fn_like(&mut self, fk: FnKind, fd: &hir::FnDecl, - b: &hir::Block, + b: &hir::Expr, s: Span, fn_id: ast::NodeId) -> ConstQualif { @@ -265,7 +265,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, + b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) { self.fn_like(fk, fd, b, s, fn_id); diff --git a/src/librustc_passes/hir_stats.rs b/src/librustc_passes/hir_stats.rs index 84cf85e2fc4e6..417987d9664e0 100644 --- a/src/librustc_passes/hir_stats.rs +++ b/src/librustc_passes/hir_stats.rs @@ -164,7 +164,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, + b: &'v hir::Expr, s: Span, id: NodeId) { self.record("FnDecl", Id::None, fd); @@ -295,11 +295,10 @@ impl<'v> ast_visit::Visitor for StatCollector<'v> { fn visit_fn(&mut self, fk: ast_visit::FnKind, fd: &ast::FnDecl, - b: &ast::Block, s: Span, _: NodeId) { self.record("FnDecl", Id::None, fd); - ast_visit::walk_fn(self, fk, fd, b, s) + ast_visit::walk_fn(self, fk, fd, s) } fn visit_trait_item(&mut self, ti: &ast::TraitItem) { diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index e942707acd56b..e58cd89381933 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -54,7 +54,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> { self.with_context(Loop, |v| v.visit_block(&b)); } hir::ExprClosure(.., ref b, _) => { - self.with_context(Closure, |v| v.visit_block(&b)); + self.with_context(Closure, |v| v.visit_expr(&b)); } hir::ExprBreak(_) => self.require_loop("break", e.span), hir::ExprAgain(_) => self.require_loop("continue", e.span), diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs index c3ef5a72a2944..d55ce4c356384 100644 --- a/src/librustc_passes/rvalues.rs +++ b/src/librustc_passes/rvalues.rs @@ -35,7 +35,7 @@ impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for RvalueContext<'a, 'tcx> { fn visit_fn(&mut self, fk: intravisit::FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, + b: &'v hir::Expr, s: Span, fn_id: ast::NodeId) { // FIXME (@jroesch) change this to be an inference context diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0c7c1a55a6182..664efc27fbb53 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -596,7 +596,6 @@ impl<'a> Visitor for Resolver<'a> { fn visit_fn(&mut self, function_kind: FnKind, declaration: &FnDecl, - block: &Block, _: Span, node_id: NodeId) { let rib_kind = match function_kind { @@ -604,13 +603,45 @@ impl<'a> Visitor for Resolver<'a> { self.visit_generics(generics); ItemRibKind } - FnKind::Method(_, sig, _) => { + FnKind::Method(_, sig, _, _) => { self.visit_generics(&sig.generics); MethodRibKind(!sig.decl.has_self()) } - FnKind::Closure => ClosureRibKind(node_id), + FnKind::Closure(_) => ClosureRibKind(node_id), }; - self.resolve_function(rib_kind, declaration, block); + + // Create a value rib for the function. + self.value_ribs.push(Rib::new(rib_kind)); + + // Create a label rib for the function. + self.label_ribs.push(Rib::new(rib_kind)); + + // Add each argument to the rib. + let mut bindings_list = FxHashMap(); + for argument in &declaration.inputs { + self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); + + self.visit_ty(&argument.ty); + + debug!("(resolving function) recorded argument"); + } + visit::walk_fn_ret_ty(self, &declaration.output); + + // Resolve the function body. + match function_kind { + FnKind::ItemFn(.., body) | + FnKind::Method(.., body) => { + self.visit_block(body); + } + FnKind::Closure(body) => { + self.visit_expr(body); + } + }; + + debug!("(resolving function) leaving function"); + + self.label_ribs.pop(); + self.value_ribs.pop(); } } @@ -1856,36 +1887,6 @@ impl<'a> Resolver<'a> { self.value_ribs.pop(); } - fn resolve_function(&mut self, - rib_kind: RibKind<'a>, - declaration: &FnDecl, - block: &Block) { - // Create a value rib for the function. - self.value_ribs.push(Rib::new(rib_kind)); - - // Create a label rib for the function. - self.label_ribs.push(Rib::new(rib_kind)); - - // Add each argument to the rib. - let mut bindings_list = FxHashMap(); - for argument in &declaration.inputs { - self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list); - - self.visit_ty(&argument.ty); - - debug!("(resolving function) recorded argument"); - } - visit::walk_fn_ret_ty(self, &declaration.output); - - // Resolve the function body. - self.visit_block(block); - - debug!("(resolving function) leaving function"); - - self.label_ribs.pop(); - self.value_ribs.pop(); - } - fn resolve_trait_reference(&mut self, id: NodeId, trait_path: &Path, diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index db4788c3ceadb..7f7ef6d3ab7af 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1414,7 +1414,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } // walk the body - self.nest(ex.id, |v| v.visit_block(&body)); + self.nest(ex.id, |v| v.visit_expr(body)); } ast::ExprKind::ForLoop(ref pattern, ref subexpression, ref block, _) | ast::ExprKind::WhileLet(ref pattern, ref subexpression, ref block, _) => { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 15b29573ac4e8..ca630624cdb38 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -13,7 +13,7 @@ use rustc::hir::def::{Def, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::infer::{self, InferOk, TypeOrigin}; use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference}; -use check::{FnCtxt, Expectation}; +use check::{FnCtxt, Expectation, Diverges}; use util::nodemap::FxHashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; @@ -360,9 +360,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } true } -} -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_match(&self, expr: &'gcx hir::Expr, discrim: &'gcx hir::Expr, @@ -390,14 +388,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { discrim_ty = self.next_ty_var(); self.check_expr_has_type(discrim, discrim_ty); }; + let discrim_diverges = self.diverges.get(); + self.diverges.set(Diverges::Maybe); // Typecheck the patterns first, so that we get types for all the // bindings. - for arm in arms { + let all_arm_pats_diverge: Vec<_> = arms.iter().map(|arm| { + let mut all_pats_diverge = Diverges::WarnedAlways; for p in &arm.pats { + self.diverges.set(Diverges::Maybe); self.check_pat(&p, discrim_ty); + all_pats_diverge &= self.diverges.get(); } - } + all_pats_diverge + }).collect(); // Now typecheck the blocks. // @@ -410,6 +414,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // type in that case) let expected = expected.adjust_for_branches(self); let mut result_ty = self.next_diverging_ty_var(); + 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 @@ -422,11 +427,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => result_ty }; - for (i, arm) in arms.iter().enumerate() { + for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { if let Some(ref e) = arm.guard { + self.diverges.set(pats_diverge); self.check_expr_has_type(e, tcx.types.bool); } + + self.diverges.set(pats_diverge); 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; @@ -476,11 +485,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; } + // We won't diverge unless the discriminant or all arms diverge. + self.diverges.set(discrim_diverges | all_arms_diverge); + result_ty } -} -impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn check_pat_struct(&self, pat: &'gcx hir::Pat, path: &hir::Path, diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index d478f1092bd87..af834f3f84d47 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -23,7 +23,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &hir::Expr, _capture: hir::CaptureClause, decl: &'gcx hir::FnDecl, - body: &'gcx hir::Block, + body: &'gcx hir::Expr, expected: Expectation<'tcx>) -> Ty<'tcx> { debug!("check_expr_closure(expr={:?},expected={:?})", @@ -44,7 +44,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr: &hir::Expr, opt_kind: Option, decl: &'gcx hir::FnDecl, - body: &'gcx hir::Block, + body: &'gcx hir::Expr, expected_sig: Option>) -> Ty<'tcx> { let expr_def_id = self.tcx.map.local_def_id(expr.id); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f7e05f4777ecc..f6f585eb05f5f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -106,17 +106,18 @@ use util::common::{block_query, ErrorReported, indenter, loop_query}; use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap}; use std::cell::{Cell, Ref, RefCell}; +use std::cmp; use std::mem::replace; -use std::ops::Deref; +use std::ops::{self, Deref}; use syntax::abi::Abi; use syntax::ast; use syntax::attr; -use syntax::codemap::{self, Spanned}; +use syntax::codemap::{self, original_sp, Spanned}; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::parse::token::{self, InternedString, keywords}; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; -use syntax_pos::{self, Span}; +use syntax_pos::{self, BytePos, Span}; use rustc::hir::intravisit::{self, Visitor}; use rustc::hir::{self, PatKind}; @@ -351,6 +352,59 @@ impl UnsafetyState { } } +/// Whether a node ever exits normally or not. +/// Tracked semi-automatically (through type variables +/// marked as diverging), with some manual adjustments +/// for control-flow primitives (approximating a CFG). +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +enum Diverges { + /// Potentially unknown, some cases converge, + /// others require a CFG to determine them. + Maybe, + + /// Definitely known to diverge and therefore + /// not reach the next sibling or its parent. + Always, + + /// Same as `Always` but with a reachability + /// warning already emitted + WarnedAlways +} + +// Convenience impls for combinig `Diverges`. + +impl ops::BitAnd for Diverges { + type Output = Self; + fn bitand(self, other: Self) -> Self { + cmp::min(self, other) + } +} + +impl ops::BitOr for Diverges { + type Output = Self; + fn bitor(self, other: Self) -> Self { + cmp::max(self, other) + } +} + +impl ops::BitAndAssign for Diverges { + fn bitand_assign(&mut self, other: Self) { + *self = *self & other; + } +} + +impl ops::BitOrAssign for Diverges { + fn bitor_assign(&mut self, other: Self) { + *self = *self | other; + } +} + +impl Diverges { + fn always(self) -> bool { + self >= Diverges::Always + } +} + #[derive(Clone)] pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ast_ty_to_ty_cache: RefCell>>, @@ -371,6 +425,12 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ps: RefCell, + /// Whether the last checked node can ever exit. + diverges: Cell, + + /// Whether any child nodes have any type errors. + has_errors: Cell, + inh: &'a Inherited<'a, 'gcx, 'tcx>, } @@ -534,7 +594,7 @@ pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult { fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, decl: &'tcx hir::FnDecl, - body: &'tcx hir::Block, + body: &'tcx hir::Expr, fn_id: ast::NodeId, span: Span) { let raw_fty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(fn_id)).ty; @@ -558,7 +618,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body); fcx.select_all_obligations_and_apply_defaults(); - fcx.closure_analyze_fn(body); + fcx.closure_analyze(body); fcx.select_obligations_where_possible(); fcx.check_casts(); fcx.select_all_obligations_or_error(); // Casts can introduce new obligations. @@ -654,7 +714,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { // Don't descend into the bodies of nested closures fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl, - _: &'gcx hir::Block, _: Span, _: ast::NodeId) { } + _: &'gcx hir::Expr, _: Span, _: ast::NodeId) { } } /// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function @@ -669,7 +729,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fn_sig: &ty::FnSig<'tcx>, decl: &'gcx hir::FnDecl, fn_id: ast::NodeId, - body: &'gcx hir::Block) + body: &'gcx hir::Expr) -> FnCtxt<'a, 'gcx, 'tcx> { let mut fn_sig = fn_sig.clone(); @@ -709,18 +769,12 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.write_ty(input.id, arg_ty); } - visit.visit_block(body); + visit.visit_expr(body); } inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig); - // FIXME(aburka) do we need this special case? and should it be is_uninhabited? - let expected = if fcx.ret_ty.is_never() { - NoExpectation - } else { - ExpectHasType(fcx.ret_ty) - }; - fcx.check_block_with_expected(body, expected); + fcx.check_expr_coercable_to_type(body, fcx.ret_ty); fcx } @@ -1198,7 +1252,7 @@ fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, fcx.check_expr_coercable_to_type(expr, expected_type); fcx.select_all_obligations_and_apply_defaults(); - fcx.closure_analyze_const(expr); + fcx.closure_analyze(expr); fcx.select_obligations_where_possible(); fcx.check_casts(); fcx.select_all_obligations_or_error(); @@ -1497,6 +1551,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ret_ty: rty, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), + diverges: Cell::new(Diverges::Maybe), + has_errors: Cell::new(false), inh: inh, } } @@ -1513,6 +1569,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.sess.err_count() - self.err_count_on_creation } + /// Produce warning on the given node, if the current point in the + /// function is unreachable, and there hasn't been another warning. + fn warn_if_unreachable(&self, id: ast::NodeId, span: Span, kind: &str) { + if self.diverges.get() == Diverges::Always { + self.diverges.set(Diverges::WarnedAlways); + + self.tcx.sess.add_lint(lint::builtin::UNREACHABLE_CODE, + id, span, + format!("unreachable {}", kind)); + } + } + /// Resolves type variables in `ty` if possible. Unlike the infcx /// version (resolve_type_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort @@ -1583,6 +1651,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("write_ty({}, {:?}) in fcx {}", node_id, ty, self.tag()); self.tables.borrow_mut().node_types.insert(node_id, ty); + + if ty.references_error() { + self.has_errors.set(true); + } + + // FIXME(canndrew): This is_never should probably be an is_uninhabited + if ty.is_never() || self.type_var_diverges(ty) { + self.diverges.set(self.diverges.get() | Diverges::Always); + } } pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) { @@ -2518,21 +2595,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Check the arguments. // We do this in a pretty awful way: first we typecheck any arguments - // that are not anonymous functions, then we typecheck the anonymous - // functions. This is so that we have more information about the types - // of arguments when we typecheck the functions. This isn't really the - // right way to do this. - let xs = [false, true]; - let mut any_diverges = false; // has any of the arguments diverged? - let mut warned = false; // have we already warned about unreachable code? - for check_blocks in &xs { - let check_blocks = *check_blocks; - debug!("check_blocks={}", check_blocks); + // that are not closures, then we typecheck the closures. This is so + // that we have more information about the types of arguments when we + // typecheck the functions. This isn't really the right way to do this. + for &check_closures in &[false, true] { + debug!("check_closures={}", check_closures); // More awful hacks: before we check argument types, try to do // an "opportunistic" vtable resolution of any trait bounds on // the call. This helps coercions. - if check_blocks { + if check_closures { self.select_obligations_where_possible(); } @@ -2547,61 +2619,43 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { supplied_arg_count }; for (i, arg) in args.iter().take(t).enumerate() { - if any_diverges && !warned { - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - arg.id, - arg.span, - "unreachable expression".to_string()); - warned = true; + // Warn only for the first loop (the "no closures" one). + // Closure arguments themselves can't be diverging, but + // a previous argument can, e.g. `foo(panic!(), || {})`. + if !check_closures { + self.warn_if_unreachable(arg.id, arg.span, "expression"); } - let is_block = match arg.node { + + let is_closure = match arg.node { hir::ExprClosure(..) => true, _ => false }; - if is_block == check_blocks { - debug!("checking the argument"); - let formal_ty = formal_tys[i]; + if is_closure != check_closures { + continue; + } - // The special-cased logic below has three functions: - // 1. Provide as good of an expected type as possible. - let expected = expected_arg_tys.get(i).map(|&ty| { - Expectation::rvalue_hint(self, ty) - }); + debug!("checking the argument"); + let formal_ty = formal_tys[i]; - let checked_ty = self.check_expr_with_expectation(&arg, - expected.unwrap_or(ExpectHasType(formal_ty))); - // 2. Coerce to the most detailed type that could be coerced - // to, which is `expected_ty` if `rvalue_hint` returns an - // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. - let coerce_ty = expected.and_then(|e| e.only_has_type(self)); - self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty)); - - // 3. Relate the expected type and the formal one, - // if the expected type was used for the coercion. - coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty)); - } + // The special-cased logic below has three functions: + // 1. Provide as good of an expected type as possible. + let expected = expected_arg_tys.get(i).map(|&ty| { + Expectation::rvalue_hint(self, ty) + }); - if let Some(&arg_ty) = self.tables.borrow().node_types.get(&arg.id) { - // FIXME(canndrew): This is_never should probably be an is_uninhabited - any_diverges = any_diverges || - self.type_var_diverges(arg_ty) || - arg_ty.is_never(); - } - } - if any_diverges && !warned { - let parent = self.tcx.map.get_parent_node(args[0].id); - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - parent, - sp, - "unreachable call".to_string()); - warned = true; + let checked_ty = self.check_expr_with_expectation(&arg, + expected.unwrap_or(ExpectHasType(formal_ty))); + // 2. Coerce to the most detailed type that could be coerced + // to, which is `expected_ty` if `rvalue_hint` returns an + // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. + let coerce_ty = expected.and_then(|e| e.only_has_type(self)); + self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty)); + + // 3. Relate the expected type and the formal one, + // if the expected type was used for the coercion. + coerce_ty.map(|ty| self.demand_suptype(arg.span, formal_ty, ty)); } - } // We also need to make sure we at least write the ty of the other @@ -2852,18 +2906,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { sp: Span, expected: Expectation<'tcx>) -> Ty<'tcx> { let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool); + let cond_diverges = self.diverges.get(); + self.diverges.set(Diverges::Maybe); let expected = expected.adjust_for_branches(self); let then_ty = self.check_block_with_expected(then_blk, expected); + let then_diverges = self.diverges.get(); + self.diverges.set(Diverges::Maybe); let unit = self.tcx.mk_nil(); let (origin, expected, found, result) = if let Some(else_expr) = opt_else_expr { let else_ty = self.check_expr_with_expectation(else_expr, expected); - let origin = TypeOrigin::IfExpression(sp); + let else_diverges = self.diverges.get(); // Only try to coerce-unify if we have a then expression // to assign coercions to, otherwise it's () or diverging. + let origin = TypeOrigin::IfExpression(sp); let result = if let Some(ref then) = then_blk.expr { let res = self.try_find_coercion_lub(origin, || Some(&**then), then_ty, else_expr, else_ty); @@ -2889,8 +2948,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) }) }; + + // We won't diverge unless both branches do (or the condition does). + self.diverges.set(cond_diverges | then_diverges & else_diverges); + (origin, then_ty, else_ty, result) } else { + // If the condition is false we can't diverge. + self.diverges.set(cond_diverges); + let origin = TypeOrigin::IfExpressionWithNoElse(sp); (origin, unit, then_ty, self.eq_types(true, origin, unit, then_ty) @@ -3352,10 +3418,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lvalue_pref: LvaluePreference) -> Ty<'tcx> { debug!(">> typechecking: expr={:?} expected={:?}", expr, expected); + + // Warn for expressions after diverging siblings. + self.warn_if_unreachable(expr.id, expr.span, "expression"); + + // Hide the outer diverging and has_errors flags. + let old_diverges = self.diverges.get(); + let old_has_errors = self.has_errors.get(); + self.diverges.set(Diverges::Maybe); + self.has_errors.set(false); + let ty = self.check_expr_kind(expr, expected, lvalue_pref); + // Warn for non-block expressions with diverging children. + match expr.node { + hir::ExprBlock(_) | + hir::ExprLoop(..) | hir::ExprWhile(..) | + hir::ExprIf(..) | hir::ExprMatch(..) => {} + + _ => self.warn_if_unreachable(expr.id, expr.span, "expression") + } + + // Record the type, which applies it effects. + // We need to do this after the warning above, so that + // we don't warn for the diverging expression itself. self.write_ty(expr.id, ty); + // Combine the diverging and has_error flags. + self.diverges.set(self.diverges.get() | old_diverges); + self.has_errors.set(self.has_errors.get() | old_has_errors); + debug!("type of expr({}) {} is...", expr.id, pprust::expr_to_string(expr)); debug!("... {:?}, expected is {:?}", @@ -3580,22 +3672,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr.span, expected) } hir::ExprWhile(ref cond, ref body, _) => { - let cond_ty = self.check_expr_has_type(&cond, tcx.types.bool); + self.check_expr_has_type(&cond, tcx.types.bool); + let cond_diverging = self.diverges.get(); self.check_block_no_value(&body); - let body_ty = self.node_ty(body.id); - if cond_ty.references_error() || body_ty.references_error() { + + // We may never reach the body so it diverging means nothing. + self.diverges.set(cond_diverging); + + if self.has_errors.get() { tcx.types.err - } - else { + } else { tcx.mk_nil() } } hir::ExprLoop(ref body, _) => { self.check_block_no_value(&body); - if !may_break(tcx, expr.id, &body) { - tcx.types.never - } else { + if may_break(tcx, expr.id, &body) { + // No way to know whether it's diverging because + // of a `break` or an outer `break` or `return. + self.diverges.set(Diverges::Maybe); + tcx.mk_nil() + } else { + tcx.types.never } } hir::ExprMatch(ref discrim, ref arms, match_src) => { @@ -3928,55 +4027,66 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) { - let node_id; - let mut saw_bot = false; - let mut saw_err = false; + // Don't do all the complex logic below for DeclItem. match stmt.node { - hir::StmtDecl(ref decl, id) => { - node_id = id; - match decl.node { - hir::DeclLocal(ref l) => { - self.check_decl_local(&l); - let l_t = self.node_ty(l.id); - saw_bot = saw_bot || self.type_var_diverges(l_t); - saw_err = saw_err || l_t.references_error(); - } - hir::DeclItem(_) => {/* ignore for now */ } + hir::StmtDecl(ref decl, id) => { + match decl.node { + hir::DeclLocal(_) => {} + hir::DeclItem(_) => { + self.write_nil(id); + return; + } + } } - } - hir::StmtExpr(ref expr, id) => { - node_id = id; - // Check with expected type of () - let ty = self.check_expr_has_type(&expr, self.tcx.mk_nil()); - saw_bot = saw_bot || self.type_var_diverges(ty); - saw_err = saw_err || ty.references_error(); - } - hir::StmtSemi(ref expr, id) => { - node_id = id; - let ty = self.check_expr(&expr); - saw_bot |= self.type_var_diverges(ty); - saw_err |= ty.references_error(); - } + hir::StmtExpr(..) | hir::StmtSemi(..) => {} } - if saw_bot { - self.write_ty(node_id, self.next_diverging_ty_var()); - } - else if saw_err { + + self.warn_if_unreachable(stmt.node.id(), stmt.span, "statement"); + + // Hide the outer diverging and has_errors flags. + let old_diverges = self.diverges.get(); + let old_has_errors = self.has_errors.get(); + self.diverges.set(Diverges::Maybe); + self.has_errors.set(false); + + let node_id = match stmt.node { + hir::StmtDecl(ref decl, id) => { + match decl.node { + hir::DeclLocal(ref l) => { + self.check_decl_local(&l); + } + hir::DeclItem(_) => {/* ignore for now */ } + } + id + } + hir::StmtExpr(ref expr, id) => { + // Check with expected type of () + self.check_expr_has_type(&expr, self.tcx.mk_nil()); + id + } + hir::StmtSemi(ref expr, id) => { + self.check_expr(&expr); + id + } + }; + + if self.has_errors.get() { self.write_error(node_id); - } - else { + } else if self.diverges.get().always() { + self.write_ty(node_id, self.next_diverging_ty_var()); + } else { self.write_nil(node_id); } + + // Combine the diverging and has_error flags. + self.diverges.set(self.diverges.get() | old_diverges); + self.has_errors.set(self.has_errors.get() | old_has_errors); } pub fn check_block_no_value(&self, blk: &'gcx hir::Block) { - let blkty = self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil())); - if blkty.references_error() { - self.write_error(blk.id); - } else { - let nilty = self.tcx.mk_nil(); - self.demand_suptype(blk.span, nilty, blkty); - } + let unit = self.tcx.mk_nil(); + let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); + self.demand_suptype(blk.span, unit, ty); } fn check_block_with_expected(&self, @@ -3988,72 +4098,81 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { replace(&mut *fcx_ps, unsafety_state) }; - let mut warned = false; - let mut any_diverges = false; - let mut any_err = false; for s in &blk.stmts { self.check_stmt(s); - let s_id = s.node.id(); - let s_ty = self.node_ty(s_id); - if any_diverges && !warned && match s.node { - hir::StmtDecl(ref decl, _) => { - match decl.node { - hir::DeclLocal(_) => true, - _ => false, + } + + let mut ty = match blk.expr { + Some(ref e) => self.check_expr_with_expectation(e, expected), + None => self.tcx.mk_nil() + }; + + if self.diverges.get().always() { + if let ExpectHasType(ety) = expected { + // Avoid forcing a type (only `!` for now) in unreachable code. + // FIXME(aburka) do we need this special case? and should it be is_uninhabited? + if !ety.is_never() { + if let Some(ref e) = blk.expr { + // Coerce the tail expression to the right type. + self.demand_coerce(e, ty, ety); } } - hir::StmtExpr(..) | hir::StmtSemi(..) => true, - } { - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - s_id, - s.span, - "unreachable statement".to_string()); - warned = true; } - // FIXME(canndrew): This is_never should probably be an is_uninhabited - any_diverges = any_diverges || - self.type_var_diverges(s_ty) || - s_ty.is_never(); - any_err = any_err || s_ty.references_error(); - } - let ty = match blk.expr { - None => if any_err { - self.tcx.types.err - } else if any_diverges { - self.next_diverging_ty_var() + + ty = self.next_diverging_ty_var(); + } else if let ExpectHasType(ety) = expected { + if let Some(ref e) = blk.expr { + // Coerce the tail expression to the right type. + self.demand_coerce(e, ty, ety); } else { - self.tcx.mk_nil() - }, - Some(ref e) => { - if any_diverges && !warned { - self.tcx - .sess - .add_lint(lint::builtin::UNREACHABLE_CODE, - e.id, - e.span, - "unreachable expression".to_string()); - } - let ety = match expected { - ExpectHasType(ety) => { - self.check_expr_coercable_to_type(&e, ety); - ety - } - _ => { - self.check_expr_with_expectation(&e, expected) - } - }; + // We're not diverging and there's an expected type, which, + // in case it's not `()`, could result in an error higher-up. + // We have a chance to error here early and be more helpful. + let origin = TypeOrigin::Misc(blk.span); + let trace = TypeTrace::types(origin, false, ty, ety); + match self.sub_types(false, origin, ty, ety) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }, + Err(err) => { + let mut err = self.report_and_explain_type_error(trace, &err); + + // Be helpful when the user wrote `{... expr;}` and + // taking the `;` off is enough to fix the error. + let mut extra_semi = None; + if let Some(stmt) = blk.stmts.last() { + if let hir::StmtSemi(ref e, _) = stmt.node { + if self.can_sub_types(self.node_ty(e.id), ety).is_ok() { + extra_semi = Some(stmt); + } + } + } + if let Some(last_stmt) = extra_semi { + let original_span = original_sp(self.tcx.sess.codemap(), + last_stmt.span, blk.span); + let span_semi = Span { + lo: original_span.hi - BytePos(1), + hi: original_span.hi, + expn_id: original_span.expn_id + }; + err.span_help(span_semi, "consider removing this semicolon:"); + } - if any_err { - self.tcx.types.err - } else if any_diverges { - self.next_diverging_ty_var() - } else { - ety + err.emit(); + } } } - }; + + // We already applied the type (and potentially errored), + // use the expected type to avoid further errors out. + ty = ety; + } + + if self.has_errors.get() || ty.references_error() { + ty = self.tcx.types.err + } + self.write_ty(blk.id, ty); *self.ps.borrow_mut() = prev; diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index 411bd7e7b5ca1..8b4975b7e3a2f 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -75,8 +75,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match BinOpCategory::from(op) { BinOpCategory::Shortcircuit => { // && and || are a simple case. + let lhs_diverges = self.diverges.get(); self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty); self.check_expr_coercable_to_type(rhs_expr, tcx.mk_bool()); + + // Depending on the LHS' value, the RHS can never execute. + self.diverges.set(lhs_diverges); + tcx.mk_bool() } _ => { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 6f6538254c46b..d4e5e9a5bb355 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -142,13 +142,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn regionck_fn(&self, fn_id: ast::NodeId, decl: &hir::FnDecl, - blk: &hir::Block) { + body: &hir::Expr) { debug!("regionck_fn(id={})", fn_id); - let mut rcx = RegionCtxt::new(self, RepeatingScope(blk.id), blk.id, Subject(fn_id)); + let mut rcx = RegionCtxt::new(self, RepeatingScope(body.id), body.id, Subject(fn_id)); if self.err_count_since_creation() == 0 { // regionck assumes typeck succeeded - rcx.visit_fn_body(fn_id, decl, blk, self.tcx.map.span(fn_id)); + rcx.visit_fn_body(fn_id, decl, body, self.tcx.map.span(fn_id)); } rcx.free_region_map.relate_free_regions_from_predicates( @@ -268,7 +268,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn visit_fn_body(&mut self, id: ast::NodeId, // the id of the fn itself fn_decl: &hir::FnDecl, - body: &hir::Block, + body: &hir::Expr, span: Span) { // When we enter a function, we can derive @@ -305,7 +305,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { self.relate_free_regions(&fn_sig_tys[..], body.id, span); self.link_fn_args(self.tcx.region_maps.node_extent(body.id), &fn_decl.inputs[..]); - self.visit_block(body); + self.visit_expr(body); self.visit_region_obligations(body.id); let call_site_scope = self.call_site_scope.unwrap(); @@ -480,7 +480,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { // regions, until regionck, as described in #3238. fn visit_fn(&mut self, _fk: intravisit::FnKind<'v>, fd: &'v hir::FnDecl, - b: &'v hir::Block, span: Span, id: ast::NodeId) { + b: &'v hir::Expr, span: Span, id: ast::NodeId) { self.visit_fn_body(id, fd, b, span) } @@ -825,7 +825,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn check_expr_fn_block(&mut self, expr: &hir::Expr, - body: &hir::Block) { + body: &hir::Expr) { let repeating_scope = self.set_repeating_scope(body.id); intravisit::walk_expr(self, expr); self.set_repeating_scope(repeating_scope); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index aa221c33b5ddb..2fea86cb21207 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -57,18 +57,7 @@ use rustc::util::nodemap::NodeMap; // PUBLIC ENTRY POINTS impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn closure_analyze_fn(&self, body: &hir::Block) { - let mut seed = SeedBorrowKind::new(self); - seed.visit_block(body); - - let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds); - adjust.visit_block(body); - - // it's our job to process these. - assert!(self.deferred_call_resolutions.borrow().is_empty()); - } - - pub fn closure_analyze_const(&self, body: &hir::Expr) { + pub fn closure_analyze(&self, body: &hir::Expr) { let mut seed = SeedBorrowKind::new(self); seed.visit_expr(body); @@ -110,7 +99,7 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { fn check_closure(&mut self, expr: &hir::Expr, capture_clause: hir::CaptureClause, - _body: &hir::Block) + _body: &hir::Expr) { let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id); if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) { @@ -164,7 +153,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { id: ast::NodeId, span: Span, decl: &hir::FnDecl, - body: &hir::Block) { + body: &hir::Expr) { /*! * Analysis starting point. */ @@ -497,7 +486,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for AdjustBorrowKind<'a, 'gcx, 'tcx> { fn visit_fn(&mut self, fn_kind: intravisit::FnKind<'v>, decl: &'v hir::FnDecl, - body: &'v hir::Block, + body: &'v hir::Expr, span: Span, id: ast::NodeId) { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 741f327ac99e1..2c1a9a7b17748 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -347,7 +347,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { fn check_item_fn(&mut self, item: &hir::Item, - body: &hir::Block) + body: &hir::Expr) { self.for_item(item).with_fcx(|fcx, this| { let free_substs = &fcx.parameter_environment.free_substs; diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 5ef3e8699602b..9f3214a0d813e 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -49,11 +49,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn resolve_type_vars_in_fn(&self, decl: &hir::FnDecl, - blk: &hir::Block, + body: &hir::Expr, item_id: ast::NodeId) { assert_eq!(self.writeback_errors.get(), false); let mut wbcx = WritebackCx::new(self); - wbcx.visit_block(blk); + wbcx.visit_expr(body); for arg in &decl.inputs { wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id); wbcx.visit_pat(&arg.pat); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9751ad6aa43c3..f5cd089e923d7 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1017,10 +1017,10 @@ pub enum ExprKind { Loop(P, Option), /// A `match` block. Match(P, Vec), - /// A closure (for example, `move |a, b, c| {a + b + c}`) + /// A closure (for example, `move |a, b, c| a + b + c`) /// /// The final span is the span of the argument block `|...|` - Closure(CaptureBy, P, P, Span), + Closure(CaptureBy, P, P, Span), /// A block (`{ ... }`) Block(P), diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 37bd83be7b4d4..c3e28cbb006a0 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -198,17 +198,13 @@ pub trait AstBuilder { fn lambda_fn_decl(&self, span: Span, fn_decl: P, - blk: P, + body: P, fn_decl_span: Span) -> P; - fn lambda(&self, span: Span, ids: Vec, blk: P) -> P; - fn lambda0(&self, span: Span, blk: P) -> P; - fn lambda1(&self, span: Span, blk: P, ident: ast::Ident) -> P; - - fn lambda_expr(&self, span: Span, ids: Vec , blk: P) -> P; - fn lambda_expr_0(&self, span: Span, expr: P) -> P; - fn lambda_expr_1(&self, span: Span, expr: P, ident: ast::Ident) -> P; + fn lambda(&self, span: Span, ids: Vec, body: P) -> P; + fn lambda0(&self, span: Span, body: P) -> P; + fn lambda1(&self, span: Span, body: P, ident: ast::Ident) -> P; fn lambda_stmts(&self, span: Span, ids: Vec, blk: Vec) -> P; @@ -940,19 +936,19 @@ impl<'a> AstBuilder for ExtCtxt<'a> { fn lambda_fn_decl(&self, span: Span, fn_decl: P, - blk: P, + body: P, fn_decl_span: Span) // span of the `|...|` part -> P { self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref, fn_decl, - blk, + body, fn_decl_span)) } fn lambda(&self, span: Span, ids: Vec, - blk: P) + body: P) -> P { let fn_decl = self.fn_decl( ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(), @@ -962,26 +958,15 @@ impl<'a> AstBuilder for ExtCtxt<'a> { // part of the lambda, but it probably (maybe?) corresponds to // the entire lambda body. Probably we should extend the API // here, but that's not entirely clear. - self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref, fn_decl, blk, span)) - } - - fn lambda0(&self, span: Span, blk: P) -> P { - self.lambda(span, Vec::new(), blk) + self.expr(span, ast::ExprKind::Closure(ast::CaptureBy::Ref, fn_decl, body, span)) } - fn lambda1(&self, span: Span, blk: P, ident: ast::Ident) -> P { - self.lambda(span, vec![ident], blk) + fn lambda0(&self, span: Span, body: P) -> P { + self.lambda(span, Vec::new(), body) } - fn lambda_expr(&self, span: Span, ids: Vec, - expr: P) -> P { - self.lambda(span, ids, self.block_expr(expr)) - } - fn lambda_expr_0(&self, span: Span, expr: P) -> P { - self.lambda0(span, self.block_expr(expr)) - } - fn lambda_expr_1(&self, span: Span, expr: P, ident: ast::Ident) -> P { - self.lambda1(span, self.block_expr(expr), ident) + fn lambda1(&self, span: Span, body: P, ident: ast::Ident) -> P { + self.lambda(span, vec![ident], body) } fn lambda_stmts(&self, @@ -989,14 +974,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> { ids: Vec, stmts: Vec) -> P { - self.lambda(span, ids, self.block(span, stmts)) + self.lambda(span, ids, self.expr_block(self.block(span, stmts))) } fn lambda_stmts_0(&self, span: Span, stmts: Vec) -> P { - self.lambda0(span, self.block(span, stmts)) + self.lambda0(span, self.expr_block(self.block(span, stmts))) } fn lambda_stmts_1(&self, span: Span, stmts: Vec, ident: ast::Ident) -> P { - self.lambda1(span, self.block(span, stmts), ident) + self.lambda1(span, self.expr_block(self.block(span, stmts)), ident) } fn arg(&self, span: Span, ident: ast::Ident, ty: P) -> ast::Arg { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a6493872338fa..f51822ec2fe80 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1228,12 +1228,11 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { fn visit_fn(&mut self, fn_kind: FnKind, fn_decl: &ast::FnDecl, - block: &ast::Block, span: Span, _node_id: NodeId) { // check for const fn declarations match fn_kind { - FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _) => { + FnKind::ItemFn(_, _, _, Spanned { node: ast::Constness::Const, .. }, _, _, _) => { gate_feature_post!(&self, const_fn, span, "const fn is unstable"); } _ => { @@ -1245,13 +1244,13 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { } match fn_kind { - FnKind::ItemFn(_, _, _, _, abi, _) | - FnKind::Method(_, &ast::MethodSig { abi, .. }, _) => { + FnKind::ItemFn(_, _, _, _, abi, _, _) | + FnKind::Method(_, &ast::MethodSig { abi, .. }, _, _) => { self.check_abi(abi, span); } _ => {} } - visit::walk_fn(self, fn_kind, fn_decl, block, span); + visit::walk_fn(self, fn_kind, fn_decl, span); } fn visit_trait_item(&mut self, ti: &ast::TraitItem) { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 1deeaf422316c..2e62f23578d81 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1201,7 +1201,7 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::Closure(capture_clause, decl, body, span) => { ExprKind::Closure(capture_clause, folder.fold_fn_decl(decl), - folder.fold_block(body), + folder.fold_expr(body), folder.new_span(span)) } ExprKind::Block(blk) => ExprKind::Block(folder.fold_block(blk)), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b670a7384739b..7d15334ff9f4e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3162,25 +3162,12 @@ impl<'a> Parser<'a> { let decl = self.parse_fn_block_decl()?; let decl_hi = self.prev_span.hi; let body = match decl.output { - FunctionRetTy::Default(_) => { - // If no explicit return type is given, parse any - // expr and wrap it up in a dummy block: - let body_expr = self.parse_expr()?; - P(ast::Block { - id: ast::DUMMY_NODE_ID, - span: body_expr.span, - stmts: vec![Stmt { - span: body_expr.span, - node: StmtKind::Expr(body_expr), - id: ast::DUMMY_NODE_ID, - }], - rules: BlockCheckMode::Default, - }) - } + FunctionRetTy::Default(_) => self.parse_expr()?, _ => { // If an explicit return type is given, require a // block to appear (RFC 968). - self.parse_block()? + let body_lo = self.span.lo; + self.parse_block_expr(body_lo, BlockCheckMode::Default, ThinVec::new())? } }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 7352792a8a252..203c19285ac2c 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2128,26 +2128,8 @@ impl<'a> State<'a> { try!(self.print_fn_block_args(&decl)); try!(space(&mut self.s)); - - let default_return = match decl.output { - ast::FunctionRetTy::Default(..) => true, - _ => false - }; - - match body.stmts.last().map(|stmt| &stmt.node) { - Some(&ast::StmtKind::Expr(ref i_expr)) if default_return && - body.stmts.len() == 1 => { - // we extract the block, so as not to create another set of boxes - if let ast::ExprKind::Block(ref blk) = i_expr.node { - try!(self.print_block_unclosed_with_attrs(&blk, &i_expr.attrs)); - } else { - // this is a bare expression - try!(self.print_expr(&i_expr)); - try!(self.end()); // need to close a box - } - } - _ => try!(self.print_block_unclosed(&body)), - } + try!(self.print_expr(body)); + try!(self.end()); // need to close a box // a box will be closed by print_expr, but we didn't want an overall // wrapper so we closed the corresponding opening. so create an diff --git a/src/libsyntax/util/node_count.rs b/src/libsyntax/util/node_count.rs index 14244bbdddf28..a1f07381db705 100644 --- a/src/libsyntax/util/node_count.rs +++ b/src/libsyntax/util/node_count.rs @@ -75,9 +75,9 @@ impl Visitor for NodeCounter { self.count += 1; walk_generics(self, g) } - fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, b: &Block, s: Span, _: NodeId) { + fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, s: Span, _: NodeId) { self.count += 1; - walk_fn(self, fk, fd, b, s) + walk_fn(self, fk, fd, s) } fn visit_trait_item(&mut self, ti: &TraitItem) { self.count += 1; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 7fb3e5c6bee1d..7c1ff617ab64d 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -31,13 +31,13 @@ use codemap::Spanned; #[derive(Copy, Clone, PartialEq, Eq)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() - ItemFn(Ident, &'a Generics, Unsafety, Spanned, Abi, &'a Visibility), + ItemFn(Ident, &'a Generics, Unsafety, Spanned, Abi, &'a Visibility, &'a Block), /// fn foo(&self) - Method(Ident, &'a MethodSig, Option<&'a Visibility>), + Method(Ident, &'a MethodSig, Option<&'a Visibility>, &'a Block), - /// |x, y| {} - Closure, + /// |x, y| body + Closure(&'a Expr), } /// Each method of the Visitor trait is a hook to be potentially @@ -68,8 +68,8 @@ pub trait Visitor: Sized { fn visit_expr_post(&mut self, _ex: &Expr) { } fn visit_ty(&mut self, t: &Ty) { walk_ty(self, t) } fn visit_generics(&mut self, g: &Generics) { walk_generics(self, g) } - fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, b: &Block, s: Span, _: NodeId) { - walk_fn(self, fk, fd, b, s) + fn visit_fn(&mut self, fk: FnKind, fd: &FnDecl, s: Span, _: NodeId) { + walk_fn(self, fk, fd, s) } fn visit_trait_item(&mut self, ti: &TraitItem) { walk_trait_item(self, ti) } fn visit_impl_item(&mut self, ii: &ImplItem) { walk_impl_item(self, ii) } @@ -246,9 +246,8 @@ pub fn walk_item(visitor: &mut V, item: &Item) { } ItemKind::Fn(ref declaration, unsafety, constness, abi, ref generics, ref body) => { visitor.visit_fn(FnKind::ItemFn(item.ident, generics, unsafety, - constness, abi, &item.vis), + constness, abi, &item.vis, body), declaration, - body, item.span, item.id) } @@ -519,26 +518,27 @@ pub fn walk_fn_decl(visitor: &mut V, function_declaration: &FnDecl) visitor.visit_fn_ret_ty(&function_declaration.output) } -pub fn walk_fn_kind(visitor: &mut V, function_kind: FnKind) { - match function_kind { - FnKind::ItemFn(_, generics, _, _, _, _) => { +pub fn walk_fn(visitor: &mut V, kind: FnKind, declaration: &FnDecl, _span: Span) + where V: Visitor, +{ + match kind { + FnKind::ItemFn(_, generics, _, _, _, _, body) => { visitor.visit_generics(generics); + walk_fn_decl(visitor, declaration); + visitor.visit_block(body); } - FnKind::Method(_, ref sig, _) => { + FnKind::Method(_, ref sig, _, body) => { visitor.visit_generics(&sig.generics); + walk_fn_decl(visitor, declaration); + visitor.visit_block(body); + } + FnKind::Closure(body) => { + walk_fn_decl(visitor, declaration); + visitor.visit_expr(body); } - FnKind::Closure => {} } } -pub fn walk_fn(visitor: &mut V, kind: FnKind, declaration: &FnDecl, body: &Block, _span: Span) - where V: Visitor, -{ - walk_fn_kind(visitor, kind); - walk_fn_decl(visitor, declaration); - visitor.visit_block(body) -} - pub fn walk_trait_item(visitor: &mut V, trait_item: &TraitItem) { visitor.visit_ident(trait_item.span, trait_item.ident); walk_list!(visitor, visit_attribute, &trait_item.attrs); @@ -552,8 +552,8 @@ pub fn walk_trait_item(visitor: &mut V, trait_item: &TraitItem) { walk_fn_decl(visitor, &sig.decl); } TraitItemKind::Method(ref sig, Some(ref body)) => { - visitor.visit_fn(FnKind::Method(trait_item.ident, sig, None), &sig.decl, - body, trait_item.span, trait_item.id); + visitor.visit_fn(FnKind::Method(trait_item.ident, sig, None, body), + &sig.decl, trait_item.span, trait_item.id); } TraitItemKind::Type(ref bounds, ref default) => { walk_list!(visitor, visit_ty_param_bound, bounds); @@ -575,8 +575,8 @@ pub fn walk_impl_item(visitor: &mut V, impl_item: &ImplItem) { visitor.visit_expr(expr); } ImplItemKind::Method(ref sig, ref body) => { - visitor.visit_fn(FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis)), &sig.decl, - body, impl_item.span, impl_item.id); + visitor.visit_fn(FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis), body), + &sig.decl, impl_item.span, impl_item.id); } ImplItemKind::Type(ref ty) => { visitor.visit_ty(ty); @@ -711,9 +711,8 @@ pub fn walk_expr(visitor: &mut V, expression: &Expr) { walk_list!(visitor, visit_arm, arms); } ExprKind::Closure(_, ref function_declaration, ref body, _decl_span) => { - visitor.visit_fn(FnKind::Closure, + visitor.visit_fn(FnKind::Closure(body), function_declaration, - body, expression.span, expression.id) } diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 10db56d46f6df..dc1f7b4e6201e 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -133,7 +133,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, cx.ident_of("read_struct"), vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()), cx.expr_usize(trait_span, nfields), - cx.lambda_expr_1(trait_span, result, blkarg)]) + cx.lambda1(trait_span, result, blkarg)]) } StaticEnum(_, ref fields) => { let variant = cx.ident_of("i"); @@ -165,7 +165,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, let result = cx.expr_ok(trait_span, cx.expr_match(trait_span, cx.expr_ident(trait_span, variant), arms)); - let lambda = cx.lambda_expr(trait_span, vec![blkarg, variant], result); + let lambda = cx.lambda(trait_span, vec![blkarg, variant], result); let variant_vec = cx.expr_vec(trait_span, variants); let variant_vec = cx.expr_addr_of(trait_span, variant_vec); let result = cx.expr_method_call(trait_span, @@ -176,7 +176,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, decoder, cx.ident_of("read_enum"), vec![cx.expr_str(trait_span, substr.type_ident.name.as_str()), - cx.lambda_expr_1(trait_span, result, blkarg)]) + cx.lambda1(trait_span, result, blkarg)]) } _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"), }; diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index 640296d7f06fc..ebbddc6e48084 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -197,7 +197,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, }; let self_ref = cx.expr_addr_of(span, self_.clone()); let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); - let lambda = cx.lambda_expr_1(span, enc, blkarg); + let lambda = cx.lambda1(span, enc, blkarg); let call = cx.expr_method_call(span, blkencoder.clone(), emit_struct_field, @@ -246,7 +246,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, let self_ref = cx.expr_addr_of(span, self_.clone()); let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]); - let lambda = cx.lambda_expr_1(span, enc, blkarg); + let lambda = cx.lambda1(span, enc, blkarg); let call = cx.expr_method_call(span, blkencoder.clone(), emit_variant_arg, @@ -273,7 +273,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, cx.expr_usize(trait_span, idx), cx.expr_usize(trait_span, fields.len()), blk]); - let blk = cx.lambda_expr_1(trait_span, call, blkarg); + let blk = cx.lambda1(trait_span, call, blkarg); let ret = cx.expr_method_call(trait_span, encoder, cx.ident_of("emit_enum"), diff --git a/src/test/compile-fail/E0138.rs b/src/test/compile-fail/E0138.rs index d4630d7c2effb..11d90658ab26a 100644 --- a/src/test/compile-fail/E0138.rs +++ b/src/test/compile-fail/E0138.rs @@ -11,10 +11,10 @@ #![feature(start)] #[start] -fn foo(argc: isize, argv: *const *const u8) -> isize {} +fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } //~^ NOTE previous `start` function here #[start] -fn f(argc: isize, argv: *const *const u8) -> isize {} +fn f(argc: isize, argv: *const *const u8) -> isize { 0 } //~^ ERROR E0138 //~| NOTE multiple `start` functions diff --git a/src/test/compile-fail/consider-removing-last-semi.rs b/src/test/compile-fail/consider-removing-last-semi.rs index 2e110cb3d0bc8..530a0e4156228 100644 --- a/src/test/compile-fail/consider-removing-last-semi.rs +++ b/src/test/compile-fail/consider-removing-last-semi.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn f() -> String { //~ ERROR E0269 +fn f() -> String { //~ ERROR mismatched types 0u8; "bla".to_string(); //~ HELP consider removing this semicolon } -fn g() -> String { //~ ERROR E0269 +fn g() -> String { //~ ERROR mismatched types "this won't work".to_string(); "removeme".to_string(); //~ HELP consider removing this semicolon } diff --git a/src/test/compile-fail/diverging-fn-tail-35849.rs b/src/test/compile-fail/diverging-fn-tail-35849.rs index 6dc447b4dc887..3a27c08413328 100644 --- a/src/test/compile-fail/diverging-fn-tail-35849.rs +++ b/src/test/compile-fail/diverging-fn-tail-35849.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn _converge() -> ! { //~ ERROR computation may converge - 42 +fn _converge() -> ! { + 42 //~ ERROR mismatched types } fn main() { } diff --git a/src/test/compile-fail/issue-11714.rs b/src/test/compile-fail/issue-11714.rs index 998576097a0a0..192f78e41cb43 100644 --- a/src/test/compile-fail/issue-11714.rs +++ b/src/test/compile-fail/issue-11714.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn blah() -> i32 { //~ ERROR not all control paths return a value +fn blah() -> i32 { //~ ERROR mismatched types 1 ; //~ HELP consider removing this semicolon: diff --git a/src/test/compile-fail/issue-13428.rs b/src/test/compile-fail/issue-13428.rs index c771970650d31..9406199afc231 100644 --- a/src/test/compile-fail/issue-13428.rs +++ b/src/test/compile-fail/issue-13428.rs @@ -10,7 +10,7 @@ // Regression test for #13428 -fn foo() -> String { //~ ERROR not all control paths return a value +fn foo() -> String { //~ ERROR mismatched types format!("Hello {}", "world") // Put the trailing semicolon on its own line to test that the @@ -18,7 +18,7 @@ fn foo() -> String { //~ ERROR not all control paths return a value ; //~ HELP consider removing this semicolon } -fn bar() -> String { //~ ERROR not all control paths return a value +fn bar() -> String { //~ ERROR mismatched types "foobar".to_string() ; //~ HELP consider removing this semicolon } diff --git a/src/test/compile-fail/issue-22645.rs b/src/test/compile-fail/issue-22645.rs index 402b9a04496e9..81f66e3e2cfee 100644 --- a/src/test/compile-fail/issue-22645.rs +++ b/src/test/compile-fail/issue-22645.rs @@ -17,7 +17,7 @@ struct Bob; impl Add for Bob { type Output = Bob; - fn add(self, rhs : RHS) -> Bob {} + fn add(self, rhs : RHS) -> Bob { Bob } } fn main() { diff --git a/src/test/compile-fail/issue-22684.rs b/src/test/compile-fail/issue-22684.rs index b7ffbefba6a08..a791758ad1763 100644 --- a/src/test/compile-fail/issue-22684.rs +++ b/src/test/compile-fail/issue-22684.rs @@ -15,7 +15,7 @@ mod foo { } pub trait Baz { - fn bar(&self) -> bool {} + fn bar(&self) -> bool { true } } impl Baz for Foo {} } diff --git a/src/test/compile-fail/issue-29161.rs b/src/test/compile-fail/issue-29161.rs index bc09f61a754c2..97ba222fe45f0 100644 --- a/src/test/compile-fail/issue-29161.rs +++ b/src/test/compile-fail/issue-29161.rs @@ -13,7 +13,7 @@ mod a { impl Default for A { pub fn default() -> A { //~ ERROR unnecessary visibility qualifier - A; + A } } } diff --git a/src/test/compile-fail/issue-32323.rs b/src/test/compile-fail/issue-32323.rs index e3461e52e1c71..e5cb813032771 100644 --- a/src/test/compile-fail/issue-32323.rs +++ b/src/test/compile-fail/issue-32323.rs @@ -13,6 +13,6 @@ pub trait Tr<'a> { } pub fn f<'a, T: Tr<'a>>() -> >::Out {} -//~^ ERROR not all control paths return a value +//~^ ERROR mismatched types pub fn main() {} diff --git a/src/test/compile-fail/issue-5239-1.rs b/src/test/compile-fail/issue-5239-1.rs index 06e3c9a207b78..a77b27150d797 100644 --- a/src/test/compile-fail/issue-5239-1.rs +++ b/src/test/compile-fail/issue-5239-1.rs @@ -11,7 +11,7 @@ // Regression test for issue #5239 fn main() { - let x = |ref x: isize| -> isize { x += 1; }; + let x = |ref x: isize| { x += 1; }; //~^ ERROR E0368 //~| NOTE cannot use `+=` on type `&isize` } diff --git a/src/test/compile-fail/issue-6458-4.rs b/src/test/compile-fail/issue-6458-4.rs index c3f3a718ad0e2..a078cdea4ac4d 100644 --- a/src/test/compile-fail/issue-6458-4.rs +++ b/src/test/compile-fail/issue-6458-4.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo(b: bool) -> Result { - Err("bar".to_string()); - //~^ ERROR unable to infer enough type information about `_` [E0282] - //~| NOTE cannot infer type for `_` - //~| NOTE type annotations or generic parameter binding +fn foo(b: bool) -> Result { //~ ERROR mismatched types + Err("bar".to_string()); //~ HELP consider removing this semicolon } fn main() { diff --git a/src/test/compile-fail/liveness-forgot-ret.rs b/src/test/compile-fail/liveness-forgot-ret.rs index e08515e40af78..1ee4be08a1c50 100644 --- a/src/test/compile-fail/liveness-forgot-ret.rs +++ b/src/test/compile-fail/liveness-forgot-ret.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: not all control paths return a value - fn god_exists(a: isize) -> bool { return god_exists(a); } fn f(a: isize) -> isize { if god_exists(a) { return 5; }; } +//~^ ERROR mismatched types fn main() { f(12); } diff --git a/src/test/compile-fail/liveness-issue-2163.rs b/src/test/compile-fail/liveness-issue-2163.rs index 7c94e33b47b38..69bceec8c3225 100644 --- a/src/test/compile-fail/liveness-issue-2163.rs +++ b/src/test/compile-fail/liveness-issue-2163.rs @@ -13,6 +13,6 @@ use std::vec::Vec; fn main() { let a: Vec = Vec::new(); a.iter().all(|_| -> bool { - //~^ ERROR not all control paths return a value + //~^ ERROR mismatched types }); } diff --git a/src/test/compile-fail/liveness-missing-ret2.rs b/src/test/compile-fail/liveness-missing-ret2.rs index b53bb6159e8dd..a35eb1af4f336 100644 --- a/src/test/compile-fail/liveness-missing-ret2.rs +++ b/src/test/compile-fail/liveness-missing-ret2.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: not all control paths return a value - -fn f() -> isize { +fn f() -> isize { //~ ERROR mismatched types // Make sure typestate doesn't interpret this match expression as // the function result match true { true => { } _ => {} }; diff --git a/src/test/compile-fail/liveness-return-last-stmt-semi.rs b/src/test/compile-fail/liveness-return-last-stmt-semi.rs index 03733cc2eb596..ada91c38d48c3 100644 --- a/src/test/compile-fail/liveness-return-last-stmt-semi.rs +++ b/src/test/compile-fail/liveness-return-last-stmt-semi.rs @@ -11,16 +11,16 @@ // regression test for #8005 macro_rules! test { () => { fn foo() -> i32 { 1; } } } - //~^ ERROR not all control paths return a value + //~^ ERROR mismatched types //~| HELP consider removing this semicolon -fn no_return() -> i32 {} //~ ERROR not all control paths return a value +fn no_return() -> i32 {} //~ ERROR mismatched types -fn bar(x: u32) -> u32 { //~ ERROR not all control paths return a value +fn bar(x: u32) -> u32 { //~ ERROR mismatched types x * 2; //~ HELP consider removing this semicolon } -fn baz(x: u64) -> u32 { //~ ERROR not all control paths return a value +fn baz(x: u64) -> u32 { //~ ERROR mismatched types x * 2; } diff --git a/src/test/compile-fail/main-wrong-type-2.rs b/src/test/compile-fail/main-wrong-type-2.rs index 7434a6c960b2d..2878cbc7fc154 100644 --- a/src/test/compile-fail/main-wrong-type-2.rs +++ b/src/test/compile-fail/main-wrong-type-2.rs @@ -10,4 +10,5 @@ fn main() -> char { //~^ ERROR: main function has wrong type + ' ' } diff --git a/src/test/compile-fail/on-unimplemented/on-trait.rs b/src/test/compile-fail/on-unimplemented/on-trait.rs index 3a789f3faeb2a..0f4b0919b6500 100644 --- a/src/test/compile-fail/on-unimplemented/on-trait.rs +++ b/src/test/compile-fail/on-unimplemented/on-trait.rs @@ -16,7 +16,7 @@ trait Foo {} fn foobar>() -> T { - + panic!() } #[rustc_on_unimplemented="a collection of type `{Self}` cannot be built from an iterator over elements of type `{A}`"] diff --git a/src/test/compile-fail/private-in-public-lint.rs b/src/test/compile-fail/private-in-public-lint.rs index 8e23bfcfb1051..4796548112d9e 100644 --- a/src/test/compile-fail/private-in-public-lint.rs +++ b/src/test/compile-fail/private-in-public-lint.rs @@ -13,7 +13,7 @@ mod m1 { struct Priv; impl Pub { - pub fn f() -> Priv {} //~ ERROR private type in public interface + pub fn f() -> Priv {Priv} //~ ERROR private type in public interface } } @@ -24,7 +24,7 @@ mod m2 { struct Priv; impl Pub { - pub fn f() -> Priv {} //~ ERROR private type in public interface + pub fn f() -> Priv {Priv} //~ ERROR private type in public interface } } diff --git a/src/test/compile-fail/required-lang-item.rs b/src/test/compile-fail/required-lang-item.rs index 1aa22a1676ef2..ce40702b3dc2a 100644 --- a/src/test/compile-fail/required-lang-item.rs +++ b/src/test/compile-fail/required-lang-item.rs @@ -11,6 +11,7 @@ #![feature(lang_items, no_core)] #![no_core] +#[lang="copy"] pub trait Copy { } #[lang="sized"] pub trait Sized { } // error-pattern:requires `start` lang_item diff --git a/src/test/compile-fail/unreachable-in-call.rs b/src/test/compile-fail/unreachable-in-call.rs index 5a3257d54db21..72462468432d9 100644 --- a/src/test/compile-fail/unreachable-in-call.rs +++ b/src/test/compile-fail/unreachable-in-call.rs @@ -24,7 +24,7 @@ fn diverge_first() { get_u8()); //~ ERROR unreachable expression } fn diverge_second() { - call( //~ ERROR unreachable call + call( //~ ERROR unreachable expression get_u8(), diverge()); } diff --git a/src/test/compile-fail/where-clauses-unsatisfied.rs b/src/test/compile-fail/where-clauses-unsatisfied.rs index 278a8db4e1ad4..ffc39008c4e5a 100644 --- a/src/test/compile-fail/where-clauses-unsatisfied.rs +++ b/src/test/compile-fail/where-clauses-unsatisfied.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn equal(_: &T, _: &T) -> bool where T : Eq { -} +fn equal(a: &T, b: &T) -> bool where T : Eq { a == b } struct Struct; diff --git a/src/test/parse-fail/closure-return-syntax.rs b/src/test/parse-fail/closure-return-syntax.rs index da6245597f8f4..1da6735918012 100644 --- a/src/test/parse-fail/closure-return-syntax.rs +++ b/src/test/parse-fail/closure-return-syntax.rs @@ -12,5 +12,6 @@ // unless it uses braces. fn main() { - let x = || -> i32 22; //~ ERROR expected `{`, found `22` + let x = || -> i32 22; + //~^ ERROR expected one of `!`, `(`, `::`, `<`, or `{`, found `22` } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 40ff4852e3856..24b0f90d08e4d 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -18,18 +18,18 @@ // #4264 fixed-length vector types -pub fn foo(_: [i32; (3 as usize)]) { } +pub fn foo(_: [i32; (3 as usize)]) ({ } as ()) -pub fn bar() { - const FOO: usize = ((5 as usize) - (4 as usize) as usize); - let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]); +pub fn bar() ({ + const FOO: usize = ((5 as usize) - (4 as usize) as usize); + let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]); - let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]); + let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]); - let _ = - (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as &[i32; 3]) - as *const _ as *const [i32; 3]) as *const [i32; (3 as usize)] as - *const [i32; 3]); + let _ = + (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) + as &[i32; 3]) as *const _ as *const [i32; 3]) as + *const [i32; (3 as usize)] as *const [i32; 3]); @@ -38,58 +38,66 @@ - (($crate::fmt::format as - fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((::std::fmt::Arguments::new_v1 - as - fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({ - static __STATIC_FMTSTR: - &'static [&'static str] - = - (&([("test" - as - &'static str)] - as - [&'static str; 1]) - as - &'static [&'static str; 1]); - (__STATIC_FMTSTR - as - &'static [&'static str]) - } - as - &[&str]), - (&(match (() - as - ()) - { - () - => - ([] - as - [std::fmt::ArgumentV1<'_>; 0]), - } - as - [std::fmt::ArgumentV1<'_>; 0]) - as - &[std::fmt::ArgumentV1<'_>; 0])) - as - std::fmt::Arguments<'_>)) - as std::string::String); -} + + (($crate::fmt::format as + fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((::std::fmt::Arguments::new_v1 + as + fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({ + static __STATIC_FMTSTR: + &'static [&'static str] + = + (&([("test" + as + &'static str)] + as + [&'static str; 1]) + as + &'static [&'static str; 1]); + (__STATIC_FMTSTR + as + &'static [&'static str]) + } + as + &[&str]), + (&(match (() + as + ()) + { + () + => + ([] + as + [std::fmt::ArgumentV1<'_>; 0]), + } + as + [std::fmt::ArgumentV1<'_>; 0]) + as + &[std::fmt::ArgumentV1<'_>; 0])) + as + std::fmt::Arguments<'_>)) + as std::string::String); + } as ()) pub type Foo = [i32; (3 as usize)]; pub struct Bar { pub x: [i32; (3 as usize)], } pub struct TupleBar([i32; (4 as usize)]); pub enum Baz { BazVariant([i32; (5 as usize)]), } -pub fn id(x: T) -> T { (x as T) } -pub fn use_id() { - let _ = - ((id::<[i32; (3 as usize)]> as - fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32), - (2 as i32), - (3 as i32)] as - [i32; 3])) as - [i32; 3]); -} -fn main() { } +pub fn id(x: T) -> T ({ (x as T) } as T) +pub fn use_id() ({ + let _ = + ((id::<[i32; (3 as usize)]> as + fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 + as + i32), + (2 + as + i32), + (3 + as + i32)] + as + [i32; 3])) + as [i32; 3]); + } as ()) +fn main() ({ } as ()) diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs index e52932cd7befa..1c443020d2e93 100644 --- a/src/test/pretty/stmt_expr_attributes.rs +++ b/src/test/pretty/stmt_expr_attributes.rs @@ -198,14 +198,20 @@ fn _11() { }; let _ = #[attr] || #[attr] (); let _ = #[attr] move || #[attr] (); - let _ = #[attr] || { - #![attr] - #[attr] - () }; - let _ = #[attr] move || { - #![attr] - #[attr] - () }; + let _ = + #[attr] || + { + #![attr] + #[attr] + () + }; + let _ = + #[attr] move || + { + #![attr] + #[attr] + () + }; let _ = #[attr] { #![attr] diff --git a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot index f699771ef24c6..8ea8370ab235d 100644 --- a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot @@ -2,6 +2,8 @@ digraph block { N0[label="entry"]; N1[label="exit"]; N2[label="block { }"]; + N3[label="expr { }"]; N0 -> N2; - N2 -> N1; + N2 -> N3; + N3 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot index d924890b3118c..5982fbea76902 100644 --- a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot @@ -4,8 +4,10 @@ digraph block { N2[label="expr 1"]; N3[label="stmt 1;"]; N4[label="block { 1; }"]; + N5[label="expr { 1; }"]; N0 -> N2; N2 -> N3; N3 -> N4; - N4 -> N1; + N4 -> N5; + N5 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot index 1f4a58ba0a3c2..1639785bd68c0 100644 --- a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot @@ -4,8 +4,10 @@ digraph block { 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 -> N1; + N4 -> N5; + N5 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot index 8b6500761850f..b0ae00d81675a 100644 --- a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot @@ -6,10 +6,12 @@ digraph block { 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 -> N1; + N6 -> N7; + N7 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot index fde6cc2900550..41ace15a4c680 100644 --- a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot @@ -5,9 +5,11 @@ digraph block { 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 -> N1; + N5 -> N6; + N6 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot index efd56cd0c75e4..72b8ae71751c2 100644 --- a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot @@ -9,6 +9,7 @@ digraph block { 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; @@ -17,5 +18,6 @@ digraph block { N6 -> N7; N7 -> N8; N8 -> N9; - N9 -> N1; + N9 -> N10; + N10 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot index 54e9d89d3fb56..acba71ef625ff 100644 --- a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot @@ -7,11 +7,13 @@ digraph block { 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 -> N1; + N7 -> N8; + N8 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot index c60cd1cfd2774..251e2b39f14c8 100644 --- a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot @@ -17,6 +17,7 @@ digraph block { 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; @@ -33,5 +34,6 @@ digraph block { N15 -> N7; N7 -> N16; N16 -> N17; - N17 -> N1; + N17 -> N18; + N18 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot index da0120b7bdc52..e2779c9414a9e 100644 --- a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot @@ -16,6 +16,7 @@ digraph block { 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; @@ -32,5 +33,6 @@ digraph block { N9 -> N15; N14 -> N15; N15 -> N16; - N16 -> N1; + N16 -> N17; + N17 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot index c98d1b0bed5de..536abde91e81a 100644 --- a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot @@ -24,6 +24,7 @@ digraph block { 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; @@ -48,5 +49,6 @@ digraph block { N14 -> N23; N22 -> N23; N23 -> N24; - N24 -> N1; + N24 -> N25; + N25 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot index 516c39ef560a2..a3b531b1e2f41 100644 --- a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot @@ -15,6 +15,7 @@ digraph block { 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; @@ -30,5 +31,6 @@ digraph block { N13 -> N14; N14 -> N5; N9 -> N15; - N15 -> N1; + N15 -> N16; + N16 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot index 9b66fd581cb43..70034d299ba95 100644 --- a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot @@ -15,6 +15,7 @@ digraph block { 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; @@ -29,5 +30,6 @@ digraph block { N12 -> N13; N13 -> N14; N14 -> N15; - N15 -> N1; + N15 -> N16; + N16 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot index 071af6faf6f96..245afc43504c4 100644 --- a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot @@ -22,6 +22,7 @@ digraph block { 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; @@ -44,5 +45,6 @@ digraph block { N20 -> N21; N21 -> N5; N6 -> N22; - N22 -> N1; + N22 -> N23; + N23 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot index fb7d2ad97bd5f..0f268bd0f2aeb 100644 --- a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot @@ -24,6 +24,7 @@ digraph block { 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; @@ -48,5 +49,6 @@ digraph block { N22 -> N23; N23 -> N10; N10 -> N24; - N24 -> N1; + N24 -> N25; + N25 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot index 66250aa441e43..719a6cf2619d3 100644 --- a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot @@ -15,6 +15,7 @@ digraph block { 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; @@ -30,5 +31,6 @@ digraph block { N7 -> N14; N13 -> N14; N14 -> N15; - N15 -> N1; + N15 -> N16; + N16 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot index 4c94630f4e1fb..d8cbd8411e209 100644 --- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot @@ -49,6 +49,7 @@ digraph block { 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; @@ -99,5 +100,6 @@ digraph block { N47 -> N48; N48 -> N8; N9 -> N49; - N49 -> N1; + N49 -> N50; + N50 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot index d7d027cefb59b..b11881247fb6a 100644 --- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot @@ -52,6 +52,7 @@ digraph block { 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; @@ -105,5 +106,6 @@ digraph block { N49 -> N50; N50 -> N51; N51 -> N52; - N52 -> N1; + N52 -> N53; + N53 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot index f87b70a71caea..705eece77558d 100644 --- a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot @@ -8,6 +8,7 @@ digraph block { 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; @@ -15,5 +16,6 @@ digraph block { N5 -> N6; N6 -> N7; N7 -> N8; - N8 -> N1; + N8 -> N9; + N9 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot index 8ea4256133296..c1d6e3023fbc1 100644 --- a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot @@ -9,6 +9,7 @@ digraph block { N7[label="expr inner(inner(18))"]; N8[label="stmt inner(inner(18));"]; N9[label="block { inner(inner(18)); }"]; + N10[label="expr { inner(inner(18)); }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -17,5 +18,6 @@ digraph block { N6 -> N7; N7 -> N8; N8 -> N9; - N9 -> N1; + N9 -> N10; + N10 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot index bc0ca08d42257..d2f9f41f647be 100644 --- a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot @@ -12,6 +12,7 @@ digraph block { N10[label="expr s.inner().inner()"]; N11[label="stmt s.inner().inner();"]; N12[label="block { let s = S19{x: 19,}; s.inner().inner(); }"]; + N13[label="expr { let s = S19{x: 19,}; s.inner().inner(); }"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -23,5 +24,6 @@ digraph block { N9 -> N10; N10 -> N11; N11 -> N12; - N12 -> N1; + N12 -> N13; + N13 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot index 21e84fb858bcf..120eab4dac909 100644 --- a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot @@ -12,6 +12,7 @@ digraph block { 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; @@ -23,5 +24,6 @@ digraph block { N9 -> N10; N10 -> N11; N11 -> N12; - N12 -> N1; + N12 -> N13; + N13 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot index 796bf4910c9e2..370dcdd8554da 100644 --- a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot @@ -47,6 +47,7 @@ digraph block { 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; @@ -95,5 +96,6 @@ digraph block { N45 -> N46; N46 -> N8; N9 -> N47; - N47 -> N1; + N47 -> N48; + N48 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot index 9e8049f07415a..9d3bc22831a13 100644 --- a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot @@ -50,6 +50,7 @@ digraph block { 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; @@ -101,5 +102,6 @@ digraph block { N47 -> N48; N48 -> N49; N49 -> N50; - N50 -> N1; + N50 -> N51; + N51 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot index b3f285049c576..f152977438c50 100644 --- a/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f23.dot-expected.dot @@ -52,6 +52,7 @@ digraph block { 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; @@ -107,5 +108,6 @@ digraph block { N24 -> N51; N51 -> N11; N15 -> N52; - N52 -> N1; + N52 -> N53; + N53 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot index 43b3295bf3be9..e40dd014f0a4d 100644 --- a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot @@ -76,6 +76,7 @@ digraph block { 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; @@ -155,5 +156,6 @@ digraph block { N29 -> N75; N75 -> N11; N12 -> N76; - N76 -> N1; + N76 -> N77; + N77 -> N1; } diff --git a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot index 50fdffb781d11..1e2df1ab5e7b7 100644 --- a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot @@ -76,6 +76,7 @@ digraph block { 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; @@ -155,5 +156,6 @@ digraph block { N29 -> N75; N75 -> N11; N12 -> N76; - N76 -> N1; + N76 -> N77; + N77 -> N1; }