Merge ExpnId
and SyntaxContext
.
This commit is contained in:
parent
496996c2af
commit
ec7c0aece1
46 changed files with 456 additions and 702 deletions
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)> {
|
||||
|
|
|
@ -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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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![]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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 ||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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:");
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" {
|
||||
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;
|
||||
}
|
||||
expn_id = i.call_site.expn_id;
|
||||
last_macro = Some(i.call_site);
|
||||
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
|
||||
});
|
||||
|
||||
|
|
|
@ -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 {
|
||||
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(')');
|
||||
|
||||
cx.current_expansion.mark.set_expn_info(ExpnInfo {
|
||||
call_site: span,
|
||||
callee: codemap::NameAndSpan {
|
||||
format: codemap::MacroAttribute(Symbol::intern(attr_name)),
|
||||
span: Some(span),
|
||||
callee: NameAndSpan {
|
||||
format: ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)),
|
||||
span: None,
|
||||
allow_internal_unstable: true,
|
||||
},
|
||||
}),
|
||||
..span
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
});
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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![]);
|
||||
|
|
|
@ -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![]);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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[..] {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
};
|
||||
)*
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue