about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libsyntax/ext/expand.rs1
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs16
-rw-r--r--src/libsyntax/ext/tt/quoted.rs2
-rw-r--r--src/libsyntax/parse/parser.rs8
-rw-r--r--src/libsyntax/tokenstream.rs32
-rw-r--r--src/libsyntax_pos/lib.rs19
-rw-r--r--src/test/ui/did_you_mean/issue-31424.stderr2
-rw-r--r--src/test/ui/span/macro-span-replacement.rs19
-rw-r--r--src/test/ui/span/macro-span-replacement.stderr11
9 files changed, 97 insertions, 13 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index d2e51c9cb48..dc0848176d6 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -1046,6 +1046,7 @@ impl<'feat> ExpansionConfig<'feat> {
 }
 
 // A Marker adds the given mark to the syntax context.
+#[derive(Debug)]
 pub struct Marker(pub Mark);
 
 impl Folder for Marker {
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index f786b1abb8a..8e746676ecd 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -119,8 +119,22 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
                     quoted::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
                     _ => cx.span_bug(sp, "malformed macro rhs"),
                 };
+
+                let rhs_spans = rhs.iter().map(|t| t.span()).collect::<Vec<_>>();
                 // rhs has holes ( `$id` and `$(...)` that need filled)
-                let tts = transcribe(cx, Some(named_matches), rhs);
+                let mut tts = transcribe(cx, Some(named_matches), rhs);
+
+                // Replace all the tokens for the corresponding positions in the macro, to maintain
+                // proper positions in error reporting, while maintaining the macro_backtrace.
+                if rhs_spans.len() == tts.len() {
+                    tts = tts.map_enumerated(|i, tt| {
+                        let mut tt = tt.clone();
+                        let mut sp = rhs_spans[i];
+                        sp.ctxt = tt.span().ctxt;
+                        tt.set_span(sp);
+                        tt
+                    });
+                }
 
                 if cx.trace_macros() {
                     trace_macros_note(cx, sp, format!("to `{}`", tts));
diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs
index 74fa85d130b..6fdcadd1dde 100644
--- a/src/libsyntax/ext/tt/quoted.rs
+++ b/src/libsyntax/ext/tt/quoted.rs
@@ -128,7 +128,7 @@ impl TokenTree {
         }
     }
 
