Skip to content

Commit 5bbdbfa

Browse files
nagisabrson
authored andcommitted
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 bd01426 commit 5bbdbfa

File tree

3 files changed

+72
-72
lines changed

3 files changed

+72
-72
lines changed

src/libsyntax/codemap.rs

+44-53
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};
@@ -226,17 +226,17 @@ pub struct FileMapAndBytePos { pub fm: Rc<FileMap>, pub pos: BytePos }
226226

227227

228228
// _____________________________________________________________________________
229-
// MacroFormat, NameAndSpan, ExpnInfo, ExpnId
229+
// ExpnFormat, NameAndSpan, ExpnInfo, ExpnId
230230
//
231231

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

@@ -246,7 +246,7 @@ pub struct NameAndSpan {
246246
/// with this Span.
247247
pub name: String,
248248
/// The format with which the macro was invoked.
249-
pub format: MacroFormat,
249+
pub format: ExpnFormat,
250250
/// Whether the macro is allowed to use #[unstable]/feature-gated
251251
/// features internally without forcing the whole crate to opt-in
252252
/// to them.
@@ -257,11 +257,11 @@ pub struct NameAndSpan {
257257
pub span: Option<Span>
258258
}
259259

260-
/// Extra information for tracking macro expansion of spans
260+
/// Extra information for tracking spans of macro and syntax sugar expansion
261261
#[derive(Hash, Debug)]
262262
pub struct ExpnInfo {
263-
/// The location of the actual macro invocation, e.g. `let x =
264-
/// foo!();`
263+
/// The location of the actual macro invocation or syntax sugar , e.g.
264+
/// `let x = foo!();` or `if let Some(y) = x {}`
265265
///
266266
/// This may recursively refer to other macro invocations, e.g. if
267267
/// `foo!()` invoked `bar!()` internally, and there was an
@@ -270,12 +270,7 @@ pub struct ExpnInfo {
270270
/// call_site span would have its own ExpnInfo, with the call_site
271271
/// pointing to the `foo!` invocation.
272272
pub call_site: Span,
273-
/// Information about the macro and its definition.
274-
///
275-
/// The `callee` of the inner expression in the `call_site`
276-
/// example would point to the `macro_rules! bar { ... }` and that
277-
/// of the `bar!()` invocation would point to the `macro_rules!
278-
/// foo { ... }`.
273+
/// Information about the expansion.
279274
pub callee: NameAndSpan
280275
}
281276

@@ -633,7 +628,39 @@ impl CodeMap {
633628

634629
/// Lookup source information about a BytePos
635630
pub fn lookup_char_pos(&self, pos: BytePos) -> Loc {
636-
self.lookup_pos(pos)
631+
let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos);
632+
let line = a + 1; // Line numbers start at 1
633+
let chpos = self.bytepos_to_file_charpos(pos);
634+
let linebpos = (*f.lines.borrow())[a];
635+
let linechpos = self.bytepos_to_file_charpos(linebpos);
636+
debug!("byte pos {:?} is on the line at byte pos {:?}",
637+
pos, linebpos);
638+
debug!("char pos {:?} is on the line at char pos {:?}",
639+
chpos, linechpos);
640+
debug!("byte is on line: {}", line);
641+
assert!(chpos >= linechpos);
642+
Loc {
643+
file: f,
644+
line: line,
645+
col: chpos - linechpos
646+
}
647+
}
648+
649+
fn lookup_line(&self, pos: BytePos) -> FileMapAndLine {
650+
let idx = self.lookup_filemap_idx(pos);
651+
652+
let files = self.files.borrow();
653+
let f = (*files)[idx].clone();
654+
let mut a = 0;
655+
{
656+
let lines = f.lines.borrow();
657+
let mut b = lines.len();
658+
while b - a > 1 {
659+
let m = (a + b) / 2;
660+
if (*lines)[m] > pos { b = m; } else { a = m; }
661+
}
662+
}
663+
FileMapAndLine {fm: f, line: a}
637664
}
638665

639666
pub fn lookup_char_pos_adj(&self, pos: BytePos) -> LocWithOpt {
@@ -833,42 +860,6 @@ impl CodeMap {
833860
return a;
834861
}
835862

836-
fn lookup_line(&self, pos: BytePos) -> FileMapAndLine {
837-
let idx = self.lookup_filemap_idx(pos);
838-
839-
let files = self.files.borrow();
840-
let f = (*files)[idx].clone();
841-
let mut a = 0;
842-
{
843-
let lines = f.lines.borrow();
844-
let mut b = lines.len();
845-
while b - a > 1 {
846-
let m = (a + b) / 2;
847-
if (*lines)[m] > pos { b = m; } else { a = m; }
848-
}
849-
}
850-
FileMapAndLine {fm: f, line: a}
851-
}
852-
853-
fn lookup_pos(&self, pos: BytePos) -> Loc {
854-
let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos);
855-
let line = a + 1; // Line numbers start at 1
856-
let chpos = self.bytepos_to_file_charpos(pos);
857-
let linebpos = (*f.lines.borrow())[a];
858-
let linechpos = self.bytepos_to_file_charpos(linebpos);
859-
debug!("byte pos {:?} is on the line at byte pos {:?}",
860-
pos, linebpos);
861-
debug!("char pos {:?} is on the line at char pos {:?}",
862-
chpos, linechpos);
863-
debug!("byte is on line: {}", line);
864-
assert!(chpos >= linechpos);
865-
Loc {
866-
file: f,
867-
line: line,
868-
col: chpos - linechpos
869-
}
870-
}
871-
872863
pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId {
873864
let mut expansions = self.expansions.borrow_mut();
874865
expansions.push(expn_info);

src/libsyntax/ext/base.rs

+25-16
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

+3-3
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)