Skip to content

Commit 7ff55ea

Browse files
committed
Fix file!(), line!() and column!() macros
These used to return wrong results in case they were expanded inside compiler’s iternal syntax sugar (closures, if-let) expansions Fixes #26322
1 parent 73fb19c commit 7ff55ea

File tree

3 files changed

+72
-72
lines changed

3 files changed

+72
-72
lines changed

src/libsyntax/codemap.rs

Lines changed: 44 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
//! within the CodeMap, which upon request can be converted to line and column
1818
//! information, source code snippets, etc.
1919
20-
pub use self::MacroFormat::*;
20+
pub use self::ExpnFormat::*;
2121

2222
use std::cell::RefCell;
2323
use std::ops::{Add, Sub};
@@ -228,17 +228,17 @@ pub struct FileMapAndBytePos { pub fm: Rc<FileMap>, pub pos: BytePos }
228228

229229

230230
// _____________________________________________________________________________
231-
// MacroFormat, NameAndSpan, ExpnInfo, ExpnId
231+
// ExpnFormat, NameAndSpan, ExpnInfo, ExpnId
232232
//
233233

234-
/// The syntax with which a macro was invoked.
235-
#[derive(Clone, Copy, Hash, Debug)]
236-
pub enum MacroFormat {
234+
/// The source of expansion.
235+
#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
236+
pub enum ExpnFormat {
237237
/// e.g. #[derive(...)] <item>
238238
MacroAttribute,
239239
/// e.g. `format!()`
240240
MacroBang,
241-
/// Expansion performed by the compiler (libsyntax::expand).
241+
/// Syntax sugar expansion performed by the compiler (libsyntax::expand).
242242
CompilerExpansion,
243243
}
244244

@@ -248,7 +248,7 @@ pub struct NameAndSpan {
248248
/// with this Span.
249249
pub name: String,
250250
/// The format with which the macro was invoked.
251-
pub format: MacroFormat,
251+
pub format: ExpnFormat,
252252
/// Whether the macro is allowed to use #[unstable]/feature-gated
253253
/// features internally without forcing the whole crate to opt-in
254254
/// to them.
@@ -259,11 +259,11 @@ pub struct NameAndSpan {
259259
pub span: Option<Span>
260260
}
261261

262-
/// Extra information for tracking macro expansion of spans
262+
/// Extra information for tracking spans of macro and syntax sugar expansion
263263
#[derive(Hash, Debug)]
264264
pub struct ExpnInfo {
265-
/// The location of the actual macro invocation, e.g. `let x =
266-
/// foo!();`
265+
/// The location of the actual macro invocation or syntax sugar , e.g.
266+
/// `let x = foo!();` or `if let Some(y) = x {}`
267267
///
268268
/// This may recursively refer to other macro invocations, e.g. if
269269
/// `foo!()` invoked `bar!()` internally, and there was an
@@ -272,12 +272,7 @@ pub struct ExpnInfo {
272272
/// call_site span would have its own ExpnInfo, with the call_site
273273
/// pointing to the `foo!` invocation.
274274
pub call_site: Span,
275-
/// Information about the macro and its definition.
276-
///
277-
/// The `callee` of the inner expression in the `call_site`
278-
/// example would point to the `macro_rules! bar { ... }` and that
279-
/// of the `bar!()` invocation would point to the `macro_rules!
280-
/// foo { ... }`.
275+
/// Information about the expansion.
281276
pub callee: NameAndSpan
282277
}
283278

@@ -677,7 +672,39 @@ impl CodeMap {
677672

678673
/// Lookup source information about a BytePos
679674
pub fn lookup_char_pos(&self, pos: BytePos) -> Loc {
680-
self.lookup_pos(pos)
675+
let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos);
676+
let line = a + 1; // Line numbers start at 1
677+
let chpos = self.bytepos_to_file_charpos(pos);
678+
let linebpos = (*f.lines.borrow())[a];
679+
let linechpos = self.bytepos_to_file_charpos(linebpos);
680+
debug!("byte pos {:?} is on the line at byte pos {:?}",
681+
pos, linebpos);
682+
debug!("char pos {:?} is on the line at char pos {:?}",
683+
chpos, linechpos);
684+
debug!("byte is on line: {}", line);
685+
assert!(chpos >= linechpos);
686+
Loc {
687+
file: f,
688+
line: line,
689+
col: chpos - linechpos
690+
}
691+
}
692+
693+
fn lookup_line(&self, pos: BytePos) -> FileMapAndLine {
694+
let idx = self.lookup_filemap_idx(pos);
695+
696+
let files = self.files.borrow();
697+
let f = (*files)[idx].clone();
698+
let mut a = 0;
699+
{
700+
let lines = f.lines.borrow();
701+
let mut b = lines.len();
702+
while b - a > 1 {
703+
let m = (a + b) / 2;
704+
if (*lines)[m] > pos { b = m; } else { a = m; }
705+
}
706+
}
707+
FileMapAndLine {fm: f, line: a}
681708
}
682709

683710
pub fn lookup_char_pos_adj(&self, pos: BytePos) -> LocWithOpt {
@@ -877,42 +904,6 @@ impl CodeMap {
877904
return a;
878905
}
879906

880-
fn lookup_line(&self, pos: BytePos) -> FileMapAndLine {
881-
let idx = self.lookup_filemap_idx(pos);
882-
883-
let files = self.files.borrow();
884-
let f = (*files)[idx].clone();
885-
let mut a = 0;
886-
{
887-
let lines = f.lines.borrow();
888-
let mut b = lines.len();
889-
while b - a > 1 {
890-
let m = (a + b) / 2;
891-
if (*lines)[m] > pos { b = m; } else { a = m; }
892-
}
893-
}
894-
FileMapAndLine {fm: f, line: a}
895-
}
896-
897-
fn lookup_pos(&self, pos: BytePos) -> Loc {
898-
let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos);
899-
let line = a + 1; // Line numbers start at 1
900-
let chpos = self.bytepos_to_file_charpos(pos);
901-
let linebpos = (*f.lines.borrow())[a];
902-
let linechpos = self.bytepos_to_file_charpos(linebpos);
903-
debug!("byte pos {:?} is on the line at byte pos {:?}",
904-
pos, linebpos);
905-
debug!("char pos {:?} is on the line at char pos {:?}",
906-
chpos, linechpos);
907-
debug!("byte is on line: {}", line);
908-
assert!(chpos >= linechpos);
909-
Loc {
910-
file: f,
911-
line: line,
912-
col: chpos - linechpos
913-
}
914-
}
915-
916907
pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId {
917908
let mut expansions = self.expansions.borrow_mut();
918909
expansions.push(expn_info);

src/libsyntax/ext/base.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub use self::SyntaxExtension::*;
1313
use ast;
1414
use ast::Name;
1515
use codemap;
16-
use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION};
16+
use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION, CompilerExpansion};
1717
use ext;
1818
use ext::expand;
1919
use ext::tt::macro_rules;
@@ -658,6 +658,8 @@ impl<'a> ExtCtxt<'a> {
658658
})
659659
}
660660
pub fn backtrace(&self) -> ExpnId { self.backtrace }
661+
662+
/// Original span that caused the current exapnsion to happen.
661663
pub fn original_span(&self) -> Span {
662664
let mut expn_id = self.backtrace;
663665
let mut call_site = None;
@@ -672,26 +674,33 @@ impl<'a> ExtCtxt<'a> {
672674
}
673675
call_site.expect("missing expansion backtrace")
674676
}
675-
pub fn original_span_in_file(&self) -> Span {
677+
678+
/// Returns span for the macro which originally caused the current expansion to happen.
679+
///
680+
/// Stops backtracing at include! boundary.
681+
pub fn expansion_cause(&self) -> Span {
676682
let mut expn_id = self.backtrace;
677-
let mut call_site = None;
683+
let mut last_macro = None;
684+
let mut current_expn = None;
678685
loop {
679-
let expn_info = self.codemap().with_expn_info(expn_id, |ei| {
680-
ei.map(|ei| (ei.call_site, ei.callee.name == "include"))
681-
});
682-
match expn_info {
683-
None => break,
684-
Some((cs, is_include)) => {
685-
if is_include {
686-
// Don't recurse into file using "include!".
687-
break;
686+
if self.codemap().with_expn_info(expn_id, |info| {
687+
info.map_or(None, |i| {
688+
if i.callee.name == "include" {
689+
// Stop going up the backtrace once include! is encountered
690+
return None;
688691
}
689-
call_site = Some(cs);
690-
expn_id = cs.expn_id;
691-
}
692+
expn_id = i.call_site.expn_id;
693+
current_expn = Some(i.call_site);
694+
if i.callee.format != CompilerExpansion {
695+
last_macro = Some(i.call_site)
696+
}
697+
return Some(());
698+
})
699+
}).is_none() {
700+
break
692701
}
693702
}
694-
call_site.expect("missing expansion backtrace")
703+
last_macro.expect("missing expansion backtrace")
695704
}
696705

697706
pub fn mod_push(&mut self, i: ast::Ident) { self.mod_path.push(i); }

src/libsyntax/ext/source_util.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn expand_line(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
3434
-> Box<base::MacResult+'static> {
3535
base::check_zero_tts(cx, sp, tts, "line!");
3636

37-
let topmost = cx.original_span_in_file();
37+
let topmost = cx.expansion_cause();
3838
let loc = cx.codemap().lookup_char_pos(topmost.lo);
3939

4040
base::MacEager::expr(cx.expr_u32(topmost, loc.line as u32))
@@ -45,7 +45,7 @@ pub fn expand_column(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
4545
-> Box<base::MacResult+'static> {
4646
base::check_zero_tts(cx, sp, tts, "column!");
4747

48-
let topmost = cx.original_span_in_file();
48+
let topmost = cx.expansion_cause();
4949
let loc = cx.codemap().lookup_char_pos(topmost.lo);
5050

5151
base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32))
@@ -58,7 +58,7 @@ pub fn expand_file(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
5858
-> Box<base::MacResult+'static> {
5959
base::check_zero_tts(cx, sp, tts, "file!");
6060

61-
let topmost = cx.original_span_in_file();
61+
let topmost = cx.expansion_cause();
6262
let loc = cx.codemap().lookup_char_pos(topmost.lo);
6363
let filename = token::intern_and_get_ident(&loc.file.name);
6464
base::MacEager::expr(cx.expr_str(topmost, filename))

0 commit comments

Comments
 (0)