-    /// Retrieve the TokenTree's span.
+    /// Retrieve the `TokenTree`'s span.
     pub fn span(&self) -> Span {
         match *self {
             TokenTree::Token(sp, _) |
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index ae3edfcbf32..553cac80d82 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -150,7 +150,7 @@ fn maybe_append(mut lhs: Vec<Attribute>, rhs: Option<Vec<Attribute>>)
     lhs
 }
 
-#[derive(Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq)]
 enum PrevTokenKind {
     DocComment,
     Comma,
@@ -6090,8 +6090,7 @@ impl<'a> Parser<'a> {
             let (delim, tts) = self.expect_delimited_token_tree()?;
             if delim != token::Brace {
                 if !self.eat(&token::Semi) {
-                    let prev_span = self.prev_span;
-                    self.span_err(prev_span,
+                    self.span_err(self.prev_span,
                                   "macros that expand to items must either \
                                    be surrounded with braces or followed by \
                                    a semicolon");
@@ -6108,8 +6107,7 @@ impl<'a> Parser<'a> {
         match visibility {
             Visibility::Inherited => {}
             _ => {
-                let prev_span = self.prev_span;
-                return Err(self.span_fatal(prev_span, "unmatched visibility `pub`"));
+                return Err(self.span_fatal(self.prev_span, "unmatched visibility `pub`"));
             }
         }
 
diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs
index 8eee25405df..747bc7b4385 100644
--- a/src/libsyntax/tokenstream.rs
+++ b/src/libsyntax/tokenstream.rs
@@ -131,6 +131,15 @@ impl TokenTree {
         }
     }
 
+    /// Modify the `TokenTree`'s span inplace.
+    pub fn set_span(&mut self, span: Span) {
+        match *self {
+            TokenTree::Token(ref mut sp, _) | TokenTree::Delimited(ref mut sp, _) => {
+                *sp = span;
+            }
+        }
+    }
+
     /// Indicates if the stream is a token that is equal to the provided token.
     pub fn eq_token(&self, t: Token) -> bool {
         match *self {
@@ -190,6 +199,14 @@ impl PartialEq<TokenStream> for TokenStream {
 }
 
 impl TokenStream {
+    pub fn len(&self) -> usize {
+        if let TokenStreamKind::Stream(ref slice) = self.kind {
+            slice.len()
+        } else {
+            0
+        }
+    }
+
     pub fn empty() -> TokenStream {
         TokenStream { kind: TokenStreamKind::Empty }
     }
@@ -241,6 +258,21 @@ impl TokenStream {
         }
     }
 
+    pub fn map_enumerated<F: FnMut(usize, TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
+        let mut trees = self.into_trees();
+        let mut result = Vec::new();
+        let mut i = 0;
+        while let Some(stream) = trees.next_as_stream() {
+            result.push(match stream.kind {
+                TokenStreamKind::Tree(tree) => f(i, tree).into(),
+                TokenStreamKind::JointTree(tree) => f(i, tree).joint(),
+                _ => unreachable!()
+            });
+            i += 1;
+        }
+        TokenStream::concat(result)
+    }
+
     pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
         let mut trees = self.into_trees();
         let mut result = Vec::new();
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index a7c247689cc..ad5f3845e2b 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -100,6 +100,7 @@ impl Span {
         if self.source_equal(&DUMMY_SP) { other } else { self }
     }
 
+    /// Return true if `self` fully encloses `other`.
     pub fn contains(self, other: Span) -> bool {
         self.lo <= other.lo && other.hi <= self.hi
     }
@@ -184,15 +185,21 @@ impl Span {
         result
     }
 
+    /// Return a `Span` that would enclose both `self` and `end`.
     pub fn to(self, end: Span) -> Span {
-        // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
-        if self.ctxt == SyntaxContext::empty() {
-            Span { lo: self.lo, ..end }
-        } else {
-            Span { hi: end.hi, ..self }
+        Span {
+            lo: cmp::min(self.lo, end.lo),
+            hi: cmp::max(self.hi, end.hi),
+            // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
+            ctxt: if self.ctxt == SyntaxContext::empty() {
+                end.ctxt
+            } else {
+                self.ctxt
+            },
         }
     }
 
+    /// Return a `Span` between the end of `self` to the beginning of `end`.
     pub fn between(self, end: Span) -> Span {
         Span {
             lo: self.hi,
@@ -205,6 +212,7 @@ impl Span {
         }
     }
 
+    /// Return a `Span` between the beginning of `self` to the beginning of `end`.
     pub fn until(self, end: Span) -> Span {
         Span {
             lo: self.lo,
@@ -852,6 +860,7 @@ pub struct FileLines {
 thread_local!(pub static SPAN_DEBUG: Cell<fn(Span, &mut fmt::Formatter) -> fmt::Result> =
                 Cell::new(default_span_debug));
 
+#[derive(Debug)]
 pub struct MacroBacktrace {
     /// span where macro was applied to generate this code
     pub call_site: Span,
diff --git a/src/test/ui/did_you_mean/issue-31424.stderr b/src/test/ui/did_you_mean/issue-31424.stderr
index 023f9ef1def..47dc7c97572 100644
--- a/src/test/ui/did_you_mean/issue-31424.stderr
+++ b/src/test/ui/did_you_mean/issue-31424.stderr
@@ -11,7 +11,7 @@ error[E0596]: cannot borrow immutable argument `self` as mutable
   --> $DIR/issue-31424.rs:23:15
    |
 22 |     fn bar(self: &mut Self) {
-   |            ---- consider changing this to `mut self`
+   |            --------------- consider changing this to `mut self: &mut Self`
 23 |         (&mut self).bar();
    |               ^^^^ cannot borrow mutably
 
diff --git a/src/test/ui/span/macro-span-replacement.rs b/src/test/ui/span/macro-span-replacement.rs
new file mode 100644
index 00000000000..d779bec4ace
--- /dev/null
+++ b/src/test/ui/span/macro-span-replacement.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 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.
+
+macro_rules! m {
+    ($a:tt $b:tt) => {
+        $b $a;
+    }
+}
+
+fn main() {
+    m!(S struct);
+}
diff --git a/src/test/ui/span/macro-span-replacement.stderr b/src/test/ui/span/macro-span-replacement.stderr
new file mode 100644
index 00000000000..e7336697f48
--- /dev/null
+++ b/src/test/ui/span/macro-span-replacement.stderr
@@ -0,0 +1,11 @@
+warning: struct is never used: `S`
+  --> $DIR/macro-span-replacement.rs:13:9
+   |
+13 |         $b $a;
+   |         ^^^^^^
+...
+18 |     m!(S struct);
+   |     ------------- in this macro invocation
+   |
+   = note: #[warn(dead_code)] on by default
+