Merge branch 'master' into issue-32540

This commit is contained in:
Esteban Küber 2017-04-04 08:10:22 -07:00
commit dedb7bbbbf
664 changed files with 11577 additions and 8696 deletions

View file

@ -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" }

View file

@ -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,
}
}
}

View file

@ -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,
};

View file

@ -17,6 +17,8 @@
//! within the CodeMap, which upon request can be converted to line and column
//! information, source code snippets, etc.
pub use syntax_pos::*;
pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo, NameAndSpan};
pub use self::ExpnFormat::*;
use std::cell::RefCell;
@ -26,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);
}
}

View file

@ -12,11 +12,11 @@ pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT
use ast::{self, Attribute, Name, PatKind, MetaItem};
use attr::HasAttrs;
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
use errors::{DiagnosticBuilder, FatalError};
use codemap::{self, CodeMap, Spanned, respan};
use syntax_pos::{Span, DUMMY_SP};
use errors::DiagnosticBuilder;
use ext::expand::{self, Expansion, Invocation};
use ext::hygiene::Mark;
use ext::hygiene::{Mark, SyntaxContext};
use fold::{self, Folder};
use parse::{self, parser, DirectoryOwnership};
use parse::token;
@ -56,6 +56,14 @@ impl HasAttrs for Annotatable {
}
impl Annotatable {
pub fn span(&self) -> Span {
match *self {
Annotatable::Item(ref item) => item.span,
Annotatable::TraitItem(ref trait_item) => trait_item.span,
Annotatable::ImplItem(ref impl_item) => impl_item.span,
}
}
pub fn expect_item(self) -> P<ast::Item> {
match self {
Annotatable::Item(i) => i,
@ -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
});

View file

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

View file

@ -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)
}
}

View file

@ -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)
}
}

View file

@ -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)

View file

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

View file

@ -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),

View file

@ -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 {

View file

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

View file

@ -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()));

View file

@ -28,7 +28,7 @@ use self::AttributeGate::*;
use abi::Abi;
use ast::{self, NodeId, PatKind, RangeEnd};
use attr;
use codemap::{CodeMap, Spanned};
use codemap::Spanned;
use syntax_pos::Span;
use errors::{DiagnosticBuilder, Handler, FatalError};
use visit::{self, FnKind, Visitor};
@ -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);

View file

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

View file

@ -125,7 +125,7 @@ pub mod ptr;
pub mod show_span;
pub mod std_inject;
pub mod str;
pub mod symbol;
pub use syntax_pos::symbol;
pub mod test;
pub mod tokenstream;
pub mod visit;
@ -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;

View file

@ -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) )

View file

@ -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")));

View file

@ -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 =

View file

@ -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 {

View file

@ -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

View file

@ -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,
}
}

View file

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

View file

@ -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));
}
}

View file

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

View file

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

View file

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