Use the macro structure spans instead of the invocation
This commit is contained in:
parent
cc800531cc
commit
e99d309c56
8 changed files with 108 additions and 14 deletions
|
@ -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 {
|
||||
|
|
|
@ -119,8 +119,21 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
|
|||
quoted::TokenTree::Delimited(_, ref delimed) => delimed.tts.clone(),
|
||||
_ => cx.span_bug(sp, "malformed macro rhs"),
|
||||
};
|
||||
|
||||
// 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.clone());
|
||||
|
||||
// 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.len() == tts.len() {
|
||||
tts = tts.map_pos(|i, tt| {
|
||||
let mut tt = tt.clone();
|
||||
let mut sp = rhs[i].span();
|
||||
sp.ctxt = tt.span().ctxt;
|
||||
tt.set_span(sp);
|
||||
tt
|
||||
});
|
||||
}
|
||||
|
||||
if cx.trace_macros() {
|
||||
trace_macros_note(cx, sp, format!("to `{}`", tts));
|
||||
|
|
|
@ -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, _) |
|
||||
|
|
|
@ -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`"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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_pos<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();
|
||||
|
|
|
@ -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,32 @@ impl Span {
|
|||
result
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
pub fn empty_ctxt(&self) -> bool {
|
||||
self.ctxt == SyntaxContext::empty()
|
||||
}
|
||||
|
||||
/// Return a `Span` that would enclose both `self` and `end`.
|
||||
pub fn to(self, end: Span) -> Span {
|
||||
let lo = if self.lo < end.lo {
|
||||
self.lo
|
||||
} else {
|
||||
end.lo
|
||||
};
|
||||
let hi = if self.hi > end.hi {
|
||||
self.hi
|
||||
} else {
|
||||
end.hi
|
||||
};
|
||||
// FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
|
||||
let ctxt = if self.ctxt == SyntaxContext::empty() {
|
||||
end.ctxt
|
||||
} else {
|
||||
self.ctxt
|
||||
};
|
||||
Span {lo, hi, 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 +223,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 +871,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,
|
||||
|
|
19
src/test/ui/span/macro-span-replacement.rs
Normal file
19
src/test/ui/span/macro-span-replacement.rs
Normal file
|
@ -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);
|
||||
}
|
11
src/test/ui/span/macro-span-replacement.stderr
Normal file
11
src/test/ui/span/macro-span-replacement.stderr
Normal file
|
@ -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
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue