mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-12 01:47:38 +00:00
Auto merge of #26347 - nagisa:macro-exp, r=nrc
r? @nrc, because breakage was caused by https://github.com/rust-lang/rust/pull/25318
This commit is contained in:
commit
20d23d8e57
@ -17,7 +17,7 @@
|
|||||||
//! within the CodeMap, which upon request can be converted to line and column
|
//! within the CodeMap, which upon request can be converted to line and column
|
||||||
//! information, source code snippets, etc.
|
//! information, source code snippets, etc.
|
||||||
|
|
||||||
pub use self::MacroFormat::*;
|
pub use self::ExpnFormat::*;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ops::{Add, Sub};
|
use std::ops::{Add, Sub};
|
||||||
@ -228,17 +228,17 @@ pub struct FileMapAndBytePos { pub fm: Rc<FileMap>, pub pos: BytePos }
|
|||||||
|
|
||||||
|
|
||||||
// _____________________________________________________________________________
|
// _____________________________________________________________________________
|
||||||
// MacroFormat, NameAndSpan, ExpnInfo, ExpnId
|
// ExpnFormat, NameAndSpan, ExpnInfo, ExpnId
|
||||||
//
|
//
|
||||||
|
|
||||||
/// The syntax with which a macro was invoked.
|
/// The source of expansion.
|
||||||
#[derive(Clone, Copy, Hash, Debug)]
|
#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
|
||||||
pub enum MacroFormat {
|
pub enum ExpnFormat {
|
||||||
/// e.g. #[derive(...)] <item>
|
/// e.g. #[derive(...)] <item>
|
||||||
MacroAttribute,
|
MacroAttribute,
|
||||||
/// e.g. `format!()`
|
/// e.g. `format!()`
|
||||||
MacroBang,
|
MacroBang,
|
||||||
/// Expansion performed by the compiler (libsyntax::expand).
|
/// Syntax sugar expansion performed by the compiler (libsyntax::expand).
|
||||||
CompilerExpansion,
|
CompilerExpansion,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,7 +248,7 @@ pub struct NameAndSpan {
|
|||||||
/// with this Span.
|
/// with this Span.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// The format with which the macro was invoked.
|
/// The format with which the macro was invoked.
|
||||||
pub format: MacroFormat,
|
pub format: ExpnFormat,
|
||||||
/// Whether the macro is allowed to use #[unstable]/feature-gated
|
/// Whether the macro is allowed to use #[unstable]/feature-gated
|
||||||
/// features internally without forcing the whole crate to opt-in
|
/// features internally without forcing the whole crate to opt-in
|
||||||
/// to them.
|
/// to them.
|
||||||
@ -259,11 +259,11 @@ pub struct NameAndSpan {
|
|||||||
pub span: Option<Span>
|
pub span: Option<Span>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extra information for tracking macro expansion of spans
|
/// Extra information for tracking spans of macro and syntax sugar expansion
|
||||||
#[derive(Hash, Debug)]
|
#[derive(Hash, Debug)]
|
||||||
pub struct ExpnInfo {
|
pub struct ExpnInfo {
|
||||||
/// The location of the actual macro invocation, e.g. `let x =
|
/// The location of the actual macro invocation or syntax sugar , e.g.
|
||||||
/// foo!();`
|
/// `let x = foo!();` or `if let Some(y) = x {}`
|
||||||
///
|
///
|
||||||
/// This may recursively refer to other macro invocations, e.g. if
|
/// This may recursively refer to other macro invocations, e.g. if
|
||||||
/// `foo!()` invoked `bar!()` internally, and there was an
|
/// `foo!()` invoked `bar!()` internally, and there was an
|
||||||
@ -272,12 +272,7 @@ pub struct ExpnInfo {
|
|||||||
/// call_site span would have its own ExpnInfo, with the call_site
|
/// call_site span would have its own ExpnInfo, with the call_site
|
||||||
/// pointing to the `foo!` invocation.
|
/// pointing to the `foo!` invocation.
|
||||||
pub call_site: Span,
|
pub call_site: Span,
|
||||||
/// Information about the macro and its definition.
|
/// Information about the expansion.
|
||||||
///
|
|
||||||
/// The `callee` of the inner expression in the `call_site`
|
|
||||||
/// example would point to the `macro_rules! bar { ... }` and that
|
|
||||||
/// of the `bar!()` invocation would point to the `macro_rules!
|
|
||||||
/// foo { ... }`.
|
|
||||||
pub callee: NameAndSpan
|
pub callee: NameAndSpan
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -677,7 +672,39 @@ impl CodeMap {
|
|||||||
|
|
||||||
/// Lookup source information about a BytePos
|
/// Lookup source information about a BytePos
|
||||||
pub fn lookup_char_pos(&self, pos: BytePos) -> Loc {
|
pub fn lookup_char_pos(&self, pos: BytePos) -> Loc {
|
||||||
self.lookup_pos(pos)
|
let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos);
|
||||||
|
let line = a + 1; // Line numbers start at 1
|
||||||
|
let chpos = self.bytepos_to_file_charpos(pos);
|
||||||
|
let linebpos = (*f.lines.borrow())[a];
|
||||||
|
let linechpos = self.bytepos_to_file_charpos(linebpos);
|
||||||
|
debug!("byte pos {:?} is on the line at byte pos {:?}",
|
||||||
|
pos, linebpos);
|
||||||
|
debug!("char pos {:?} is on the line at char pos {:?}",
|
||||||
|
chpos, linechpos);
|
||||||
|
debug!("byte is on line: {}", line);
|
||||||
|
assert!(chpos >= linechpos);
|
||||||
|
Loc {
|
||||||
|
file: f,
|
||||||
|
line: line,
|
||||||
|
col: chpos - linechpos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lookup_line(&self, pos: BytePos) -> FileMapAndLine {
|
||||||
|
let idx = self.lookup_filemap_idx(pos);
|
||||||
|
|
||||||
|
let files = self.files.borrow();
|
||||||
|
let f = (*files)[idx].clone();
|
||||||
|
let mut a = 0;
|
||||||
|
{
|
||||||
|
let lines = f.lines.borrow();
|
||||||
|
let mut b = lines.len();
|
||||||
|
while b - a > 1 {
|
||||||
|
let m = (a + b) / 2;
|
||||||
|
if (*lines)[m] > pos { b = m; } else { a = m; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FileMapAndLine {fm: f, line: a}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_char_pos_adj(&self, pos: BytePos) -> LocWithOpt {
|
pub fn lookup_char_pos_adj(&self, pos: BytePos) -> LocWithOpt {
|
||||||
@ -877,42 +904,6 @@ impl CodeMap {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_line(&self, pos: BytePos) -> FileMapAndLine {
|
|
||||||
let idx = self.lookup_filemap_idx(pos);
|
|
||||||
|
|
||||||
let files = self.files.borrow();
|
|
||||||
let f = (*files)[idx].clone();
|
|
||||||
let mut a = 0;
|
|
||||||
{
|
|
||||||
let lines = f.lines.borrow();
|
|
||||||
let mut b = lines.len();
|
|
||||||
while b - a > 1 {
|
|
||||||
let m = (a + b) / 2;
|
|
||||||
if (*lines)[m] > pos { b = m; } else { a = m; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
FileMapAndLine {fm: f, line: a}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup_pos(&self, pos: BytePos) -> Loc {
|
|
||||||
let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos);
|
|
||||||
let line = a + 1; // Line numbers start at 1
|
|
||||||
let chpos = self.bytepos_to_file_charpos(pos);
|
|
||||||
let linebpos = (*f.lines.borrow())[a];
|
|
||||||
let linechpos = self.bytepos_to_file_charpos(linebpos);
|
|
||||||
debug!("byte pos {:?} is on the line at byte pos {:?}",
|
|
||||||
pos, linebpos);
|
|
||||||
debug!("char pos {:?} is on the line at char pos {:?}",
|
|
||||||
chpos, linechpos);
|
|
||||||
debug!("byte is on line: {}", line);
|
|
||||||
assert!(chpos >= linechpos);
|
|
||||||
Loc {
|
|
||||||
file: f,
|
|
||||||
line: line,
|
|
||||||
col: chpos - linechpos
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId {
|
pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId {
|
||||||
let mut expansions = self.expansions.borrow_mut();
|
let mut expansions = self.expansions.borrow_mut();
|
||||||
expansions.push(expn_info);
|
expansions.push(expn_info);
|
||||||
|
@ -13,7 +13,7 @@ pub use self::SyntaxExtension::*;
|
|||||||
use ast;
|
use ast;
|
||||||
use ast::Name;
|
use ast::Name;
|
||||||
use codemap;
|
use codemap;
|
||||||
use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION};
|
use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION, CompilerExpansion};
|
||||||
use ext;
|
use ext;
|
||||||
use ext::expand;
|
use ext::expand;
|
||||||
use ext::tt::macro_rules;
|
use ext::tt::macro_rules;
|
||||||
@ -658,6 +658,8 @@ impl<'a> ExtCtxt<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn backtrace(&self) -> ExpnId { self.backtrace }
|
pub fn backtrace(&self) -> ExpnId { self.backtrace }
|
||||||
|
|
||||||
|
/// Original span that caused the current exapnsion to happen.
|
||||||
pub fn original_span(&self) -> Span {
|
pub fn original_span(&self) -> Span {
|
||||||
let mut expn_id = self.backtrace;
|
let mut expn_id = self.backtrace;
|
||||||
let mut call_site = None;
|
let mut call_site = None;
|
||||||
@ -672,26 +674,31 @@ impl<'a> ExtCtxt<'a> {
|
|||||||
}
|
}
|
||||||
call_site.expect("missing expansion backtrace")
|
call_site.expect("missing expansion backtrace")
|
||||||
}
|
}
|
||||||
pub fn original_span_in_file(&self) -> Span {
|
|
||||||
|
/// Returns span for the macro which originally caused the current expansion to happen.
|
||||||
|
///
|
||||||
|
/// Stops backtracing at include! boundary.
|
||||||
|
pub fn expansion_cause(&self) -> Span {
|
||||||
let mut expn_id = self.backtrace;
|
let mut expn_id = self.backtrace;
|
||||||
let mut call_site = None;
|
let mut last_macro = None;
|
||||||
loop {
|
loop {
|
||||||
let expn_info = self.codemap().with_expn_info(expn_id, |ei| {
|
if self.codemap().with_expn_info(expn_id, |info| {
|
||||||
ei.map(|ei| (ei.call_site, ei.callee.name == "include"))
|
info.map_or(None, |i| {
|
||||||
});
|
if i.callee.name == "include" {
|
||||||
match expn_info {
|
// Stop going up the backtrace once include! is encountered
|
||||||
None => break,
|
return None;
|
||||||
Some((cs, is_include)) => {
|
|
||||||
if is_include {
|
|
||||||
// Don't recurse into file using "include!".
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
call_site = Some(cs);
|
expn_id = i.call_site.expn_id;
|
||||||
expn_id = cs.expn_id;
|
if i.callee.format != CompilerExpansion {
|
||||||
|
last_macro = Some(i.call_site)
|
||||||
|
}
|
||||||
|
return Some(());
|
||||||
|
})
|
||||||
|
}).is_none() {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
last_macro.expect("missing expansion backtrace")
|
||||||
call_site.expect("missing expansion backtrace")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mod_push(&mut self, i: ast::Ident) { self.mod_path.push(i); }
|
pub fn mod_push(&mut self, i: ast::Ident) { self.mod_path.push(i); }
|
||||||
|
@ -34,7 +34,7 @@ pub fn expand_line(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
|||||||
-> Box<base::MacResult+'static> {
|
-> Box<base::MacResult+'static> {
|
||||||
base::check_zero_tts(cx, sp, tts, "line!");
|
base::check_zero_tts(cx, sp, tts, "line!");
|
||||||
|
|
||||||
let topmost = cx.original_span_in_file();
|
let topmost = cx.expansion_cause();
|
||||||
let loc = cx.codemap().lookup_char_pos(topmost.lo);
|
let loc = cx.codemap().lookup_char_pos(topmost.lo);
|
||||||
|
|
||||||
base::MacEager::expr(cx.expr_u32(topmost, loc.line as u32))
|
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])
|
|||||||
-> Box<base::MacResult+'static> {
|
-> Box<base::MacResult+'static> {
|
||||||
base::check_zero_tts(cx, sp, tts, "column!");
|
base::check_zero_tts(cx, sp, tts, "column!");
|
||||||
|
|
||||||
let topmost = cx.original_span_in_file();
|
let topmost = cx.expansion_cause();
|
||||||
let loc = cx.codemap().lookup_char_pos(topmost.lo);
|
let loc = cx.codemap().lookup_char_pos(topmost.lo);
|
||||||
|
|
||||||
base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32))
|
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])
|
|||||||
-> Box<base::MacResult+'static> {
|
-> Box<base::MacResult+'static> {
|
||||||
base::check_zero_tts(cx, sp, tts, "file!");
|
base::check_zero_tts(cx, sp, tts, "file!");
|
||||||
|
|
||||||
let topmost = cx.original_span_in_file();
|
let topmost = cx.expansion_cause();
|
||||||
let loc = cx.codemap().lookup_char_pos(topmost.lo);
|
let loc = cx.codemap().lookup_char_pos(topmost.lo);
|
||||||
let filename = token::intern_and_get_ident(&loc.file.name);
|
let filename = token::intern_and_get_ident(&loc.file.name);
|
||||||
base::MacEager::expr(cx.expr_str(topmost, filename))
|
base::MacEager::expr(cx.expr_str(topmost, filename))
|
||||||
|
36
src/test/run-pass/issue-26322.rs
Normal file
36
src/test/run-pass/issue-26322.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2015 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! columnline {
|
||||||
|
() => (
|
||||||
|
(column!(), line!())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! indirectcolumnline {
|
||||||
|
() => (
|
||||||
|
(||{ columnline!() })()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let closure = || {
|
||||||
|
columnline!()
|
||||||
|
};
|
||||||
|
let iflet = if let Some(_) = Some(0) {
|
||||||
|
columnline!()
|
||||||
|
} else { (0, 0) };
|
||||||
|
let cl = columnline!();
|
||||||
|
assert_eq!(closure(), (8, 25));
|
||||||
|
assert_eq!(iflet, (8, 28));
|
||||||
|
assert_eq!(cl, (13, 30));
|
||||||
|
let indirect = indirectcolumnline!();
|
||||||
|
assert_eq!(indirect, (19, 34));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user