about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libproc_macro/lib.rs15
-rw-r--r--src/test/ui-fulldeps/proc-macro/auxiliary/parent-source-spans.rs51
-rw-r--r--src/test/ui-fulldeps/proc-macro/parent-source-spans.rs61
-rw-r--r--src/test/ui-fulldeps/proc-macro/parent-source-spans.stderr128
4 files changed, 255 insertions, 0 deletions
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 4300c97d0ff..50e70e3bce7 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -221,6 +221,21 @@ impl Span {
         }
     }
 
+    /// The `Span` for the tokens in the previous macro expansion from which
+    /// `self` was generated from, if any.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn parent(&self) -> Option<Span> {
+        self.0.ctxt().outer().expn_info().map(|i| Span(i.call_site))
+    }
+
+    /// The span for the origin source code that `self` was generated from. If
+    /// this `Span` wasn't generated from other macro expansions then the return
+    /// value is the same as `*self`.
+    #[unstable(feature = "proc_macro", issue = "38356")]
+    pub fn source(&self) -> Span {
+        Span(self.0.source_callsite())
+    }
+
     /// Get the starting line/column in the source file for this span.
     #[unstable(feature = "proc_macro", issue = "38356")]
     pub fn start(&self) -> LineColumn {
diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/parent-source-spans.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/parent-source-spans.rs
new file mode 100644
index 00000000000..3eb96c2ab96
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/auxiliary/parent-source-spans.rs
@@ -0,0 +1,51 @@
+// Copyright 2018 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.
+
+// no-prefer-dynamic
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::{TokenStream, TokenTree, TokenNode, Span};
+
+fn lit_span(tt: TokenTree) -> (Span, String) {
+    use TokenNode::*;
+    match tt.kind {
+        Literal(..) | Group(..) => (tt.span, tt.to_string().trim().into()),
+        _ => panic!("expected a literal in token tree, got: {:?}", tt)
+    }
+}
+
+#[proc_macro]
+pub fn parent_source_spans(input: TokenStream) -> TokenStream {
+    let mut tokens = input.into_iter();
+    let (sp1, str1) = lit_span(tokens.next().expect("first string"));
+    let _ = tokens.next();
+    let (sp2, str2) = lit_span(tokens.next().expect("second string"));
+
+    sp1.error(format!("first final: {}", str1)).emit();
+    sp2.error(format!("second final: {}", str2)).emit();
+
+    if let (Some(p1), Some(p2)) = (sp1.parent(), sp2.parent()) {
+        p1.error(format!("first parent: {}", str1)).emit();
+        p2.error(format!("second parent: {}", str2)).emit();
+
+        if let (Some(gp1), Some(gp2)) = (p1.parent(), p2.parent()) {
+            gp1.error(format!("first grandparent: {}", str1)).emit();
+            gp2.error(format!("second grandparent: {}", str2)).emit();
+        }
+    }
+
+    sp1.source().error(format!("first source: {}", str1)).emit();
+    sp2.source().error(format!("second source: {}", str2)).emit();
+
+    "ok".parse().unwrap()
+}
diff --git a/src/test/ui-fulldeps/proc-macro/parent-source-spans.rs b/src/test/ui-fulldeps/proc-macro/parent-source-spans.rs
new file mode 100644
index 00000000000..4c71afbac4d
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/parent-source-spans.rs
@@ -0,0 +1,61 @@
+// Copyright 2018 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.
+
+// aux-build:parent-source-spans.rs
+// ignore-stage1
+
+#![feature(proc_macro, decl_macro)]
+
+extern crate parent_source_spans;
+
+use parent_source_spans::parent_source_spans;
+
+macro one($a:expr, $b:expr) {
+    two!($a, $b);
+    //~^ ERROR first parent: "hello"
+    //~| ERROR second parent: "world"
+}
+
+macro two($a:expr, $b:expr) {
+    three!($a, $b);
+    //~^ ERROR first final: "hello"
+    //~| ERROR second final: "world"
+    //~| ERROR first final: "yay"
+    //~| ERROR second final: "rust"
+}
+
+// forwarding tokens directly doesn't create a new source chain
+macro three($($tokens:tt)*) {
+    four!($($tokens)*);
+}
+
+macro four($($tokens:tt)*) {
+    parent_source_spans!($($tokens)*);
+}
+
+fn main() {
+    one!("hello", "world");
+    //~^ ERROR first grandparent: "hello"
+    //~| ERROR second grandparent: "world"
+    //~| ERROR first source: "hello"
+    //~| ERROR second source: "world"
+
+    two!("yay", "rust");
+    //~^ ERROR first parent: "yay"
+    //~| ERROR second parent: "rust"
+    //~| ERROR first source: "yay"
+    //~| ERROR second source: "rust"
+
+    three!("hip", "hop");
+    //~^ ERROR first final: "hip"
+    //~| ERROR second final: "hop"
+    //~| ERROR first source: "hip"
+    //~| ERROR second source: "hop"
+}
diff --git a/src/test/ui-fulldeps/proc-macro/parent-source-spans.stderr b/src/test/ui-fulldeps/proc-macro/parent-source-spans.stderr
new file mode 100644
index 00000000000..7194b05b18e
--- /dev/null
+++ b/src/test/ui-fulldeps/proc-macro/parent-source-spans.stderr
@@ -0,0 +1,128 @@
+error: first final: "hello"
+  --> $DIR/parent-source-spans.rs:27:12
+   |
+27 |     three!($a, $b);
+   |            ^^
+...
+44 |     one!("hello", "world");
+   |     ----------------------- in this macro invocation
+
+error: second final: "world"
+  --> $DIR/parent-source-spans.rs:27:16
+   |
+27 |     three!($a, $b);
+   |                ^^
+...
+44 |     one!("hello", "world");
+   |     ----------------------- in this macro invocation
+
+error: first parent: "hello"
+  --> $DIR/parent-source-spans.rs:21:5
+   |
+21 |     two!($a, $b);
+   |     ^^^^^^^^^^^^^
+...
+44 |     one!("hello", "world");
+   |     ----------------------- in this macro invocation
+
+error: second parent: "world"
+  --> $DIR/parent-source-spans.rs:21:5
+   |
+21 |     two!($a, $b);
+   |     ^^^^^^^^^^^^^
+...
+44 |     one!("hello", "world");
+   |     ----------------------- in this macro invocation
+
+error: first grandparent: "hello"
+  --> $DIR/parent-source-spans.rs:44:5
+   |
+44 |     one!("hello", "world");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: second grandparent: "world"
+  --> $DIR/parent-source-spans.rs:44:5
+   |
+44 |     one!("hello", "world");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: first source: "hello"
+  --> $DIR/parent-source-spans.rs:44:5
+   |
+44 |     one!("hello", "world");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: second source: "world"
+  --> $DIR/parent-source-spans.rs:44:5
+   |
+44 |     one!("hello", "world");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: first final: "yay"
+  --> $DIR/parent-source-spans.rs:27:12
+   |
+27 |     three!($a, $b);
+   |            ^^
+...
+50 |     two!("yay", "rust");
+   |     -------------------- in this macro invocation
+
+error: second final: "rust"
+  --> $DIR/parent-source-spans.rs:27:16
+   |
+27 |     three!($a, $b);
+   |                ^^
+...
+50 |     two!("yay", "rust");
+   |     -------------------- in this macro invocation
+
+error: first parent: "yay"
+  --> $DIR/parent-source-spans.rs:50:5
+   |
+50 |     two!("yay", "rust");
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: second parent: "rust"
+  --> $DIR/parent-source-spans.rs:50:5
+   |
+50 |     two!("yay", "rust");
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: first source: "yay"
+  --> $DIR/parent-source-spans.rs:50:5
+   |
+50 |     two!("yay", "rust");
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: second source: "rust"
+  --> $DIR/parent-source-spans.rs:50:5
+   |
+50 |     two!("yay", "rust");
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: first final: "hip"
+  --> $DIR/parent-source-spans.rs:56:12
+   |
+56 |     three!("hip", "hop");
+   |            ^^^^^
+
+error: second final: "hop"
+  --> $DIR/parent-source-spans.rs:56:19
+   |
+56 |     three!("hip", "hop");
+   |                   ^^^^^
+
+error: first source: "hip"
+  --> $DIR/parent-source-spans.rs:56:12
+   |
+56 |     three!("hip", "hop");
+   |            ^^^^^
+
+error: second source: "hop"
+  --> $DIR/parent-source-spans.rs:56:19
+   |
+56 |     three!("hip", "hop");
+   |                   ^^^^^
+
+error: aborting due to 18 previous errors
+