about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/liveness.rs9
-rw-r--r--src/libsyntax/codemap.rs11
-rw-r--r--src/libsyntax/parse/mod.rs2
-rw-r--r--src/libsyntax/parse/parser.rs24
-rw-r--r--src/test/compile-fail/issue-13428.rs26
5 files changed, 54 insertions, 18 deletions
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index a9cc45d2b13..65f1a48114e 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -117,7 +117,7 @@ use std::rc::Rc;
 use std::str;
 use std::uint;
 use syntax::ast::*;
-use syntax::codemap::Span;
+use syntax::codemap::{BytePos, original_sp, Span};
 use syntax::parse::token::special_idents;
 use syntax::parse::token;
 use syntax::print::pprust::{expr_to_str, block_to_str};
@@ -1473,10 +1473,11 @@ impl<'a> Liveness<'a> {
                 };
                 if ends_with_stmt {
                     let last_stmt = body.stmts.last().unwrap();
+                    let original_span = original_sp(last_stmt.span, sp);
                     let span_semicolon = Span {
-                        lo: last_stmt.span.hi,
-                        hi: last_stmt.span.hi,
-                        expn_info: last_stmt.span.expn_info
+                        lo: original_span.hi - BytePos(1),
+                        hi: original_span.hi,
+                        expn_info: original_span.expn_info
                     };
                     self.ir.tcx.sess.span_note(
                         span_semicolon, "consider removing this semicolon:");
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index b174dffdfec..3c890189ed9 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -141,6 +141,17 @@ pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
     Span {lo: lo, hi: hi, expn_info: None}
 }
 
+/// 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),
+    }
+}
+
 /// A source code location used for error reporting
 pub struct Loc {
     /// Information about the original source
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index eca9f955d93..f83ee200c9e 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -686,7 +686,7 @@ mod test {
                                                       }),
                                                 span: sp(17,18)},
                                                 ast::DUMMY_NODE_ID),
-                                            span: sp(17,18)}),
+                                            span: sp(17,19)}),
                                         expr: None,
                                         id: ast::DUMMY_NODE_ID,
                                         rules: ast::DefaultBlock, // no idea
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 379403e5409..6943d03e6f1 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3260,9 +3260,14 @@ impl<'a> Parser<'a> {
                             match self.token {
                                 token::SEMI => {
                                     self.bump();
+                                    let span_with_semi = Span {
+                                        lo: stmt.span.lo,
+                                        hi: self.last_span.hi,
+                                        expn_info: stmt.span.expn_info,
+                                    };
                                     stmts.push(@codemap::Spanned {
                                         node: StmtSemi(e, stmt_id),
-                                        span: stmt.span,
+                                        span: span_with_semi,
                                     });
                                 }
                                 token::RBRACE => {
@@ -3275,33 +3280,26 @@ impl<'a> Parser<'a> {
                         }
                         StmtMac(ref m, _) => {
                             // statement macro; might be an expr
-                            let has_semi;
                             match self.token {
                                 token::SEMI => {
-                                    has_semi = true;
+                                    self.bump();
+                                    stmts.push(@codemap::Spanned {
+                                        node: StmtMac((*m).clone(), true),
+                                        span: stmt.span,
+                                    });
                                 }
                                 token::RBRACE => {
                                     // if a block ends in `m!(arg)` without
                                     // a `;`, it must be an expr
-                                    has_semi = false;
                                     expr = Some(
                                         self.mk_mac_expr(stmt.span.lo,
                                                          stmt.span.hi,
                                                          m.node.clone()));
                                 }
                                 _ => {
-                                    has_semi = false;
                                     stmts.push(stmt);
                                 }
                             }
-
-                            if has_semi {
-                                self.bump();
-                                stmts.push(@codemap::Spanned {
-                                    node: StmtMac((*m).clone(), true),
-                                    span: stmt.span,
-                                });
-                            }
                         }
                         _ => { // all other kinds of statements:
                             stmts.push(stmt);
diff --git a/src/test/compile-fail/issue-13428.rs b/src/test/compile-fail/issue-13428.rs
new file mode 100644
index 00000000000..7e24d909237
--- /dev/null
+++ b/src/test/compile-fail/issue-13428.rs
@@ -0,0 +1,26 @@
+// 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() {}