Change:
Code: Compilation attempt: It should be pointing at the semi-colon on the next line, not the comma on this line.
The note message was introduced in . It doesn't seem to handle this situation properly.

Discussion:
use std::str; use std::uint; use syntax::ast::*; <del> use syntax::codemap::Span; </del> <ins> use syntax::codemap::{BytePos, original_sp, Span}; </ins> use syntax::parse::token::special_idents; use syntax::parse::token; use syntax::print::pprust::{expr_to_str, block_to_str};

}; if ends_with_stmt { let last_stmt = body.stmts.last().unwrap(); <ins> let original_span = original_sp(last_stmt.span, sp); </ins> let span_semicolon = Span { <del> lo: last_stmt.span.hi, hi: last_stmt.span.hi, expn_info: last_stmt.span.expn_info </del> <ins> lo: original_span.hi - BytePos(1), hi: original_span.hi, expn_info: original_span.expn_info </ins> }; self.ir.tcx.sess.span_note( span_semicolon, "consider removing this semicolon:");

Span {lo: lo, hi: hi, expn_info: None} } <ins> /// Return the span itself if it doesn't come from a macro expansion, /// otherwise return the call site span up to the `enclosing_sp` by /// following the `expn_info` chain. pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span { match (sp.expn_info, enclosing_sp.expn_info) { (None, _) => sp, (Some(expn1), Some(expn2)) if expn1.call_site == expn2.call_site => sp, (Some(expn1), _) => original_sp(expn1.call_site, enclosing_sp), } } </ins> /// A source code location used for error reporting pub struct Loc { /// Information about the original source

}), span: sp(17,18)}, ast::DUMMY_NODE_ID), <del> span: sp(17,18)}), </del> <ins> span: sp(17,19)}), </ins> expr: None, id: ast::DUMMY_NODE_ID, rules: ast::DefaultBlock, // no idea

match self.token { token::SEMI => { self.bump(); <ins> let span_with_semi = Span { lo: stmt.span.lo, hi: self.last_span.hi, expn_info: stmt.span.expn_info, }; </ins> stmts.push(@codemap::Spanned { node: StmtSemi(e, stmt_id), <del> span: stmt.span, </del> <ins> span: span_with_semi, </ins> }); } token::RBRACE => {

} StmtMac(ref m, _) => { // statement macro; might be an expr <del> let has_semi; </del> match self.token { token::SEMI => { <del> has_semi = true; </del> <ins> self.bump(); stmts.push(@codemap::Spanned { node: StmtMac((*m).clone(), true), span: stmt.span, }); </ins> } token::RBRACE => { // if a block ends in `m!(arg)` without // a `;`, it must be an expr <del> has_semi = false; </del> expr = Some( self.mk_mac_expr(stmt.span.lo, stmt.span.hi, m.node.clone())); } _ => { <del> has_semi = false; </del> stmts.push(stmt); } } <del> if has_semi { self.bump(); stmts.push(@codemap::Spanned { node: StmtMac((*m).clone(), true), span: stmt.span, }); } </del> } _ => { // all other kinds of statements: stmts.push(stmt);

<ins> // Copyright 2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. // Regression test for #13428 fn foo() -> ~str {  //~ ERROR not all control paths return a value format!("Hello {}", "world") // Put the trailing semicolon on its own line to test that the // note message gets the offending semicolon exactly ;   //~ NOTE consider removing this semicolon } fn bar() -> ~str {  //~ ERROR not all control paths return a value "foobar".to_owned() ;   //~ NOTE consider removing this semicolon } pub fn main() {} </ins>