diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index ead2ee83d8150..8d6e2b6f6b34c 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -439,7 +439,7 @@ fn visit_fn(v: &mut LivenessVisitor, // check for various error conditions lsets.visit_block(body, ()); - lsets.check_ret(id, sp, fk, entry_ln); + lsets.check_ret(id, sp, fk, entry_ln, body); lsets.warn_about_unused_args(decl, entry_ln); } @@ -1575,7 +1575,8 @@ impl Liveness { id: NodeId, sp: Span, _fk: &FnKind, - entry_ln: LiveNode) { + entry_ln: LiveNode, + body: &Block) { if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { // if no_ret_var is live, then we fall off the end of the // function without any kind of return expression: @@ -1588,9 +1589,30 @@ impl Liveness { self.tcx.sess.span_err( sp, "some control paths may return"); } else { + let ends_with_stmt = match body.expr { + None if body.stmts.len() > 0 => + match body.stmts.last().node { + StmtSemi(e, _) => { + let t_stmt = ty::expr_ty(self.tcx, e); + ty::get(t_stmt).sty == ty::get(t_ret).sty + }, + _ => false + }, + _ => false + }; + if ends_with_stmt { + let last_stmt = body.stmts.last(); + let span_semicolon = Span { + lo: last_stmt.span.hi, + hi: last_stmt.span.hi, + expn_info: last_stmt.span.expn_info + }; + self.tcx.sess.span_note( + span_semicolon, "consider removing this semicolon:"); + } self.tcx.sess.span_err( sp, "not all control paths return a value"); - } + } } } diff --git a/src/test/compile-fail/liveness-return-last-stmt-semi.rs b/src/test/compile-fail/liveness-return-last-stmt-semi.rs new file mode 100644 index 0000000000000..dc131698b9065 --- /dev/null +++ b/src/test/compile-fail/liveness-return-last-stmt-semi.rs @@ -0,0 +1,30 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// regression test for #8005 + +#[feature(macro_rules)]; + +macro_rules! test ( () => { fn foo() -> int { 1i; } } ) //~ ERROR not all control paths return a value + //~^ NOTE consider removing this semicolon + +fn no_return() -> int {} //~ ERROR not all control paths return a value + +fn bar(x: u32) -> u32 { //~ ERROR not all control paths return a value + x * 2; //~ NOTE consider removing this semicolon +} + +fn baz(x: u64) -> u32 { //~ ERROR not all control paths return a value + x * 2; +} + +fn main() { + test!(); +}