Merge `ExpnId` and `SyntaxContext`.

This commit is contained in:
Jeffrey Seyfried 2017-03-17 04:04:41 +00:00
parent 496996c2af
commit ec7c0aece1
46 changed files with 456 additions and 702 deletions

View File

@ -57,6 +57,7 @@ use std::mem;
use syntax::attr;
use syntax::ast::*;
use syntax::errors;
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::ptr::P;
use syntax::codemap::{self, respan, Spanned};
use syntax::std_inject;
@ -392,7 +393,8 @@ impl<'a> LoweringContext<'a> {
}
fn allow_internal_unstable(&self, reason: &'static str, mut span: Span) -> Span {
span.expn_id = self.sess.codemap().record_expansion(codemap::ExpnInfo {
let mark = Mark::fresh();
mark.set_expn_info(codemap::ExpnInfo {
call_site: span,
callee: codemap::NameAndSpan {
format: codemap::CompilerDesugaring(Symbol::intern(reason)),
@ -400,6 +402,7 @@ impl<'a> LoweringContext<'a> {
allow_internal_unstable: true,
},
});
span.ctxt = SyntaxContext::empty().apply_mark(mark);
span
}
@ -1986,7 +1989,7 @@ impl<'a> LoweringContext<'a> {
volatile: asm.volatile,
alignstack: asm.alignstack,
dialect: asm.dialect,
expn_id: asm.expn_id,
ctxt: asm.ctxt,
};
let outputs =
asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect();

View File

@ -33,11 +33,12 @@ use hir::def::Def;
use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
use util::nodemap::{NodeMap, FxHashSet};
use syntax_pos::{Span, ExpnId, DUMMY_SP};
use syntax_pos::{Span, DUMMY_SP};
use syntax::codemap::{self, Spanned};
use syntax::abi::Abi;
use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
use syntax::ext::hygiene::SyntaxContext;
use syntax::ptr::P;
use syntax::symbol::{Symbol, keywords};
use syntax::tokenstream::TokenStream;
@ -1367,7 +1368,7 @@ pub struct InlineAsm {
pub volatile: bool,
pub alignstack: bool,
pub dialect: AsmDialect,
pub expn_id: ExpnId,
pub ctxt: SyntaxContext,
}
/// represents an argument in a function header

View File

@ -47,10 +47,6 @@ impl<'tcx> CachingCodemapView<'tcx> {
}
}
pub fn codemap(&self) -> &'tcx CodeMap {
self.codemap
}
pub fn byte_pos_to_line_and_col(&mut self,
pos: BytePos)
-> Option<(Rc<FileMap>, usize, BytePos)> {

View File

@ -236,7 +236,7 @@ impl CodeExtent {
// (This is the special case aluded to in the
// doc-comment for this method)
let stmt_span = blk.stmts[r.first_statement_index as usize].span;
Some(Span { lo: stmt_span.hi, hi: blk.span.hi, expn_id: stmt_span.expn_id })
Some(Span { lo: stmt_span.hi, hi: blk.span.hi, ctxt: stmt_span.ctxt })
}
}
}

View File

