Merge branch 'master' into issue-32540
This commit is contained in:
commit
dedb7bbbbf
664 changed files with 11577 additions and 8696 deletions
|
|
@ -10,7 +10,7 @@ crate-type = ["dylib"]
|
|||
|
||||
[dependencies]
|
||||
serialize = { path = "../libserialize" }
|
||||
log = { path = "../liblog" }
|
||||
log = "0.3"
|
||||
rustc_bitflags = { path = "../librustc_bitflags" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
|
|
|
|||
|
|
@ -14,73 +14,25 @@ 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::{Span, DUMMY_SP};
|
||||
use codemap::{respan, Spanned};
|
||||
use abi::Abi;
|
||||
use ext::hygiene::SyntaxContext;
|
||||
use ext::hygiene::{Mark, SyntaxContext};
|
||||
use print::pprust;
|
||||
use ptr::P;
|
||||
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,
|
||||
|
|
@ -255,6 +207,14 @@ impl NodeId {
|
|||
pub fn as_u32(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn placeholder_from_mark(mark: Mark) -> Self {
|
||||
NodeId(mark.as_u32())
|
||||
}
|
||||
|
||||
pub fn placeholder_to_mark(self) -> Mark {
|
||||
Mark::from_u32(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for NodeId {
|
||||
|
|
@ -275,6 +235,16 @@ impl serialize::UseSpecializedDecodable for NodeId {
|
|||
}
|
||||
}
|
||||
|
||||
impl indexed_vec::Idx for NodeId {
|
||||
fn new(idx: usize) -> Self {
|
||||
NodeId::new(idx)
|
||||
}
|
||||
|
||||
fn index(self) -> usize {
|
||||
self.as_usize()
|
||||
}
|
||||
}
|
||||
|
||||
/// Node id used to represent the root of the crate.
|
||||
pub const CRATE_NODE_ID: NodeId = NodeId(0);
|
||||
|
||||
|
|
@ -1426,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.
|
||||
|
|
@ -1463,7 +1433,7 @@ impl Arg {
|
|||
TyKind::Rptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyKind::ImplicitSelf => {
|
||||
Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
|
||||
}
|
||||
_ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi),
|
||||
_ => Some(respan(self.pat.span.to(self.ty.span),
|
||||
SelfKind::Explicit(self.ty.clone(), mutbl))),
|
||||
}
|
||||
}
|
||||
|
|
@ -1480,7 +1450,7 @@ impl Arg {
|
|||
}
|
||||
|
||||
pub fn from_self(eself: ExplicitSelf, eself_ident: SpannedIdent) -> Arg {
|
||||
let span = mk_sp(eself.span.lo, eself_ident.span.hi);
|
||||
let span = eself.span.to(eself_ident.span);
|
||||
let infer_ty = P(Ty {
|
||||
id: DUMMY_NODE_ID,
|
||||
node: TyKind::ImplicitSelf,
|
||||
|
|
@ -1717,11 +1687,11 @@ pub struct PolyTraitRef {
|
|||
}
|
||||
|
||||
impl PolyTraitRef {
|
||||
pub fn new(lifetimes: Vec<LifetimeDef>, path: Path, lo: BytePos, hi: BytePos) -> Self {
|
||||
pub fn new(lifetimes: Vec<LifetimeDef>, path: Path, span: Span) -> Self {
|
||||
PolyTraitRef {
|
||||
bound_lifetimes: lifetimes,
|
||||
trait_ref: TraitRef { path: path, ref_id: DUMMY_NODE_ID },
|
||||
span: mk_sp(lo, hi),
|
||||
span: span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ use ast;
|
|||
use ast::{AttrId, Attribute, Name, Ident};
|
||||
use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind};
|
||||
use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind};
|
||||
use codemap::{Spanned, spanned, dummy_spanned, mk_sp};
|
||||
use syntax_pos::{Span, BytePos, DUMMY_SP};
|
||||
use codemap::{Spanned, respan, dummy_spanned};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use errors::Handler;
|
||||
use feature_gate::{Features, GatedCfg};
|
||||
use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
|
||||
|
|
@ -447,17 +447,16 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute
|
|||
}
|
||||
}
|
||||
|
||||
pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, lo: BytePos, hi: BytePos)
|
||||
-> Attribute {
|
||||
pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, span: Span) -> Attribute {
|
||||
let style = doc_comment_style(&text.as_str());
|
||||
let lit = spanned(lo, hi, LitKind::Str(text, ast::StrStyle::Cooked));
|
||||
let lit = respan(span, LitKind::Str(text, ast::StrStyle::Cooked));
|
||||
Attribute {
|
||||
id: id,
|
||||
style: style,
|
||||
path: ast::Path::from_ident(mk_sp(lo, hi), ast::Ident::from_str("doc")),
|
||||
tokens: MetaItemKind::NameValue(lit).tokens(mk_sp(lo, hi)),
|
||||
path: ast::Path::from_ident(span, ast::Ident::from_str("doc")),
|
||||
tokens: MetaItemKind::NameValue(lit).tokens(span),
|
||||
is_sugared_doc: true,
|
||||
span: mk_sp(lo, hi),
|
||||
span: span,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1016,9 +1015,10 @@ impl MetaItem {
|
|||
{
|
||||
let (mut span, name) = match tokens.next() {
|
||||
Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name),
|
||||
Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => return match **nt {
|
||||
token::Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
|
||||
_ => None,
|
||||
Some(TokenTree::Token(_, Token::Interpolated(ref nt))) => match **nt {
|
||||
token::Nonterminal::NtIdent(ident) => (ident.span, ident.node.name),
|
||||
token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()),
|
||||
_ => return None,
|
||||
},
|
||||
_ => return None,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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,45 +28,27 @@ 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,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
pub fn spanned<T>(lo: BytePos, hi: BytePos, t: T) -> Spanned<T> {
|
||||
respan(mk_sp(lo, hi), t)
|
||||
}
|
||||
|
||||
pub fn respan<T>(sp: Span, t: T) -> Spanned<T> {
|
||||
Spanned {node: t, span: sp}
|
||||
}
|
||||
|
|
@ -73,47 +57,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 +104,6 @@ impl FileLoader for RealFileLoader {
|
|||
|
||||
pub struct CodeMap {
|
||||
pub files: RefCell<Vec<Rc<FileMap>>>,
|
||||
expansions: RefCell<Vec<ExpnInfo>>,
|
||||
file_loader: Box<FileLoader>
|
||||
}
|
||||
|
||||
|
|
@ -169,7 +111,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 +118,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 +293,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 +323,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 +331,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,157 +345,6 @@ impl CodeMap {
|
|||
hi.col.to_usize() + 1)).to_string()
|
||||
}
|
||||
|
||||
// Returns true if two spans have the same callee
|
||||
// (Assumes the same ExpnFormat implies same callee)
|
||||
fn match_callees(&self, sp_a: &Span, sp_b: &Span) -> bool {
|
||||
let fmt_a = self
|
||||
.with_expn_info(sp_a.expn_id,
|
||||
|ei| ei.map(|ei| ei.callee.format.clone()));
|
||||
|
||||
let fmt_b = self
|
||||
.with_expn_info(sp_b.expn_id,
|
||||
|ei| ei.map(|ei| ei.callee.format.clone()));
|
||||
fmt_a == fmt_b
|
||||
}
|
||||
|
||||
/// Returns a formatted string showing the expansion chain of a span
|
||||
///
|
||||
/// Spans are printed in the following format:
|
||||
///
|
||||
/// filename:start_line:col: end_line:col
|
||||
/// snippet
|
||||
/// Callee:
|
||||
/// Callee span
|
||||
/// Callsite:
|
||||
/// Callsite span
|
||||
///
|
||||
/// Callees and callsites are printed recursively (if available, otherwise header
|
||||
/// and span is omitted), expanding into their own callee/callsite spans.
|
||||
/// Each layer of recursion has an increased indent, and snippets are truncated
|
||||
/// to at most 50 characters. Finally, recursive calls to the same macro are squashed,
|
||||
/// with '...' used to represent any number of recursive calls.
|
||||
pub fn span_to_expanded_string(&self, sp: Span) -> String {
|
||||
self.span_to_expanded_string_internal(sp, "")
|
||||
}
|
||||
|
||||
fn span_to_expanded_string_internal(&self, sp:Span, indent: &str) -> String {
|
||||
let mut indent = indent.to_owned();
|
||||
let mut output = "".to_owned();
|
||||
let span_str = self.span_to_string(sp);
|
||||
let mut span_snip = self.span_to_snippet(sp)
|
||||
.unwrap_or("Snippet unavailable".to_owned());
|
||||
|
||||
// Truncate by code points - in worst case this will be more than 50 characters,
|
||||
// but ensures at least 50 characters and respects byte boundaries.
|
||||
let char_vec: Vec<(usize, char)> = span_snip.char_indices().collect();
|
||||
if char_vec.len() > 50 {
|
||||
span_snip.truncate(char_vec[49].0);
|
||||
span_snip.push_str("...");
|
||||
}
|
||||
|
||||
output.push_str(&format!("{}{}\n{}`{}`\n", indent, span_str, indent, span_snip));
|
||||
|
||||
if sp.expn_id == NO_EXPANSION || sp.expn_id == COMMAND_LINE_EXPN {
|
||||
return output;
|
||||
}
|
||||
|
||||
let mut callee = self.with_expn_info(sp.expn_id,
|
||||
|ei| ei.and_then(|ei| ei.callee.span.clone()));
|
||||
let mut callsite = self.with_expn_info(sp.expn_id,
|
||||
|ei| ei.map(|ei| ei.call_site.clone()));
|
||||
|
||||
indent.push_str(" ");
|
||||
let mut is_recursive = false;
|
||||
|
||||
while callee.is_some() && self.match_callees(&sp, &callee.unwrap()) {
|
||||
callee = self.with_expn_info(callee.unwrap().expn_id,
|
||||
|ei| ei.and_then(|ei| ei.callee.span.clone()));
|
||||
is_recursive = true;
|
||||
}
|
||||
if let Some(span) = callee {
|
||||
output.push_str(&indent);
|
||||
output.push_str("Callee:\n");
|
||||
if is_recursive {
|
||||
output.push_str(&indent);
|
||||
output.push_str("...\n");
|
||||
}
|
||||
output.push_str(&(self.span_to_expanded_string_internal(span, &indent)));
|
||||
}
|
||||
|
||||
is_recursive = false;
|
||||
while callsite.is_some() && self.match_callees(&sp, &callsite.unwrap()) {
|
||||
callsite = self.with_expn_info(callsite.unwrap().expn_id,
|
||||
|ei| ei.map(|ei| ei.call_site.clone()));
|
||||
is_recursive = true;
|
||||
}
|
||||
if let Some(span) = callsite {
|
||||
output.push_str(&indent);
|
||||
output.push_str("Callsite:\n");
|
||||
if is_recursive {
|
||||
output.push_str(&indent);
|
||||
output.push_str("...\n");
|
||||
}
|
||||
output.push_str(&(self.span_to_expanded_string_internal(span, &indent)));
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
/// 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()
|
||||
}
|
||||
|
|
@ -723,111 +508,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 {
|
||||
|
|
@ -843,9 +526,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)
|
||||
}
|
||||
|
|
@ -858,7 +538,6 @@ impl CodeMapper for CodeMap {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use symbol::keywords;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[test]
|
||||
|
|
@ -1007,7 +686,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");
|
||||
|
|
@ -1023,7 +702,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
|
||||
|
|
@ -1053,7 +732,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()));
|
||||
|
|
@ -1063,65 +742,12 @@ 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");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn t10() {
|
||||
// Test span_to_expanded_string works in base case (no expansion)
|
||||
let cm = init_code_map();
|
||||
let span = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION };
|
||||
let sstr = cm.span_to_expanded_string(span);
|
||||
assert_eq!(sstr, "blork.rs:1:1: 1:12\n`first line.`\n");
|
||||
|
||||
let span = Span { lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION };
|
||||
let sstr = cm.span_to_expanded_string(span);
|
||||
assert_eq!(sstr, "blork.rs:2:1: 2:12\n`second line`\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn t11() {
|
||||
// Test span_to_expanded_string works with expansion
|
||||
let cm = init_code_map();
|
||||
let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION };
|
||||
let format = ExpnFormat::MacroBang(keywords::Invalid.name());
|
||||
let callee = NameAndSpan { format: format,
|
||||
allow_internal_unstable: false,
|
||||
span: None };
|
||||
|
||||
let info = ExpnInfo { call_site: root, callee: callee };
|
||||
let id = cm.record_expansion(info);
|
||||
let sp = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id };
|
||||
|
||||
let sstr = cm.span_to_expanded_string(sp);
|
||||
assert_eq!(sstr,
|
||||
"blork.rs:2:1: 2:12\n`second line`\n Callsite:\n \
|
||||
blork.rs:1:1: 1:12\n `first line.`\n");
|
||||
}
|
||||
|
||||
/// Test merging two spans on the same line
|
||||
#[test]
|
||||
fn span_merging() {
|
||||
let cm = CodeMap::new();
|
||||
let inputtext = "bbbb BB bb CCC\n";
|
||||
let selection1 = " ~~ \n";
|
||||
let selection2 = " ~~~\n";
|
||||
cm.new_filemap_and_lines("blork.rs", None, inputtext);
|
||||
let span1 = span_from_selection(inputtext, selection1);
|
||||
let span2 = span_from_selection(inputtext, selection2);
|
||||
|
||||
if let Some(sp) = cm.merge_spans(span1, span2) {
|
||||
let sstr = cm.span_to_expanded_string(sp);
|
||||
assert_eq!(sstr, "blork.rs:1:6: 1:15\n`BB bb CCC`\n");
|
||||
}
|
||||
else {
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Test failing to merge two spans on different lines
|
||||
#[test]
|
||||
fn span_merging_fail() {
|
||||
|
|
@ -1170,7 +796,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);
|
||||
|
|
@ -1180,82 +806,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 }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn t12() {
|
||||
// Test span_to_expanded_string collapses recursive macros and handles
|
||||
// recursive callsite and callee expansions
|
||||
let cm = init_code_map();
|
||||
let end = init_expansion_chain(&cm);
|
||||
let sstr = cm.span_to_expanded_string(end);
|
||||
let res_str =
|
||||
r"blork2.rs:2:1: 2:12
|
||||
`second line`
|
||||
Callsite:
|
||||
...
|
||||
blork2.rs:1:1: 1:12
|
||||
`first line.`
|
||||
Callee:
|
||||
blork.rs:2:1: 2:12
|
||||
`second line`
|
||||
Callee:
|
||||
blork.rs:1:1: 1:12
|
||||
`first line.`
|
||||
Callsite:
|
||||
blork.rs:1:1: 1:12
|
||||
`first line.`
|
||||
Callsite:
|
||||
...
|
||||
blork.rs:2:1: 2:12
|
||||
`second line`
|
||||
Callee:
|
||||
blork.rs:1:1: 1:12
|
||||
`first line.`
|
||||
Callsite:
|
||||
blork.rs:1:1: 1:12
|
||||
`first line.`
|
||||
";
|
||||
assert_eq!(sstr, res_str);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -201,7 +209,26 @@ impl<F> TTMacroExpander for F
|
|||
{
|
||||
fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, input: TokenStream)
|
||||
-> Box<MacResult+'cx> {
|
||||
(*self)(ecx, span, &input.trees().collect::<Vec<_>>())
|
||||
struct AvoidInterpolatedIdents;
|
||||
|
||||
impl Folder for AvoidInterpolatedIdents {
|
||||
fn fold_tt(&mut self, tt: tokenstream::TokenTree) -> tokenstream::TokenTree {
|
||||
if let tokenstream::TokenTree::Token(_, token::Interpolated(ref nt)) = tt {
|
||||
if let token::NtIdent(ident) = **nt {
|
||||
return tokenstream::TokenTree::Token(ident.span, token::Ident(ident.node));
|
||||
}
|
||||
}
|
||||
fold::noop_fold_tt(tt, self)
|
||||
}
|
||||
|
||||
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
|
||||
fold::noop_fold_mac(mac, self)
|
||||
}
|
||||
}
|
||||
|
||||
let input: Vec<_> =
|
||||
input.trees().map(|tt| AvoidInterpolatedIdents.fold_tt(tt)).collect();
|
||||
(*self)(ecx, span, &input)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -602,7 +629,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 +659,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 +683,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 +714,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 +795,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 {
|
||||
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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,11 +8,12 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use ast::{self, Block, Ident, PatKind, Path};
|
||||
use ast::{self, Block, Ident, NodeId, PatKind, Path};
|
||||
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 {
|
||||
|
|
@ -321,7 +322,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
while let Some(expansions) = expansions.pop() {
|
||||
for (mark, expansion) in expansions.into_iter().rev() {
|
||||
let derives = derives.remove(&mark).unwrap_or_else(Vec::new);
|
||||
placeholder_expander.add(mark.as_placeholder_id(), expansion, derives);
|
||||
placeholder_expander.add(NodeId::placeholder_from_mark(mark), expansion, derives);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
@ -703,7 +687,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
|
|||
..self.cx.current_expansion.clone()
|
||||
},
|
||||
});
|
||||
placeholder(expansion_kind, mark.as_placeholder_id())
|
||||
placeholder(expansion_kind, NodeId::placeholder_from_mark(mark))
|
||||
}
|
||||
|
||||
fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: ExpansionKind) -> Expansion {
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,127 +0,0 @@
|
|||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Machinery for hygienic macros, inspired by the MTWT[1] paper.
|
||||
//!
|
||||
//! [1] Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler.
|
||||
//! 2012. *Macros that work together: Compile-time bindings, partial expansion,
|
||||
//! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
|
||||
//! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093
|
||||
|
||||
use ast::NodeId;
|
||||
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)]
|
||||
pub struct SyntaxContext(u32);
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SyntaxContextData {
|
||||
pub outer_mark: Mark,
|
||||
pub prev_ctxt: SyntaxContext,
|
||||
}
|
||||
|
||||
/// A mark is a unique id associated with a macro expansion.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable, RustcDecodable)]
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
/// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST.
|
||||
pub fn root() -> Self {
|
||||
Mark(0)
|
||||
}
|
||||
|
||||
pub fn from_placeholder_id(id: NodeId) -> Self {
|
||||
Mark(id.as_u32())
|
||||
}
|
||||
|
||||
pub fn as_placeholder_id(self) -> NodeId {
|
||||
NodeId::from_u32(self.0)
|
||||
}
|
||||
|
||||
pub fn as_u32(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct HygieneData {
|
||||
syntax_contexts: Vec<SyntaxContextData>,
|
||||
markings: HashMap<(SyntaxContext, Mark), SyntaxContext>,
|
||||
next_mark: Mark,
|
||||
}
|
||||
|
||||
impl HygieneData {
|
||||
fn new() -> Self {
|
||||
HygieneData {
|
||||
syntax_contexts: vec![SyntaxContextData {
|
||||
outer_mark: Mark::root(),
|
||||
prev_ctxt: SyntaxContext::empty(),
|
||||
}],
|
||||
markings: HashMap::new(),
|
||||
next_mark: Mark(1),
|
||||
}
|
||||
}
|
||||
|
||||
fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
|
||||
thread_local! {
|
||||
static HYGIENE_DATA: RefCell<HygieneData> = RefCell::new(HygieneData::new());
|
||||
}
|
||||
HYGIENE_DATA.with(|data| f(&mut *data.borrow_mut()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset_hygiene_data() {
|
||||
HygieneData::with(|data| *data = HygieneData::new())
|
||||
}
|
||||
|
||||
impl SyntaxContext {
|
||||
pub const fn empty() -> Self {
|
||||
SyntaxContext(0)
|
||||
}
|
||||
|
||||
pub fn data(self) -> SyntaxContextData {
|
||||
HygieneData::with(|data| data.syntax_contexts[self.0 as usize])
|
||||
}
|
||||
|
||||
/// Extend a syntax context with a given mark
|
||||
pub fn apply_mark(self, mark: Mark) -> SyntaxContext {
|
||||
// Applying the same mark twice is a no-op
|
||||
let ctxt_data = self.data();
|
||||
if mark == ctxt_data.outer_mark {
|
||||
return ctxt_data.prev_ctxt;
|
||||
}
|
||||
|
||||
HygieneData::with(|data| {
|
||||
let syntax_contexts = &mut data.syntax_contexts;
|
||||
*data.markings.entry((self, mark)).or_insert_with(|| {
|
||||
syntax_contexts.push(SyntaxContextData {
|
||||
outer_mark: mark,
|
||||
prev_ctxt: self,
|
||||
});
|
||||
SyntaxContext(syntax_contexts.len() as u32 - 1)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SyntaxContext {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "#{}", self.0)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use ast;
|
||||
use ast::{self, NodeId};
|
||||
use codemap::{DUMMY_SP, dummy_spanned};
|
||||
use ext::base::ExtCtxt;
|
||||
use ext::expand::{Expansion, ExpansionKind};
|
||||
|
|
@ -88,7 +88,7 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
|
|||
let mut expansion = expansion.fold_with(self);
|
||||
if let Expansion::Items(mut items) = expansion {
|
||||
for derive in derives {
|
||||
match self.remove(derive.as_placeholder_id()) {
|
||||
match self.remove(NodeId::placeholder_from_mark(derive)) {
|
||||
Expansion::Items(derived_items) => items.extend(derived_items),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
|
@ -106,8 +106,8 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
|
|||
impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
|
||||
fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
|
||||
match item.node {
|
||||
ast::ItemKind::Mac(ref mac) if !mac.node.path.segments.is_empty() => {}
|
||||
ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(),
|
||||
ast::ItemKind::MacroDef(_) => return SmallVector::one(item),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
|
@ -178,17 +178,9 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> {
|
|||
block.stmts = block.stmts.move_flat_map(|mut stmt| {
|
||||
remaining_stmts -= 1;
|
||||
|
||||
match stmt.node {
|
||||
// Avoid wasting a node id on a trailing expression statement,
|
||||
// which shares a HIR node with the expression itself.
|
||||
ast::StmtKind::Expr(ref expr) if remaining_stmts == 0 => stmt.id = expr.id,
|
||||
|
||||
_ if self.monotonic => {
|
||||
assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
|
||||
stmt.id = self.cx.resolver.next_node_id();
|
||||
}
|
||||
|
||||
_ => {}
|
||||
if self.monotonic {
|
||||
assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
|
||||
stmt.id = self.cx.resolver.next_node_id();
|
||||
}
|
||||
|
||||
Some(stmt)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ pub use self::ParseResult::*;
|
|||
use self::TokenTreeOrTokenTreeVec::*;
|
||||
|
||||
use ast::Ident;
|
||||
use syntax_pos::{self, BytePos, mk_sp, Span};
|
||||
use syntax_pos::{self, BytePos, Span};
|
||||
use codemap::Spanned;
|
||||
use errors::FatalError;
|
||||
use ext::tt::quoted::{self, TokenTree};
|
||||
|
|
@ -285,7 +285,7 @@ fn inner_parse_loop(sess: &ParseSess,
|
|||
eof_eis: &mut SmallVector<Box<MatcherPos>>,
|
||||
bb_eis: &mut SmallVector<Box<MatcherPos>>,
|
||||
token: &Token,
|
||||
span: &syntax_pos::Span)
|
||||
span: syntax_pos::Span)
|
||||
-> ParseResult<()> {
|
||||
while let Some(mut ei) = cur_eis.pop() {
|
||||
// When unzipped trees end, remove them
|
||||
|
|
@ -323,8 +323,7 @@ fn inner_parse_loop(sess: &ParseSess,
|
|||
for idx in ei.match_lo..ei.match_hi {
|
||||
let sub = ei.matches[idx].clone();
|
||||
new_pos.matches[idx]
|
||||
.push(Rc::new(MatchedSeq(sub, mk_sp(ei.sp_lo,
|
||||
span.hi))));
|
||||
.push(Rc::new(MatchedSeq(sub, Span { lo: ei.sp_lo, ..span })));
|
||||
}
|
||||
|
||||
new_pos.match_cur = ei.match_hi;
|
||||
|
|
@ -426,7 +425,7 @@ pub fn parse(sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], directory: Op
|
|||
assert!(next_eis.is_empty());
|
||||
|
||||
match inner_parse_loop(sess, &mut cur_eis, &mut next_eis, &mut eof_eis, &mut bb_eis,
|
||||
&parser.token, &parser.span) {
|
||||
&parser.token, parser.span) {
|
||||
Success(_) => {},
|
||||
Failure(sp, tok) => return Failure(sp, tok),
|
||||
Error(sp, msg) => return Error(sp, msg),
|
||||
|
|
@ -493,7 +492,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal {
|
|||
_ => {}
|
||||
}
|
||||
// check at the beginning and the parser checks after each bump
|
||||
p.check_unknown_macro_variable();
|
||||
p.process_potential_macro_variable();
|
||||
match name {
|
||||
"item" => match panictry!(p.parse_item()) {
|
||||
Some(i) => token::NtItem(i),
|
||||
|
|
|
|||
|
|
@ -119,9 +119,9 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
|||
};
|
||||
let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), false);
|
||||
p.root_module_name = cx.current_expansion.module.mod_path.last()
|
||||
.map(|id| (*id.name.as_str()).to_owned());
|
||||
.map(|id| id.name.as_str().to_string());
|
||||
|
||||
p.check_unknown_macro_variable();
|
||||
p.process_potential_macro_variable();
|
||||
// Let the context choose how to interpret the result.
|
||||
// Weird, but useful for X-macros.
|
||||
return Box::new(ParserAnyMacro {
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
@ -134,11 +136,14 @@ pub fn parse(input: tokenstream::TokenStream, expect_matchers: bool, sess: &Pars
|
|||
TokenTree::Token(start_sp, token::SubstNt(ident)) if expect_matchers => {
|
||||
let span = match trees.next() {
|
||||
Some(tokenstream::TokenTree::Token(span, token::Colon)) => match trees.next() {
|
||||
Some(tokenstream::TokenTree::Token(end_sp, token::Ident(kind))) => {
|
||||
let span = Span { lo: start_sp.lo, ..end_sp };
|
||||
result.push(TokenTree::MetaVarDecl(span, ident, kind));
|
||||
continue
|
||||
}
|
||||
Some(tokenstream::TokenTree::Token(end_sp, ref tok)) => match tok.ident() {
|
||||
Some(kind) => {
|
||||
let span = Span { lo: start_sp.lo, ..end_sp };
|
||||
result.push(TokenTree::MetaVarDecl(span, ident, kind));
|
||||
continue
|
||||
}
|
||||
_ => end_sp,
|
||||
},
|
||||
tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
|
||||
},
|
||||
tree @ _ => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp),
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use ast::Ident;
|
|||
use errors::Handler;
|
||||
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
|
||||
use ext::tt::quoted;
|
||||
use parse::token::{self, SubstNt, Token, NtIdent, NtTT};
|
||||
use parse::token::{self, SubstNt, Token, NtTT};
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use tokenstream::{TokenStream, TokenTree, Delimited};
|
||||
use util::small_vector::SmallVector;
|
||||
|
|
@ -154,13 +154,6 @@ pub fn transcribe(sp_diag: &Handler,
|
|||
None => result.push(TokenTree::Token(sp, SubstNt(ident)).into()),
|
||||
Some(cur_matched) => if let MatchedNonterminal(ref nt) = *cur_matched {
|
||||
match **nt {
|
||||
// sidestep the interpolation tricks for ident because
|
||||
// (a) idents can be in lots of places, so it'd be a pain
|
||||
// (b) we actually can, since it's a token.
|
||||
NtIdent(ref sn) => {
|
||||
let token = TokenTree::Token(sn.span, token::Ident(sn.node));
|
||||
result.push(token.into());
|
||||
}
|
||||
NtTT(ref tt) => result.push(tt.clone().into()),
|
||||
_ => {
|
||||
let token = TokenTree::Token(sp, token::Interpolated(nt.clone()));
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
@ -818,7 +818,7 @@ pub struct GatedCfg {
|
|||
|
||||
impl GatedCfg {
|
||||
pub fn gate(cfg: &ast::MetaItem) -> Option<GatedCfg> {
|
||||
let name = &*cfg.name().as_str();
|
||||
let name = cfg.name().as_str();
|
||||
GATED_CFGS.iter()
|
||||
.position(|info| info.0 == name)
|
||||
.map(|idx| {
|
||||
|
|
@ -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);
|
||||
}
|
||||
}}
|
||||
|
|
@ -865,8 +864,7 @@ macro_rules! gate_feature {
|
|||
impl<'a> Context<'a> {
|
||||
fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
|
||||
debug!("check_attribute(attr = {:?})", attr);
|
||||
let name = unwrap_or!(attr.name(), return);
|
||||
|
||||
let name = unwrap_or!(attr.name(), return).as_str();
|
||||
for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES {
|
||||
if name == n {
|
||||
if let &Gated(_, ref name, ref desc, ref has_feature) = gateage {
|
||||
|
|
@ -885,12 +883,12 @@ impl<'a> Context<'a> {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if name.as_str().starts_with("rustc_") {
|
||||
if name.starts_with("rustc_") {
|
||||
gate_feature!(self, rustc_attrs, attr.span,
|
||||
"unless otherwise specified, attributes \
|
||||
with the prefix `rustc_` \
|
||||
are reserved for internal compiler diagnostics");
|
||||
} else if name.as_str().starts_with("derive_") {
|
||||
} else if name.starts_with("derive_") {
|
||||
gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE);
|
||||
} else if !attr::is_known(attr) {
|
||||
// Only run the custom attribute lint during regular
|
||||
|
|
@ -909,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);
|
||||
}
|
||||
|
||||
|
|
@ -1017,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)
|
||||
}
|
||||
}}
|
||||
|
|
@ -1097,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);
|
||||
}
|
||||
|
|
@ -1531,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;
|
||||
|
|
@ -136,12 +136,12 @@ pub mod print {
|
|||
}
|
||||
|
||||
pub mod ext {
|
||||
pub use syntax_pos::hygiene;
|
||||
pub mod base;
|
||||
pub mod build;
|
||||
pub mod derive;
|
||||
pub mod expand;
|
||||
pub mod placeholders;
|
||||
pub mod hygiene;
|
||||
pub mod quote;
|
||||
pub mod source_util;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@
|
|||
|
||||
use attr;
|
||||
use ast;
|
||||
use syntax_pos::{mk_sp, Span};
|
||||
use codemap::spanned;
|
||||
use codemap::respan;
|
||||
use parse::common::SeqSep;
|
||||
use parse::PResult;
|
||||
use parse::token::{self, Nonterminal};
|
||||
|
|
@ -49,8 +48,7 @@ impl<'a> Parser<'a> {
|
|||
just_parsed_doc_comment = false;
|
||||
}
|
||||
token::DocComment(s) => {
|
||||
let Span { lo, hi, .. } = self.span;
|
||||
let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, lo, hi);
|
||||
let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span);
|
||||
if attr.style != ast::AttrStyle::Outer {
|
||||
let mut err = self.fatal("expected outer doc comment");
|
||||
err.note("inner doc comments like this (starting with \
|
||||
|
|
@ -94,7 +92,7 @@ impl<'a> Parser<'a> {
|
|||
self.token);
|
||||
let (span, path, tokens, mut style) = match self.token {
|
||||
token::Pound => {
|
||||
let lo = self.span.lo;
|
||||
let lo = self.span;
|
||||
self.bump();
|
||||
|
||||
if inner_parse_policy == InnerAttributeParsePolicy::Permitted {
|
||||
|
|
@ -122,9 +120,9 @@ impl<'a> Parser<'a> {
|
|||
self.expect(&token::OpenDelim(token::Bracket))?;
|
||||
let (path, tokens) = self.parse_path_and_tokens()?;
|
||||
self.expect(&token::CloseDelim(token::Bracket))?;
|
||||
let hi = self.prev_span.hi;
|
||||
let hi = self.prev_span;
|
||||
|
||||
(mk_sp(lo, hi), path, tokens, style)
|
||||
(lo.to(hi), path, tokens, style)
|
||||
}
|
||||
_ => {
|
||||
let token_str = self.this_token_to_string();
|
||||
|
|
@ -189,8 +187,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
token::DocComment(s) => {
|
||||
// we need to get the position of this token before we bump.
|
||||
let Span { lo, hi, .. } = self.span;
|
||||
let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, lo, hi);
|
||||
let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), s, self.span);
|
||||
if attr.style == ast::AttrStyle::Inner {
|
||||
attrs.push(attr);
|
||||
self.bump();
|
||||
|
|
@ -238,11 +235,10 @@ impl<'a> Parser<'a> {
|
|||
return Ok(meta);
|
||||
}
|
||||
|
||||
let lo = self.span.lo;
|
||||
let lo = self.span;
|
||||
let ident = self.parse_ident()?;
|
||||
let node = self.parse_meta_item_kind()?;
|
||||
let hi = self.prev_span.hi;
|
||||
Ok(ast::MetaItem { name: ident.name, node: node, span: mk_sp(lo, hi) })
|
||||
Ok(ast::MetaItem { name: ident.name, node: node, span: lo.to(self.prev_span) })
|
||||
}
|
||||
|
||||
pub fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> {
|
||||
|
|
@ -258,26 +254,25 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// matches meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;
|
||||
fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
|
||||
let sp = self.span;
|
||||
let lo = self.span.lo;
|
||||
let lo = self.span;
|
||||
|
||||
match self.parse_unsuffixed_lit() {
|
||||
Ok(lit) => {
|
||||
return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::Literal(lit)))
|
||||
return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::Literal(lit)))
|
||||
}
|
||||
Err(ref mut err) => self.diagnostic().cancel(err)
|
||||
}
|
||||
|
||||
match self.parse_meta_item() {
|
||||
Ok(mi) => {
|
||||
return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::MetaItem(mi)))
|
||||
return Ok(respan(lo.to(self.prev_span), ast::NestedMetaItemKind::MetaItem(mi)))
|
||||
}
|
||||
Err(ref mut err) => self.diagnostic().cancel(err)
|
||||
}
|
||||
|
||||
let found = self.this_token_to_string();
|
||||
let msg = format!("expected unsuffixed literal or identifier, found {}", found);
|
||||
Err(self.diagnostic().struct_span_err(sp, &msg))
|
||||
Err(self.diagnostic().struct_span_err(lo, &msg))
|
||||
}
|
||||
|
||||
/// matches meta_seq = ( COMMASEP(meta_item_inner) )
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use ast::{self, Ident};
|
||||
use syntax_pos::{self, BytePos, CharPos, Pos, Span};
|
||||
use syntax_pos::{self, BytePos, CharPos, Pos, Span, NO_EXPANSION};
|
||||
use codemap::CodeMap;
|
||||
use errors::{FatalError, DiagnosticBuilder};
|
||||
use parse::{token, ParseSess};
|
||||
|
|
@ -68,6 +68,10 @@ pub struct StringReader<'a> {
|
|||
open_braces: Vec<(token::DelimToken, Span)>,
|
||||
}
|
||||
|
||||
fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
|
||||
Span { lo: lo, hi: hi, ctxt: NO_EXPANSION }
|
||||
}
|
||||
|
||||
impl<'a> StringReader<'a> {
|
||||
fn next_token(&mut self) -> TokenAndSpan where Self: Sized {
|
||||
let res = self.try_next_token();
|
||||
|
|
@ -225,12 +229,12 @@ impl<'a> StringReader<'a> {
|
|||
|
||||
/// Report a fatal error spanning [`from_pos`, `to_pos`).
|
||||
fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError {
|
||||
self.fatal_span(syntax_pos::mk_sp(from_pos, to_pos), m)
|
||||
self.fatal_span(mk_sp(from_pos, to_pos), m)
|
||||
}
|
||||
|
||||
/// Report a lexical error spanning [`from_pos`, `to_pos`).
|
||||
fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) {
|
||||
self.err_span(syntax_pos::mk_sp(from_pos, to_pos), m)
|
||||
self.err_span(mk_sp(from_pos, to_pos), m)
|
||||
}
|
||||
|
||||
/// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
|
||||
|
|
@ -254,7 +258,7 @@ impl<'a> StringReader<'a> {
|
|||
for c in c.escape_default() {
|
||||
m.push(c)
|
||||
}
|
||||
self.sess.span_diagnostic.struct_span_fatal(syntax_pos::mk_sp(from_pos, to_pos), &m[..])
|
||||
self.sess.span_diagnostic.struct_span_fatal(mk_sp(from_pos, to_pos), &m[..])
|
||||
}
|
||||
|
||||
/// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
|
||||
|
|
@ -278,7 +282,7 @@ impl<'a> StringReader<'a> {
|
|||
for c in c.escape_default() {
|
||||
m.push(c)
|
||||
}
|
||||
self.sess.span_diagnostic.struct_span_err(syntax_pos::mk_sp(from_pos, to_pos), &m[..])
|
||||
self.sess.span_diagnostic.struct_span_err(mk_sp(from_pos, to_pos), &m[..])
|
||||
}
|
||||
|
||||
/// Report a lexical error spanning [`from_pos`, `to_pos`), appending the
|
||||
|
|
@ -302,11 +306,11 @@ impl<'a> StringReader<'a> {
|
|||
None => {
|
||||
if self.is_eof() {
|
||||
self.peek_tok = token::Eof;
|
||||
self.peek_span = syntax_pos::mk_sp(self.filemap.end_pos, self.filemap.end_pos);
|
||||
self.peek_span = mk_sp(self.filemap.end_pos, self.filemap.end_pos);
|
||||
} else {
|
||||
let start_bytepos = self.pos;
|
||||
self.peek_tok = self.next_token_inner()?;
|
||||
self.peek_span = syntax_pos::mk_sp(start_bytepos, self.pos);
|
||||
self.peek_span = mk_sp(start_bytepos, self.pos);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -489,7 +493,7 @@ impl<'a> StringReader<'a> {
|
|||
if let Some(c) = self.ch {
|
||||
if c.is_whitespace() {
|
||||
let msg = "called consume_any_line_comment, but there was whitespace";
|
||||
self.sess.span_diagnostic.span_err(syntax_pos::mk_sp(self.pos, self.pos), msg);
|
||||
self.sess.span_diagnostic.span_err(mk_sp(self.pos, self.pos), msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -532,13 +536,13 @@ impl<'a> StringReader<'a> {
|
|||
|
||||
Some(TokenAndSpan {
|
||||
tok: tok,
|
||||
sp: syntax_pos::mk_sp(start_bpos, self.pos),
|
||||
sp: mk_sp(start_bpos, self.pos),
|
||||
})
|
||||
})
|
||||
} else {
|
||||
Some(TokenAndSpan {
|
||||
tok: token::Comment,
|
||||
sp: syntax_pos::mk_sp(start_bpos, self.pos),
|
||||
sp: mk_sp(start_bpos, self.pos),
|
||||
})
|
||||
};
|
||||
}
|
||||
|
|
@ -571,7 +575,7 @@ impl<'a> StringReader<'a> {
|
|||
}
|
||||
return Some(TokenAndSpan {
|
||||
tok: token::Shebang(self.name_from(start)),
|
||||
sp: syntax_pos::mk_sp(start, self.pos),
|
||||
sp: mk_sp(start, self.pos),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -599,7 +603,7 @@ impl<'a> StringReader<'a> {
|
|||
}
|
||||
let c = Some(TokenAndSpan {
|
||||
tok: token::Whitespace,
|
||||
sp: syntax_pos::mk_sp(start_bpos, self.pos),
|
||||
sp: mk_sp(start_bpos, self.pos),
|
||||
});
|
||||
debug!("scanning whitespace: {:?}", c);
|
||||
c
|
||||
|
|
@ -661,7 +665,7 @@ impl<'a> StringReader<'a> {
|
|||
|
||||
Some(TokenAndSpan {
|
||||
tok: tok,
|
||||
sp: syntax_pos::mk_sp(start_bpos, self.pos),
|
||||
sp: mk_sp(start_bpos, self.pos),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -858,7 +862,7 @@ impl<'a> StringReader<'a> {
|
|||
let valid = if self.ch_is('{') {
|
||||
self.scan_unicode_escape(delim) && !ascii_only
|
||||
} else {
|
||||
let span = syntax_pos::mk_sp(start, self.pos);
|
||||
let span = mk_sp(start, self.pos);
|
||||
self.sess.span_diagnostic
|
||||
.struct_span_err(span, "incorrect unicode escape sequence")
|
||||
.span_help(span,
|
||||
|
|
@ -896,13 +900,13 @@ impl<'a> StringReader<'a> {
|
|||
},
|
||||
c);
|
||||
if e == '\r' {
|
||||
err.span_help(syntax_pos::mk_sp(escaped_pos, pos),
|
||||
err.span_help(mk_sp(escaped_pos, pos),
|
||||
"this is an isolated carriage return; consider \
|
||||
checking your editor and version control \
|
||||
settings");
|
||||
}
|
||||
if (e == '{' || e == '}') && !ascii_only {
|
||||
err.span_help(syntax_pos::mk_sp(escaped_pos, pos),
|
||||
err.span_help(mk_sp(escaped_pos, pos),
|
||||
"if used in a formatting string, curly braces \
|
||||
are escaped with `{{` and `}}`");
|
||||
}
|
||||
|
|
@ -1735,7 +1739,7 @@ mod tests {
|
|||
sp: Span {
|
||||
lo: BytePos(21),
|
||||
hi: BytePos(23),
|
||||
expn_id: NO_EXPANSION,
|
||||
ctxt: NO_EXPANSION,
|
||||
},
|
||||
};
|
||||
assert_eq!(tok1, tok2);
|
||||
|
|
@ -1749,7 +1753,7 @@ mod tests {
|
|||
sp: Span {
|
||||
lo: BytePos(24),
|
||||
hi: BytePos(28),
|
||||
expn_id: NO_EXPANSION,
|
||||
ctxt: NO_EXPANSION,
|
||||
},
|
||||
};
|
||||
assert_eq!(tok3, tok4);
|
||||
|
|
@ -1908,7 +1912,7 @@ mod tests {
|
|||
let mut lexer = setup(&cm, &sh, "// test\r\n/// test\r\n".to_string());
|
||||
let comment = lexer.next_token();
|
||||
assert_eq!(comment.tok, token::Comment);
|
||||
assert_eq!(comment.sp, ::syntax_pos::mk_sp(BytePos(0), BytePos(7)));
|
||||
assert_eq!((comment.sp.lo, comment.sp.hi), (BytePos(0), BytePos(7)));
|
||||
assert_eq!(lexer.next_token().tok, token::Whitespace);
|
||||
assert_eq!(lexer.next_token().tok,
|
||||
token::DocComment(Symbol::intern("/// test")));
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
// Characters and their corresponding confusables were collected from
|
||||
// http://www.unicode.org/Public/security/revision-06/confusables.txt
|
||||
|
||||
use syntax_pos::mk_sp as make_span;
|
||||
use syntax_pos::{Span, NO_EXPANSION};
|
||||
use errors::DiagnosticBuilder;
|
||||
use super::StringReader;
|
||||
|
||||
|
|
@ -234,7 +234,7 @@ pub fn check_for_substitution<'a>(reader: &StringReader<'a>,
|
|||
.iter()
|
||||
.find(|&&(c, _, _)| c == ch)
|
||||
.map(|&(_, u_name, ascii_char)| {
|
||||
let span = make_span(reader.pos, reader.next_pos);
|
||||
let span = Span { lo: reader.pos, hi: reader.next_pos, ctxt: NO_EXPANSION };
|
||||
match ASCII_ARRAY.iter().find(|&&(c, _)| c == ascii_char) {
|
||||
Some(&(ascii_char, ascii_name)) => {
|
||||
let msg =
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
use ast::{self, CrateConfig};
|
||||
use codemap::CodeMap;
|
||||
use syntax_pos::{self, Span, FileMap};
|
||||
use syntax_pos::{self, Span, FileMap, NO_EXPANSION};
|
||||
use errors::{Handler, ColorConfig, DiagnosticBuilder};
|
||||
use feature_gate::UnstableFeatures;
|
||||
use parse::parser::Parser;
|
||||
|
|
@ -178,7 +178,7 @@ pub fn filemap_to_parser<'a>(sess: &'a ParseSess, filemap: Rc<FileMap>, ) -> Par
|
|||
let mut parser = stream_to_parser(sess, filemap_to_stream(sess, filemap));
|
||||
|
||||
if parser.token == token::Eof && parser.span == syntax_pos::DUMMY_SP {
|
||||
parser.span = syntax_pos::mk_sp(end_pos, end_pos);
|
||||
parser.span = Span { lo: end_pos, hi: end_pos, ctxt: NO_EXPANSION };
|
||||
}
|
||||
|
||||
parser
|
||||
|
|
@ -218,9 +218,7 @@ pub fn filemap_to_stream(sess: &ParseSess, filemap: Rc<FileMap>) -> TokenStream
|
|||
|
||||
/// Given stream and the ParseSess, produce a parser
|
||||
pub fn stream_to_parser<'a>(sess: &'a ParseSess, stream: TokenStream) -> Parser<'a> {
|
||||
let mut p = Parser::new(sess, stream, None, false);
|
||||
p.check_unknown_macro_variable();
|
||||
p
|
||||
Parser::new(sess, stream, None, false)
|
||||
}
|
||||
|
||||
/// Parse a string representing a character literal into its final form.
|
||||
|
|
@ -665,7 +663,7 @@ mod tests {
|
|||
|
||||
// produce a syntax_pos::span
|
||||
fn sp(a: u32, b: u32) -> Span {
|
||||
Span {lo: BytePos(a), hi: BytePos(b), expn_id: NO_EXPANSION}
|
||||
Span {lo: BytePos(a), hi: BytePos(b), ctxt: NO_EXPANSION}
|
||||
}
|
||||
|
||||
fn str2seg(s: &str, lo: u32, hi: u32) -> ast::PathSegment {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ pub trait ParserObsoleteMethods {
|
|||
impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
|
||||
/// Reports an obsolete syntax non-fatal error.
|
||||
#[allow(unused_variables)]
|
||||
#[allow(unreachable_code)]
|
||||
fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) {
|
||||
let (kind_str, desc, error) = match kind {
|
||||
// Nothing here at the moment
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -211,9 +211,7 @@ impl Token {
|
|||
ModSep => true, // global path
|
||||
Pound => true, // expression attributes
|
||||
Interpolated(ref nt) => match **nt {
|
||||
NtExpr(..) => true,
|
||||
NtBlock(..) => true,
|
||||
NtPath(..) => true,
|
||||
NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true,
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
|
|
@ -236,8 +234,7 @@ impl Token {
|
|||
Lt | BinOp(Shl) => true, // associated path
|
||||
ModSep => true, // global path
|
||||
Interpolated(ref nt) => match **nt {
|
||||
NtTy(..) => true,
|
||||
NtPath(..) => true,
|
||||
NtIdent(..) | NtTy(..) | NtPath(..) => true,
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
|
|
@ -252,12 +249,20 @@ impl Token {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn ident(&self) -> Option<ast::Ident> {
|
||||
match *self {
|
||||
Ident(ident) => Some(ident),
|
||||
Interpolated(ref nt) => match **nt {
|
||||
NtIdent(ident) => Some(ident.node),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the token is an identifier.
|
||||
pub fn is_ident(&self) -> bool {
|
||||
match *self {
|
||||
Ident(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
self.ident().is_some()
|
||||
}
|
||||
|
||||
/// Returns `true` if the token is a documentation comment.
|
||||
|
|
@ -311,18 +316,15 @@ impl Token {
|
|||
|
||||
/// Returns `true` if the token is a given keyword, `kw`.
|
||||
pub fn is_keyword(&self, kw: keywords::Keyword) -> bool {
|
||||
match *self {
|
||||
Ident(id) => id.name == kw.name(),
|
||||
_ => false,
|
||||
}
|
||||
self.ident().map(|ident| ident.name == kw.name()).unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn is_path_segment_keyword(&self) -> bool {
|
||||
match *self {
|
||||
Ident(id) => id.name == keywords::Super.name() ||
|
||||
id.name == keywords::SelfValue.name() ||
|
||||
id.name == keywords::SelfType.name(),
|
||||
_ => false,
|
||||
match self.ident() {
|
||||
Some(id) => id.name == keywords::Super.name() ||
|
||||
id.name == keywords::SelfValue.name() ||
|
||||
id.name == keywords::SelfType.name(),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -333,18 +335,16 @@ impl Token {
|
|||
|
||||
/// Returns `true` if the token is a strict keyword.
|
||||
pub fn is_strict_keyword(&self) -> bool {
|
||||
match *self {
|
||||
Ident(id) => id.name >= keywords::As.name() &&
|
||||
id.name <= keywords::While.name(),
|
||||
match self.ident() {
|
||||
Some(id) => id.name >= keywords::As.name() && id.name <= keywords::While.name(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the token is a keyword reserved for possible future use.
|
||||
pub fn is_reserved_keyword(&self) -> bool {
|
||||
match *self {
|
||||
Ident(id) => id.name >= keywords::Abstract.name() &&
|
||||
id.name <= keywords::Yield.name(),
|
||||
match self.ident() {
|
||||
Some(id) => id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -1,306 +0,0 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! An "interner" is a data structure that associates values with usize tags and
|
||||
//! allows bidirectional lookup; i.e. given a value, one can easily find the
|
||||
//! type, and vice versa.
|
||||
|
||||
use serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
/// A symbol is an interned or gensymed string.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Symbol(u32);
|
||||
|
||||
// The interner in thread-local, so `Symbol` shouldn't move between threads.
|
||||
impl !Send for Symbol { }
|
||||
|
||||
impl Symbol {
|
||||
/// Maps a string to its interned representation.
|
||||
pub fn intern(string: &str) -> Self {
|
||||
with_interner(|interner| interner.intern(string))
|
||||
}
|
||||
|
||||
/// gensym's a new usize, using the current interner.
|
||||
pub fn gensym(string: &str) -> Self {
|
||||
with_interner(|interner| interner.gensym(string))
|
||||
}
|
||||
|
||||
pub fn as_str(self) -> InternedString {
|
||||
with_interner(|interner| unsafe {
|
||||
InternedString {
|
||||
string: ::std::mem::transmute::<&str, &str>(interner.get(self))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_u32(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Symbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}({})", self, self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Symbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Symbol {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
s.emit_str(&self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for Symbol {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<Symbol, D::Error> {
|
||||
Ok(Symbol::intern(&d.read_str()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<&'a str> for Symbol {
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
*self.as_str() == **other
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Interner {
|
||||
names: HashMap<Box<str>, Symbol>,
|
||||
strings: Vec<Box<str>>,
|
||||
}
|
||||
|
||||
impl Interner {
|
||||
pub fn new() -> Self {
|
||||
Interner::default()
|
||||
}
|
||||
|
||||
fn prefill(init: &[&str]) -> Self {
|
||||
let mut this = Interner::new();
|
||||
for &string in init {
|
||||
this.intern(string);
|
||||
}
|
||||
this
|
||||
}
|
||||
|
||||
pub fn intern(&mut self, string: &str) -> Symbol {
|
||||
if let Some(&name) = self.names.get(string) {
|
||||
return name;
|
||||
}
|
||||
|
||||
let name = Symbol(self.strings.len() as u32);
|
||||
let string = string.to_string().into_boxed_str();
|
||||
self.strings.push(string.clone());
|
||||
self.names.insert(string, name);
|
||||
name
|
||||
}
|
||||
|
||||
fn gensym(&mut self, string: &str) -> Symbol {
|
||||
let gensym = Symbol(self.strings.len() as u32);
|
||||
// leave out of `names` to avoid colliding
|
||||
self.strings.push(string.to_string().into_boxed_str());
|
||||
gensym
|
||||
}
|
||||
|
||||
pub fn get(&self, name: Symbol) -> &str {
|
||||
&self.strings[name.0 as usize]
|
||||
}
|
||||
}
|
||||
|
||||
// In this macro, there is the requirement that the name (the number) must be monotonically
|
||||
// increasing by one in the special identifiers, starting at 0; the same holds for the keywords,
|
||||
// except starting from the next number instead of zero.
|
||||
macro_rules! declare_keywords {(
|
||||
$( ($index: expr, $konst: ident, $string: expr) )*
|
||||
) => {
|
||||
pub mod keywords {
|
||||
use ast;
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Keyword {
|
||||
ident: ast::Ident,
|
||||
}
|
||||
impl Keyword {
|
||||
#[inline] pub fn ident(self) -> ast::Ident { self.ident }
|
||||
#[inline] pub fn name(self) -> ast::Name { self.ident.name }
|
||||
}
|
||||
$(
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $konst: Keyword = Keyword {
|
||||
ident: ast::Ident::with_empty_ctxt(super::Symbol($index))
|
||||
};
|
||||
)*
|
||||
}
|
||||
|
||||
impl Interner {
|
||||
fn fresh() -> Self {
|
||||
Interner::prefill(&[$($string,)*])
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
// NB: leaving holes in the ident table is bad! a different ident will get
|
||||
// interned with the id from the hole, but it will be between the min and max
|
||||
// of the reserved words, and thus tagged as "reserved".
|
||||
// After modifying this list adjust `is_strict_keyword`/`is_reserved_keyword`,
|
||||
// this should be rarely necessary though if the keywords are kept in alphabetic order.
|
||||
declare_keywords! {
|
||||
// Invalid identifier
|
||||
(0, Invalid, "")
|
||||
|
||||
// Strict keywords used in the language.
|
||||
(1, As, "as")
|
||||
(2, Box, "box")
|
||||
(3, Break, "break")
|
||||
(4, Const, "const")
|
||||
(5, Continue, "continue")
|
||||
(6, Crate, "crate")
|
||||
(7, Else, "else")
|
||||
(8, Enum, "enum")
|
||||
(9, Extern, "extern")
|
||||
(10, False, "false")
|
||||
(11, Fn, "fn")
|
||||
(12, For, "for")
|
||||
(13, If, "if")
|
||||
(14, Impl, "impl")
|
||||
(15, In, "in")
|
||||
(16, Let, "let")
|
||||
(17, Loop, "loop")
|
||||
(18, Match, "match")
|
||||
(19, Mod, "mod")
|
||||
(20, Move, "move")
|
||||
(21, Mut, "mut")
|
||||
(22, Pub, "pub")
|
||||
(23, Ref, "ref")
|
||||
(24, Return, "return")
|
||||
(25, SelfValue, "self")
|
||||
(26, SelfType, "Self")
|
||||
(27, Static, "static")
|
||||
(28, Struct, "struct")
|
||||
(29, Super, "super")
|
||||
(30, Trait, "trait")
|
||||
(31, True, "true")
|
||||
(32, Type, "type")
|
||||
(33, Unsafe, "unsafe")
|
||||
(34, Use, "use")
|
||||
(35, Where, "where")
|
||||
(36, While, "while")
|
||||
|
||||
// Keywords reserved for future use.
|
||||
(37, Abstract, "abstract")
|
||||
(38, Alignof, "alignof")
|
||||
(39, Become, "become")
|
||||
(40, Do, "do")
|
||||
(41, Final, "final")
|
||||
(42, Macro, "macro")
|
||||
(43, Offsetof, "offsetof")
|
||||
(44, Override, "override")
|
||||
(45, Priv, "priv")
|
||||
(46, Proc, "proc")
|
||||
(47, Pure, "pure")
|
||||
(48, Sizeof, "sizeof")
|
||||
(49, Typeof, "typeof")
|
||||
(50, Unsized, "unsized")
|
||||
(51, Virtual, "virtual")
|
||||
(52, Yield, "yield")
|
||||
|
||||
// Weak keywords, have special meaning only in specific contexts.
|
||||
(53, Default, "default")
|
||||
(54, StaticLifetime, "'static")
|
||||
(55, Union, "union")
|
||||
(56, Catch, "catch")
|
||||
|
||||
// A virtual keyword that resolves to the crate root when used in a lexical scope.
|
||||
(57, CrateRoot, "{{root}}")
|
||||
}
|
||||
|
||||
// If an interner exists in TLS, return it. Otherwise, prepare a fresh one.
|
||||
fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T {
|
||||
thread_local!(static INTERNER: RefCell<Interner> = {
|
||||
RefCell::new(Interner::fresh())
|
||||
});
|
||||
INTERNER.with(|interner| f(&mut *interner.borrow_mut()))
|
||||
}
|
||||
|
||||
/// Represents a string stored in the thread-local interner. Because the
|
||||
/// interner lives for the life of the thread, this can be safely treated as an
|
||||
/// immortal string, as long as it never crosses between threads.
|
||||
///
|
||||
/// FIXME(pcwalton): You must be careful about what you do in the destructors
|
||||
/// of objects stored in TLS, because they may run after the interner is
|
||||
/// destroyed. In particular, they must not access string contents. This can
|
||||
/// be fixed in the future by just leaking all strings until thread death
|
||||
/// somehow.
|
||||
#[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
|
||||
pub struct InternedString {
|
||||
string: &'static str,
|
||||
}
|
||||
|
||||
impl !Send for InternedString { }
|
||||
|
||||
impl ::std::ops::Deref for InternedString {
|
||||
type Target = str;
|
||||
fn deref(&self) -> &str { self.string }
|
||||
}
|
||||
|
||||
impl fmt::Debug for InternedString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(self.string, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InternedString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(self.string, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for InternedString {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
|
||||
Ok(Symbol::intern(&d.read_str()?).as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for InternedString {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
s.emit_str(self.string)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn interner_tests() {
|
||||
let mut i: Interner = Interner::new();
|
||||
// first one is zero:
|
||||
assert_eq!(i.intern("dog"), Symbol(0));
|
||||
// re-use gets the same entry:
|
||||
assert_eq!(i.intern ("dog"), Symbol(0));
|
||||
// different string gets a different #:
|
||||
assert_eq!(i.intern("cat"), Symbol(1));
|
||||
assert_eq!(i.intern("cat"), Symbol(1));
|
||||
// dog is still at zero
|
||||
assert_eq!(i.intern("dog"), Symbol(0));
|
||||
// gensym gets 3
|
||||
assert_eq!(i.gensym("zebra"), Symbol(2));
|
||||
// gensym of same string gets new number :
|
||||
assert_eq!(i.gensym("zebra"), Symbol(3));
|
||||
// gensym of *existing* string gets new number:
|
||||
assert_eq!(i.gensym("dog"), Symbol(4));
|
||||
}
|
||||
}
|
||||
|
|
@ -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)]
|
||||
|
|
@ -616,7 +609,7 @@ fn mk_tests(cx: &TestCtxt) -> P<ast::Item> {
|
|||
|
||||
fn is_test_crate(krate: &ast::Crate) -> bool {
|
||||
match attr::find_crate_name(&krate.attrs) {
|
||||
Some(s) if "test" == &*s.as_str() => true,
|
||||
Some(s) if "test" == s.as_str() => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue