Skip to content

Commit a9a03d9

Browse files
committed
Auto merge of #47099 - SergioBenitez:master, r=jseyfried
Add 'Span::parent()' and 'Span::source()' to proc_macro API. As the title suggests: a couple of useful methods for `proc_macro`.
2 parents 90e019b + ab365be commit a9a03d9

File tree

4 files changed

+255
-0
lines changed

4 files changed

+255
-0
lines changed

Diff for: src/libproc_macro/lib.rs

+15
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,21 @@ impl Span {
221221
}
222222
}
223223

224+
/// The `Span` for the tokens in the previous macro expansion from which
225+
/// `self` was generated from, if any.
226+
#[unstable(feature = "proc_macro", issue = "38356")]
227+
pub fn parent(&self) -> Option<Span> {
228+
self.0.ctxt().outer().expn_info().map(|i| Span(i.call_site))
229+
}
230+
231+
/// The span for the origin source code that `self` was generated from. If
232+
/// this `Span` wasn't generated from other macro expansions then the return
233+
/// value is the same as `*self`.
234+
#[unstable(feature = "proc_macro", issue = "38356")]
235+
pub fn source(&self) -> Span {
236+
Span(self.0.source_callsite())
237+
}
238+
224239
/// Get the starting line/column in the source file for this span.
225240
#[unstable(feature = "proc_macro", issue = "38356")]
226241
pub fn start(&self) -> LineColumn {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// no-prefer-dynamic
12+
#![feature(proc_macro)]
13+
#![crate_type = "proc-macro"]
14+
15+
extern crate proc_macro;
16+
17+
use proc_macro::{TokenStream, TokenTree, TokenNode, Span};
18+
19+
fn lit_span(tt: TokenTree) -> (Span, String) {
20+
use TokenNode::*;
21+
match tt.kind {
22+
Literal(..) | Group(..) => (tt.span, tt.to_string().trim().into()),
23+
_ => panic!("expected a literal in token tree, got: {:?}", tt)
24+
}
25+
}
26+
27+
#[proc_macro]
28+
pub fn parent_source_spans(input: TokenStream) -> TokenStream {
29+
let mut tokens = input.into_iter();
30+
let (sp1, str1) = lit_span(tokens.next().expect("first string"));
31+
let _ = tokens.next();
32+
let (sp2, str2) = lit_span(tokens.next().expect("second string"));
33+
34+
sp1.error(format!("first final: {}", str1)).emit();
35+
sp2.error(format!("second final: {}", str2)).emit();
36+
37+
if let (Some(p1), Some(p2)) = (sp1.parent(), sp2.parent()) {
38+
p1.error(format!("first parent: {}", str1)).emit();
39+
p2.error(format!("second parent: {}", str2)).emit();
40+
41+
if let (Some(gp1), Some(gp2)) = (p1.parent(), p2.parent()) {
42+
gp1.error(format!("first grandparent: {}", str1)).emit();
43+
gp2.error(format!("second grandparent: {}", str2)).emit();
44+
}
45+
}
46+
47+
sp1.source().error(format!("first source: {}", str1)).emit();
48+
sp2.source().error(format!("second source: {}", str2)).emit();
49+
50+
"ok".parse().unwrap()
51+
}
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// aux-build:parent-source-spans.rs
12+
// ignore-stage1
13+
14+
#![feature(proc_macro, decl_macro)]
15+
16+
extern crate parent_source_spans;
17+
18+
use parent_source_spans::parent_source_spans;
19+
20+
macro one($a:expr, $b:expr) {
21+
two!($a, $b);
22+
//~^ ERROR first parent: "hello"
23+
//~| ERROR second parent: "world"
24+
}
25+
26+
macro two($a:expr, $b:expr) {
27+
three!($a, $b);
28+
//~^ ERROR first final: "hello"
29+
//~| ERROR second final: "world"
30+
//~| ERROR first final: "yay"
31+
//~| ERROR second final: "rust"
32+
}
33+
34+
// forwarding tokens directly doesn't create a new source chain
35+
macro three($($tokens:tt)*) {
36+
four!($($tokens)*);
37+
}
38+
39+
macro four($($tokens:tt)*) {
40+
parent_source_spans!($($tokens)*);
41+
}
42+
43+
fn main() {
44+
one!("hello", "world");
45+
//~^ ERROR first grandparent: "hello"
46+
//~| ERROR second grandparent: "world"
47+
//~| ERROR first source: "hello"
48+
//~| ERROR second source: "world"
49+
50+
two!("yay", "rust");
51+
//~^ ERROR first parent: "yay"
52+
//~| ERROR second parent: "rust"
53+
//~| ERROR first source: "yay"
54+
//~| ERROR second source: "rust"
55+
56+
three!("hip", "hop");
57+
//~^ ERROR first final: "hip"
58+
//~| ERROR second final: "hop"
59+
//~| ERROR first source: "hip"
60+
//~| ERROR second source: "hop"
61+
}
+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
error: first final: "hello"
2+
--> $DIR/parent-source-spans.rs:27:12
3+
|
4+
27 | three!($a, $b);
5+
| ^^
6+
...
7+
44 | one!("hello", "world");
8+
| ----------------------- in this macro invocation
9+
10+
error: second final: "world"
11+
--> $DIR/parent-source-spans.rs:27:16
12+
|
13+
27 | three!($a, $b);
14+
| ^^
15+
...
16+
44 | one!("hello", "world");
17+
| ----------------------- in this macro invocation
18+
19+
error: first parent: "hello"
20+
--> $DIR/parent-source-spans.rs:21:5
21+
|
22+
21 | two!($a, $b);
23+
| ^^^^^^^^^^^^^
24+
...
25+
44 | one!("hello", "world");
26+
| ----------------------- in this macro invocation
27+
28+
error: second parent: "world"
29+
--> $DIR/parent-source-spans.rs:21:5
30+
|
31+
21 | two!($a, $b);
32+
| ^^^^^^^^^^^^^
33+
...
34+
44 | one!("hello", "world");
35+
| ----------------------- in this macro invocation
36+
37+
error: first grandparent: "hello"
38+
--> $DIR/parent-source-spans.rs:44:5
39+
|
40+
44 | one!("hello", "world");
41+
| ^^^^^^^^^^^^^^^^^^^^^^^
42+
43+
error: second grandparent: "world"
44+
--> $DIR/parent-source-spans.rs:44:5
45+
|
46+
44 | one!("hello", "world");
47+
| ^^^^^^^^^^^^^^^^^^^^^^^
48+
49+
error: first source: "hello"
50+
--> $DIR/parent-source-spans.rs:44:5
51+
|
52+
44 | one!("hello", "world");
53+
| ^^^^^^^^^^^^^^^^^^^^^^^
54+
55+
error: second source: "world"
56+
--> $DIR/parent-source-spans.rs:44:5
57+
|
58+
44 | one!("hello", "world");
59+
| ^^^^^^^^^^^^^^^^^^^^^^^
60+
61+
error: first final: "yay"
62+
--> $DIR/parent-source-spans.rs:27:12
63+
|
64+
27 | three!($a, $b);
65+
| ^^
66+
...
67+
50 | two!("yay", "rust");
68+
| -------------------- in this macro invocation
69+
70+
error: second final: "rust"
71+
--> $DIR/parent-source-spans.rs:27:16
72+
|
73+
27 | three!($a, $b);
74+
| ^^
75+
...
76+
50 | two!("yay", "rust");
77+
| -------------------- in this macro invocation
78+
79+
error: first parent: "yay"
80+
--> $DIR/parent-source-spans.rs:50:5
81+
|
82+
50 | two!("yay", "rust");
83+
| ^^^^^^^^^^^^^^^^^^^^
84+
85+
error: second parent: "rust"
86+
--> $DIR/parent-source-spans.rs:50:5
87+
|
88+
50 | two!("yay", "rust");
89+
| ^^^^^^^^^^^^^^^^^^^^
90+
91+
error: first source: "yay"
92+
--> $DIR/parent-source-spans.rs:50:5
93+
|
94+
50 | two!("yay", "rust");
95+
| ^^^^^^^^^^^^^^^^^^^^
96+
97+
error: second source: "rust"
98+
--> $DIR/parent-source-spans.rs:50:5
99+
|
100+
50 | two!("yay", "rust");
101+
| ^^^^^^^^^^^^^^^^^^^^
102+
103+
error: first final: "hip"
104+
--> $DIR/parent-source-spans.rs:56:12
105+
|
106+
56 | three!("hip", "hop");
107+
| ^^^^^
108+
109+
error: second final: "hop"
110+
--> $DIR/parent-source-spans.rs:56:19
111+
|
112+
56 | three!("hip", "hop");
113+
| ^^^^^
114+
115+
error: first source: "hip"
116+
--> $DIR/parent-source-spans.rs:56:12
117+
|
118+
56 | three!("hip", "hop");
119+
| ^^^^^
120+
121+
error: second source: "hop"
122+
--> $DIR/parent-source-spans.rs:56:19
123+
|
124+
56 | three!("hip", "hop");
125+
| ^^^^^
126+
127+
error: aborting due to 18 previous errors
128+

0 commit comments

Comments
 (0)