@ -467,7 +467,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}
pub fn check_stability(self, def_id: DefId, id: NodeId, span: Span) {
if self.sess.codemap().span_allows_unstable(span) {
if span.allows_unstable() {
debug!("stability: \
skipping span={:?} since it is internal", span);
return;

View File

@ -580,7 +580,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
krate = time(time_passes, "crate injection", || {
let alt_std_name = sess.opts.alt_std_name.clone();
syntax::std_inject::maybe_inject_crates_ref(&sess.parse_sess, krate, alt_std_name)
syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name)
});
let mut addl_plugins = Some(addl_plugins);
@ -798,7 +798,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
// Discard hygiene data, which isn't required after lowering to HIR.
if !keep_hygiene_data(sess) {
syntax::ext::hygiene::reset_hygiene_data();
syntax::ext::hygiene::clear_markings();
}
Ok(ExpansionResult {

View File

@ -10,7 +10,7 @@
use self::Destination::*;
use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos};
use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan, CharPos};
use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper};
use RenderSpan::*;
@ -151,7 +151,7 @@ impl EmitterWriter {
if let Some(ref cm) = self.cm {
for span_label in msp.span_labels() {
if span_label.span == DUMMY_SP || span_label.span == COMMAND_LINE_SP {
if span_label.span == DUMMY_SP {
continue;
}
let lo = cm.lookup_char_pos(span_label.span.lo);
@ -615,7 +615,7 @@ impl EmitterWriter {
let mut max = 0;
if let Some(ref cm) = self.cm {
for primary_span in msp.primary_spans() {
if primary_span != &DUMMY_SP && primary_span != &COMMAND_LINE_SP {
if primary_span != &DUMMY_SP {
let hi = cm.lookup_char_pos(primary_span.hi);
if hi.line > max {
max = hi.line;
@ -623,7 +623,7 @@ impl EmitterWriter {
}
}
for span_label in msp.span_labels() {
if span_label.span != DUMMY_SP && span_label.span != COMMAND_LINE_SP {
if span_label.span != DUMMY_SP {
let hi = cm.lookup_char_pos(span_label.span.hi);
if hi.line > max {
max = hi.line;
@ -659,20 +659,20 @@ impl EmitterWriter {
// First, find all the spans in <*macros> and point instead at their use site
for sp in span.primary_spans() {
if (*sp == COMMAND_LINE_SP) || (*sp == DUMMY_SP) {
if *sp == DUMMY_SP {
continue;
}
if cm.span_to_filename(sp.clone()).contains("macros>") {
let v = cm.macro_backtrace(sp.clone());
let v = sp.macro_backtrace();
if let Some(use_site) = v.last() {
before_after.push((sp.clone(), use_site.call_site.clone()));
}
}
for trace in cm.macro_backtrace(sp.clone()).iter().rev() {
for trace in sp.macro_backtrace().iter().rev() {
// Only show macro locations that are local
// and display them like a span_note
if let Some(def_site) = trace.def_site_span {
if (def_site == COMMAND_LINE_SP) || (def_site == DUMMY_SP) {
if def_site == DUMMY_SP {
continue;
}
// Check to make sure we're not in any <*macros>
@ -689,11 +689,11 @@ impl EmitterWriter {
span.push_span_label(label_span, label_text);
}
for sp_label in span.span_labels() {
if (sp_label.span == COMMAND_LINE_SP) || (sp_label.span == DUMMY_SP) {
if sp_label.span == DUMMY_SP {
continue;
}
if cm.span_to_filename(sp_label.span.clone()).contains("macros>") {
let v = cm.macro_backtrace(sp_label.span.clone());
let v = sp_label.span.macro_backtrace();
if let Some(use_site) = v.last() {
before_after.push((sp_label.span.clone(), use_site.call_site.clone()));
}
@ -848,7 +848,7 @@ impl EmitterWriter {
// Make sure our primary file comes first
let primary_lo = if let (Some(ref cm), Some(ref primary_span)) =
(self.cm.as_ref(), msp.primary_span().as_ref()) {
if primary_span != &&DUMMY_SP && primary_span != &&COMMAND_LINE_SP {
if primary_span != &&DUMMY_SP {
cm.lookup_char_pos(primary_span.lo)
} else {
emit_to_destination(&buffer.render(), level, &mut self.dst)?;

View File

@ -48,7 +48,6 @@ pub mod styled_buffer;
mod lock;
use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION};
use syntax_pos::MacroBacktrace;
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum RenderSpan {
@ -75,7 +74,6 @@ pub trait CodeMapper {
fn span_to_lines(&self, sp: Span) -> FileLinesResult;
fn span_to_string(&self, sp: Span) -> String;
fn span_to_filename(&self, sp: Span) -> FileName;
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
}
@ -120,7 +118,7 @@ impl CodeSuggestion {
let bounding_span = Span {
lo: lo,
hi: hi,
expn_id: NO_EXPANSION,
ctxt: NO_EXPANSION,
};
let lines = cm.span_to_lines(bounding_span).unwrap();
assert!(!lines.lines.is_empty());

View File

@ -17,9 +17,10 @@ use self::SawTraitOrImplItemComponent::*;
use syntax::abi::Abi;
use syntax::ast::{self, Name, NodeId};
use syntax::attr;
use syntax::ext::hygiene::SyntaxContext;
use syntax::parse::token;
use syntax::symbol::InternedString;
use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos};
use syntax_pos::{Span, BytePos};
use syntax::tokenstream;
use rustc::hir;
use rustc::hir::*;
@ -92,10 +93,10 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
span.hi
};
let expn_kind = match span.expn_id {
NO_EXPANSION => SawSpanExpnKind::NoExpansion,
COMMAND_LINE_EXPN => SawSpanExpnKind::CommandLine,
_ => SawSpanExpnKind::SomeExpansion,
let expn_kind = if span.ctxt == SyntaxContext::empty() {
SawSpanExpnKind::NoExpansion
} else {
SawSpanExpnKind::SomeExpansion
};
let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo);
@ -121,8 +122,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
saw.hash(self.st);
if expn_kind == SawSpanExpnKind::SomeExpansion {
let call_site = self.codemap.codemap().source_callsite(span);
self.hash_span(call_site);
self.hash_span(span.source_callsite());
}
}
@ -483,7 +483,6 @@ fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent {
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
enum SawSpanExpnKind {
NoExpansion,
CommandLine,
SomeExpansion,
}
@ -501,7 +500,7 @@ impl<'a> Hash for StableInlineAsm<'a> {
volatile,
alignstack,
dialect,
expn_id: _, // This is used for error reporting
ctxt: _, // This is used for error reporting
} = *self.0;
asm.as_str().hash(state);

View File

@ -223,7 +223,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
}
// This comes from a macro that has #[allow_internal_unstable].
if self.tcx.sess.codemap().span_allows_unstable(self.span) {
if self.span.allows_unstable() {
return;
}
@ -805,7 +805,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
self.def_id.is_local() &&
// this doesn't come from a macro that has #[allow_internal_unstable]
!self.tcx.sess.codemap().span_allows_unstable(self.span)
!self.span.allows_unstable()
{
let mut err = self.tcx.sess.struct_span_err(self.span,
"const fns are an unstable feature");

View File

@ -20,7 +20,7 @@ use std::env;
use std::mem;
use std::path::PathBuf;
use syntax::ast;
use syntax_pos::{Span, COMMAND_LINE_SP};
use syntax_pos::{Span, DUMMY_SP};
/// Pointer to a registrar function.
pub type PluginRegistrarFun =
@ -81,7 +81,7 @@ pub fn load_plugins(sess: &Session,
if let Some(plugins) = addl_plugins {
for plugin in plugins {
loader.load_plugin(COMMAND_LINE_SP, &plugin, vec![]);
loader.load_plugin(DUMMY_SP, &plugin, vec![]);
}
}

View File

@ -690,9 +690,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
// Note we take care to use the source callsite/callee, to handle
// nested expansions and ensure we only generate data for source-visible
// macro uses.
let callsite = self.tcx.sess.codemap().source_callsite(span);
let callee = self.tcx.sess.codemap().source_callee(span);
let callee = option_try!(callee);
let callsite = span.source_callsite();
let callee = option_try!(span.source_callee());
let callee_span = option_try!(callee.span);
// Ignore attribute macros, their spans are usually mangled
@ -1013,5 +1012,5 @@ fn escape(s: String) -> String {
// Helper function to determine if a span came from a
// macro expansion or syntax extension.
pub fn generated_code(span: Span) -> bool {
span.expn_id != NO_EXPANSION || span == DUMMY_SP
span.ctxt != NO_EXPANSION || span == DUMMY_SP
}

View File

@ -462,8 +462,7 @@ impl<'a> SpanUtils<'a> {
// Otherwise, a generated span is deemed invalid if it is not a sub-span of the root
// callsite. This filters out macro internal variables and most malformed spans.
let span = self.sess.codemap().source_callsite(parent);
!(span.contains(parent))
!parent.source_callsite().contains(parent)
}
}

View File

@ -111,14 +111,14 @@ pub fn trans_inline_asm<'a, 'tcx>(
bcx.store(v, val, None);
}
// Store expn_id in a metadata node so we can map LLVM errors
// Store mark in a metadata node so we can map LLVM errors
// back to source locations. See #17552.
unsafe {
let key = "srcloc";
let kind = llvm::LLVMGetMDKindIDInContext(bcx.ccx.llcx(),
key.as_ptr() as *const c_char, key.len() as c_uint);
let val: llvm::ValueRef = C_i32(bcx.ccx, ia.expn_id.into_u32() as i32);
let val: llvm::ValueRef = C_i32(bcx.ccx, ia.ctxt.outer().as_u32() as i32);
llvm::LLVMSetMetadata(r, kind,
llvm::LLVMMDNodeInContext(bcx.ccx.llcx(), &val, 1));

View File

@ -371,14 +371,14 @@ struct HandlerFreeVars<'a> {
unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>,
msg: &'b str,
cookie: c_uint) {
use syntax_pos::ExpnId;
use syntax::ext::hygiene::Mark;
match cgcx.lto_ctxt {
Some((sess, _)) => {
sess.codemap().with_expn_info(ExpnId::from_u32(cookie), |info| match info {
match Mark::from_u32(cookie).expn_info() {
Some(ei) => sess.span_err(ei.call_site, msg),
None => sess.err(msg),
});
};
}
None => {

View File

@ -26,7 +26,7 @@ use monomorphize::{self, Instance};
use abi::FnType;
use type_of;
use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span};
use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span};
use syntax::symbol::keywords;
use std::iter;
@ -124,24 +124,18 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
// In order to have a good line stepping behavior in debugger, we overwrite debug
// locations of macro expansions with that of the outermost expansion site
// (unless the crate is being compiled with `-Z debug-macros`).
if source_info.span.expn_id == NO_EXPANSION ||
source_info.span.expn_id == COMMAND_LINE_EXPN ||
self.ccx.sess().opts.debugging_opts.debug_macros {
if source_info.span.ctxt == NO_EXPANSION ||
self.ccx.sess().opts.debugging_opts.debug_macros {
let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo);
(scope, source_info.span)
} else {
let cm = self.ccx.sess().codemap();
// Walk up the macro expansion chain until we reach a non-expanded span.
// We also stop at the function body level because no line stepping can occurr
// at the level above that.
let mut span = source_info.span;
while span.expn_id != NO_EXPANSION &&
span.expn_id != COMMAND_LINE_EXPN &&
span.expn_id != self.mir.span.expn_id {
if let Some(callsite_span) = cm.with_expn_info(span.expn_id,
|ei| ei.map(|ei| ei.call_site.clone())) {
span = callsite_span;
while span.ctxt != NO_EXPANSION && span.ctxt != self.mir.span.ctxt {
if let Some(info) = span.ctxt.outer().expn_info() {
span = info.call_site;
} else {
break;
}

View File

@ -4161,12 +4161,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}
if let Some(last_stmt) = extra_semi {
let original_span = original_sp(self.tcx.sess.codemap(),
last_stmt.span, blk.span);
let original_span = original_sp(last_stmt.span, blk.span);
let span_semi = Span {
lo: original_span.hi - BytePos(1),
hi: original_span.hi,
expn_id: original_span.expn_id
ctxt: original_span.ctxt,
};
err.span_help(span_semi, "consider removing this semicolon:");
}

View File

@ -14,10 +14,10 @@ pub use self::TyParamBound::*;
pub use self::UnsafeSource::*;
pub use self::ViewPath_::*;
pub use self::PathParameters::*;
pub use symbol::Symbol as Name;
pub use symbol::{Ident, Symbol as Name};
pub use util::ThinVec;
use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP, ExpnId};
use syntax_pos::{mk_sp, BytePos, Span, DUMMY_SP};
use codemap::{respan, Spanned};
use abi::Abi;
use ext::hygiene::{Mark, SyntaxContext};
@ -27,61 +27,12 @@ use rustc_data_structures::indexed_vec;
use symbol::{Symbol, keywords};
use tokenstream::{ThinTokenStream, TokenStream};
use serialize::{self, Encoder, Decoder};
use std::collections::HashSet;
use std::fmt;
use std::rc::Rc;
use std::u32;
use serialize::{self, Encodable, Decodable, Encoder, Decoder};
/// An identifier contains a Name (index into the interner
/// table) and a SyntaxContext to track renaming and
/// macro expansion per Flatt et al., "Macros That Work Together"
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct Ident {
pub name: Symbol,
pub ctxt: SyntaxContext
}
impl Ident {
pub const fn with_empty_ctxt(name: Name) -> Ident {
Ident { name: name, ctxt: SyntaxContext::empty() }
}
/// Maps a string to an identifier with an empty syntax context.
pub fn from_str(s: &str) -> Ident {
Ident::with_empty_ctxt(Symbol::intern(s))
}
pub fn unhygienize(&self) -> Ident {
Ident { name: self.name, ctxt: SyntaxContext::empty() }
}
}
impl fmt::Debug for Ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{:?}", self.name, self.ctxt)
}
}
impl fmt::Display for Ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.name, f)
}
}
impl Encodable for Ident {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
self.name.encode(s)
}
}
impl Decodable for Ident {
fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> {
Ok(Ident::with_empty_ctxt(Name::decode(d)?))
}
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
pub struct Lifetime {
pub id: NodeId,
@ -1445,7 +1396,7 @@ pub struct InlineAsm {
pub volatile: bool,
pub alignstack: bool,
pub dialect: AsmDialect,
pub expn_id: ExpnId,
pub ctxt: SyntaxContext,
}
/// An argument in a function header.

View File

@ -17,6 +17,8 @@
//! within the CodeMap, which upon request can be converted to line and column
//! information, source code snippets, etc.
pub use syntax_pos::*;
pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo, NameAndSpan};
pub use self::ExpnFormat::*;
use std::cell::RefCell;
@ -26,35 +28,21 @@ use std::rc::Rc;
use std::env;
use std::fs;
use std::io::{self, Read};
pub use syntax_pos::*;
use errors::CodeMapper;
use ast::Name;
/// Return the span itself if it doesn't come from a macro expansion,
/// otherwise return the call site span up to the `enclosing_sp` by
/// following the `expn_info` chain.
pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span {
let call_site1 = cm.with_expn_info(sp.expn_id, |ei| ei.map(|ei| ei.call_site));
let call_site2 = cm.with_expn_info(enclosing_sp.expn_id, |ei| ei.map(|ei| ei.call_site));
pub fn original_sp(sp: Span, enclosing_sp: Span) -> Span {
let call_site1 = sp.ctxt.outer().expn_info().map(|ei| ei.call_site);
let call_site2 = enclosing_sp.ctxt.outer().expn_info().map(|ei| ei.call_site);
match (call_site1, call_site2) {
(None, _) => sp,
(Some(call_site1), Some(call_site2)) if call_site1 == call_site2 => sp,
(Some(call_site1), _) => original_sp(cm, call_site1, enclosing_sp),
(Some(call_site1), _) => original_sp(call_site1, enclosing_sp),
}
}
/// The source of expansion.
#[derive(Clone, Hash, Debug, PartialEq, Eq)]
pub enum ExpnFormat {
/// e.g. #[derive(...)] <item>
MacroAttribute(Name),
/// e.g. `format!()`
MacroBang(Name),
/// Desugaring done by the compiler during HIR lowering.
CompilerDesugaring(Name)
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub struct Spanned<T> {
pub node: T,
@ -73,47 +61,6 @@ pub fn dummy_spanned<T>(t: T) -> Spanned<T> {
respan(DUMMY_SP, t)
}
#[derive(Clone, Hash, Debug)]
pub struct NameAndSpan {
/// The format with which the macro was invoked.
pub format: ExpnFormat,
/// Whether the macro is allowed to use #[unstable]/feature-gated
/// features internally without forcing the whole crate to opt-in
/// to them.
pub allow_internal_unstable: bool,
/// The span of the macro definition itself. The macro may not
/// have a sensible definition span (e.g. something defined
/// completely inside libsyntax) in which case this is None.
pub span: Option<Span>
}
impl NameAndSpan {
pub fn name(&self) -> Name {
match self.format {
ExpnFormat::MacroAttribute(s) |
ExpnFormat::MacroBang(s) |
ExpnFormat::CompilerDesugaring(s) => s,
}
}
}
/// Extra information for tracking spans of macro and syntax sugar expansion
#[derive(Hash, Debug)]
pub struct ExpnInfo {
/// The location of the actual macro invocation or syntax sugar , e.g.
/// `let x = foo!();` or `if let Some(y) = x {}`
///
/// This may recursively refer to other macro invocations, e.g. if
/// `foo!()` invoked `bar!()` internally, and there was an
/// expression inside `bar!`; the call_site of the expression in
/// the expansion would point to the `bar!` invocation; that
/// call_site span would have its own ExpnInfo, with the call_site
/// pointing to the `foo!` invocation.
pub call_site: Span,
/// Information about the expansion.
pub callee: NameAndSpan
}
// _____________________________________________________________________________
// FileMap, MultiByteChar, FileName, FileLines
//
@ -161,7 +108,6 @@ impl FileLoader for RealFileLoader {
pub struct CodeMap {
pub files: RefCell<Vec<Rc<FileMap>>>,
expansions: RefCell<Vec<ExpnInfo>>,
file_loader: Box<FileLoader>
}
@ -169,7 +115,6 @@ impl CodeMap {
pub fn new() -> CodeMap {
CodeMap {
files: RefCell::new(Vec::new()),
expansions: RefCell::new(Vec::new()),
file_loader: Box::new(RealFileLoader)
}
}
@ -177,7 +122,6 @@ impl CodeMap {
pub fn with_file_loader(file_loader: Box<FileLoader>) -> CodeMap {
CodeMap {
files: RefCell::new(Vec::new()),
expansions: RefCell::new(Vec::new()),
file_loader: file_loader
}
}
@ -353,14 +297,14 @@ impl CodeMap {
/// Returns `Some(span)`, a union of the lhs and rhs span. The lhs must precede the rhs. If
/// there are gaps between lhs and rhs, the resulting union will cross these gaps.
/// For this to work, the spans have to be:
/// * the expn_id of both spans much match
/// * the ctxt of both spans much match
/// * the lhs span needs to end on the same line the rhs span begins
/// * the lhs span must start at or before the rhs span
pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
use std::cmp;
// make sure we're at the same expansion id
if sp_lhs.expn_id != sp_rhs.expn_id {
if sp_lhs.ctxt != sp_rhs.ctxt {
return None;
}
@ -383,7 +327,7 @@ impl CodeMap {
Some(Span {
lo: cmp::min(sp_lhs.lo, sp_rhs.lo),
hi: cmp::max(sp_lhs.hi, sp_rhs.hi),
expn_id: sp_lhs.expn_id,
ctxt: sp_lhs.ctxt,
})
} else {
None
@ -391,10 +335,6 @@ impl CodeMap {
}
pub fn span_to_string(&self, sp: Span) -> String {
if sp == COMMAND_LINE_SP {
return "<command line option>".to_string();
}
if self.files.borrow().is_empty() && sp.source_equal(&DUMMY_SP) {
return "no-location".to_string();
}
@ -409,62 +349,6 @@ impl CodeMap {
hi.col.to_usize() + 1)).to_string()
}
/// Return the source span - this is either the supplied span, or the span for
/// the macro callsite that expanded to it.
pub fn source_callsite(&self, sp: Span) -> Span {
let mut span = sp;
// Special case - if a macro is parsed as an argument to another macro, the source
// callsite is the first callsite, which is also source-equivalent to the span.
let mut first = true;
while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN {
if let Some(callsite) = self.with_expn_info(span.expn_id,
|ei| ei.map(|ei| ei.call_site.clone())) {
if first && span.source_equal(&callsite) {
if self.lookup_char_pos(span.lo).file.is_real_file() {
return Span { expn_id: NO_EXPANSION, .. span };
}
}
first = false;
span = callsite;
}
else {
break;
}
}
span
}
/// Return the source callee.
///
/// Returns None if the supplied span has no expansion trace,
/// else returns the NameAndSpan for the macro definition
/// corresponding to the source callsite.
pub fn source_callee(&self, sp: Span) -> Option<NameAndSpan> {
let mut span = sp;
// Special case - if a macro is parsed as an argument to another macro, the source
// callsite is source-equivalent to the span, and the source callee is the first callee.
let mut first = true;
while let Some(callsite) = self.with_expn_info(span.expn_id,
|ei| ei.map(|ei| ei.call_site.clone())) {
if first && span.source_equal(&callsite) {
if self.lookup_char_pos(span.lo).file.is_real_file() {
return self.with_expn_info(span.expn_id,
|ei| ei.map(|ei| ei.callee.clone()));
}
}
first = false;
if let Some(_) = self.with_expn_info(callsite.expn_id,
|ei| ei.map(|ei| ei.call_site.clone())) {
span = callsite;
}
else {
return self.with_expn_info(span.expn_id,
|ei| ei.map(|ei| ei.callee.clone()));
}
}
None
}
pub fn span_to_filename(&self, sp: Span) -> FileName {
self.lookup_char_pos(sp.lo).file.name.to_string()
}
@ -628,111 +512,9 @@ impl CodeMap {
return a;
}
pub fn record_expansion(&self, expn_info: ExpnInfo) -> ExpnId {
let mut expansions = self.expansions.borrow_mut();
expansions.push(expn_info);
let len = expansions.len();
if len > u32::max_value() as usize {
panic!("too many ExpnInfo's!");
}
ExpnId(len as u32 - 1)
}
pub fn with_expn_info<T, F>(&self, id: ExpnId, f: F) -> T where
F: FnOnce(Option<&ExpnInfo>) -> T,
{
match id {
NO_EXPANSION | COMMAND_LINE_EXPN => f(None),
ExpnId(i) => f(Some(&(*self.expansions.borrow())[i as usize]))
}
}
/// Check if a span is "internal" to a macro in which #[unstable]
/// items can be used (that is, a macro marked with
/// `#[allow_internal_unstable]`).
pub fn span_allows_unstable(&self, span: Span) -> bool {
debug!("span_allows_unstable(span = {:?})", span);
let mut allows_unstable = false;
let mut expn_id = span.expn_id;
loop {
let quit = self.with_expn_info(expn_id, |expninfo| {
debug!("span_allows_unstable: expninfo = {:?}", expninfo);
expninfo.map_or(/* hit the top level */ true, |info| {
let span_comes_from_this_expansion =
info.callee.span.map_or(span.source_equal(&info.call_site), |mac_span| {
mac_span.contains(span)
});
debug!("span_allows_unstable: span: {:?} call_site: {:?} callee: {:?}",
(span.lo, span.hi),
(info.call_site.lo, info.call_site.hi),
info.callee.span.map(|x| (x.lo, x.hi)));
debug!("span_allows_unstable: from this expansion? {}, allows unstable? {}",
span_comes_from_this_expansion,
info.callee.allow_internal_unstable);
if span_comes_from_this_expansion {
allows_unstable = info.callee.allow_internal_unstable;
// we've found the right place, stop looking
true
} else {
// not the right place, keep looking
expn_id = info.call_site.expn_id;
false
}
})
});
if quit {
break
}
}
debug!("span_allows_unstable? {}", allows_unstable);
allows_unstable
}
pub fn count_lines(&self) -> usize {
self.files.borrow().iter().fold(0, |a, f| a + f.count_lines())
}
pub fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
let mut prev_span = DUMMY_SP;
let mut span = span;
let mut result = vec![];
loop {
let span_name_span = self.with_expn_info(span.expn_id, |expn_info| {
expn_info.map(|ei| {
let (pre, post) = match ei.callee.format {
MacroAttribute(..) => ("#[", "]"),
MacroBang(..) => ("", "!"),
CompilerDesugaring(..) => ("desugaring of `", "`"),
};
let macro_decl_name = format!("{}{}{}",
pre,
ei.callee.name(),
post);
let def_site_span = ei.callee.span;
(ei.call_site, macro_decl_name, def_site_span)
})
});
match span_name_span {
None => break,
Some((call_site, macro_decl_name, def_site_span)) => {
// Don't print recursive invocations
if !call_site.source_equal(&prev_span) {
result.push(MacroBacktrace {
call_site: call_site,
macro_decl_name: macro_decl_name,
def_site_span: def_site_span,
});
}
prev_span = span;
span = call_site;
}
}
}
result
}
}
impl CodeMapper for CodeMap {
@ -748,9 +530,6 @@ impl CodeMapper for CodeMap {
fn span_to_filename(&self, sp: Span) -> FileName {
self.span_to_filename(sp)
}
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
self.macro_backtrace(span)
}
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
self.merge_spans(sp_lhs, sp_rhs)
}
@ -763,7 +542,6 @@ impl CodeMapper for CodeMap {
#[cfg(test)]
mod tests {
use super::*;
use symbol::keywords;
use std::rc::Rc;
#[test]
@ -912,7 +690,7 @@ mod tests {
fn t7() {
// Test span_to_lines for a span ending at the end of filemap
let cm = init_code_map();
let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION};
let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION};
let file_lines = cm.span_to_lines(span).unwrap();
assert_eq!(file_lines.file.name, "blork.rs");
@ -928,7 +706,7 @@ mod tests {
assert_eq!(input.len(), selection.len());
let left_index = selection.find('~').unwrap() as u32;
let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index);
Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION }
Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), ctxt: NO_EXPANSION }
}
/// Test span_to_snippet and span_to_lines for a span coverting 3
@ -958,7 +736,7 @@ mod tests {
fn t8() {
// Test span_to_snippet for a span ending at the end of filemap
let cm = init_code_map();
let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION};
let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION};
let snippet = cm.span_to_snippet(span);
assert_eq!(snippet, Ok("second line".to_string()));
@ -968,7 +746,7 @@ mod tests {
fn t9() {
// Test span_to_str for a span ending at the end of filemap
let cm = init_code_map();
let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION};
let span = Span {lo: BytePos(12), hi: BytePos(23), ctxt: NO_EXPANSION};
let sstr = cm.span_to_string(span);
assert_eq!(sstr, "blork.rs:2:1: 2:12");
@ -1022,7 +800,7 @@ mod tests {
let span = Span {
lo: BytePos(lo as u32 + file.start_pos.0),
hi: BytePos(hi as u32 + file.start_pos.0),
expn_id: NO_EXPANSION,
ctxt: NO_EXPANSION,
};
assert_eq!(&self.span_to_snippet(span).unwrap()[..],
substring);
@ -1032,45 +810,4 @@ mod tests {
}
}
}
fn init_expansion_chain(cm: &CodeMap) -> Span {
// Creates an expansion chain containing two recursive calls
// root -> expA -> expA -> expB -> expB -> end
let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION };
let format_root = ExpnFormat::MacroBang(keywords::Invalid.name());
let callee_root = NameAndSpan { format: format_root,
allow_internal_unstable: false,
span: Some(root) };
let info_a1 = ExpnInfo { call_site: root, callee: callee_root };
let id_a1 = cm.record_expansion(info_a1);
let span_a1 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a1 };
let format_a = ExpnFormat::MacroBang(keywords::As.name());
let callee_a = NameAndSpan { format: format_a,
allow_internal_unstable: false,
span: Some(span_a1) };
let info_a2 = ExpnInfo { call_site: span_a1, callee: callee_a.clone() };
let id_a2 = cm.record_expansion(info_a2);
let span_a2 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a2 };
let info_b1 = ExpnInfo { call_site: span_a2, callee: callee_a };
let id_b1 = cm.record_expansion(info_b1);
let span_b1 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b1 };
let format_b = ExpnFormat::MacroBang(keywords::Box.name());
let callee_b = NameAndSpan { format: format_b,
allow_internal_unstable: false,
span: None };
let info_b2 = ExpnInfo { call_site: span_b1, callee: callee_b.clone() };
let id_b2 = cm.record_expansion(info_b2);
let span_b2 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b2 };
let info_end = ExpnInfo { call_site: span_b2, callee: callee_b };
let id_end = cm.record_expansion(info_end);
Span { lo: BytePos(37), hi: BytePos(48), expn_id: id_end }
}
}

View File

@ -12,11 +12,11 @@ pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT
use ast::{self, Attribute, Name, PatKind, MetaItem};
use attr::HasAttrs;
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
use errors::{DiagnosticBuilder, FatalError};
use codemap::{self, CodeMap, Spanned, respan};
use syntax_pos::{Span, DUMMY_SP};
use errors::DiagnosticBuilder;
use ext::expand::{self, Expansion, Invocation};
use ext::hygiene::Mark;
use ext::hygiene::{Mark, SyntaxContext};
use fold::{self, Folder};
use parse::{self, parser, DirectoryOwnership};
use parse::token;
@ -56,6 +56,14 @@ impl HasAttrs for Annotatable {
}
impl Annotatable {
pub fn span(&self) -> Span {
match *self {
Annotatable::Item(ref item) => item.span,
Annotatable::TraitItem(ref trait_item) => trait_item.span,
Annotatable::ImplItem(ref impl_item) => impl_item.span,
}
}
pub fn expect_item(self) -> P<ast::Item> {
match self {
Annotatable::Item(i) => i,
@ -602,7 +610,6 @@ pub struct ModuleData {
pub struct ExpansionData {
pub mark: Mark,
pub depth: usize,
pub backtrace: ExpnId,
pub module: Rc<ModuleData>,
pub directory_ownership: DirectoryOwnership,
}
@ -633,7 +640,6 @@ impl<'a> ExtCtxt<'a> {
current_expansion: ExpansionData {
mark: Mark::root(),
depth: 0,
backtrace: NO_EXPANSION,
module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
directory_ownership: DirectoryOwnership::Owned,
},
@ -658,30 +664,30 @@ impl<'a> ExtCtxt<'a> {
pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
pub fn cfg(&self) -> &ast::CrateConfig { &self.parse_sess.config }
pub fn call_site(&self) -> Span {
self.codemap().with_expn_info(self.backtrace(), |ei| match ei {
match self.current_expansion.mark.expn_info() {
Some(expn_info) => expn_info.call_site,
None => self.bug("missing top span")
})
None => DUMMY_SP,
}
}
pub fn backtrace(&self) -> SyntaxContext {
SyntaxContext::empty().apply_mark(self.current_expansion.mark)
}
pub fn backtrace(&self) -> ExpnId { self.current_expansion.backtrace }
/// 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 ctxt = self.backtrace();
let mut last_macro = None;
loop {
if self.codemap().with_expn_info(expn_id, |info| {
info.map_or(None, |i| {
if i.callee.name() == "include" {
// Stop going up the backtrace once include! is encountered
return None;
}
expn_id = i.call_site.expn_id;
last_macro = Some(i.call_site);
return Some(());
})
if ctxt.outer().expn_info().map_or(None, |info| {
if info.callee.name() == "include" {
// Stop going up the backtrace once include! is encountered
return None;
}
ctxt = info.call_site.ctxt;
last_macro = Some(info.call_site);
return Some(());
}).is_none() {
break
}
@ -689,28 +695,6 @@ impl<'a> ExtCtxt<'a> {
last_macro.expect("missing expansion backtrace")
}
pub fn bt_push(&mut self, ei: ExpnInfo) {
if self.current_expansion.depth > self.ecfg.recursion_limit {
let suggested_limit = self.ecfg.recursion_limit * 2;
let mut err = self.struct_span_fatal(ei.call_site,
&format!("recursion limit reached while expanding the macro `{}`",
ei.callee.name()));
err.help(&format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit));
err.emit();
panic!(FatalError);
}
let mut call_site = ei.call_site;
call_site.expn_id = self.backtrace();
self.current_expansion.backtrace = self.codemap().record_expansion(ExpnInfo {
call_site: call_site,
callee: ei.callee
});
}
pub fn bt_pop(&mut self) {}
pub fn struct_span_warn(&self,
sp: Span,
msg: &str)
@ -792,9 +776,9 @@ impl<'a> ExtCtxt<'a> {
/// compilation on error, merely emits a non-fatal error and returns None.
pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P<ast::Expr>, err_msg: &str)
-> Option<Spanned<(Symbol, ast::StrStyle)>> {
// Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation.
// Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation.
let expr = expr.map(|mut expr| {
expr.span.expn_id = cx.backtrace();
expr.span.ctxt = expr.span.ctxt.apply_mark(cx.current_expansion.mark);
expr
});

View File

@ -9,13 +9,16 @@
// except according to those terms.
use attr::HasAttrs;
use {ast, codemap};
use ast;
use codemap::{ExpnInfo, NameAndSpan, ExpnFormat};
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use parse::parser::PathStyle;
use symbol::Symbol;
use syntax_pos::Span;
use std::collections::HashSet;
pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
let mut result = Vec::new();
attrs.retain(|attr| {
@ -41,36 +44,35 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec
result
}
fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
Span {
expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
call_site: span,
callee: codemap::NameAndSpan {
format: codemap::MacroAttribute(Symbol::intern(attr_name)),
span: Some(span),
allow_internal_unstable: true,
},
}),
..span
pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path], item: T) -> T
where T: HasAttrs,
{
let (mut names, mut pretty_name) = (HashSet::new(), "derive(".to_owned());
for (i, path) in traits.iter().enumerate() {
if i > 0 {
pretty_name.push_str(", ");
}
pretty_name.push_str(&path.to_string());
names.insert(unwrap_or!(path.segments.get(0), continue).identifier.name);
}
}
pretty_name.push(')');
pub fn add_derived_markers<T: HasAttrs>(cx: &mut ExtCtxt, traits: &[ast::Path], item: T) -> T {
let span = match traits.get(0) {
Some(path) => path.span,
None => return item,
};
cx.current_expansion.mark.set_expn_info(ExpnInfo {
call_site: span,
callee: NameAndSpan {
format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
span: None,
allow_internal_unstable: true,
},
});
let span = Span { ctxt: cx.backtrace(), ..span };
item.map_attrs(|mut attrs| {
if traits.iter().any(|path| *path == "PartialEq") &&
traits.iter().any(|path| *path == "Eq") {
let span = allow_unstable(cx, span, "derive(PartialEq, Eq)");
if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) {
let meta = cx.meta_word(span, Symbol::intern("structural_match"));
attrs.push(cx.attribute(span, meta));
}
if traits.iter().any(|path| *path == "Copy") &&
traits.iter().any(|path| *path == "Clone") {
let span = allow_unstable(cx, span, "derive(Copy, Clone)");
if names.contains(&Symbol::intern("Copy")) && names.contains(&Symbol::intern("Clone")) {
let meta = cx.meta_word(span, Symbol::intern("rustc_copy_clone_marker"));
attrs.push(cx.attribute(span, meta));
}

View File

@ -13,6 +13,7 @@ use ast::{MacStmtStyle, StmtKind, ItemKind};
use attr::{self, HasAttrs};
use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
use config::{is_test_or_bench, StripUnconfigured};
use errors::FatalError;
use ext::base::*;
use ext::derive::{add_derived_markers, collect_derives};
use ext::hygiene::Mark;
@ -27,7 +28,7 @@ use ptr::P;
use std_inject;
use symbol::Symbol;
use symbol::keywords;
use syntax_pos::{Span, ExpnId, DUMMY_SP};
use syntax_pos::{Span, DUMMY_SP};
use tokenstream::TokenStream;
use util::small_vector::SmallVector;
use visit::Visitor;
@ -273,7 +274,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let item = item
.map_attrs(|mut attrs| { attrs.retain(|a| a.path != "derive"); attrs });
let item_with_markers =
add_derived_markers(&mut self.cx, &traits, item.clone());
add_derived_markers(&mut self.cx, item.span(), &traits, item.clone());
let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new);
for path in &traits {
@ -363,11 +364,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
fn expand_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
match invoc.kind {
let result = match invoc.kind {
InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext),
InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext),
InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext),
};
if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit {
let info = self.cx.current_expansion.mark.expn_info().unwrap();
let suggested_limit = self.cx.ecfg.recursion_limit * 2;
let mut err = self.cx.struct_span_fatal(info.call_site,
&format!("recursion limit reached while expanding the macro `{}`",
info.callee.name()));
err.help(&format!(
"consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate",
suggested_limit));
err.emit();
panic!(FatalError);
}
result
}
fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion {
@ -378,11 +394,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
};
attr::mark_used(&attr);
self.cx.bt_push(ExpnInfo {
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
call_site: attr.span,
callee: NameAndSpan {
format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
span: Some(attr.span),
span: None,
allow_internal_unstable: false,
}
});
@ -403,19 +419,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
SyntaxExtension::AttrProcMacro(ref mac) => {
let item_toks = stream_for_item(&item, &self.cx.parse_sess);
let span = Span {
expn_id: self.cx.codemap().record_expansion(ExpnInfo {
call_site: attr.span,
callee: NameAndSpan {
format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))),
span: None,
allow_internal_unstable: false,
},
}),
..attr.span
};
let tok_result = mac.expand(self.cx, attr.span, attr.tokens.clone(), item_toks);
let span = Span { ctxt: self.cx.backtrace(), ..attr.span };
let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_toks);
self.parse_expansion(tok_result, kind, &attr.path, span)
}
SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
@ -440,8 +445,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let path = &mac.node.path;
let ident = ident.unwrap_or(keywords::Invalid.ident());
let marked_tts =
noop_fold_tts(mac.node.stream(), &mut Marker { mark: mark, expn_id: None });
let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker(mark));
let opt_expanded = match *ext {
NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
if ident.name != keywords::Invalid.name() {
@ -451,7 +455,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
return kind.dummy(span);
}
self.cx.bt_push(ExpnInfo {
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
call_site: span,
callee: NameAndSpan {
format: MacroBang(Symbol::intern(&format!("{}", path))),
@ -470,7 +474,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
return kind.dummy(span);
};
self.cx.bt_push(ExpnInfo {
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
call_site: span,
callee: NameAndSpan {
format: MacroBang(Symbol::intern(&format!("{}", path))),
@ -502,7 +506,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
return kind.dummy(span);
}
self.cx.bt_push(ExpnInfo {
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
call_site: span,
callee: NameAndSpan {
format: MacroBang(Symbol::intern(&format!("{}", path))),
@ -528,10 +532,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
return kind.dummy(span);
};
expanded.fold_with(&mut Marker {
mark: mark,
expn_id: Some(self.cx.backtrace()),
})
expanded.fold_with(&mut Marker(mark))
}
/// Expand a derive invocation. Returns the result of expansion.
@ -550,50 +551,33 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
id: ast::AttrId(0), style: ast::AttrStyle::Outer, is_sugared_doc: false,
};
self.cx.bt_push(ExpnInfo {
let mut expn_info = ExpnInfo {
call_site: span,
callee: NameAndSpan {
format: MacroAttribute(pretty_name),
span: None,
allow_internal_unstable: false,
}
});
};
match *ext {
SyntaxExtension::ProcMacroDerive(ref ext, _) => {
let span = Span {
expn_id: self.cx.codemap().record_expansion(ExpnInfo {
call_site: span,
callee: NameAndSpan {
format: MacroAttribute(pretty_name),
span: None,
allow_internal_unstable: false,
},
}),
..span
};
invoc.expansion_data.mark.set_expn_info(expn_info);
let span = Span { ctxt: self.cx.backtrace(), ..span };
let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this
name: keywords::Invalid.name(),
span: DUMMY_SP,
node: ast::MetaItemKind::Word,
};
return kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item));
kind.expect_from_annotatables(ext.expand(self.cx, span, &dummy, item))
}
SyntaxExtension::BuiltinDerive(func) => {
let span = Span {
expn_id: self.cx.codemap().record_expansion(ExpnInfo {
call_site: span,
callee: NameAndSpan {
format: MacroAttribute(pretty_name),
span: None,
allow_internal_unstable: true,
},
}),
..span
};
expn_info.callee.allow_internal_unstable = true;
invoc.expansion_data.mark.set_expn_info(expn_info);
let span = Span { ctxt: self.cx.backtrace(), ..span };
let mut items = Vec::new();
func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a));
return kind.expect_from_annotatables(items);
kind.expect_from_annotatables(items)
}
_ => {
let msg = &format!("macro `{}` may not be used for derive attributes", attr.path);
@ -753,10 +737,9 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
// Detect use of feature-gated or invalid attributes on macro invocations
// since they will not be detected after macro expansion.
fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
let codemap = &self.cx.parse_sess.codemap();
let features = self.cx.ecfg.features.unwrap();
for attr in attrs.iter() {
feature_gate::check_attribute(&attr, &self.cx.parse_sess, codemap, features);
feature_gate::check_attribute(&attr, &self.cx.parse_sess, features);
}
}
}
@ -1065,23 +1048,21 @@ impl<'feat> ExpansionConfig<'feat> {
}
}
// A Marker adds the given mark to the syntax context and
// sets spans' `expn_id` to the given expn_id (unless it is `None`).
struct Marker { mark: Mark, expn_id: Option<ExpnId> }
// A Marker adds the given mark to the syntax context.
struct Marker(Mark);
impl Folder for Marker {
fn fold_ident(&mut self, mut ident: Ident) -> Ident {
ident.ctxt = ident.ctxt.apply_mark(self.mark);
ident.ctxt = ident.ctxt.apply_mark(self.0);
ident
}
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
noop_fold_mac(mac, self)
}
fn new_span(&mut self, mut span: Span) -> Span {
if let Some(expn_id) = self.expn_id {
span.expn_id = expn_id;
}
span.ctxt = span.ctxt.apply_mark(self.0);
span
}
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
noop_fold_mac(mac, self)
}
}

View File

@ -185,7 +185,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::Toke
fn res_rel_file(cx: &mut ExtCtxt, sp: syntax_pos::Span, arg: &Path) -> PathBuf {
// NB: relative paths are resolved relative to the compilation unit
if !arg.is_absolute() {
let callsite = cx.codemap().source_callsite(sp);
let callsite = sp.source_callsite();
let mut cu = PathBuf::from(&cx.codemap().span_to_filename(callsite));
cu.pop();
cu.push(arg);

View File

@ -34,17 +34,19 @@ impl Delimited {
}
pub fn open_tt(&self, span: Span) -> TokenTree {
let open_span = match span {
DUMMY_SP => DUMMY_SP,
_ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span },
let open_span = if span == DUMMY_SP {
DUMMY_SP
} else {
Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }
};
TokenTree::Token(open_span, self.open_token())
}
pub fn close_tt(&self, span: Span) -> TokenTree {
let close_span = match span {
DUMMY_SP => DUMMY_SP,
_ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span },
let close_span = if span == DUMMY_SP {
DUMMY_SP
} else {
Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }
};
TokenTree::Token(close_span, self.close_token())
}

View File

@ -28,7 +28,7 @@ use self::AttributeGate::*;
use abi::Abi;
use ast::{self, NodeId, PatKind, RangeEnd};
use attr;
use codemap::{CodeMap, Spanned};
use codemap::Spanned;
use syntax_pos::Span;
use errors::{DiagnosticBuilder, Handler, FatalError};
use visit::{self, FnKind, Visitor};
@ -831,7 +831,7 @@ impl GatedCfg {
pub fn check_and_emit(&self, sess: &ParseSess, features: &Features) {
let (cfg, feature, has_feature) = GATED_CFGS[self.index];
if !has_feature(features) && !sess.codemap().span_allows_unstable(self.span) {
if !has_feature(features) && !self.span.allows_unstable() {
let explain = format!("`cfg({})` is experimental and subject to change", cfg);
emit_feature_err(sess, feature, self.span, GateIssue::Language, &explain);
}
@ -841,7 +841,6 @@ impl GatedCfg {
struct Context<'a> {
features: &'a Features,
parse_sess: &'a ParseSess,
cm: &'a CodeMap,
plugin_attributes: &'a [(String, AttributeType)],
}
@ -850,7 +849,7 @@ macro_rules! gate_feature_fn {
let (cx, has_feature, span, name, explain) = ($cx, $has_feature, $span, $name, $explain);
let has_feature: bool = has_feature(&$cx.features);
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
if !has_feature && !cx.cm.span_allows_unstable(span) {
if !has_feature && !span.allows_unstable() {
emit_feature_err(cx.parse_sess, name, span, GateIssue::Language, explain);
}
}}
@ -908,12 +907,8 @@ impl<'a> Context<'a> {
}
}
pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess,
cm: &CodeMap, features: &Features) {
let cx = Context {
features: features, parse_sess: parse_sess,
cm: cm, plugin_attributes: &[]
};
pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] };
cx.check_attribute(attr, true);
}
@ -1016,7 +1011,7 @@ struct PostExpansionVisitor<'a> {
macro_rules! gate_feature_post {
($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{
let (cx, span) = ($cx, $span);
if !cx.context.cm.span_allows_unstable(span) {
if !span.allows_unstable() {
gate_feature!(cx.context, $feature, span, $explain)
}
}}
@ -1096,7 +1091,7 @@ fn starts_with_digit(s: &str) -> bool {
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
fn visit_attribute(&mut self, attr: &ast::Attribute) {
if !self.context.cm.span_allows_unstable(attr.span) {
if !attr.span.allows_unstable() {
// check for gated attributes
self.context.check_attribute(attr, false);
}
@ -1530,7 +1525,6 @@ pub fn check_crate(krate: &ast::Crate,
let ctx = Context {
features: features,
parse_sess: sess,
cm: sess.codemap(),
plugin_attributes: plugin_attributes,
};
visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);

View File

@ -202,7 +202,7 @@ impl DiagnosticSpan {
// backtrace ourselves, but the `macro_backtrace` helper makes
// some decision, such as dropping some frames, and I don't
// want to duplicate that logic here.
let backtrace = je.cm.macro_backtrace(span).into_iter();
let backtrace = span.macro_backtrace().into_iter();
DiagnosticSpan::from_span_full(span,
is_primary,
label,

View File

@ -125,7 +125,7 @@ pub mod ptr;
pub mod show_span;
pub mod std_inject;
pub mod str;
pub mod symbol;
pub use syntax_pos::symbol;
pub mod test;
pub mod tokenstream;
pub mod visit;

View File

@ -5036,11 +5036,7 @@ impl<'a> Parser<'a> {
the path:",
path);
self.expect(&token::CloseDelim(token::Paren))?; // `)`
let sp = Span {
lo: start_span.lo,
hi: self.prev_span.hi,
expn_id: start_span.expn_id,
};
let sp = start_span.to(self.prev_span);
let mut err = self.span_fatal_help(sp, &msg, &suggestion);
err.span_suggestion(path_span, &help_msg, format!("in {}", path));
err.emit(); // emit diagnostic, but continue with public visibility

View File

@ -10,29 +10,27 @@
use ast;
use attr;
use ext::hygiene::{Mark, SyntaxContext};
use symbol::{Symbol, keywords};
use syntax_pos::{DUMMY_SP, Span};
use codemap::{self, ExpnInfo, NameAndSpan, MacroAttribute};
use parse::ParseSess;
use ptr::P;
use tokenstream::TokenStream;
/// Craft a span that will be ignored by the stability lint's
/// call to codemap's is_internal check.
/// The expanded code uses the unstable `#[prelude_import]` attribute.
fn ignored_span(sess: &ParseSess, sp: Span) -> Span {
let info = ExpnInfo {
fn ignored_span(sp: Span) -> Span {
let mark = Mark::fresh();
mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP,
callee: NameAndSpan {
format: MacroAttribute(Symbol::intern("std_inject")),
span: None,
allow_internal_unstable: true,
}
};
let expn_id = sess.codemap().record_expansion(info);
let mut sp = sp;
sp.expn_id = expn_id;
return sp;
});
Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..sp }
}
pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> {
@ -45,10 +43,7 @@ pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> {
}
}
pub fn maybe_inject_crates_ref(sess: &ParseSess,
mut krate: ast::Crate,
alt_std_name: Option<String>)
-> ast::Crate {
pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option<String>) -> ast::Crate {
let name = match injected_crate_name(&krate) {
Some(name) => name,
None => return krate,
@ -67,7 +62,7 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess,
span: DUMMY_SP,
}));
let span = ignored_span(sess, DUMMY_SP);
let span = ignored_span(DUMMY_SP);
krate.module.items.insert(0, P(ast::Item {
attrs: vec![ast::Attribute {
style: ast::AttrStyle::Outer,

View File

@ -31,6 +31,7 @@ use entry::{self, EntryPointType};
use ext::base::{ExtCtxt, Resolver};
use ext::build::AstBuilder;
use ext::expand::ExpansionConfig;
use ext::hygiene::{Mark, SyntaxContext};
use fold::Folder;
use util::move_map::MoveMap;
use fold;
@ -62,6 +63,7 @@ struct TestCtxt<'a> {
testfns: Vec<Test>,
reexport_test_harness_main: Option<Symbol>,
is_test_crate: bool,
ctxt: SyntaxContext,
// top-level re-export submodule, filled out after folding is finished
toplevel_reexport: Option<Ident>,
@ -275,6 +277,7 @@ fn generate_test_harness(sess: &ParseSess,
let mut cleaner = EntryPointCleaner { depth: 0 };
let krate = cleaner.fold_crate(krate);
let mark = Mark::fresh();
let mut cx: TestCtxt = TestCtxt {
sess: sess,
span_diagnostic: sd,
@ -284,15 +287,16 @@ fn generate_test_harness(sess: &ParseSess,
reexport_test_harness_main: reexport_test_harness_main,
is_test_crate: is_test_crate(&krate),
toplevel_reexport: None,
ctxt: SyntaxContext::empty().apply_mark(mark),
};
cx.ext_cx.crate_root = Some("std");
cx.ext_cx.bt_push(ExpnInfo {
mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP,
callee: NameAndSpan {
format: MacroAttribute(Symbol::intern("test")),
span: None,
allow_internal_unstable: false,
allow_internal_unstable: true,
}
});
@ -307,18 +311,7 @@ fn generate_test_harness(sess: &ParseSess,
/// call to codemap's is_internal check.
/// The expanded code calls some unstable functions in the test crate.
fn ignored_span(cx: &TestCtxt, sp: Span) -> Span {
let info = ExpnInfo {
call_site: sp,
callee: NameAndSpan {
format: MacroAttribute(Symbol::intern("test")),
span: None,
allow_internal_unstable: true,
}
};
let expn_id = cx.sess.codemap().record_expansion(info);
let mut sp = sp;
sp.expn_id = expn_id;
return sp;
Span { ctxt: cx.ctxt, ..sp }
}
#[derive(PartialEq)]

View File

@ -83,7 +83,7 @@ fn make_span(file_text: &str, start: &Position, end: &Position) -> Span {
Span {
lo: BytePos(start as u32),
hi: BytePos(end as u32),
expn_id: NO_EXPANSION,
ctxt: NO_EXPANSION,
}
}

View File

@ -56,18 +56,20 @@ impl Delimited {
/// Returns the opening delimiter as a token tree.
pub fn open_tt(&self, span: Span) -> TokenTree {
let open_span = match span {
DUMMY_SP => DUMMY_SP,
_ => Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span },
let open_span = if span == DUMMY_SP {
DUMMY_SP
} else {
Span { hi: span.lo + BytePos(self.delim.len() as u32), ..span }
};
TokenTree::Token(open_span, self.open_token())
}
/// Returns the closing delimiter as a token tree.
pub fn close_tt(&self, span: Span) -> TokenTree {
let close_span = match span {
DUMMY_SP => DUMMY_SP,
_ => Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span },
let close_span = if span == DUMMY_SP {
DUMMY_SP
} else {
Span { lo: span.hi - BytePos(self.delim.len() as u32), ..span }
};
TokenTree::Token(close_span, self.close_token())
}
@ -425,7 +427,7 @@ mod tests {
Span {
lo: BytePos(a),
hi: BytePos(b),
expn_id: NO_EXPANSION,
ctxt: NO_EXPANSION,
}
}

View File

@ -13,7 +13,6 @@
use self::State::*;
use syntax::ast;
use syntax::codemap;
use syntax::ext::base;
use syntax::ext::base::*;
use syntax::feature_gate;
@ -240,15 +239,6 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
}
}
let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
call_site: sp,
callee: codemap::NameAndSpan {
format: codemap::MacroBang(Symbol::intern("asm")),
span: None,
allow_internal_unstable: false,
},
});
MacEager::expr(P(ast::Expr {
id: ast::DUMMY_NODE_ID,
node: ast::ExprKind::InlineAsm(P(ast::InlineAsm {
@ -260,7 +250,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
volatile: volatile,
alignstack: alignstack,
dialect: dialect,
expn_id: expn_id,
ctxt: cx.backtrace(),
})),
span: sp,
attrs: ast::ThinVec::new(),

View File

@ -111,7 +111,7 @@ fn cs_clone_shallow(name: &str,
ty: P<ast::Ty>, span: Span, helper_name: &str) {
// Generate statement `let _: helper_name<ty>;`,
// set the expn ID so we can use the unstable struct.
let span = super::allow_unstable(cx, span, "derive(Clone)");
let span = Span { ctxt: cx.backtrace(), ..span};
let assert_path = cx.path_all(span, true,
cx.std_path(&["clone", helper_name]),
vec![], vec![ty], vec![]);

View File

@ -58,7 +58,7 @@ fn cs_total_eq_assert(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
ty: P<ast::Ty>, span: Span, helper_name: &str) {
// Generate statement `let _: helper_name<ty>;`,
// set the expn ID so we can use the unstable struct.
let span = super::allow_unstable(cx, span, "derive(Eq)");
let span = Span { ctxt: cx.backtrace(), ..span };
let assert_path = cx.path_all(span, true,
cx.std_path(&["cmp", helper_name]),
vec![], vec![ty], vec![]);

View File

@ -66,8 +66,8 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<E
StaticEnum(..) => cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"),
};
// We want to make sure we have the expn_id set so that we can use unstable methods
let span = Span { expn_id: cx.backtrace(), ..span };
// We want to make sure we have the ctxt set so that we can use unstable methods
let span = Span { ctxt: cx.backtrace(), ..span };
let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
let builder = Ident::from_str("builder");
let builder_expr = cx.expr_ident(span, builder.clone());

View File

@ -375,7 +375,7 @@ fn find_type_parameters(ty: &ast::Ty,
}
fn visit_mac(&mut self, mac: &ast::Mac) {
let span = Span { expn_id: self.span.expn_id, ..mac.span };
let span = Span { ctxt: self.span.ctxt, ..mac.span };
self.cx.span_err(span, "`derive` cannot be used on items with type macros");
}
}
@ -1458,7 +1458,7 @@ impl<'a> MethodDef<'a> {
.iter()
.map(|v| {
let ident = v.node.name;
let sp = Span { expn_id: trait_.span.expn_id, ..v.span };
let sp = Span { ctxt: trait_.span.ctxt, ..v.span };
let summary = trait_.summarise_struct(cx, &v.node.data);
(ident, sp, summary)
})
@ -1478,7 +1478,7 @@ impl<'a> TraitDef<'a> {
let mut named_idents = Vec::new();
let mut just_spans = Vec::new();
for field in struct_def.fields() {
let sp = Span { expn_id: self.span.expn_id, ..field.span };
let sp = Span { ctxt: self.span.ctxt, ..field.span };
match field.ident {
Some(ident) => named_idents.push((ident, sp)),
_ => just_spans.push(sp),
@ -1523,7 +1523,7 @@ impl<'a> TraitDef<'a> {
let mut paths = Vec::new();
let mut ident_exprs = Vec::new();
for (i, struct_field) in struct_def.fields().iter().enumerate() {
let sp = Span { expn_id: self.span.expn_id, ..struct_field.span };
let sp = Span { ctxt: self.span.ctxt, ..struct_field.span };
let ident = cx.ident_of(&format!("{}_{}", prefix, i));
paths.push(codemap::Spanned {
span: sp,
@ -1544,7 +1544,7 @@ impl<'a> TraitDef<'a> {
cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
}
codemap::Spanned {
span: Span { expn_id: self.span.expn_id, ..pat.span },
span: Span { ctxt: self.span.ctxt, ..pat.span },
node: ast::FieldPat {
ident: ident.unwrap(),
pat: pat,
@ -1576,7 +1576,7 @@ impl<'a> TraitDef<'a> {
mutbl: ast::Mutability)
-> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
let variant_ident = variant.node.name;
let sp = Span { expn_id: self.span.expn_id, ..variant.span };
let sp = Span { ctxt: self.span.ctxt, ..variant.span };
let variant_path = cx.path(sp, vec![enum_ident, variant_ident]);
self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl)
}

View File

@ -12,9 +12,9 @@
use std::rc::Rc;
use syntax::ast;
use syntax::codemap;
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver};
use syntax::ext::build::AstBuilder;
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::ptr::P;
use syntax::symbol::Symbol;
use syntax_pos::Span;
@ -74,20 +74,6 @@ pub mod ord;
pub mod generic;
fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span {
Span {
expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
call_site: span,
callee: codemap::NameAndSpan {
format: codemap::MacroAttribute(Symbol::intern(attr_name)),
span: Some(span),
allow_internal_unstable: true,
},
}),
..span
}
}
macro_rules! derive_traits {
($( $name:expr => $func:path, )+) => {
pub fn is_builtin_trait(name: ast::Name) -> bool {
@ -177,15 +163,15 @@ fn call_intrinsic(cx: &ExtCtxt,
intrinsic: &str,
args: Vec<P<ast::Expr>>)
-> P<ast::Expr> {
span.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
call_site: span,
callee: codemap::NameAndSpan {
format: codemap::MacroAttribute(Symbol::intern("derive")),
span: Some(span),
allow_internal_unstable: true,
},
});
if cx.current_expansion.mark.expn_info().unwrap().callee.allow_internal_unstable {
span.ctxt = cx.backtrace();
} else { // Avoid instability errors with user defined curstom derives, cc #36316
let mut info = cx.current_expansion.mark.expn_info().unwrap();
info.callee.allow_internal_unstable = true;
let mark = Mark::fresh();
mark.set_expn_info(info);
span.ctxt = SyntaxContext::empty().apply_mark(mark);
}
let path = cx.std_path(&["intrinsics", intrinsic]);
let call = cx.expr_call_global(span, path, args);

View File

@ -641,10 +641,11 @@ impl<'a, 'b> Context<'a, 'b> {
fn format_arg(ecx: &ExtCtxt,
macsp: Span,
sp: Span,
mut sp: Span,
ty: &ArgumentType,
arg: P<ast::Expr>)
-> P<ast::Expr> {
sp.ctxt = sp.ctxt.apply_mark(ecx.current_expansion.mark);
let trait_ = match *ty {
Placeholder(ref tyname) => {
match &tyname[..] {

View File

@ -17,6 +17,7 @@ use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::expand::ExpansionConfig;
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::fold::Folder;
use syntax::parse::ParseSess;
use syntax::ptr::P;
@ -360,7 +361,8 @@ fn mk_registrar(cx: &mut ExtCtxt,
custom_derives: &[ProcMacroDerive],
custom_attrs: &[ProcMacroDef],
custom_macros: &[ProcMacroDef]) -> P<ast::Item> {
let eid = cx.codemap().record_expansion(ExpnInfo {
let mark = Mark::fresh();
mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP,
callee: NameAndSpan {
format: MacroAttribute(Symbol::intern("proc_macro")),
@ -368,7 +370,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
allow_internal_unstable: true,
}
});
let span = Span { expn_id: eid, ..DUMMY_SP };
let span = Span { ctxt: SyntaxContext::empty().apply_mark(mark), ..DUMMY_SP };
let proc_macro = Ident::from_str("proc_macro");
let krate = cx.item(span,

View File

@ -15,12 +15,16 @@
//! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
//! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093
use Span;
use symbol::Symbol;
use serialize::{Encodable, Decodable, Encoder, Decoder};
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
/// A SyntaxContext represents a chain of macro expansions (represented by marks).
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Default)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SyntaxContext(u32);
#[derive(Copy, Clone)]
@ -36,8 +40,8 @@ pub struct Mark(u32);
impl Mark {
pub fn fresh() -> Self {
HygieneData::with(|data| {
let next_mark = Mark(data.next_mark.0 + 1);
::std::mem::replace(&mut data.next_mark, next_mark)
data.marks.push(None);
Mark(data.marks.len() as u32 - 1)
})
}
@ -53,23 +57,31 @@ impl Mark {
pub fn from_u32(raw: u32) -> Mark {
Mark(raw)
}
pub fn expn_info(self) -> Option<ExpnInfo> {
HygieneData::with(|data| data.marks[self.0 as usize].clone())
}
pub fn set_expn_info(self, info: ExpnInfo) {
HygieneData::with(|data| data.marks[self.0 as usize] = Some(info))
}
}
struct HygieneData {
marks: Vec<Option<ExpnInfo>>,
syntax_contexts: Vec<SyntaxContextData>,
markings: HashMap<(SyntaxContext, Mark), SyntaxContext>,
next_mark: Mark,
}
impl HygieneData {
fn new() -> Self {
HygieneData {
marks: vec![None],
syntax_contexts: vec![SyntaxContextData {
outer_mark: Mark::root(),
prev_ctxt: SyntaxContext::empty(),
}],
markings: HashMap::new(),
next_mark: Mark(1),
}
}
@ -81,8 +93,8 @@ impl HygieneData {
}
}
pub fn reset_hygiene_data() {
HygieneData::with(|data| *data = HygieneData::new())
pub fn clear_markings() {
HygieneData::with(|data| data.markings = HashMap::new());
}
impl SyntaxContext {
@ -113,6 +125,10 @@ impl SyntaxContext {
})
})
}
pub fn outer(self) -> Mark {
HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark)
}
}
impl fmt::Debug for SyntaxContext {
@ -120,3 +136,67 @@ impl fmt::Debug for SyntaxContext {
write!(f, "#{}", self.0)
}
}
/// Extra information for tracking spans of macro and syntax sugar expansion
#[derive(Clone, Hash, Debug)]
pub struct ExpnInfo {
/// The location of the actual macro invocation or syntax sugar , e.g.
/// `let x = foo!();` or `if let Some(y) = x {}`
///
/// This may recursively refer to other macro invocations, e.g. if
/// `foo!()` invoked `bar!()` internally, and there was an
/// expression inside `bar!`; the call_site of the expression in
/// the expansion would point to the `bar!` invocation; that
/// call_site span would have its own ExpnInfo, with the call_site
/// pointing to the `foo!` invocation.
pub call_site: Span,
/// Information about the expansion.
pub callee: NameAndSpan
}
#[derive(Clone, Hash, Debug)]
pub struct NameAndSpan {
/// The format with which the macro was invoked.
pub format: ExpnFormat,
/// Whether the macro is allowed to use #[unstable]/feature-gated
/// features internally without forcing the whole crate to opt-in
/// to them.
pub allow_internal_unstable: bool,
/// The span of the macro definition itself. The macro may not
/// have a sensible definition span (e.g. something defined
/// completely inside libsyntax) in which case this is None.
pub span: Option<Span>
}
impl NameAndSpan {
pub fn name(&self) -> Symbol {
match self.format {
ExpnFormat::MacroAttribute(s) |
ExpnFormat::MacroBang(s) |
ExpnFormat::CompilerDesugaring(s) => s,
}
}
}
/// The source of expansion.
#[derive(Clone, Hash, Debug, PartialEq, Eq)]
pub enum ExpnFormat {
/// e.g. #[derive(...)] <item>
MacroAttribute(Symbol),
/// e.g. `format!()`
MacroBang(Symbol),
/// Desugaring done by the compiler during HIR lowering.
CompilerDesugaring(Symbol)
}
impl Encodable for SyntaxContext {
fn encode<E: Encoder>(&self, _: &mut E) -> Result<(), E::Error> {
Ok(()) // FIXME(jseyfried) intercrate hygiene
}
}
impl Decodable for SyntaxContext {
fn decode<D: Decoder>(_: &mut D) -> Result<SyntaxContext, D::Error> {
Ok(SyntaxContext::empty()) // FIXME(jseyfried) intercrate hygiene
}
}

View File

@ -25,6 +25,7 @@
#![feature(const_fn)]
#![feature(custom_attribute)]
#![feature(optin_builtin_traits)]
#![allow(unused_attributes)]
#![feature(rustc_private)]
#![feature(staged_api)]
@ -43,6 +44,9 @@ extern crate serialize;
extern crate serialize as rustc_serialize; // used by deriving
pub mod hygiene;
pub use hygiene::{SyntaxContext, ExpnInfo, ExpnFormat, NameAndSpan};
pub mod symbol;
pub type FileName = String;
@ -60,7 +64,7 @@ pub struct Span {
pub hi: BytePos,
/// Information about where the macro came from, if this piece of
/// code was created by a macro expansion.
pub expn_id: ExpnId
pub ctxt: SyntaxContext,
}
/// A collection of spans. Spans have two orthogonal attributes:
@ -79,7 +83,7 @@ impl Span {
/// Returns a new span representing just the end-point of this span
pub fn end_point(self) -> Span {
let lo = cmp::max(self.hi.0 - 1, self.lo.0);
Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id}
Span { lo: BytePos(lo), hi: self.hi, ctxt: self.ctxt }
}
/// Returns `self` if `self` is not the dummy span, and `other` otherwise.
@ -107,6 +111,69 @@ impl Span {
None
}
}
/// Return the source span - this is either the supplied span, or the span for
/// the macro callsite that expanded to it.
pub fn source_callsite(self) -> Span {
self.ctxt.outer().expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self)
}
/// Return the source callee.
///
/// Returns None if the supplied span has no expansion trace,
/// else returns the NameAndSpan for the macro definition
/// corresponding to the source callsite.
pub fn source_callee(self) -> Option<NameAndSpan> {
fn source_callee(info: ExpnInfo) -> NameAndSpan {
match info.call_site.ctxt.outer().expn_info() {
Some(info) => source_callee(info),
None => info.callee,
}
}
self.ctxt.outer().expn_info().map(source_callee)
}
/// Check if a span is "internal" to a macro in which #[unstable]
/// items can be used (that is, a macro marked with
/// `#[allow_internal_unstable]`).
pub fn allows_unstable(&self) -> bool {
match self.ctxt.outer().expn_info() {
Some(info) => info.callee.allow_internal_unstable,
None => false,
}
}
pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> {
let mut prev_span = DUMMY_SP;
let mut result = vec![];
loop {
let info = match self.ctxt.outer().expn_info() {
Some(info) => info,
None => break,
};
let (pre, post) = match info.callee.format {
ExpnFormat::MacroAttribute(..) => ("#[", "]"),
ExpnFormat::MacroBang(..) => ("", "!"),
ExpnFormat::CompilerDesugaring(..) => ("desugaring of `", "`"),
};
let macro_decl_name = format!("{}{}{}", pre, info.callee.name(), post);
let def_site_span = info.callee.span;
// Don't print recursive invocations
if !info.call_site.source_equal(&prev_span) {
result.push(MacroBacktrace {
call_site: info.call_site,
macro_decl_name: macro_decl_name,
def_site_span: def_site_span,
});
}
prev_span = self;
self = info.call_site;
}
result
}
}
#[derive(Clone, Debug)]
@ -147,8 +214,8 @@ impl serialize::UseSpecializedDecodable for Span {
}
fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}",
span.lo, span.hi, span.expn_id)
write!(f, "Span {{ lo: {:?}, hi: {:?}, ctxt: {:?} }}",
span.lo, span.hi, span.ctxt)
}
impl fmt::Debug for Span {
@ -157,12 +224,7 @@ impl fmt::Debug for Span {
}
}
pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION };
// Generic span to be used for code originating from the command line
pub const COMMAND_LINE_SP: Span = Span { lo: BytePos(0),
hi: BytePos(0),
expn_id: COMMAND_LINE_EXPN };
pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), ctxt: NO_EXPANSION };
impl MultiSpan {
pub fn new() -> MultiSpan {
@ -256,22 +318,7 @@ impl From<Span> for MultiSpan {
}
}
#[derive(PartialEq, Eq, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Copy, Ord, PartialOrd)]
pub struct ExpnId(pub u32);
pub const NO_EXPANSION: ExpnId = ExpnId(!0);
// For code appearing from the command line
pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(!1);
impl ExpnId {
pub fn from_u32(id: u32) -> ExpnId {
ExpnId(id)
}
pub fn into_u32(self) -> u32 {
self.0
}
}
pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty();
/// Identifies an offset of a multi-byte character in a FileMap
#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq)]
@ -651,7 +698,7 @@ thread_local!(pub static SPAN_DEBUG: Cell<fn(Span, &mut fmt::Formatter) -> fmt::
/* assuming that we're not in macro expansion */
pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
Span {lo: lo, hi: hi, expn_id: NO_EXPANSION}
Span {lo: lo, hi: hi, ctxt: NO_EXPANSION}
}
pub struct MacroBacktrace {

View File

@ -12,11 +12,58 @@
//! allows bidirectional lookup; i.e. given a value, one can easily find the
//! type, and vice versa.
use hygiene::SyntaxContext;
use serialize::{Decodable, Decoder, Encodable, Encoder};
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Ident {
pub name: Symbol,
pub ctxt: SyntaxContext,
}
impl Ident {
pub const fn with_empty_ctxt(name: Symbol) -> Ident {
Ident { name: name, ctxt: SyntaxContext::empty() }
}
/// Maps a string to an identifier with an empty syntax context.
pub fn from_str(string: &str) -> Ident {
Ident::with_empty_ctxt(Symbol::intern(string))
}
pub fn unhygienize(self) -> Ident {
Ident { name: self.name, ctxt: SyntaxContext::empty() }
}
}
impl fmt::Debug for Ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{:?}", self.name, self.ctxt)
}
}
impl fmt::Display for Ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.name, f)
}
}
impl Encodable for Ident {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
self.name.encode(s)
}
}
impl Decodable for Ident {
fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> {
Ok(Ident::with_empty_ctxt(Symbol::decode(d)?))
}
}
/// A symbol is an interned or gensymed string.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Symbol(u32);
@ -128,19 +175,19 @@ macro_rules! declare_keywords {(
$( ($index: expr, $konst: ident, $string: expr) )*
) => {
pub mod keywords {
use ast;
use super::{Symbol, Ident};
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Keyword {
ident: ast::Ident,
ident: Ident,
}
impl Keyword {
#[inline] pub fn ident(self) -> ast::Ident { self.ident }
#[inline] pub fn name(self) -> ast::Name { self.ident.name }
#[inline] pub fn ident(self) -> Ident { self.ident }
#[inline] pub fn name(self) -> Symbol { self.ident.name }
}
$(
#[allow(non_upper_case_globals)]
pub const $konst: Keyword = Keyword {
ident: ast::Ident::with_empty_ctxt(super::Symbol($index))
ident: Ident::with_empty_ctxt(super::Symbol($index))
};
)*
}

View File

@ -27,14 +27,6 @@ fn main() {
&ps,
syntax::ext::expand::ExpansionConfig::default("qquote".to_string()),
&mut resolver);
cx.bt_push(syntax::codemap::ExpnInfo {
call_site: DUMMY_SP,
callee: syntax::codemap::NameAndSpan {
format: syntax::codemap::MacroBang(Symbol::intern("")),
allow_internal_unstable: false,
span: None,
}
});
let cx = &mut cx;
assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23");

View File

@ -30,14 +30,6 @@ fn main() {
&ps,
syntax::ext::expand::ExpansionConfig::default("qquote".to_string()),
&mut resolver);
cx.bt_push(syntax::codemap::ExpnInfo {
call_site: DUMMY_SP,
callee: syntax::codemap::NameAndSpan {
format: syntax::codemap::MacroBang(Symbol::intern("")),
allow_internal_unstable: false,
span: None,
}
});
let cx = &mut cx;
println!("{}", pprust::expr_to_string(&*quote_expr!(&cx, 23)));

View File

@ -26,14 +26,6 @@ fn main() {
&ps,
syntax::ext::expand::ExpansionConfig::default("qquote".to_string()),
&mut resolver);
cx.bt_push(syntax::codemap::ExpnInfo {
call_site: DUMMY_SP,
callee: syntax::codemap::NameAndSpan {
format: syntax::codemap::MacroBang(Symbol::intern("")),
allow_internal_unstable: false,
span: None,
}
});
let cx = &mut cx;
macro_rules! check {