diff options
| author | QuietMisdreavus <grey@quietmisdreavus.net> | 2017-04-09 10:38:38 -0500 |
|---|---|---|
| committer | QuietMisdreavus <grey@quietmisdreavus.net> | 2017-04-09 10:38:38 -0500 |
| commit | 8dd4c44ef6c851afcc9651c9b32df005e35d0d1d (patch) | |
| tree | 5dc8ec96361b673f8d4162821a97f8f021d83436 /src/libsyntax | |
| parent | bfd01b7f40ae2cbfe9acbc1d10e79ffe16870df8 (diff) | |
| parent | 2c48ae6f7ffae392d85c86240c67f49df01f44fd (diff) | |
| download | rust-8dd4c44ef6c851afcc9651c9b32df005e35d0d1d.tar.gz rust-8dd4c44ef6c851afcc9651c9b32df005e35d0d1d.zip | |
merge with master to pick up pulldown switch
Diffstat (limited to 'src/libsyntax')
36 files changed, 1712 insertions, 2271 deletions
diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 0b38f5450b6..97d37266130 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -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" } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a456fa51225..c6a3e8a2ded 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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, 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, @@ -116,6 +68,12 @@ pub struct Path { pub segments: Vec<PathSegment>, } +impl<'a> PartialEq<&'a str> for Path { + fn eq(&self, string: &&'a str) -> bool { + self.segments.len() == 1 && self.segments[0].identifier.name == *string + } +} + impl fmt::Debug for Path { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "path({})", pprust::path_to_string(self)) @@ -249,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 { @@ -269,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); @@ -1385,6 +1361,8 @@ pub enum TyKind { ImplicitSelf, // A macro in the type position. Mac(Mac), + /// Placeholder for a kind that has failed to be defined. + Err, } /// Inline assembly dialect. @@ -1420,7 +1398,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. @@ -1457,7 +1435,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))), } } @@ -1474,7 +1452,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, @@ -1681,7 +1659,8 @@ pub struct AttrId(pub usize); pub struct Attribute { pub id: AttrId, pub style: AttrStyle, - pub value: MetaItem, + pub path: Path, + pub tokens: TokenStream, pub is_sugared_doc: bool, pub span: Span, } @@ -1709,6 +1688,16 @@ pub struct PolyTraitRef { pub span: Span, } +impl PolyTraitRef { + 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: span, + } + } +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Visibility { Public, diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 096657a6e7a..6f5f52ff1e9 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -15,20 +15,24 @@ pub use self::ReprAttr::*; pub use self::IntType::*; use ast; -use ast::{AttrId, Attribute, Name}; +use ast::{AttrId, Attribute, Name, Ident}; use ast::{MetaItem, MetaItemKind, NestedMetaItem, NestedMetaItemKind}; -use ast::{Lit, Expr, Item, Local, Stmt, StmtKind}; -use codemap::{Spanned, spanned, dummy_spanned, mk_sp}; -use syntax_pos::{Span, BytePos, DUMMY_SP}; +use ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind}; +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}; -use parse::ParseSess; +use parse::parser::Parser; +use parse::{self, ParseSess, PResult}; +use parse::token::{self, Token}; use ptr::P; use symbol::Symbol; +use tokenstream::{TokenStream, TokenTree, Delimited}; use util::ThinVec; use std::cell::{RefCell, Cell}; +use std::iter; thread_local! { static USED_ATTRS: RefCell<Vec<u64>> = RefCell::new(Vec::new()); @@ -185,26 +189,38 @@ impl NestedMetaItem { impl Attribute { pub fn check_name(&self, name: &str) -> bool { - let matches = self.name() == name; + let matches = self.path == name; if matches { mark_used(self); } matches } - pub fn name(&self) -> Name { self.meta().name() } + pub fn name(&self) -> Option<Name> { + match self.path.segments.len() { + 1 => Some(self.path.segments[0].identifier.name), + _ => None, + } + } pub fn value_str(&self) -> Option<Symbol> { - self.meta().value_str() + self.meta().and_then(|meta| meta.value_str()) } - pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> { - self.meta().meta_item_list() + pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> { + match self.meta() { + Some(MetaItem { node: MetaItemKind::List(list), .. }) => Some(list), + _ => None + } } - pub fn is_word(&self) -> bool { self.meta().is_word() } + pub fn is_word(&self) -> bool { + self.path.segments.len() == 1 && self.tokens.is_empty() + } - pub fn span(&self) -> Span { self.meta().span } + pub fn span(&self) -> Span { + self.span + } pub fn is_meta_item_list(&self) -> bool { self.meta_item_list().is_some() @@ -225,7 +241,7 @@ impl MetaItem { match self.node { MetaItemKind::NameValue(ref v) => { match v.node { - ast::LitKind::Str(ref s, _) => Some((*s).clone()), + LitKind::Str(ref s, _) => Some((*s).clone()), _ => None, } }, @@ -264,8 +280,66 @@ impl MetaItem { impl Attribute { /// Extract the MetaItem from inside this Attribute. - pub fn meta(&self) -> &MetaItem { - &self.value + pub fn meta(&self) -> Option<MetaItem> { + let mut tokens = self.tokens.trees().peekable(); + Some(MetaItem { + name: match self.path.segments.len() { + 1 => self.path.segments[0].identifier.name, + _ => return None, + }, + node: if let Some(node) = MetaItemKind::from_tokens(&mut tokens) { + if tokens.peek().is_some() { + return None; + } + node + } else { + return None; + }, + span: self.span, + }) + } + + pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, + { + let mut parser = Parser::new(sess, self.tokens.clone(), None, false); + let result = f(&mut parser)?; + if parser.token != token::Eof { + parser.unexpected()?; + } + Ok(result) + } + + pub fn parse_list<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, Vec<T>> + where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, + { + if self.tokens.is_empty() { + return Ok(Vec::new()); + } + self.parse(sess, |parser| { + parser.expect(&token::OpenDelim(token::Paren))?; + let mut list = Vec::new(); + while !parser.eat(&token::CloseDelim(token::Paren)) { + list.push(f(parser)?); + if !parser.eat(&token::Comma) { + parser.expect(&token::CloseDelim(token::Paren))?; + break + } + } + Ok(list) + }) + } + + pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { + if self.path.segments.len() > 1 { + sess.span_diagnostic.span_err(self.path.span, "expected ident, found path"); + } + + Ok(MetaItem { + name: self.path.segments.last().unwrap().identifier.name, + node: self.parse(sess, |parser| parser.parse_meta_item_kind())?, + span: self.span, + }) } /// Convert self to a normal #[doc="foo"] comment, if it is a @@ -293,7 +367,7 @@ impl Attribute { /* Constructors */ pub fn mk_name_value_item_str(name: Name, value: Symbol) -> MetaItem { - let value_lit = dummy_spanned(ast::LitKind::Str(value, ast::StrStyle::Cooked)); + let value_lit = dummy_spanned(LitKind::Str(value, ast::StrStyle::Cooked)); mk_spanned_name_value_item(DUMMY_SP, name, value_lit) } @@ -348,7 +422,8 @@ pub fn mk_spanned_attr_inner(sp: Span, id: AttrId, item: MetaItem) -> Attribute Attribute { id: id, style: ast::AttrStyle::Inner, - value: item, + path: ast::Path::from_ident(item.span, ast::Ident::with_empty_ctxt(item.name)), + tokens: item.node.tokens(item.span), is_sugared_doc: false, span: sp, } @@ -365,41 +440,34 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute Attribute { id: id, style: ast::AttrStyle::Outer, - value: item, + path: ast::Path::from_ident(item.span, ast::Ident::with_empty_ctxt(item.name)), + tokens: item.node.tokens(item.span), is_sugared_doc: false, span: sp, } } -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, ast::LitKind::Str(text, ast::StrStyle::Cooked)); + let lit = respan(span, LitKind::Str(text, ast::StrStyle::Cooked)); Attribute { id: id, style: style, - value: MetaItem { - span: mk_sp(lo, hi), - name: Symbol::intern("doc"), - node: MetaItemKind::NameValue(lit), - }, + 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, } } pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool { - debug!("attr::list_contains_name (name={})", name); items.iter().any(|item| { - debug!(" testing: {:?}", item.name()); item.check_name(name) }) } pub fn contains_name(attrs: &[Attribute], name: &str) -> bool { - debug!("attr::contains_name (name={})", name); attrs.iter().any(|item| { - debug!(" testing: {}", item.name()); item.check_name(name) }) } @@ -452,8 +520,14 @@ pub enum InlineAttr { /// Determine what `#[inline]` attribute is present in `attrs`, if any. pub fn find_inline_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> InlineAttr { attrs.iter().fold(InlineAttr::None, |ia, attr| { - match attr.value.node { - _ if attr.value.name != "inline" => ia, + if attr.path != "inline" { + return ia; + } + let meta = match attr.meta() { + Some(meta) => meta.node, + None => return ia, + }; + match meta { MetaItemKind::Word => { mark_used(attr); InlineAttr::Hint @@ -574,14 +648,15 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, let mut rustc_depr: Option<RustcDeprecation> = None; 'outer: for attr in attrs_iter { - let tag = attr.name(); - if tag != "rustc_deprecated" && tag != "unstable" && tag != "stable" { + if attr.path != "rustc_deprecated" && attr.path != "unstable" && attr.path != "stable" { continue // not a stability level } mark_used(attr); - if let Some(metas) = attr.meta_item_list() { + let meta = attr.meta(); + if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta { + let meta = meta.as_ref().unwrap(); let get = |meta: &MetaItem, item: &mut Option<Symbol>| { if item.is_some() { handle_errors(diagnostic, meta.span, AttrError::MultipleItem(meta.name())); @@ -596,7 +671,7 @@ fn find_stability_generic<'a, I>(diagnostic: &Handler, } }; - match &*tag.as_str() { + match &*meta.name.as_str() { "rustc_deprecated" => { if rustc_depr.is_some() { span_err!(diagnostic, item_sp, E0540, @@ -772,7 +847,7 @@ fn find_deprecation_generic<'a, I>(diagnostic: &Handler, let mut depr: Option<Deprecation> = None; 'outer: for attr in attrs_iter { - if attr.name() != "deprecated" { + if attr.path != "deprecated" { continue } @@ -847,8 +922,8 @@ pub fn find_deprecation(diagnostic: &Handler, attrs: &[Attribute], /// structure layout, and `packed` to remove padding. pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr> { let mut acc = Vec::new(); - match attr.value.node { - ast::MetaItemKind::List(ref items) if attr.value.name == "repr" => { + if attr.path == "repr" { + if let Some(items) = attr.meta_item_list() { mark_used(attr); for item in items { if !item.is_meta_item() { @@ -883,8 +958,6 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr> } } } - // Not a "repr" hint: ignore. - _ => { } } acc } @@ -931,6 +1004,207 @@ impl IntType { } } +impl MetaItem { + fn tokens(&self) -> TokenStream { + let ident = TokenTree::Token(self.span, Token::Ident(Ident::with_empty_ctxt(self.name))); + TokenStream::concat(vec![ident.into(), self.node.tokens(self.span)]) + } + + fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem> + where I: Iterator<Item = TokenTree>, + { + let (mut span, name) = match tokens.next() { + Some(TokenTree::Token(span, Token::Ident(ident))) => (span, ident.name), + 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, + }; + let node = match MetaItemKind::from_tokens(tokens) { + Some(node) => node, + _ => return None, + }; + if let Some(last_span) = node.last_span() { + span.hi = last_span.hi; + } + Some(MetaItem { name: name, span: span, node: node }) + } +} + +impl MetaItemKind { + fn last_span(&self) -> Option<Span> { + match *self { + MetaItemKind::Word => None, + MetaItemKind::List(ref list) => list.last().map(NestedMetaItem::span), + MetaItemKind::NameValue(ref lit) => Some(lit.span), + } + } + + pub fn tokens(&self, span: Span) -> TokenStream { + match *self { + MetaItemKind::Word => TokenStream::empty(), + MetaItemKind::NameValue(ref lit) => { + TokenStream::concat(vec![TokenTree::Token(span, Token::Eq).into(), lit.tokens()]) + } + MetaItemKind::List(ref list) => { + let mut tokens = Vec::new(); + for (i, item) in list.iter().enumerate() { + if i > 0 { + tokens.push(TokenTree::Token(span, Token::Comma).into()); + } + tokens.push(item.node.tokens()); + } + TokenTree::Delimited(span, Delimited { + delim: token::Paren, + tts: TokenStream::concat(tokens).into(), + }).into() + } + } + } + + fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItemKind> + where I: Iterator<Item = TokenTree>, + { + let delimited = match tokens.peek().cloned() { + Some(TokenTree::Token(_, token::Eq)) => { + tokens.next(); + return if let Some(TokenTree::Token(span, token)) = tokens.next() { + LitKind::from_token(token) + .map(|lit| MetaItemKind::NameValue(Spanned { node: lit, span: span })) + } else { + None + }; + } + Some(TokenTree::Delimited(_, ref delimited)) if delimited.delim == token::Paren => { + tokens.next(); + delimited.stream() + } + _ => return Some(MetaItemKind::Word), + }; + + let mut tokens = delimited.into_trees().peekable(); + let mut result = Vec::new(); + while let Some(..) = tokens.peek() { + match NestedMetaItemKind::from_tokens(&mut tokens) { + Some(item) => result.push(Spanned { span: item.span(), node: item }), + None => return None, + } + match tokens.next() { + None | Some(TokenTree::Token(_, Token::Comma)) => {} + _ => return None, + } + } + Some(MetaItemKind::List(result)) + } +} + +impl NestedMetaItemKind { + fn span(&self) -> Span { + match *self { + NestedMetaItemKind::MetaItem(ref item) => item.span, + NestedMetaItemKind::Literal(ref lit) => lit.span, + } + } + + fn tokens(&self) -> TokenStream { + match *self { + NestedMetaItemKind::MetaItem(ref item) => item.tokens(), + NestedMetaItemKind::Literal(ref lit) => lit.tokens(), + } + } + + fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItemKind> + where I: Iterator<Item = TokenTree>, + { + if let Some(TokenTree::Token(span, token)) = tokens.peek().cloned() { + if let Some(node) = LitKind::from_token(token) { + tokens.next(); + return Some(NestedMetaItemKind::Literal(Spanned { node: node, span: span })); + } + } + + MetaItem::from_tokens(tokens).map(NestedMetaItemKind::MetaItem) + } +} + +impl Lit { + fn tokens(&self) -> TokenStream { + TokenTree::Token(self.span, self.node.token()).into() + } +} + +impl LitKind { + fn token(&self) -> Token { + use std::ascii; + + match *self { + LitKind::Str(string, ast::StrStyle::Cooked) => { + let mut escaped = String::new(); + for ch in string.as_str().chars() { + escaped.extend(ch.escape_unicode()); + } + Token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None) + } + LitKind::Str(string, ast::StrStyle::Raw(n)) => { + Token::Literal(token::Lit::StrRaw(string, n), None) + } + LitKind::ByteStr(ref bytes) => { + let string = bytes.iter().cloned().flat_map(ascii::escape_default) + .map(Into::<char>::into).collect::<String>(); + Token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None) + } + LitKind::Byte(byte) => { + let string: String = ascii::escape_default(byte).map(Into::<char>::into).collect(); + Token::Literal(token::Lit::Byte(Symbol::intern(&string)), None) + } + LitKind::Char(ch) => { + let string: String = ch.escape_default().map(Into::<char>::into).collect(); + Token::Literal(token::Lit::Char(Symbol::intern(&string)), None) + } + LitKind::Int(n, ty) => { + let suffix = match ty { + ast::LitIntType::Unsigned(ty) => Some(Symbol::intern(ty.ty_to_string())), + ast::LitIntType::Signed(ty) => Some(Symbol::intern(ty.ty_to_string())), + ast::LitIntType::Unsuffixed => None, + }; + Token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())), suffix) + } + LitKind::Float(symbol, ty) => { + Token::Literal(token::Lit::Float(symbol), Some(Symbol::intern(ty.ty_to_string()))) + } + LitKind::FloatUnsuffixed(symbol) => Token::Literal(token::Lit::Float(symbol), None), + LitKind::Bool(value) => Token::Ident(Ident::with_empty_ctxt(Symbol::intern(match value { + true => "true", + false => "false", + }))), + } + } + + fn from_token(token: Token) -> Option<LitKind> { + match token { + Token::Ident(ident) if ident.name == "true" => Some(LitKind::Bool(true)), + Token::Ident(ident) if ident.name == "false" => Some(LitKind::Bool(false)), + Token::Interpolated(ref nt) => match **nt { + token::NtExpr(ref v) => match v.node { + ExprKind::Lit(ref lit) => Some(lit.node.clone()), + _ => None, + }, + _ => None, + }, + Token::Literal(lit, suf) => { + let (suffix_illegal, result) = parse::lit_token(lit, suf, None); + if suffix_illegal && suf.is_some() { + return None; + } + result + } + _ => None, + } + } +} + pub trait HasAttrs: Sized { fn attrs(&self) -> &[ast::Attribute]; fn map_attrs<F: FnOnce(Vec<ast::Attribute>) -> Vec<ast::Attribute>>(self, f: F) -> Self; diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 0f4b844b0ea..4d67390d442 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -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); - } } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index ea12a31770f..ede8a33df65 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -13,9 +13,10 @@ use feature_gate::{feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features use {fold, attr}; use ast; use codemap::Spanned; -use parse::ParseSess; -use ptr::P; +use parse::{token, ParseSess}; +use syntax_pos::Span; +use ptr::P; use util::small_vector::SmallVector; /// A folder that strips out items that do not belong in the current configuration. @@ -84,43 +85,33 @@ impl<'a> StripUnconfigured<'a> { return Some(attr); } - let attr_list = match attr.meta_item_list() { - Some(attr_list) => attr_list, - None => { - let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`"; - self.sess.span_diagnostic.span_err(attr.span, msg); - return None; - } - }; - - let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) { - (2, Some(cfg), Some(mi)) => (cfg, mi), - _ => { - let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`"; - self.sess.span_diagnostic.span_err(attr.span, msg); + let (cfg, path, tokens, span) = match attr.parse(self.sess, |parser| { + parser.expect(&token::OpenDelim(token::Paren))?; + let cfg = parser.parse_meta_item()?; + parser.expect(&token::Comma)?; + let lo = parser.span.lo; + let (path, tokens) = parser.parse_path_and_tokens()?; + parser.expect(&token::CloseDelim(token::Paren))?; + Ok((cfg, path, tokens, Span { lo: lo, ..parser.prev_span })) + }) { + Ok(result) => result, + Err(mut e) => { + e.emit(); return None; } }; - use attr::cfg_matches; - match (cfg.meta_item(), mi.meta_item()) { - (Some(cfg), Some(mi)) => - if cfg_matches(&cfg, self.sess, self.features) { - self.process_cfg_attr(ast::Attribute { - id: attr::mk_attr_id(), - style: attr.style, - value: mi.clone(), - is_sugared_doc: false, - span: mi.span, - }) - } else { - None - }, - _ => { - let msg = "unexpected literal(s) in `#[cfg_attr(<cfg pattern>, <attr>)]`"; - self.sess.span_diagnostic.span_err(attr.span, msg); - None - } + if attr::cfg_matches(&cfg, self.sess, self.features) { + self.process_cfg_attr(ast::Attribute { + id: attr::mk_attr_id(), + style: attr.style, + path: path, + tokens: tokens, + is_sugared_doc: false, + span: span, + }) + } else { + None } } @@ -132,9 +123,12 @@ impl<'a> StripUnconfigured<'a> { return false; } - let mis = match attr.value.node { - ast::MetaItemKind::List(ref mis) if is_cfg(&attr) => mis, - _ => return true + let mis = if !is_cfg(&attr) { + return true; + } else if let Some(mis) = attr.meta_item_list() { + mis + } else { + return true; }; if mis.len() != 1 { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index dc7e7673eb0..fda026fec64 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -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 }); diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 77cc7bab031..e7c5d8278d9 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -9,73 +9,71 @@ // 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; -pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec<(Symbol, 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| { - if attr.name() != "derive" { + if attr.path != "derive" { return true; } - if attr.value_str().is_some() { - cx.span_err(attr.span, "unexpected value in `derive`"); - return false; - } - - let traits = attr.meta_item_list().unwrap_or(&[]).to_owned(); - if traits.is_empty() { - cx.span_warn(attr.span, "empty trait list in `derive`"); - return false; - } - - for titem in traits { - if titem.word().is_none() { - cx.span_err(titem.span, "malformed `derive` entry"); - return false; + match attr.parse_list(cx.parse_sess, + |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) { + Ok(ref traits) if traits.is_empty() => { + cx.span_warn(attr.span, "empty trait list in `derive`"); + false + } + Ok(traits) => { + result.extend(traits); + true + } + Err(mut e) => { + e.emit(); + false } - result.push((titem.name().unwrap(), titem.span)); } - - true }); 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: &[(Symbol, Span)], item: T) -> T { - let span = match traits.get(0) { - Some(&(_, span)) => 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(|&(name, _)| name == "PartialEq") && - traits.iter().any(|&(name, _)| name == "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(|&(name, _)| name == "Copy") && - traits.iter().any(|&(name, _)| name == "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)); } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 10168f010a0..1b3352f73ad 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -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}; -use ast::{Name, MacStmtStyle, StmtKind, ItemKind}; +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::{self, Span, ExpnId}; +use syntax_pos::{Span, DUMMY_SP}; use tokenstream::TokenStream; use util::small_vector::SmallVector; use visit::Visitor; @@ -165,12 +166,11 @@ pub enum InvocationKind { }, Attr { attr: Option<ast::Attribute>, - traits: Vec<(Symbol, Span)>, + traits: Vec<Path>, item: Annotatable, }, Derive { - name: Symbol, - span: Span, + path: Path, item: Annotatable, }, } @@ -180,8 +180,8 @@ impl Invocation { match self.kind { InvocationKind::Bang { span, .. } => span, InvocationKind::Attr { attr: Some(ref attr), .. } => attr.span, - InvocationKind::Attr { attr: None, .. } => syntax_pos::DUMMY_SP, - InvocationKind::Derive { span, .. } => span, + InvocationKind::Attr { attr: None, .. } => DUMMY_SP, + InvocationKind::Derive { ref path, .. } => path.span, } } } @@ -272,17 +272,16 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.collect_invocations(expansion, &[]) } else if let InvocationKind::Attr { attr: None, traits, item } = invoc.kind { let item = item - .map_attrs(|mut attrs| { attrs.retain(|a| a.name() != "derive"); attrs }); + .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 &(name, span) in &traits { + for path in &traits { let mark = Mark::fresh(); derives.push(mark); - let path = ast::Path::from_ident(span, Ident::with_empty_ctxt(name)); let item = match self.cx.resolver.resolve_macro( - Mark::root(), &path, MacroKind::Derive, false) { + Mark::root(), path, MacroKind::Derive, false) { Ok(ext) => match *ext { SyntaxExtension::BuiltinDerive(..) => item_with_markers.clone(), _ => item.clone(), @@ -290,7 +289,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => item.clone(), }; invocations.push(Invocation { - kind: InvocationKind::Derive { name: name, span: span, item: item }, + kind: InvocationKind::Derive { path: path.clone(), item: item }, expansion_kind: invoc.expansion_kind, expansion_data: ExpansionData { mark: mark, @@ -323,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); } } @@ -365,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 { @@ -380,53 +394,41 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; attr::mark_used(&attr); - let name = attr.name(); - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: attr.span, callee: NameAndSpan { - format: MacroAttribute(name), - span: Some(attr.span), + format: MacroAttribute(Symbol::intern(&format!("{}", attr.path))), + span: None, allow_internal_unstable: false, } }); match *ext { MultiModifier(ref mac) => { - let item = mac.expand(self.cx, attr.span, &attr.value, item); + let meta = panictry!(attr.parse_meta(&self.cx.parse_sess)); + let item = mac.expand(self.cx, attr.span, &meta, item); kind.expect_from_annotatables(item) } MultiDecorator(ref mac) => { let mut items = Vec::new(); - mac.expand(self.cx, attr.span, &attr.value, &item, - &mut |item| items.push(item)); + let meta = panictry!(attr.parse_meta(&self.cx.parse_sess)); + mac.expand(self.cx, attr.span, &meta, &item, &mut |item| items.push(item)); items.push(item); kind.expect_from_annotatables(items) } SyntaxExtension::AttrProcMacro(ref mac) => { - let attr_toks = stream_for_attr_args(&attr, &self.cx.parse_sess); 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(name), - span: None, - allow_internal_unstable: false, - }, - }), - ..attr.span - }; - - let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks); - self.parse_expansion(tok_result, kind, name, span) + 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(..) => { - self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name)); + self.cx.span_err(attr.span, &format!("`{}` is a derive mode", attr.path)); kind.dummy(attr.span) } _ => { - let msg = &format!("macro `{}` may not be used in attributes", name); + let msg = &format!("macro `{}` may not be used in attributes", attr.path); self.cx.span_err(attr.span, &msg); kind.dummy(attr.span) } @@ -442,23 +444,21 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; let path = &mac.node.path; - let extname = path.segments.last().unwrap().identifier.name; 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() { let msg = - format!("macro {}! expects no ident argument, given '{}'", extname, ident); + format!("macro {}! expects no ident argument, given '{}'", path, ident); self.cx.span_err(path.span, &msg); return kind.dummy(span); } - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { - format: MacroBang(extname), + format: MacroBang(Symbol::intern(&format!("{}", path))), span: exp_span, allow_internal_unstable: allow_internal_unstable, }, @@ -470,14 +470,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { IdentTT(ref expander, tt_span, allow_internal_unstable) => { if ident.name == keywords::Invalid.name() { self.cx.span_err(path.span, - &format!("macro {}! expects an ident argument", extname)); + &format!("macro {}! expects an ident argument", path)); return kind.dummy(span); }; - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { - format: MacroBang(extname), + format: MacroBang(Symbol::intern(&format!("{}", path))), span: tt_span, allow_internal_unstable: allow_internal_unstable, } @@ -489,27 +489,27 @@ impl<'a, 'b> MacroExpander<'a, 'b> { MultiDecorator(..) | MultiModifier(..) | SyntaxExtension::AttrProcMacro(..) => { self.cx.span_err(path.span, - &format!("`{}` can only be used in attributes", extname)); + &format!("`{}` can only be used in attributes", path)); return kind.dummy(span); } SyntaxExtension::ProcMacroDerive(..) | SyntaxExtension::BuiltinDerive(..) => { - self.cx.span_err(path.span, &format!("`{}` is a derive mode", extname)); + self.cx.span_err(path.span, &format!("`{}` is a derive mode", path)); return kind.dummy(span); } SyntaxExtension::ProcMacro(ref expandfun) => { if ident.name != keywords::Invalid.name() { let msg = - format!("macro {}! expects no ident argument, given '{}'", extname, ident); + format!("macro {}! expects no ident argument, given '{}'", path, ident); self.cx.span_err(path.span, &msg); return kind.dummy(span); } - self.cx.bt_push(ExpnInfo { + invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { - format: MacroBang(extname), + format: MacroBang(Symbol::intern(&format!("{}", path))), // FIXME procedural macros do not have proper span info // yet, when they do, we should use it here. span: None, @@ -519,7 +519,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); let tok_result = expandfun.expand(self.cx, span, marked_tts); - Some(self.parse_expansion(tok_result, kind, extname, span)) + Some(self.parse_expansion(tok_result, kind, path, span)) } }; @@ -532,74 +532,62 @@ 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. fn expand_derive_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion { let Invocation { expansion_kind: kind, .. } = invoc; - let (name, span, item) = match invoc.kind { - InvocationKind::Derive { name, span, item } => (name, span, item), + let (path, item) = match invoc.kind { + InvocationKind::Derive { path, item } => (path, item), _ => unreachable!(), }; - let mitem = ast::MetaItem { name: name, span: span, node: ast::MetaItemKind::Word }; - let pretty_name = Symbol::intern(&format!("derive({})", name)); + let pretty_name = Symbol::intern(&format!("derive({})", path)); + let span = path.span; + let attr = ast::Attribute { + path: path, tokens: TokenStream::empty(), span: span, + // irrelevant: + 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: Some(span), + 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, &mitem, 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, &mitem, &item, &mut |a| { - items.push(a) - }); - return kind.expect_from_annotatables(items); + func(self.cx, span, &attr.meta().unwrap(), &item, &mut |a| items.push(a)); + kind.expect_from_annotatables(items) } _ => { - let msg = &format!("macro `{}` may not be used for derive attributes", name); + let msg = &format!("macro `{}` may not be used for derive attributes", attr.path); self.cx.span_err(span, &msg); kind.dummy(span) } } } - fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, name: Name, span: Span) + fn parse_expansion(&mut self, toks: TokenStream, kind: ExpansionKind, path: &Path, span: Span) -> Expansion { let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::<Vec<_>>()); let expansion = match parser.parse_expansion(kind, false) { @@ -609,7 +597,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return kind.dummy(span); } }; - parser.ensure_complete_parse(name, kind.name(), span); + parser.ensure_complete_parse(path, kind.name(), span); // FIXME better span info expansion.fold_with(&mut ChangeSpan { span: span }) } @@ -653,19 +641,19 @@ impl<'a> Parser<'a> { } ExpansionKind::Expr => Expansion::Expr(self.parse_expr()?), ExpansionKind::OptExpr => Expansion::OptExpr(Some(self.parse_expr()?)), - ExpansionKind::Ty => Expansion::Ty(self.parse_ty_no_plus()?), + ExpansionKind::Ty => Expansion::Ty(self.parse_ty()?), ExpansionKind::Pat => Expansion::Pat(self.parse_pat()?), }) } - pub fn ensure_complete_parse(&mut self, macro_name: ast::Name, kind_name: &str, span: Span) { + pub fn ensure_complete_parse(&mut self, macro_path: &Path, kind_name: &str, span: Span) { if self.token != token::Eof { let msg = format!("macro expansion ignores token `{}` and any following", self.this_token_to_string()); let mut err = self.diagnostic().struct_span_err(self.span, &msg); let msg = format!("caused by the macro expansion here; the usage \ of `{}!` is likely invalid in {} context", - macro_name, kind_name); + macro_path, kind_name); err.span_note(span, &msg).emit(); } } @@ -699,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 { @@ -708,20 +696,20 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect_attr(&mut self, attr: Option<ast::Attribute>, - traits: Vec<(Symbol, Span)>, + traits: Vec<Path>, item: Annotatable, kind: ExpansionKind) -> Expansion { if !traits.is_empty() && (kind == ExpansionKind::TraitItems || kind == ExpansionKind::ImplItems) { - self.cx.span_err(traits[0].1, "`derive` can be only be applied to items"); + self.cx.span_err(traits[0].span, "`derive` can be only be applied to items"); return kind.expect_from_annotatables(::std::iter::once(item)); } self.collect(kind, InvocationKind::Attr { attr: attr, traits: traits, item: item }) } // If `item` is an attr invocation, remove and return the macro attribute. - fn classify_item<T>(&mut self, mut item: T) -> (Option<ast::Attribute>, Vec<(Symbol, Span)>, T) + fn classify_item<T>(&mut self, mut item: T) -> (Option<ast::Attribute>, Vec<Path>, T) where T: HasAttrs, { let (mut attr, mut traits) = (None, Vec::new()); @@ -749,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); } } } @@ -784,32 +771,6 @@ fn stream_for_item(item: &Annotatable, parse_sess: &ParseSess) -> TokenStream { string_to_stream(text, parse_sess) } -fn stream_for_attr_args(attr: &ast::Attribute, parse_sess: &ParseSess) -> TokenStream { - use ast::MetaItemKind::*; - use print::pp::Breaks; - use print::pprust::PrintState; - - let token_string = match attr.value.node { - // For `#[foo]`, an empty token - Word => return TokenStream::empty(), - // For `#[foo(bar, baz)]`, returns `(bar, baz)` - List(ref items) => pprust::to_string(|s| { - s.popen()?; - s.commasep(Breaks::Consistent, - &items[..], - |s, i| s.print_meta_list_item(&i))?; - s.pclose() - }), - // For `#[foo = "bar"]`, returns `= "bar"` - NameValue(ref lit) => pprust::to_string(|s| { - s.word_space("=")?; - s.print_literal(lit) - }), - }; - - string_to_stream(token_string, parse_sess) -} - fn string_to_stream(text: String, parse_sess: &ParseSess) -> TokenStream { let filename = String::from("<macro expansion>"); filemap_to_stream(parse_sess, parse_sess.codemap().new_filemap(filename, None, text)) @@ -926,7 +887,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`). // In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`). // Thus, if `inner` is the dummy span, we know the module is inline. - let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP; + let inline_module = item.span.contains(inner) || inner == DUMMY_SP; if inline_module { if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") { @@ -1087,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) + } } diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs deleted file mode 100644 index 57f5ab73d37..00000000000 --- a/src/libsyntax/ext/hygiene.rs +++ /dev/null @@ -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) - } -} diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index f60b1d17a5e..4fb138d506a 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -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) diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 69ff726e719..d7a85baa3ff 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -220,16 +220,24 @@ pub mod rt { } impl ToTokens for ast::Attribute { - fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> { + fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { let mut r = vec![]; // FIXME: The spans could be better r.push(TokenTree::Token(self.span, token::Pound)); if self.style == ast::AttrStyle::Inner { r.push(TokenTree::Token(self.span, token::Not)); } + let mut inner = Vec::new(); + for (i, segment) in self.path.segments.iter().enumerate() { + if i > 0 { + inner.push(TokenTree::Token(self.span, token::Colon).into()); + } + inner.push(TokenTree::Token(self.span, token::Ident(segment.identifier)).into()); + } + inner.push(self.tokens.clone()); + r.push(TokenTree::Delimited(self.span, tokenstream::Delimited { - delim: token::Bracket, - tts: self.value.to_tokens(cx).into_iter().collect::<TokenStream>().into(), + delim: token::Bracket, tts: TokenStream::concat(inner).into() })); r } @@ -406,7 +414,7 @@ pub fn parse_arm_panic(parser: &mut Parser) -> Arm { } pub fn parse_ty_panic(parser: &mut Parser) -> P<Ty> { - panictry!(parser.parse_ty_no_plus()) + panictry!(parser.parse_ty()) } pub fn parse_stmt_panic(parser: &mut Parser) -> Option<Stmt> { diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 39b92c7d007..0103d6ea959 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -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); diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index b9cb3d82d4f..6cd1fea2e75 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -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), @@ -488,12 +487,12 @@ pub fn parse(sess: &ParseSess, tts: TokenStream, ms: &[TokenTree], directory: Op fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { match name { "tt" => { - return token::NtTT(panictry!(p.parse_token_tree())); + return token::NtTT(p.parse_token_tree()); } _ => {} } // 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), @@ -512,7 +511,7 @@ fn parse_nt<'a>(p: &mut Parser<'a>, sp: Span, name: &str) -> Nonterminal { }, "pat" => token::NtPat(panictry!(p.parse_pat())), "expr" => token::NtExpr(panictry!(p.parse_expr())), - "ty" => token::NtTy(panictry!(p.parse_ty_no_plus())), + "ty" => token::NtTy(panictry!(p.parse_ty())), // this could be handled like a token, since it is one "ident" => match p.token { token::Ident(sn) => { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 7aa1230f9ae..93348c8f083 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -51,7 +51,8 @@ impl<'a> ParserAnyMacro<'a> { } // Make sure we don't have any tokens left to parse so we don't silently drop anything. - parser.ensure_complete_parse(macro_ident.name, kind.name(), site_span); + let path = ast::Path::from_ident(site_span, macro_ident); + parser.ensure_complete_parse(&path, kind.name(), site_span); expansion } } @@ -118,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 { diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index d56859d805c..d216effbd45 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -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), diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 24004492be2..947089b0b9a 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -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())); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 15913d56d16..c68e2ae3468 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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}; @@ -260,9 +260,6 @@ declare_features! ( // impl specialization (RFC 1210) (active, specialization, "1.7.0", Some(31844)), - // pub(restricted) visibilities (RFC 1422) - (active, pub_restricted, "1.9.0", Some(32409)), - // Allow Drop types in statics/const functions (RFC 1440) (active, drop_types_in_const, "1.9.0", Some(33156)), @@ -295,9 +292,6 @@ declare_features! ( // Allows attributes on lifetime/type formal parameters in generics (RFC 1327) (active, generic_param_attrs, "1.11.0", Some(34761)), - // The #![windows_subsystem] attribute - (active, windows_subsystem, "1.14.0", Some(37499)), - // Allows #[link(..., cfg(..))] (active, link_cfg, "1.14.0", Some(37406)), @@ -340,8 +334,15 @@ declare_features! ( // `extern "x86-interrupt" fn()` (active, abi_x86_interrupt, "1.17.0", Some(40180)), + // Allows the `catch {...}` expression (active, catch_expr, "1.17.0", Some(31436)), + + // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work. + (active, rvalue_static_promotion, "1.15.1", Some(38865)), + + // Used to preserve symbols (see llvm.used) + (active, used, "1.18.0", Some(40289)), ); declare_features! ( @@ -406,6 +407,10 @@ declare_features! ( (accepted, field_init_shorthand, "1.17.0", Some(37340)), // Allows the definition recursive static items. (accepted, static_recursion, "1.17.0", Some(29719)), + // pub(restricted) visibilities (RFC 1422) + (accepted, pub_restricted, "1.18.0", Some(32409)), + // The #![windows_subsystem] attribute + (accepted, windows_subsystem, "1.18.0", Some(37499)), ); // If you change this, please modify src/doc/unstable-book as well. You must // move that documentation into the relevant place in the other docs, and @@ -745,6 +750,10 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "unwind_attributes", "#[unwind] is experimental", cfg_fn!(unwind_attributes))), + ("used", Whitelisted, Gated( + Stability::Unstable, "used", + "the `#[used]` attribute is an experimental feature", + cfg_fn!(used))), // used in resolve ("prelude_import", Whitelisted, Gated(Stability::Unstable, @@ -765,11 +774,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "unboxed_closures are still evolving", cfg_fn!(unboxed_closures))), - ("windows_subsystem", Whitelisted, Gated(Stability::Unstable, - "windows_subsystem", - "the windows subsystem attribute \ - is currently unstable", - cfg_fn!(windows_subsystem))), + ("windows_subsystem", Whitelisted, Ungated), ("proc_macro_attribute", Normal, Gated(Stability::Unstable, "proc_macro", @@ -815,7 +820,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| { @@ -828,7 +833,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); } @@ -838,7 +843,6 @@ impl GatedCfg { struct Context<'a> { features: &'a Features, parse_sess: &'a ParseSess, - cm: &'a CodeMap, plugin_attributes: &'a [(String, AttributeType)], } @@ -847,7 +851,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); } }} @@ -862,22 +866,22 @@ 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 = &*attr.name().as_str(); + let name = unwrap_or!(attr.name(), return).as_str(); for &(n, ty, ref gateage) in BUILTIN_ATTRIBUTES { - if n == name { + if name == n { if let &Gated(_, ref name, ref desc, ref has_feature) = gateage { gate_feature_fn!(self, has_feature, attr.span, name, desc); } - debug!("check_attribute: {:?} is builtin, {:?}, {:?}", name, ty, gateage); + debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage); return; } } for &(ref n, ref ty) in self.plugin_attributes { - if n == name { + if attr.path == &**n { // Plugins can't gate attributes, so we don't check for it // unlike the code above; we only use this loop to // short-circuit to avoid the checks below - debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty); + debug!("check_attribute: {:?} is registered by a plugin, {:?}", attr.path, ty); return; } } @@ -888,9 +892,7 @@ impl<'a> Context<'a> { are reserved for internal compiler diagnostics"); } else if name.starts_with("derive_") { gate_feature!(self, custom_derive, attr.span, EXPLAIN_DERIVE_UNDERSCORE); - } else if attr::is_known(attr) { - debug!("check_attribute: {:?} is known", name); - } else { + } else if !attr::is_known(attr) { // Only run the custom attribute lint during regular // feature gate checking. Macro gating runs // before the plugin attributes are registered @@ -901,18 +903,14 @@ impl<'a> Context<'a> { unknown to the compiler and \ may have meaning \ added to it in the future", - name)); + attr.path)); } } } } -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); } @@ -1015,7 +1013,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) } }} @@ -1095,12 +1093,17 @@ 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); } - if contains_novel_literal(&attr.value) { + if self.context.features.proc_macro && attr::is_known(attr) { + return + } + + let meta = panictry!(attr.parse_meta(&self.context.parse_sess)); + if contains_novel_literal(&meta) { gate_feature_post!(&self, attr_literals, attr.span, "non-string literals in attributes, or string \ literals in top-level positions, are experimental"); @@ -1163,8 +1166,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { `#[repr(simd)]` instead"); } for attr in &i.attrs { - if attr.name() == "repr" { - for item in attr.meta_item_list().unwrap_or(&[]) { + if attr.path == "repr" { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name("simd") { gate_feature_post!(&self, repr_simd, i.span, "SIMD types are experimental \ @@ -1410,17 +1413,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { visit::walk_impl_item(self, ii); } - fn visit_vis(&mut self, vis: &'a ast::Visibility) { - let span = match *vis { - ast::Visibility::Crate(span) => span, - ast::Visibility::Restricted { ref path, .. } => path.span, - _ => return, - }; - gate_feature_post!(&self, pub_restricted, span, "`pub(restricted)` syntax is experimental"); - - visit::walk_vis(self, vis) - } - fn visit_generics(&mut self, g: &'a ast::Generics) { for t in &g.ty_params { if !t.attrs.is_empty() { @@ -1535,7 +1527,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); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 9f11d0173d6..92e25b00e0a 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -358,7 +358,7 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> { t.map(|Ty {id, node, span}| Ty { id: fld.new_id(id), node: match node { - TyKind::Infer | TyKind::ImplicitSelf => node, + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => node, TyKind::Slice(ty) => TyKind::Slice(fld.fold_ty(ty)), TyKind::Ptr(mt) => TyKind::Ptr(fld.fold_mt(mt)), TyKind::Rptr(region, mt) => { @@ -489,7 +489,8 @@ pub fn noop_fold_attribute<T: Folder>(attr: Attribute, fld: &mut T) -> Option<At Some(Attribute { id: attr.id, style: attr.style, - value: fld.fold_meta_item(attr.value), + path: fld.fold_path(attr.path), + tokens: fld.fold_tts(attr.tokens), is_sugared_doc: attr.is_sugared_doc, span: fld.new_span(attr.span), }) @@ -612,7 +613,7 @@ pub fn noop_fold_interpolated<T: Folder>(nt: token::Nonterminal, fld: &mut T) token::NtExpr(expr) => token::NtExpr(fld.fold_expr(expr)), token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)), token::NtIdent(id) => token::NtIdent(Spanned::<Ident>{node: fld.fold_ident(id.node), ..id}), - token::NtMeta(meta_item) => token::NtMeta(fld.fold_meta_item(meta_item)), + token::NtMeta(meta) => token::NtMeta(fld.fold_meta_item(meta)), token::NtPath(path) => token::NtPath(fld.fold_path(path)), token::NtTT(tt) => token::NtTT(fld.fold_tt(tt)), token::NtArm(arm) => token::NtArm(fld.fold_arm(arm)), @@ -1371,7 +1372,7 @@ mod tests { matches_codepattern, "matches_codepattern", pprust::to_string(|s| fake_print_crate(s, &folded_crate)), - "#[a]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string()); + "#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string()); } // even inside macro defs.... diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index fd762552248..dec1b7d1d87 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -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, diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 39a9aff48bf..86ee1c5336d 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -65,6 +65,16 @@ macro_rules! panictry { }) } +#[macro_export] +macro_rules! unwrap_or { + ($opt:expr, $default:expr) => { + match $opt { + Some(x) => x, + None => $default, + } + } +} + #[macro_use] pub mod diagnostics { #[macro_use] @@ -115,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; @@ -126,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; diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index ded676da3c6..92cec462ffb 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -10,12 +10,12 @@ 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; -use parse::parser::{Parser, TokenType}; +use parse::token::{self, Nonterminal}; +use parse::parser::{Parser, TokenType, PathStyle}; +use tokenstream::TokenStream; #[derive(PartialEq, Eq, Debug)] enum InnerAttributeParsePolicy<'a> { @@ -48,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 \ @@ -91,9 +90,9 @@ impl<'a> Parser<'a> { debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", inner_parse_policy, self.token); - let (span, value, mut style) = match 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 { @@ -119,11 +118,11 @@ impl<'a> Parser<'a> { }; self.expect(&token::OpenDelim(token::Bracket))?; - let meta_item = self.parse_meta_item()?; + 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), meta_item, style) + (lo.to(hi), path, tokens, style) } _ => { let token_str = self.this_token_to_string(); @@ -143,12 +142,30 @@ impl<'a> Parser<'a> { Ok(ast::Attribute { id: attr::mk_attr_id(), style: style, - value: value, + path: path, + tokens: tokens, is_sugared_doc: false, span: span, }) } + pub fn parse_path_and_tokens(&mut self) -> PResult<'a, (ast::Path, TokenStream)> { + let meta = match self.token { + token::Interpolated(ref nt) => match **nt { + Nonterminal::NtMeta(ref meta) => Some(meta.clone()), + _ => None, + }, + _ => None, + }; + Ok(if let Some(meta) = meta { + self.bump(); + (ast::Path::from_ident(meta.span, ast::Ident::with_empty_ctxt(meta.name)), + meta.node.tokens(meta.span)) + } else { + (self.parse_path(PathStyle::Mod)?, self.parse_tokens()) + }) + } + /// Parse attributes that appear after the opening of an item. These should /// be preceded by an exclamation mark, but we accept and warn about one /// terminated by a semicolon. @@ -170,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(); @@ -219,41 +235,44 @@ impl<'a> Parser<'a> { return Ok(meta); } - let lo = self.span.lo; + let lo = self.span; let ident = self.parse_ident()?; - let node = if self.eat(&token::Eq) { + let node = self.parse_meta_item_kind()?; + 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> { + Ok(if self.eat(&token::Eq) { ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?) } else if self.token == token::OpenDelim(token::Paren) { ast::MetaItemKind::List(self.parse_meta_seq()?) } else { + self.eat(&token::OpenDelim(token::Paren)); ast::MetaItemKind::Word - }; - let hi = self.prev_span.hi; - Ok(ast::MetaItem { name: ident.name, node: node, span: mk_sp(lo, hi) }) + }) } /// 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) ) diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index de8a87e3a2b..920b2c401e2 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -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), }) }) } @@ -725,7 +729,7 @@ impl<'a> StringReader<'a> { base = 16; num_digits = self.scan_digits(16, 16); } - '0'...'9' | '_' | '.' => { + '0'...'9' | '_' | '.' | 'e' | 'E' => { num_digits = self.scan_digits(10, 10) + 1; } _ => { @@ -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"))); diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs index 6da3e5de75c..4df23da3c9c 100644 --- a/src/libsyntax/parse/lexer/unicode_chars.rs +++ b/src/libsyntax/parse/lexer/unicode_chars.rs @@ -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 = diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 88535f91379..c63a6524f74 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -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. @@ -374,38 +372,80 @@ fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { s[1..].chars().all(|c| '0' <= c && c <= '9') } -fn filtered_float_lit(data: Symbol, suffix: Option<Symbol>, sd: &Handler, sp: Span) - -> ast::LitKind { +macro_rules! err { + ($opt_diag:expr, |$span:ident, $diag:ident| $($body:tt)*) => { + match $opt_diag { + Some(($span, $diag)) => { $($body)* } + None => return None, + } + } +} + +pub fn lit_token(lit: token::Lit, suf: Option<Symbol>, diag: Option<(Span, &Handler)>) + -> (bool /* suffix illegal? */, Option<ast::LitKind>) { + use ast::LitKind; + + match lit { + token::Byte(i) => (true, Some(LitKind::Byte(byte_lit(&i.as_str()).0))), + token::Char(i) => (true, Some(LitKind::Char(char_lit(&i.as_str()).0))), + + // There are some valid suffixes for integer and float literals, + // so all the handling is done internally. + token::Integer(s) => (false, integer_lit(&s.as_str(), suf, diag)), + token::Float(s) => (false, float_lit(&s.as_str(), suf, diag)), + + token::Str_(s) => { + let s = Symbol::intern(&str_lit(&s.as_str())); + (true, Some(LitKind::Str(s, ast::StrStyle::Cooked))) + } + token::StrRaw(s, n) => { + let s = Symbol::intern(&raw_str_lit(&s.as_str())); + (true, Some(LitKind::Str(s, ast::StrStyle::Raw(n)))) + } + token::ByteStr(i) => { + (true, Some(LitKind::ByteStr(byte_str_lit(&i.as_str())))) + } + token::ByteStrRaw(i, _) => { + (true, Some(LitKind::ByteStr(Rc::new(i.to_string().into_bytes())))) + } + } +} + +fn filtered_float_lit(data: Symbol, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>) + -> Option<ast::LitKind> { debug!("filtered_float_lit: {}, {:?}", data, suffix); let suffix = match suffix { Some(suffix) => suffix, - None => return ast::LitKind::FloatUnsuffixed(data), + None => return Some(ast::LitKind::FloatUnsuffixed(data)), }; - match &*suffix.as_str() { + Some(match &*suffix.as_str() { "f32" => ast::LitKind::Float(data, ast::FloatTy::F32), "f64" => ast::LitKind::Float(data, ast::FloatTy::F64), suf => { - if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { - // if it looks like a width, lets try to be helpful. - sd.struct_span_err(sp, &format!("invalid width `{}` for float literal", &suf[1..])) - .help("valid widths are 32 and 64") - .emit(); - } else { - sd.struct_span_err(sp, &format!("invalid suffix `{}` for float literal", suf)) - .help("valid suffixes are `f32` and `f64`") - .emit(); - } + err!(diag, |span, diag| { + if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { + // if it looks like a width, lets try to be helpful. + let msg = format!("invalid width `{}` for float literal", &suf[1..]); + diag.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit() + } else { + let msg = format!("invalid suffix `{}` for float literal", suf); + diag.struct_span_err(span, &msg) + .help("valid suffixes are `f32` and `f64`") + .emit(); + } + }); ast::LitKind::FloatUnsuffixed(data) } - } + }) } -pub fn float_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> ast::LitKind { +pub fn float_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>) + -> Option<ast::LitKind> { debug!("float_lit: {:?}, {:?}", s, suffix); // FIXME #2252: bounds checking float literals is deferred until trans let s = s.chars().filter(|&c| c != '_').collect::<String>(); - filtered_float_lit(Symbol::intern(&s), suffix, sd, sp) + filtered_float_lit(Symbol::intern(&s), suffix, diag) } /// Parse a string representing a byte literal into its final form. Similar to `char_lit` @@ -500,7 +540,8 @@ pub fn byte_str_lit(lit: &str) -> Rc<Vec<u8>> { Rc::new(res) } -pub fn integer_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> ast::LitKind { +pub fn integer_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>) + -> Option<ast::LitKind> { // s can only be ascii, byte indexing is fine let s2 = s.chars().filter(|&c| c != '_').collect::<String>(); @@ -524,13 +565,16 @@ pub fn integer_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> a // 1f64 and 2f32 etc. are valid float literals. if let Some(suf) = suffix { if looks_like_width_suffix(&['f'], &suf.as_str()) { - match base { - 16 => sd.span_err(sp, "hexadecimal float literal is not supported"), - 8 => sd.span_err(sp, "octal float literal is not supported"), - 2 => sd.span_err(sp, "binary float literal is not supported"), - _ => () + let err = match base { + 16 => Some("hexadecimal float literal is not supported"), + 8 => Some("octal float literal is not supported"), + 2 => Some("binary float literal is not supported"), + _ => None, + }; + if let Some(err) = err { + err!(diag, |span, diag| diag.span_err(span, err)); } - return filtered_float_lit(Symbol::intern(&s), Some(suf), sd, sp) + return filtered_float_lit(Symbol::intern(&s), Some(suf), diag) } } @@ -539,7 +583,9 @@ pub fn integer_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> a } if let Some(suf) = suffix { - if suf.as_str().is_empty() { sd.span_bug(sp, "found empty literal suffix in Some")} + if suf.as_str().is_empty() { + err!(diag, |span, diag| diag.span_bug(span, "found empty literal suffix in Some")); + } ty = match &*suf.as_str() { "isize" => ast::LitIntType::Signed(ast::IntTy::Is), "i8" => ast::LitIntType::Signed(ast::IntTy::I8), @@ -556,17 +602,20 @@ pub fn integer_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> a suf => { // i<digits> and u<digits> look like widths, so lets // give an error message along those lines - if looks_like_width_suffix(&['i', 'u'], suf) { - sd.struct_span_err(sp, &format!("invalid width `{}` for integer literal", - &suf[1..])) - .help("valid widths are 8, 16, 32, 64 and 128") - .emit(); - } else { - sd.struct_span_err(sp, &format!("invalid suffix `{}` for numeric literal", suf)) - .help("the suffix must be one of the integral types \ - (`u32`, `isize`, etc)") - .emit(); - } + err!(diag, |span, diag| { + if looks_like_width_suffix(&['i', 'u'], suf) { + let msg = format!("invalid width `{}` for integer literal", &suf[1..]); + diag.struct_span_err(span, &msg) + .help("valid widths are 8, 16, 32, 64 and 128") + .emit(); + } else { + let msg = format!("invalid suffix `{}` for numeric literal", suf); + diag.struct_span_err(span, &msg) + .help("the suffix must be one of the integral types \ + (`u32`, `isize`, etc)") + .emit(); + } + }); ty } @@ -576,7 +625,7 @@ pub fn integer_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> a debug!("integer_lit: the type is {:?}, base {:?}, the new string is {:?}, the original \ string was {:?}, the original suffix was {:?}", ty, base, s, orig, suffix); - match u128::from_str_radix(s, base) { + Some(match u128::from_str_radix(s, base) { Ok(r) => ast::LitKind::Int(r, ty), Err(_) => { // small bases are lexed as if they were base 10, e.g, the string @@ -588,11 +637,11 @@ pub fn integer_lit(s: &str, suffix: Option<Symbol>, sd: &Handler, sp: Span) -> a s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base)); if !already_errored { - sd.span_err(sp, "int literal is too large"); + err!(diag, |span, diag| diag.span_err(span, "int literal is too large")); } ast::LitKind::Int(0, ty) } - } + }) } #[cfg(test)] @@ -614,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 { @@ -961,7 +1010,7 @@ mod tests { let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name.clone(), source, &sess) .unwrap().unwrap(); - let docs = item.attrs.iter().filter(|a| a.name() == "doc") + let docs = item.attrs.iter().filter(|a| a.path == "doc") .map(|a| a.value_str().unwrap().to_string()).collect::<Vec<_>>(); let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; assert_eq!(&docs[..], b); diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index a46a788ca08..d5baec675e4 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -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 diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8f66c1a2b8c..43d21015a4f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -40,8 +40,8 @@ use ast::{Visibility, WhereClause}; use ast::{BinOpKind, UnOp}; use ast::RangeEnd; use {ast, attr}; -use codemap::{self, CodeMap, Spanned, spanned, respan}; -use syntax_pos::{self, Span, Pos, BytePos, mk_sp}; +use codemap::{self, CodeMap, Spanned, respan}; +use syntax_pos::{self, Span, BytePos}; use errors::{self, DiagnosticBuilder}; use parse::{self, classify, token}; use parse::common::SeqSep; @@ -59,8 +59,7 @@ use util::ThinVec; use std::collections::HashSet; use std::{cmp, mem, slice}; -use std::path::{Path, PathBuf}; -use std::rc::Rc; +use std::path::{self, Path, PathBuf}; bitflags! { flags Restrictions: u8 { @@ -109,13 +108,13 @@ macro_rules! maybe_whole_expr { $p.bump(); let span = $p.span; let kind = ExprKind::Path(None, (*path).clone()); - return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new())); + return Ok($p.mk_expr(span, kind, ThinVec::new())); } token::NtBlock(ref block) => { $p.bump(); let span = $p.span; let kind = ExprKind::Block((*block).clone()); - return Ok($p.mk_expr(span.lo, span.hi, kind, ThinVec::new())); + return Ok($p.mk_expr(span, kind, ThinVec::new())); } _ => {}, }; @@ -161,6 +160,7 @@ pub struct Parser<'a> { /// the span of the current token: pub span: Span, /// the span of the previous token: + pub meta_var_span: Option<Span>, pub prev_span: Span, /// the previous token kind prev_token_kind: PrevTokenKind, @@ -407,6 +407,25 @@ impl From<P<Expr>> for LhsExpr { } } +/// Create a placeholder argument. +fn dummy_arg(span: Span) -> Arg { + let spanned = Spanned { + span: span, + node: keywords::Invalid.ident() + }; + let pat = P(Pat { + id: ast::DUMMY_NODE_ID, + node: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), spanned, None), + span: span + }); + let ty = Ty { + node: TyKind::Err, + span: span, + id: ast::DUMMY_NODE_ID + }; + Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID } +} + impl<'a> Parser<'a> { pub fn new(sess: &'a ParseSess, tokens: TokenStream, @@ -418,6 +437,7 @@ impl<'a> Parser<'a> { token: token::Underscore, span: syntax_pos::DUMMY_SP, prev_span: syntax_pos::DUMMY_SP, + meta_var_span: None, prev_token_kind: PrevTokenKind::Other, restrictions: Restrictions::empty(), obsolete_set: HashSet::new(), @@ -444,6 +464,7 @@ impl<'a> Parser<'a> { parser.directory.path = PathBuf::from(sess.codemap().span_to_filename(parser.span)); parser.directory.path.pop(); } + parser.process_potential_macro_variable(); parser } @@ -549,20 +570,33 @@ impl<'a> Parser<'a> { expected.dedup(); let expect = tokens_to_string(&expected[..]); let actual = self.this_token_to_string(); - Err(self.fatal( - &(if expected.len() > 1 { - (format!("expected one of {}, found `{}`", - expect, - actual)) - } else if expected.is_empty() { - (format!("unexpected token: `{}`", - actual)) + let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { + let short_expect = if expected.len() > 6 { + format!("{} possible tokens", expected.len()) } else { - (format!("expected {}, found `{}`", - expect, - actual)) - })[..] - )) + expect.clone() + }; + (format!("expected one of {}, found `{}`", expect, actual), + (self.prev_span.next_point(), format!("expected one of {} here", short_expect))) + } else if expected.is_empty() { + (format!("unexpected token: `{}`", actual), + (self.prev_span, "unexpected token after this".to_string())) + } else { + (format!("expected {}, found `{}`", expect, actual), + (self.prev_span.next_point(), format!("expected {} here", expect))) + }; + let mut err = self.fatal(&msg_exp); + let sp = if self.token == token::Token::Eof { + // This is EOF, don't want to point at the following char, but rather the last token + self.prev_span + } else { + label_sp + }; + err.span_label(sp, &label_exp); + if !sp.source_equal(&self.span) { + err.span_label(self.span, &"unexpected token"); + } + Err(err) } } @@ -732,7 +766,7 @@ impl<'a> Parser<'a> { token::AndAnd => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::BinOp(token::And), lo, span.hi)) + Ok(self.bump_with(token::BinOp(token::And), Span { lo: lo, ..span })) } _ => self.unexpected() } @@ -766,7 +800,7 @@ impl<'a> Parser<'a> { token::BinOp(token::Shl) => { let span = self.span; let lo = span.lo + BytePos(1); - self.bump_with(token::Lt, lo, span.hi); + self.bump_with(token::Lt, Span { lo: lo, ..span }); true } _ => false, @@ -794,17 +828,17 @@ impl<'a> Parser<'a> { token::BinOp(token::Shr) => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::Gt, lo, span.hi)) + Ok(self.bump_with(token::Gt, Span { lo: lo, ..span })) } token::BinOpEq(token::Shr) => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::Ge, lo, span.hi)) + Ok(self.bump_with(token::Ge, Span { lo: lo, ..span })) } token::Ge => { let span = self.span; let lo = span.lo + BytePos(1); - Ok(self.bump_with(token::Eq, lo, span.hi)) + Ok(self.bump_with(token::Eq, Span { lo: lo, ..span })) } _ => self.unexpected() } @@ -891,7 +925,7 @@ impl<'a> Parser<'a> { self.parse_seq_to_before_tokens(kets, SeqSep::none(), - |p| p.parse_token_tree(), + |p| Ok(p.parse_token_tree()), |mut e| handler.cancel(&mut e)); } @@ -998,12 +1032,12 @@ impl<'a> Parser<'a> { -> PResult<'a, Spanned<Vec<T>>> where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>, { - let lo = self.span.lo; + let lo = self.span; self.expect(bra)?; let result = self.parse_seq_to_before_end(ket, sep, f); - let hi = self.span.hi; + let hi = self.span; self.bump(); - Ok(spanned(lo, hi, result)) + Ok(respan(lo.to(hi), result)) } /// Advance the parser by one token @@ -1013,7 +1047,7 @@ impl<'a> Parser<'a> { self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); } - self.prev_span = self.span; + self.prev_span = self.meta_var_span.take().unwrap_or(self.span); // Record last token kind for possible error recovery. self.prev_token_kind = match self.token { @@ -1029,21 +1063,18 @@ impl<'a> Parser<'a> { self.token = next.tok; self.expected_tokens.clear(); // check after each token - self.check_unknown_macro_variable(); + self.process_potential_macro_variable(); } /// Advance the parser using provided token as a next one. Use this when /// consuming a part of a token. For example a single `<` from `<<`. - pub fn bump_with(&mut self, - next: token::Token, - lo: BytePos, - hi: BytePos) { - self.prev_span = mk_sp(self.span.lo, lo); + pub fn bump_with(&mut self, next: token::Token, span: Span) { + self.prev_span = Span { hi: span.lo, ..self.span }; // It would be incorrect to record the kind of the current token, but // fortunately for tokens currently using `bump_with`, the // prev_token_kind will be of no use anyway. self.prev_token_kind = PrevTokenKind::Other; - self.span = mk_sp(lo, hi); + self.span = span; self.token = next; self.expected_tokens.clear(); } @@ -1117,57 +1148,13 @@ impl<'a> Parser<'a> { self.check_keyword(keywords::Extern) } - pub fn get_lifetime(&mut self) -> ast::Ident { + fn get_label(&mut self) -> ast::Ident { match self.token { token::Lifetime(ref ident) => *ident, _ => self.bug("not a lifetime"), } } - pub fn parse_for_in_type(&mut self) -> PResult<'a, TyKind> { - /* - Parses whatever can come after a `for` keyword in a type. - The `for` hasn't been consumed. - - - for <'lt> [unsafe] [extern "ABI"] fn (S) -> T - - for <'lt> path::foo(a, b) + Trait + 'a - */ - - let lo = self.span.lo; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - - // examine next token to decide to do - if self.token_is_bare_fn_keyword() { - self.parse_ty_bare_fn(lifetime_defs) - } else { - let hi = self.span.hi; - let trait_ref = self.parse_trait_ref()?; - let poly_trait_ref = PolyTraitRef { bound_lifetimes: lifetime_defs, - trait_ref: trait_ref, - span: mk_sp(lo, hi)}; - let other_bounds = if self.eat(&token::BinOp(token::Plus)) { - self.parse_ty_param_bounds()? - } else { - Vec::new() - }; - let all_bounds = - Some(TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)).into_iter() - .chain(other_bounds) - .collect(); - Ok(ast::TyKind::TraitObject(all_bounds)) - } - } - - pub fn parse_impl_trait_type(&mut self) -> PResult<'a, TyKind> { - // Parses whatever can come after a `impl` keyword in a type. - // The `impl` has already been consumed. - Ok(ast::TyKind::ImplTrait(self.parse_ty_param_bounds()?)) - } - - pub fn parse_ty_path(&mut self) -> PResult<'a, TyKind> { - Ok(TyKind::Path(None, self.parse_path(PathStyle::Type)?)) - } - /// parse a TyKind::BareFn type: pub fn parse_ty_bare_fn(&mut self, lifetime_defs: Vec<LifetimeDef>) -> PResult<'a, TyKind> { @@ -1218,7 +1205,7 @@ impl<'a> Parser<'a> { pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> { maybe_whole!(self, NtTraitItem, |x| x); let mut attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let (name, node) = if self.eat_keyword(keywords::Type) { let TyParam {ident, bounds, default, ..} = self.parse_ty_param(vec![])?; @@ -1242,7 +1229,7 @@ impl<'a> Parser<'a> { } else if self.token.is_path_start() { // trait item macro. // code copied from parse_macro_use_or_failure... abstraction! - let lo = self.span.lo; + let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; self.expect(&token::Not)?; @@ -1252,7 +1239,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)? } - let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts }); + let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts }); (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac)) } else { let (constness, unsafety, abi) = match self.parse_fn_front_matter() { @@ -1267,7 +1254,7 @@ impl<'a> Parser<'a> { break; } token::OpenDelim(token::Brace) => { - self.parse_token_tree()?; + self.parse_token_tree(); break; } _ => self.bump(), @@ -1322,7 +1309,7 @@ impl<'a> Parser<'a> { ident: name, attrs: attrs, node: node, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), }) } @@ -1343,89 +1330,13 @@ impl<'a> Parser<'a> { if self.eat(&token::RArrow) { Ok(FunctionRetTy::Ty(self.parse_ty_no_plus()?)) } else { - let pos = self.span.lo; - Ok(FunctionRetTy::Default(mk_sp(pos, pos))) + Ok(FunctionRetTy::Default(Span { hi: self.span.lo, ..self.span })) } } - /// Parse a type. + // Parse a type pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> { - let lo = self.span.lo; - let lhs = self.parse_ty_no_plus()?; - - if !self.eat(&token::BinOp(token::Plus)) { - return Ok(lhs); - } - - let mut bounds = self.parse_ty_param_bounds()?; - - // In type grammar, `+` is treated like a binary operator, - // and hence both L and R side are required. - if bounds.is_empty() { - let prev_span = self.prev_span; - self.span_err(prev_span, - "at least one type parameter bound \ - must be specified"); - } - - let mut lhs = lhs.unwrap(); - if let TyKind::Paren(ty) = lhs.node { - // We have to accept the first bound in parens for backward compatibility. - // Example: `(Bound) + Bound + Bound` - lhs = ty.unwrap(); - } - if let TyKind::Path(None, path) = lhs.node { - let poly_trait_ref = PolyTraitRef { - bound_lifetimes: Vec::new(), - trait_ref: TraitRef { path: path, ref_id: lhs.id }, - span: lhs.span, - }; - let poly_trait_ref = TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None); - bounds.insert(0, poly_trait_ref); - } else { - let mut err = struct_span_err!(self.sess.span_diagnostic, lhs.span, E0178, - "expected a path on the left-hand side \ - of `+`, not `{}`", - pprust::ty_to_string(&lhs)); - err.span_label(lhs.span, &format!("expected a path")); - let hi = bounds.iter().map(|x| match *x { - TraitTyParamBound(ref tr, _) => tr.span.hi, - RegionTyParamBound(ref r) => r.span.hi, - }).max_by_key(|x| x.to_usize()); - let full_span = hi.map(|hi| Span { - lo: lhs.span.lo, - hi: hi, - expn_id: lhs.span.expn_id, - }); - match (&lhs.node, full_span) { - (&TyKind::Rptr(ref lifetime, ref mut_ty), Some(full_span)) => { - let ty_str = pprust::to_string(|s| { - use print::pp::word; - use print::pprust::PrintState; - - word(&mut s.s, "&")?; - s.print_opt_lifetime(lifetime)?; - s.print_mutability(mut_ty.mutbl)?; - s.popen()?; - s.print_type(&mut_ty.ty)?; - s.print_bounds(" +", &bounds)?; - s.pclose() - }); - err.span_suggestion(full_span, "try adding parentheses (per RFC 438):", - ty_str); - } - - _ => { - help!(&mut err, - "perhaps you forgot parentheses? (per RFC 438)"); - } - } - err.emit(); - } - - let sp = mk_sp(lo, self.prev_span.hi); - let sum = TyKind::TraitObject(bounds); - Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: sum, span: sp})) + self.parse_ty_common(true) } /// Parse a type in restricted contexts where `+` is not permitted. @@ -1433,15 +1344,17 @@ impl<'a> Parser<'a> { /// `+` is prohibited to maintain operator priority (P(+) < P(&)). /// Example 2: `value1 as TYPE + value2` /// `+` is prohibited to avoid interactions with expression grammar. - pub fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> { - maybe_whole!(self, NtTy, |x| x); + fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> { + self.parse_ty_common(false) + } - let lo = self.span.lo; + fn parse_ty_common(&mut self, allow_plus: bool) -> PResult<'a, P<Ty>> { + maybe_whole!(self, NtTy, |x| x); - let t = if self.eat(&token::OpenDelim(token::Paren)) { - // (t) is a parenthesized ty - // (t,) is the type of a tuple with only one field, - // of type t + let lo = self.span; + let node = if self.eat(&token::OpenDelim(token::Paren)) { + // `(TYPE)` is a parenthesized type. + // `(TYPE,)` is a tuple with a single field of type TYPE. let mut ts = vec![]; let mut last_comma = false; while self.token != token::CloseDelim(token::Paren) { @@ -1453,81 +1366,162 @@ impl<'a> Parser<'a> { break; } } - self.expect(&token::CloseDelim(token::Paren))?; + if ts.len() == 1 && !last_comma { - TyKind::Paren(ts.into_iter().nth(0).unwrap()) + let ty = ts.into_iter().nth(0).unwrap().unwrap(); + match ty.node { + // Accept `(Trait1) + Trait2 + 'a` for backward compatibility (#39318). + TyKind::Path(None, ref path) + if allow_plus && self.token == token::BinOp(token::Plus) => { + self.bump(); // `+` + let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span)); + let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)]; + bounds.append(&mut self.parse_ty_param_bounds()?); + TyKind::TraitObject(bounds) + } + _ => TyKind::Paren(P(ty)) + } } else { TyKind::Tup(ts) } } else if self.eat(&token::Not) { + // Never type `!` TyKind::Never } else if self.eat(&token::BinOp(token::Star)) { - // STAR POINTER (bare pointer?) + // Raw pointer TyKind::Ptr(self.parse_ptr()?) } else if self.eat(&token::OpenDelim(token::Bracket)) { - // VECTOR + // Array or slice let t = self.parse_ty()?; - - // Parse the `; e` in `[ i32; e ]` - // where `e` is a const expression + // Parse optional `; EXPR` in `[TYPE; EXPR]` let t = match self.maybe_parse_fixed_length_of_vec()? { None => TyKind::Slice(t), - Some(suffix) => TyKind::Array(t, suffix) + Some(suffix) => TyKind::Array(t, suffix), }; self.expect(&token::CloseDelim(token::Bracket))?; t - } else if self.check(&token::BinOp(token::And)) || - self.check(&token::AndAnd) { - // BORROWED POINTER + } else if self.check(&token::BinOp(token::And)) || self.check(&token::AndAnd) { + // Reference self.expect_and()?; self.parse_borrowed_pointee()? - } else if self.check_keyword(keywords::For) { - // FIXME `+` has incorrect priority in trait object types starting with `for` (#39317). - self.parse_for_in_type()? - } else if self.eat_keyword(keywords::Impl) { - // FIXME figure out priority of `+` in `impl Trait1 + Trait2` (#34511). - self.parse_impl_trait_type()? - } else if self.token_is_bare_fn_keyword() { - // BARE FUNCTION - self.parse_ty_bare_fn(Vec::new())? } else if self.eat_keyword_noexpect(keywords::Typeof) { - // TYPEOF + // `typeof(EXPR)` // In order to not be ambiguous, the type must be surrounded by parens. self.expect(&token::OpenDelim(token::Paren))?; let e = self.parse_expr()?; self.expect(&token::CloseDelim(token::Paren))?; TyKind::Typeof(e) + } else if self.eat(&token::Underscore) { + // A type to be inferred `_` + TyKind::Infer } else if self.eat_lt() { + // Qualified path let (qself, path) = self.parse_qualified_path(PathStyle::Type)?; TyKind::Path(Some(qself), path) } else if self.token.is_path_start() { + // Simple path let path = self.parse_path(PathStyle::Type)?; if self.eat(&token::Not) { - // MACRO INVOCATION + // Macro invocation in type position let (_, tts) = self.expect_delimited_token_tree()?; - let hi = self.span.hi; - TyKind::Mac(spanned(lo, hi, Mac_ { path: path, tts: tts })) + TyKind::Mac(respan(lo.to(self.span), Mac_ { path: path, tts: tts })) } else { - // NAMED TYPE - TyKind::Path(None, path) + // Just a type path or bound list (trait object type) starting with a trait. + // `Type` + // `Trait1 + Trait2 + 'a` + if allow_plus && self.eat(&token::BinOp(token::Plus)) { + let poly_trait = PolyTraitRef::new(Vec::new(), path, lo.to(self.prev_span)); + let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; + bounds.append(&mut self.parse_ty_param_bounds()?); + TyKind::TraitObject(bounds) + } else { + TyKind::Path(None, path) + } } - } else if self.eat(&token::Underscore) { - // TYPE TO BE INFERRED - TyKind::Infer + } else if self.token_is_bare_fn_keyword() { + // Function pointer type + self.parse_ty_bare_fn(Vec::new())? + } else if self.check_keyword(keywords::For) { + // Function pointer type or bound list (trait object type) starting with a poly-trait. + // `for<'lt> [unsafe] [extern "ABI"] fn (&'lt S) -> T` + // `for<'lt> Trait1<'lt> + Trait2 + 'a` + let lo = self.span; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + if self.token_is_bare_fn_keyword() { + self.parse_ty_bare_fn(lifetime_defs)? + } else { + let path = self.parse_path(PathStyle::Type)?; + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); + let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)]; + if allow_plus && self.eat(&token::BinOp(token::Plus)) { + bounds.append(&mut self.parse_ty_param_bounds()?) + } + TyKind::TraitObject(bounds) + } + } else if self.eat_keyword(keywords::Impl) { + // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511). + TyKind::ImplTrait(self.parse_ty_param_bounds()?) + } else if self.check(&token::Question) { + // Bound list (trait object type) + // Bound lists starting with `'lt` are not currently supported (#40043) + TyKind::TraitObject(self.parse_ty_param_bounds_common(allow_plus)?) } else { let msg = format!("expected type, found {}", self.this_token_descr()); return Err(self.fatal(&msg)); }; - let sp = mk_sp(lo, self.prev_span.hi); - Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: t, span: sp})) + let span = lo.to(self.prev_span); + let ty = Ty { node: node, span: span, id: ast::DUMMY_NODE_ID }; + + // Try to recover from use of `+` with incorrect priority. + self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?; + + Ok(P(ty)) } - pub fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { - // look for `&'lt` or `&'foo ` and interpret `foo` as the region name: - let opt_lifetime = self.eat_lifetime(); - let mutbl = self.parse_mutability()?; + fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> { + // Do not add `+` to expected tokens. + if !allow_plus || self.token != token::BinOp(token::Plus) { + return Ok(()) + } + + self.bump(); // `+` + let bounds = self.parse_ty_param_bounds()?; + let sum_span = ty.span.to(self.prev_span); + + let mut err = struct_span_err!(self.sess.span_diagnostic, ty.span, E0178, + "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(&ty)); + err.span_label(ty.span, &format!("expected a path")); + + match ty.node { + TyKind::Rptr(ref lifetime, ref mut_ty) => { + let sum_with_parens = pprust::to_string(|s| { + use print::pp::word; + use print::pprust::PrintState; + + word(&mut s.s, "&")?; + s.print_opt_lifetime(lifetime)?; + s.print_mutability(mut_ty.mutbl)?; + s.popen()?; + s.print_type(&mut_ty.ty)?; + s.print_bounds(" +", &bounds)?; + s.pclose() + }); + err.span_suggestion(sum_span, "try adding parentheses:", sum_with_parens); + } + TyKind::Ptr(..) | TyKind::BareFn(..) => { + help!(&mut err, "perhaps you forgot parentheses?"); + } + _ => {} + } + err.emit(); + Ok(()) + } + + fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { + let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; + let mutbl = self.parse_mutability(); let ty = self.parse_ty_no_plus()?; return Ok(TyKind::Rptr(opt_lifetime, MutTy { ty: ty, mutbl: mutbl })); } @@ -1614,7 +1608,7 @@ impl<'a> Parser<'a> { P(Ty { id: ast::DUMMY_NODE_ID, node: TyKind::Infer, - span: mk_sp(self.span.lo, self.span.hi), + span: self.span, }) }; Ok(Arg { @@ -1643,44 +1637,15 @@ impl<'a> Parser<'a> { _ => { return self.unexpected_last(&self.token); } }, token::Literal(lit, suf) => { - let (suffix_illegal, out) = match lit { - token::Byte(i) => (true, LitKind::Byte(parse::byte_lit(&i.as_str()).0)), - token::Char(i) => (true, LitKind::Char(parse::char_lit(&i.as_str()).0)), - - // there are some valid suffixes for integer and - // float literals, so all the handling is done - // internally. - token::Integer(s) => { - let diag = &self.sess.span_diagnostic; - (false, parse::integer_lit(&s.as_str(), suf, diag, self.span)) - } - token::Float(s) => { - let diag = &self.sess.span_diagnostic; - (false, parse::float_lit(&s.as_str(), suf, diag, self.span)) - } - - token::Str_(s) => { - let s = Symbol::intern(&parse::str_lit(&s.as_str())); - (true, LitKind::Str(s, ast::StrStyle::Cooked)) - } - token::StrRaw(s, n) => { - let s = Symbol::intern(&parse::raw_str_lit(&s.as_str())); - (true, LitKind::Str(s, ast::StrStyle::Raw(n))) - } - token::ByteStr(i) => { - (true, LitKind::ByteStr(parse::byte_str_lit(&i.as_str()))) - } - token::ByteStrRaw(i, _) => { - (true, LitKind::ByteStr(Rc::new(i.to_string().into_bytes()))) - } - }; + let diag = Some((self.span, &self.sess.span_diagnostic)); + let (suffix_illegal, result) = parse::lit_token(lit, suf, diag); if suffix_illegal { let sp = self.span; self.expect_no_suffix(sp, &format!("{} literal", lit.short_name()), suf) } - out + result.unwrap() } _ => { return self.unexpected_last(&self.token); } }; @@ -1691,7 +1656,7 @@ impl<'a> Parser<'a> { /// Matches lit = true | false | token_lit pub fn parse_lit(&mut self) -> PResult<'a, Lit> { - let lo = self.span.lo; + let lo = self.span; let lit = if self.eat_keyword(keywords::True) { LitKind::Bool(true) } else if self.eat_keyword(keywords::False) { @@ -1700,22 +1665,22 @@ impl<'a> Parser<'a> { let lit = self.parse_lit_token()?; lit }; - Ok(codemap::Spanned { node: lit, span: mk_sp(lo, self.prev_span.hi) }) + Ok(codemap::Spanned { node: lit, span: lo.to(self.prev_span) }) } /// matches '-' lit | lit pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> { - let minus_lo = self.span.lo; + let minus_lo = self.span; let minus_present = self.eat(&token::BinOp(token::Minus)); - let lo = self.span.lo; + let lo = self.span; let literal = P(self.parse_lit()?); - let hi = self.prev_span.hi; - let expr = self.mk_expr(lo, hi, ExprKind::Lit(literal), ThinVec::new()); + let hi = self.prev_span; + let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new()); if minus_present { - let minus_hi = self.prev_span.hi; + let minus_hi = self.prev_span; let unary = self.mk_unary(UnOp::Neg, expr); - Ok(self.mk_expr(minus_lo, minus_hi, unary, ThinVec::new())) + Ok(self.mk_expr(minus_lo.to(minus_hi), unary, ThinVec::new())) } else { Ok(expr) } @@ -1792,7 +1757,7 @@ impl<'a> Parser<'a> { pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { maybe_whole!(self, NtPath, |x| x); - let lo = self.span.lo; + let lo = self.meta_var_span.unwrap_or(self.span); let is_global = self.eat(&token::ModSep); // Parse any number of segments and bound sets. A segment is an @@ -1814,17 +1779,33 @@ impl<'a> Parser<'a> { segments.insert(0, PathSegment::crate_root()); } - // Assemble the span. - // FIXME(#39450) This is bogus if part of the path is macro generated. - let span = mk_sp(lo, self.prev_span.hi); - // Assemble the result. Ok(ast::Path { - span: span, + span: lo.to(self.prev_span), segments: segments, }) } + /// Like `parse_path`, but also supports parsing `Word` meta items into paths for back-compat. + /// This is used when parsing derive macro paths in `#[derive]` attributes. + pub fn parse_path_allowing_meta(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { + let meta_ident = match self.token { + token::Interpolated(ref nt) => match **nt { + token::NtMeta(ref meta) => match meta.node { + ast::MetaItemKind::Word => Some(ast::Ident::with_empty_ctxt(meta.name)), + _ => None, + }, + _ => None, + }, + _ => None, + }; + if let Some(ident) = meta_ident { + self.bump(); + return Ok(ast::Path::from_ident(self.prev_span, ident)); + } + self.parse_path(mode) + } + /// Examples: /// - `a::b<T,U>::c<V,W>` /// - `a::b<T,U>::c(V) -> W` @@ -1833,8 +1814,8 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; - let ident_span = self.prev_span; if self.check(&token::ModSep) && self.look_ahead(1, |t| *t == token::Lt) { self.bump(); @@ -1857,7 +1838,7 @@ impl<'a> Parser<'a> { bindings: bindings, }.into() } else if self.eat(&token::OpenDelim(token::Paren)) { - let lo = self.prev_span.lo; + let lo = self.prev_span; let inputs = self.parse_seq_to_end( &token::CloseDelim(token::Paren), @@ -1870,10 +1851,10 @@ impl<'a> Parser<'a> { None }; - let hi = self.prev_span.hi; + let hi = self.prev_span; Some(P(ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData { - span: mk_sp(lo, hi), + span: lo.to(hi), inputs: inputs, output: output_ty, }))) @@ -1901,8 +1882,8 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; - let ident_span = self.prev_span; // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { @@ -1943,10 +1924,11 @@ impl<'a> Parser<'a> { let mut segments = Vec::new(); loop { // First, parse an identifier. + let ident_span = self.span; let identifier = self.parse_path_segment_ident()?; // Assemble and push the result. - segments.push(PathSegment::from_ident(identifier, self.prev_span)); + segments.push(PathSegment::from_ident(identifier, ident_span)); // If we do not see a `::` or see `::{`/`::*`, stop. if !self.check(&token::ModSep) || self.is_import_coupler() { @@ -1957,30 +1939,29 @@ impl<'a> Parser<'a> { } } - /// Parse single lifetime 'a or nothing. - pub fn eat_lifetime(&mut self) -> Option<Lifetime> { + fn check_lifetime(&mut self) -> bool { + self.expected_tokens.push(TokenType::Lifetime); + self.token.is_lifetime() + } + + /// Parse single lifetime 'a or panic. + fn expect_lifetime(&mut self) -> Lifetime { match self.token { token::Lifetime(ident) => { + let ident_span = self.span; self.bump(); - Some(Lifetime { - id: ast::DUMMY_NODE_ID, - span: self.prev_span, - name: ident.name - }) - } - _ => { - self.expected_tokens.push(TokenType::Lifetime); - None + Lifetime { name: ident.name, span: ident_span, id: ast::DUMMY_NODE_ID } } + _ => self.span_bug(self.span, "not a lifetime") } } /// Parse mutability (`mut` or nothing). - pub fn parse_mutability(&mut self) -> PResult<'a, Mutability> { + fn parse_mutability(&mut self) -> Mutability { if self.eat_keyword(keywords::Mut) { - Ok(Mutability::Mutable) + Mutability::Mutable } else { - Ok(Mutability::Immutable) + Mutability::Immutable } } @@ -1996,38 +1977,37 @@ impl<'a> Parser<'a> { /// Parse ident (COLON expr)? pub fn parse_field(&mut self) -> PResult<'a, Field> { let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let hi; // Check if a colon exists one ahead. This means we're parsing a fieldname. let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) { let fieldname = self.parse_field_name()?; self.bump(); - hi = self.prev_span.hi; + hi = self.prev_span; (fieldname, self.parse_expr()?, false) } else { let fieldname = self.parse_ident()?; - hi = self.prev_span.hi; + hi = self.prev_span; // Mimic `x: x` for the `x` field shorthand. - let path = ast::Path::from_ident(mk_sp(lo, hi), fieldname); - (fieldname, self.mk_expr(lo, hi, ExprKind::Path(None, path), ThinVec::new()), true) + let path = ast::Path::from_ident(lo.to(hi), fieldname); + (fieldname, self.mk_expr(lo.to(hi), ExprKind::Path(None, path), ThinVec::new()), true) }; Ok(ast::Field { - ident: spanned(lo, hi, fieldname), - span: mk_sp(lo, expr.span.hi), + ident: respan(lo.to(hi), fieldname), + span: lo.to(expr.span), expr: expr, is_shorthand: is_shorthand, attrs: attrs.into(), }) } - pub fn mk_expr(&mut self, lo: BytePos, hi: BytePos, node: ExprKind, attrs: ThinVec<Attribute>) - -> P<Expr> { + pub fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> { P(Expr { id: ast::DUMMY_NODE_ID, node: node, - span: mk_sp(lo, hi), + span: span, attrs: attrs.into(), }) } @@ -2081,12 +2061,11 @@ impl<'a> Parser<'a> { ExprKind::AssignOp(binop, lhs, rhs) } - pub fn mk_mac_expr(&mut self, lo: BytePos, hi: BytePos, - m: Mac_, attrs: ThinVec<Attribute>) -> P<Expr> { + pub fn mk_mac_expr(&mut self, span: Span, m: Mac_, attrs: ThinVec<Attribute>) -> P<Expr> { P(Expr { id: ast::DUMMY_NODE_ID, - node: ExprKind::Mac(codemap::Spanned {node: m, span: mk_sp(lo, hi)}), - span: mk_sp(lo, hi), + node: ExprKind::Mac(codemap::Spanned {node: m, span: span}), + span: span, attrs: attrs, }) } @@ -2108,10 +2087,10 @@ impl<'a> Parser<'a> { fn expect_delimited_token_tree(&mut self) -> PResult<'a, (token::DelimToken, ThinTokenStream)> { match self.token { - token::OpenDelim(delim) => self.parse_token_tree().map(|tree| match tree { - TokenTree::Delimited(_, delimited) => (delim, delimited.stream().into()), + token::OpenDelim(delim) => match self.parse_token_tree() { + TokenTree::Delimited(_, delimited) => Ok((delim, delimited.stream().into())), _ => unreachable!(), - }), + }, _ => Err(self.fatal("expected open delimiter")), } } @@ -2133,8 +2112,8 @@ impl<'a> Parser<'a> { // attributes by giving them a empty "already parsed" list. let mut attrs = ThinVec::new(); - let lo = self.span.lo; - let mut hi = self.span.hi; + let lo = self.span; + let mut hi = self.span; let ex: ExprKind; @@ -2163,18 +2142,19 @@ impl<'a> Parser<'a> { } self.bump(); - hi = self.prev_span.hi; + hi = self.prev_span; + let span = lo.to(hi); return if es.len() == 1 && !trailing_comma { - Ok(self.mk_expr(lo, hi, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs)) + Ok(self.mk_expr(span, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs)) } else { - Ok(self.mk_expr(lo, hi, ExprKind::Tup(es), attrs)) + Ok(self.mk_expr(span, ExprKind::Tup(es), attrs)) } }, token::OpenDelim(token::Brace) => { return self.parse_block_expr(lo, BlockCheckMode::Default, attrs); }, token::BinOp(token::Or) | token::OrOr => { - let lo = self.span.lo; + let lo = self.span; return self.parse_lambda_expr(lo, CaptureBy::Ref, attrs); }, token::OpenDelim(token::Bracket) => { @@ -2212,34 +2192,34 @@ impl<'a> Parser<'a> { ex = ExprKind::Array(vec![first_expr]); } } - hi = self.prev_span.hi; + hi = self.prev_span; } _ => { if self.eat_lt() { let (qself, path) = self.parse_qualified_path(PathStyle::Expr)?; - hi = path.span.hi; - return Ok(self.mk_expr(lo, hi, ExprKind::Path(Some(qself), path), attrs)); + hi = path.span; + return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs)); } if self.eat_keyword(keywords::Move) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_lambda_expr(lo, CaptureBy::Value, attrs); } if self.eat_keyword(keywords::If) { return self.parse_if_expr(attrs); } if self.eat_keyword(keywords::For) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_for_expr(None, lo, attrs); } if self.eat_keyword(keywords::While) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_while_expr(None, lo, attrs); } if self.token.is_lifetime() { - let label = Spanned { node: self.get_lifetime(), + let label = Spanned { node: self.get_label(), span: self.span }; - let lo = self.span.lo; + let lo = self.span; self.bump(); self.expect(&token::Colon)?; if self.eat_keyword(keywords::While) { @@ -2254,13 +2234,13 @@ impl<'a> Parser<'a> { return Err(self.fatal("expected `while`, `for`, or `loop` after a label")) } if self.eat_keyword(keywords::Loop) { - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_loop_expr(None, lo, attrs); } if self.eat_keyword(keywords::Continue) { let ex = if self.token.is_lifetime() { let ex = ExprKind::Continue(Some(Spanned{ - node: self.get_lifetime(), + node: self.get_label(), span: self.span })); self.bump(); @@ -2268,8 +2248,8 @@ impl<'a> Parser<'a> { } else { ExprKind::Continue(None) }; - let hi = self.prev_span.hi; - return Ok(self.mk_expr(lo, hi, ex, attrs)); + let hi = self.prev_span; + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } if self.eat_keyword(keywords::Match) { return self.parse_match_expr(attrs); @@ -2283,13 +2263,13 @@ impl<'a> Parser<'a> { if self.is_catch_expr() { assert!(self.eat_keyword(keywords::Do)); assert!(self.eat_keyword(keywords::Catch)); - let lo = self.prev_span.lo; + let lo = self.prev_span; return self.parse_catch_expr(lo, attrs); } if self.eat_keyword(keywords::Return) { if self.token.can_begin_expr() { let e = self.parse_expr()?; - hi = e.span.hi; + hi = e.span; ex = ExprKind::Ret(Some(e)); } else { ex = ExprKind::Ret(None); @@ -2297,7 +2277,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(keywords::Break) { let lt = if self.token.is_lifetime() { let spanned_lt = Spanned { - node: self.get_lifetime(), + node: self.get_label(), span: self.span }; self.bump(); @@ -2314,7 +2294,7 @@ impl<'a> Parser<'a> { None }; ex = ExprKind::Break(lt, e); - hi = self.prev_span.hi; + hi = self.prev_span; } else if self.token.is_keyword(keywords::Let) { // Catch this syntax error here, instead of in `check_strict_keywords`, so // that we can explicitly mention that let is not to be used as an expression @@ -2328,8 +2308,8 @@ impl<'a> Parser<'a> { if self.eat(&token::Not) { // MACRO INVOCATION expression let (_, tts) = self.expect_delimited_token_tree()?; - let hi = self.prev_span.hi; - return Ok(self.mk_mac_expr(lo, hi, Mac_ { path: pth, tts: tts }, attrs)); + let hi = self.prev_span; + return Ok(self.mk_mac_expr(lo.to(hi), Mac_ { path: pth, tts: tts }, attrs)); } if self.check(&token::OpenDelim(token::Brace)) { // This is a struct literal, unless we're prohibited @@ -2342,12 +2322,12 @@ impl<'a> Parser<'a> { } } - hi = pth.span.hi; + hi = pth.span; ex = ExprKind::Path(None, pth); } else { match self.parse_lit() { Ok(lit) => { - hi = lit.span.hi; + hi = lit.span; ex = ExprKind::Lit(P(lit)); } Err(mut err) => { @@ -2361,10 +2341,10 @@ impl<'a> Parser<'a> { } } - return Ok(self.mk_expr(lo, hi, ex, attrs)); + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } - fn parse_struct_expr(&mut self, lo: BytePos, pth: ast::Path, mut attrs: ThinVec<Attribute>) + fn parse_struct_expr(&mut self, lo: Span, pth: ast::Path, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { self.bump(); let mut fields = Vec::new(); @@ -2406,9 +2386,9 @@ impl<'a> Parser<'a> { } } - let hi = self.span.hi; + let span = lo.to(self.span); self.expect(&token::CloseDelim(token::Brace))?; - return Ok(self.mk_expr(lo, hi, ExprKind::Struct(pth, fields, base), attrs)); + return Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs)); } fn parse_or_use_outer_attributes(&mut self, @@ -2422,7 +2402,7 @@ impl<'a> Parser<'a> { } /// Parse a block or unsafe block - pub fn parse_block_expr(&mut self, lo: BytePos, blk_mode: BlockCheckMode, + pub fn parse_block_expr(&mut self, lo: Span, blk_mode: BlockCheckMode, outer_attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { @@ -2432,7 +2412,7 @@ impl<'a> Parser<'a> { attrs.extend(self.parse_inner_attributes()?); let blk = self.parse_block_tail(lo, blk_mode)?; - return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), attrs)); + return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), attrs)); } /// parse a.b or a(13) or a[4] or just a @@ -2443,12 +2423,12 @@ impl<'a> Parser<'a> { let b = self.parse_bottom_expr(); let (span, b) = self.interpolated_or_expr_span(b)?; - self.parse_dot_or_call_expr_with(b, span.lo, attrs) + self.parse_dot_or_call_expr_with(b, span, attrs) } pub fn parse_dot_or_call_expr_with(&mut self, e0: P<Expr>, - lo: BytePos, + lo: Span, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { // Stitch the list of outer attributes onto the return value. @@ -2479,11 +2459,7 @@ impl<'a> Parser<'a> { // Assuming we have just parsed `.foo` (i.e., a dot and an ident), continue // parsing into an expression. - fn parse_dot_suffix(&mut self, - ident: Ident, - ident_span: Span, - self_value: P<Expr>, - lo: BytePos) + fn parse_dot_suffix(&mut self, ident: Ident, ident_span: Span, self_value: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> { let (_, tys, bindings) = if self.eat(&token::ModSep) { self.expect_lt()?; @@ -2508,12 +2484,12 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| Ok(p.parse_expr()?) )?; - let hi = self.prev_span.hi; + let hi = self.prev_span; es.insert(0, self_value); - let id = spanned(ident_span.lo, ident_span.hi, ident); + let id = respan(ident_span.to(ident_span), ident); let nd = self.mk_method_call(id, tys, es); - self.mk_expr(lo, hi, nd, ThinVec::new()) + self.mk_expr(lo.to(hi), nd, ThinVec::new()) } // Field access. _ => { @@ -2524,32 +2500,30 @@ impl<'a> Parser<'a> { have type parameters"); } - let id = spanned(ident_span.lo, ident_span.hi, ident); + let id = respan(ident_span.to(ident_span), ident); let field = self.mk_field(self_value, id); - self.mk_expr(lo, ident_span.hi, field, ThinVec::new()) + self.mk_expr(lo.to(ident_span), field, ThinVec::new()) } }) } - fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: BytePos) -> PResult<'a, P<Expr>> { + fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> { let mut e = e0; let mut hi; loop { // expr? while self.eat(&token::Question) { - let hi = self.prev_span.hi; - e = self.mk_expr(lo, hi, ExprKind::Try(e), ThinVec::new()); + let hi = self.prev_span; + e = self.mk_expr(lo.to(hi), ExprKind::Try(e), ThinVec::new()); } // expr.f if self.eat(&token::Dot) { match self.token { token::Ident(i) => { - let dot_pos = self.prev_span.hi; - hi = self.span.hi; + let ident_span = self.span; self.bump(); - - e = self.parse_dot_suffix(i, mk_sp(dot_pos, hi), e, lo)?; + e = self.parse_dot_suffix(i, ident_span, e, lo)?; } token::Literal(token::Integer(n), suf) => { let sp = self.span; @@ -2557,16 +2531,16 @@ impl<'a> Parser<'a> { // A tuple index may not have a suffix self.expect_no_suffix(sp, "tuple index", suf); - let dot = self.prev_span.hi; - hi = self.span.hi; + let dot_span = self.prev_span; + hi = self.span; self.bump(); let index = n.as_str().parse::<usize>().ok(); match index { Some(n) => { - let id = spanned(dot, hi, n); + let id = respan(dot_span.to(hi), n); let field = self.mk_tup_field(e, id); - e = self.mk_expr(lo, hi, field, ThinVec::new()); + e = self.mk_expr(lo.to(hi), field, ThinVec::new()); } None => { let prev_span = self.prev_span; @@ -2609,10 +2583,8 @@ impl<'a> Parser<'a> { let actual = self.this_token_to_string(); self.span_err(self.span, &format!("unexpected token: `{}`", actual)); - let dot_pos = self.prev_span.hi; - e = self.parse_dot_suffix(keywords::Invalid.ident(), - mk_sp(dot_pos, dot_pos), - e, lo)?; + let dot_span = self.prev_span; + e = self.parse_dot_suffix(keywords::Invalid.ident(), dot_span, e, lo)?; } } continue; @@ -2627,10 +2599,10 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| Ok(p.parse_expr()?) )?; - hi = self.prev_span.hi; + hi = self.prev_span; let nd = self.mk_call(e, es); - e = self.mk_expr(lo, hi, nd, ThinVec::new()); + e = self.mk_expr(lo.to(hi), nd, ThinVec::new()); } // expr[...] @@ -2638,10 +2610,10 @@ impl<'a> Parser<'a> { token::OpenDelim(token::Bracket) => { self.bump(); let ix = self.parse_expr()?; - hi = self.span.hi; + hi = self.span; self.expect(&token::CloseDelim(token::Bracket))?; let index = self.mk_index(e, ix); - e = self.mk_expr(lo, hi, index, ThinVec::new()) + e = self.mk_expr(lo.to(hi), index, ThinVec::new()) } _ => return Ok(e) } @@ -2649,31 +2621,43 @@ impl<'a> Parser<'a> { return Ok(e); } - pub fn check_unknown_macro_variable(&mut self) { - if let token::SubstNt(name) = self.token { - self.fatal(&format!("unknown macro variable `{}`", name)).emit() - } + pub fn process_potential_macro_variable(&mut self) { + let ident = match self.token { + token::SubstNt(name) => { + self.fatal(&format!("unknown macro variable `{}`", name)).emit(); + return + } + token::Interpolated(ref nt) => { + self.meta_var_span = Some(self.span); + match **nt { + token::NtIdent(ident) => ident, + _ => return, + } + } + _ => return, + }; + self.token = token::Ident(ident.node); + self.span = ident.span; } /// parse a single token tree from the input. - pub fn parse_token_tree(&mut self) -> PResult<'a, TokenTree> { + pub fn parse_token_tree(&mut self) -> TokenTree { match self.token { token::OpenDelim(..) => { let frame = mem::replace(&mut self.token_cursor.frame, self.token_cursor.stack.pop().unwrap()); self.span = frame.span; self.bump(); - return Ok(TokenTree::Delimited(frame.span, Delimited { + TokenTree::Delimited(frame.span, Delimited { delim: frame.delim, tts: frame.tree_cursor.original_stream().into(), - })); + }) }, token::CloseDelim(_) | token::Eof => unreachable!(), _ => { - let token = mem::replace(&mut self.token, token::Underscore); - let res = Ok(TokenTree::Token(self.span, token)); + let (token, span) = (mem::replace(&mut self.token, token::Underscore), self.span); self.bump(); - res + TokenTree::Token(span, token) } } } @@ -2683,48 +2667,54 @@ impl<'a> Parser<'a> { pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec<TokenTree>> { let mut tts = Vec::new(); while self.token != token::Eof { - tts.push(self.parse_token_tree()?); + tts.push(self.parse_token_tree()); } Ok(tts) } + pub fn parse_tokens(&mut self) -> TokenStream { + let mut result = Vec::new(); + loop { + match self.token { + token::Eof | token::CloseDelim(..) => break, + _ => result.push(self.parse_token_tree().into()), + } + } + TokenStream::concat(result) + } + /// Parse a prefix-unary-operator expr pub fn parse_prefix_expr(&mut self, already_parsed_attrs: Option<ThinVec<Attribute>>) -> PResult<'a, P<Expr>> { let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; - let lo = self.span.lo; - let hi; + let lo = self.span; // Note: when adding new unary operators, don't forget to adjust Token::can_begin_expr() - let ex = match self.token { + let (hi, ex) = match self.token { token::Not => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - self.mk_unary(UnOp::Not, e) + (span, self.mk_unary(UnOp::Not, e)) } token::BinOp(token::Minus) => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - self.mk_unary(UnOp::Neg, e) + (span, self.mk_unary(UnOp::Neg, e)) } token::BinOp(token::Star) => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - self.mk_unary(UnOp::Deref, e) + (span, self.mk_unary(UnOp::Deref, e)) } token::BinOp(token::And) | token::AndAnd => { self.expect_and()?; - let m = self.parse_mutability()?; + let m = self.parse_mutability(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - ExprKind::AddrOf(m, e) + (span, ExprKind::AddrOf(m, e)) } token::Ident(..) if self.token.is_keyword(keywords::In) => { self.bump(); @@ -2734,20 +2724,18 @@ impl<'a> Parser<'a> { )?; let blk = self.parse_block()?; let span = blk.span; - hi = span.hi; - let blk_expr = self.mk_expr(span.lo, hi, ExprKind::Block(blk), ThinVec::new()); - ExprKind::InPlace(place, blk_expr) + let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new()); + (span, ExprKind::InPlace(place, blk_expr)) } token::Ident(..) if self.token.is_keyword(keywords::Box) => { self.bump(); let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; - hi = span.hi; - ExprKind::Box(e) + (span, ExprKind::Box(e)) } _ => return self.parse_dot_or_call_expr(Some(attrs)) }; - return Ok(self.mk_expr(lo, hi, ex, attrs)); + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); } /// Parse an associative expression @@ -2808,13 +2796,11 @@ impl<'a> Parser<'a> { // Special cases: if op == AssocOp::As { let rhs = self.parse_ty_no_plus()?; - let (lo, hi) = (lhs_span.lo, rhs.span.hi); - lhs = self.mk_expr(lo, hi, ExprKind::Cast(lhs, rhs), ThinVec::new()); + lhs = self.mk_expr(lhs_span.to(rhs.span), ExprKind::Cast(lhs, rhs), ThinVec::new()); continue } else if op == AssocOp::Colon { let rhs = self.parse_ty_no_plus()?; - let (lo, hi) = (lhs_span.lo, rhs.span.hi); - lhs = self.mk_expr(lo, hi, ExprKind::Type(lhs, rhs), ThinVec::new()); + lhs = self.mk_expr(lhs_span.to(rhs.span), ExprKind::Type(lhs, rhs), ThinVec::new()); continue } else if op == AssocOp::DotDot || op == AssocOp::DotDotDot { // If we didn’t have to handle `x..`/`x...`, it would be pretty easy to @@ -2840,7 +2826,7 @@ impl<'a> Parser<'a> { }; let r = try!(self.mk_range(Some(lhs), rhs, limits)); - lhs = self.mk_expr(lhs_span.lo, rhs_span.hi, r, ThinVec::new()); + lhs = self.mk_expr(lhs_span.to(rhs_span), r, ThinVec::new()); break } @@ -2867,7 +2853,7 @@ impl<'a> Parser<'a> { }), }?; - let (lo, hi) = (lhs_span.lo, rhs.span.hi); + let span = lhs_span.to(rhs.span); lhs = match op { AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus | AssocOp::LAnd | AssocOp::LOr | AssocOp::BitXor | @@ -2876,12 +2862,12 @@ impl<'a> Parser<'a> { AssocOp::Greater | AssocOp::GreaterEqual => { let ast_op = op.to_ast_binop().unwrap(); let binary = self.mk_binary(codemap::respan(cur_op_span, ast_op), lhs, rhs); - self.mk_expr(lo, hi, binary, ThinVec::new()) + self.mk_expr(span, binary, ThinVec::new()) } AssocOp::Assign => - self.mk_expr(lo, hi, ExprKind::Assign(lhs, rhs), ThinVec::new()), + self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), AssocOp::Inplace => - self.mk_expr(lo, hi, ExprKind::InPlace(lhs, rhs), ThinVec::new()), + self.mk_expr(span, ExprKind::InPlace(lhs, rhs), ThinVec::new()), AssocOp::AssignOp(k) => { let aop = match k { token::Plus => BinOpKind::Add, @@ -2896,7 +2882,7 @@ impl<'a> Parser<'a> { token::Shr => BinOpKind::Shr, }; let aopexpr = self.mk_assign_op(codemap::respan(cur_op_span, aop), lhs, rhs); - self.mk_expr(lo, hi, aopexpr, ThinVec::new()) + self.mk_expr(span, aopexpr, ThinVec::new()) } AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotDot => { self.bug("As, Colon, DotDot or DotDotDot branch reached") @@ -2916,10 +2902,13 @@ impl<'a> Parser<'a> { match lhs.node { ExprKind::Binary(op, _, _) if op.node.is_comparison() => { // respan to include both operators - let op_span = mk_sp(op.span.lo, self.span.hi); + let op_span = op.span.to(self.span); let mut err = self.diagnostic().struct_span_err(op_span, "chained comparison operators require parentheses"); - if op.node == BinOpKind::Lt && *outer_op == AssocOp::Greater { + if op.node == BinOpKind::Lt && + *outer_op == AssocOp::Less || // Include `<` to provide this recommendation + *outer_op == AssocOp::Greater // even in a case like the following: + { // Foo<Bar<Baz<Qux, ()>>> err.help( "use `::<...>` instead of `<...>` if you meant to specify type arguments"); } @@ -2936,8 +2925,8 @@ impl<'a> Parser<'a> { debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot); let tok = self.token.clone(); let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; - let lo = self.span.lo; - let mut hi = self.span.hi; + let lo = self.span; + let mut hi = self.span; self.bump(); let opt_end = if self.is_at_start_of_range_notation_rhs() { // RHS must be parsed with more associativity than the dots. @@ -2945,7 +2934,7 @@ impl<'a> Parser<'a> { Some(self.parse_assoc_expr_with(next_prec, LhsExpr::NotYetParsed) .map(|x|{ - hi = x.span.hi; + hi = x.span; x })?) } else { @@ -2960,7 +2949,7 @@ impl<'a> Parser<'a> { let r = try!(self.mk_range(None, opt_end, limits)); - Ok(self.mk_expr(lo, hi, r, attrs)) + Ok(self.mk_expr(lo.to(hi), r, attrs)) } fn is_at_start_of_range_notation_rhs(&self) -> bool { @@ -2980,23 +2969,23 @@ impl<'a> Parser<'a> { if self.check_keyword(keywords::Let) { return self.parse_if_let_expr(attrs); } - let lo = self.prev_span.lo; + let lo = self.prev_span; let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; let thn = self.parse_block()?; let mut els: Option<P<Expr>> = None; - let mut hi = thn.span.hi; + let mut hi = thn.span; if self.eat_keyword(keywords::Else) { let elexpr = self.parse_else_expr()?; - hi = elexpr.span.hi; + hi = elexpr.span; els = Some(elexpr); } - Ok(self.mk_expr(lo, hi, ExprKind::If(cond, thn, els), attrs)) + Ok(self.mk_expr(lo.to(hi), ExprKind::If(cond, thn, els), attrs)) } /// Parse an 'if let' expression ('if' token already eaten) pub fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { - let lo = self.prev_span.lo; + let lo = self.prev_span; self.expect_keyword(keywords::Let)?; let pat = self.parse_pat()?; self.expect(&token::Eq)?; @@ -3004,36 +2993,35 @@ impl<'a> Parser<'a> { let thn = self.parse_block()?; let (hi, els) = if self.eat_keyword(keywords::Else) { let expr = self.parse_else_expr()?; - (expr.span.hi, Some(expr)) + (expr.span, Some(expr)) } else { - (thn.span.hi, None) + (thn.span, None) }; - Ok(self.mk_expr(lo, hi, ExprKind::IfLet(pat, expr, thn, els), attrs)) + Ok(self.mk_expr(lo.to(hi), ExprKind::IfLet(pat, expr, thn, els), attrs)) } // `move |args| expr` pub fn parse_lambda_expr(&mut self, - lo: BytePos, + lo: Span, capture_clause: CaptureBy, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { let decl = self.parse_fn_block_decl()?; - let decl_hi = self.prev_span.hi; + let decl_hi = self.prev_span; let body = match decl.output { FunctionRetTy::Default(_) => self.parse_expr()?, _ => { // If an explicit return type is given, require a // block to appear (RFC 968). - let body_lo = self.span.lo; + let body_lo = self.span; self.parse_block_expr(body_lo, BlockCheckMode::Default, ThinVec::new())? } }; Ok(self.mk_expr( - lo, - body.span.hi, - ExprKind::Closure(capture_clause, decl, body, mk_sp(lo, decl_hi)), + lo.to(body.span), + ExprKind::Closure(capture_clause, decl, body, lo.to(decl_hi)), attrs)) } @@ -3043,13 +3031,13 @@ impl<'a> Parser<'a> { return self.parse_if_expr(ThinVec::new()); } else { let blk = self.parse_block()?; - return Ok(self.mk_expr(blk.span.lo, blk.span.hi, ExprKind::Block(blk), ThinVec::new())); + return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), ThinVec::new())); } } /// Parse a 'for' .. 'in' expression ('for' token already eaten) pub fn parse_for_expr(&mut self, opt_ident: Option<ast::SpannedIdent>, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { // Parse: `for <src_pat> in <src_expr> <src_loop_block>` @@ -3059,16 +3047,13 @@ impl<'a> Parser<'a> { let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = self.prev_span.hi; - - Ok(self.mk_expr(span_lo, hi, - ExprKind::ForLoop(pat, expr, loop_block, opt_ident), - attrs)) + let hi = self.prev_span; + Ok(self.mk_expr(span_lo.to(hi), ExprKind::ForLoop(pat, expr, loop_block, opt_ident), attrs)) } /// Parse a 'while' or 'while let' expression ('while' token already eaten) pub fn parse_while_expr(&mut self, opt_ident: Option<ast::SpannedIdent>, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { if self.token.is_keyword(keywords::Let) { return self.parse_while_let_expr(opt_ident, span_lo, attrs); @@ -3076,14 +3061,13 @@ impl<'a> Parser<'a> { let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - return Ok(self.mk_expr(span_lo, hi, ExprKind::While(cond, body, opt_ident), - attrs)); + let span = span_lo.to(body.span); + return Ok(self.mk_expr(span, ExprKind::While(cond, body, opt_ident), attrs)); } /// Parse a 'while let' expression ('while' token already eaten) pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::SpannedIdent>, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { self.expect_keyword(keywords::Let)?; let pat = self.parse_pat()?; @@ -3091,34 +3075,33 @@ impl<'a> Parser<'a> { let expr = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - return Ok(self.mk_expr(span_lo, hi, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs)); + let span = span_lo.to(body.span); + return Ok(self.mk_expr(span, ExprKind::WhileLet(pat, expr, body, opt_ident), attrs)); } // parse `loop {...}`, `loop` token already eaten pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::SpannedIdent>, - span_lo: BytePos, + span_lo: Span, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - Ok(self.mk_expr(span_lo, hi, ExprKind::Loop(body, opt_ident), attrs)) + let span = span_lo.to(body.span); + Ok(self.mk_expr(span, ExprKind::Loop(body, opt_ident), attrs)) } /// Parse a `do catch {...}` expression (`do catch` token already eaten) - pub fn parse_catch_expr(&mut self, span_lo: BytePos, mut attrs: ThinVec<Attribute>) + pub fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - let hi = body.span.hi; - Ok(self.mk_expr(span_lo, hi, ExprKind::Catch(body), attrs)) + Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs)) } // `match` token already eaten fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { let match_span = self.prev_span; - let lo = self.prev_span.lo; + let lo = self.prev_span; let discriminant = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?; if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) { @@ -3137,17 +3120,17 @@ impl<'a> Parser<'a> { // Recover by skipping to the end of the block. e.emit(); self.recover_stmt(); - let hi = self.span.hi; + let span = lo.to(self.span); if self.token == token::CloseDelim(token::Brace) { self.bump(); } - return Ok(self.mk_expr(lo, hi, ExprKind::Match(discriminant, arms), attrs)); + return Ok(self.mk_expr(span, ExprKind::Match(discriminant, arms), attrs)); } } } - let hi = self.span.hi; + let hi = self.span; self.bump(); - return Ok(self.mk_expr(lo, hi, ExprKind::Match(discriminant, arms), attrs)); + return Ok(self.mk_expr(lo.to(hi), ExprKind::Match(discriminant, arms), attrs)); } pub fn parse_arm(&mut self) -> PResult<'a, Arm> { @@ -3321,7 +3304,7 @@ impl<'a> Parser<'a> { } let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; let hi; if self.check(&token::DotDot) { @@ -3341,16 +3324,16 @@ impl<'a> Parser<'a> { let fieldname = self.parse_field_name()?; self.bump(); let pat = self.parse_pat()?; - hi = pat.span.hi; + hi = pat.span; (pat, fieldname, false) } else { // Parsing a pattern of the form "(box) (ref) (mut) fieldname" let is_box = self.eat_keyword(keywords::Box); - let boxed_span_lo = self.span.lo; + let boxed_span = self.span; let is_ref = self.eat_keyword(keywords::Ref); let is_mut = self.eat_keyword(keywords::Mut); let fieldname = self.parse_ident()?; - hi = self.prev_span.hi; + hi = self.prev_span; let bind_type = match (is_ref, is_mut) { (true, true) => BindingMode::ByRef(Mutability::Mutable), @@ -3362,14 +3345,14 @@ impl<'a> Parser<'a> { let fieldpat = P(ast::Pat{ id: ast::DUMMY_NODE_ID, node: PatKind::Ident(bind_type, fieldpath, None), - span: mk_sp(boxed_span_lo, hi), + span: boxed_span.to(hi), }); let subpat = if is_box { P(ast::Pat{ id: ast::DUMMY_NODE_ID, node: PatKind::Box(fieldpat), - span: mk_sp(lo, hi), + span: lo.to(hi), }) } else { fieldpat @@ -3377,7 +3360,7 @@ impl<'a> Parser<'a> { (subpat, fieldname, true) }; - fields.push(codemap::Spanned { span: mk_sp(lo, hi), + fields.push(codemap::Spanned { span: lo.to(hi), node: ast::FieldPat { ident: fieldname, pat: subpat, @@ -3391,7 +3374,7 @@ impl<'a> Parser<'a> { fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> { if self.token.is_path_start() { - let lo = self.span.lo; + let lo = self.span; let (qself, path) = if self.eat_lt() { // Parse a qualified path let (qself, path) = @@ -3401,8 +3384,8 @@ impl<'a> Parser<'a> { // Parse an unqualified path (None, self.parse_path(PathStyle::Expr)?) }; - let hi = self.prev_span.hi; - Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new())) + let hi = self.prev_span; + Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), ThinVec::new())) } else { self.parse_pat_literal_maybe_minus() } @@ -3428,7 +3411,7 @@ impl<'a> Parser<'a> { pub fn parse_pat(&mut self) -> PResult<'a, P<Pat>> { maybe_whole!(self, NtPat, |x| x); - let lo = self.span.lo; + let lo = self.span; let pat; match self.token { token::Underscore => { @@ -3439,7 +3422,7 @@ impl<'a> Parser<'a> { token::BinOp(token::And) | token::AndAnd => { // Parse &pat / &mut pat self.expect_and()?; - let mutbl = self.parse_mutability()?; + let mutbl = self.parse_mutability(); if let token::Lifetime(ident) = self.token { return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident))); } @@ -3466,7 +3449,7 @@ impl<'a> Parser<'a> { pat = self.parse_pat_ident(BindingMode::ByValue(Mutability::Mutable))?; } else if self.eat_keyword(keywords::Ref) { // Parse ref ident @ pat / ref mut ident @ pat - let mutbl = self.parse_mutability()?; + let mutbl = self.parse_mutability(); pat = self.parse_pat_ident(BindingMode::ByRef(mutbl))?; } else if self.eat_keyword(keywords::Box) { // Parse box pat @@ -3494,7 +3477,7 @@ impl<'a> Parser<'a> { // Parse macro invocation self.bump(); let (_, tts) = self.expect_delimited_token_tree()?; - let mac = spanned(lo, self.prev_span.hi, Mac_ { path: path, tts: tts }); + let mac = respan(lo.to(self.prev_span), Mac_ { path: path, tts: tts }); pat = PatKind::Mac(mac); } token::DotDotDot | token::DotDot => { @@ -3504,9 +3487,8 @@ impl<'a> Parser<'a> { _ => panic!("can only parse `..` or `...` for ranges (checked above)"), }; // Parse range - let hi = self.prev_span.hi; - let begin = - self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new()); + let span = lo.to(self.prev_span); + let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new()); self.bump(); let end = self.parse_pat_range_end()?; pat = PatKind::Range(begin, end, end_kind); @@ -3560,11 +3542,10 @@ impl<'a> Parser<'a> { } } - let hi = self.prev_span.hi; Ok(P(ast::Pat { id: ast::DUMMY_NODE_ID, node: pat, - span: mk_sp(lo, hi), + span: lo.to(self.prev_span), })) } @@ -3574,9 +3555,9 @@ impl<'a> Parser<'a> { fn parse_pat_ident(&mut self, binding_mode: ast::BindingMode) -> PResult<'a, PatKind> { + let ident_span = self.span; let ident = self.parse_ident()?; - let prev_span = self.prev_span; - let name = codemap::Spanned{span: prev_span, node: ident}; + let name = codemap::Spanned{span: ident_span, node: ident}; let sub = if self.eat(&token::At) { Some(self.parse_pat()?) } else { @@ -3600,7 +3581,7 @@ impl<'a> Parser<'a> { /// Parse a local variable declaration fn parse_local(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Local>> { - let lo = self.span.lo; + let lo = self.span; let pat = self.parse_pat()?; let mut ty = None; @@ -3613,14 +3594,14 @@ impl<'a> Parser<'a> { pat: pat, init: init, id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), attrs: attrs, })) } /// Parse a structure field fn parse_name_and_ty(&mut self, - lo: BytePos, + lo: Span, vis: Visibility, attrs: Vec<Attribute>) -> PResult<'a, StructField> { @@ -3628,7 +3609,7 @@ impl<'a> Parser<'a> { self.expect(&token::Colon)?; let ty = self.parse_ty()?; Ok(StructField { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), ident: Some(name), vis: vis, id: ast::DUMMY_NODE_ID, @@ -3738,7 +3719,7 @@ impl<'a> Parser<'a> { fn eat_macro_def(&mut self, attrs: &[Attribute], vis: &Visibility) -> PResult<'a, Option<P<Item>>> { - let lo = self.span.lo; + let lo = self.span; match self.token { token::Ident(ident) if ident.name == "macro_rules" => { if self.look_ahead(1, |t| *t == token::Not) { @@ -3761,9 +3742,9 @@ impl<'a> Parser<'a> { } } - let hi = self.prev_span.hi; + let span = lo.to(self.prev_span); let kind = ItemKind::MacroDef(tts); - Ok(Some(self.mk_item(lo, hi, id, kind, Visibility::Inherited, attrs.to_owned()))) + Ok(Some(self.mk_item(span, id, kind, Visibility::Inherited, attrs.to_owned()))) } fn parse_stmt_without_recovery(&mut self, @@ -3772,19 +3753,19 @@ impl<'a> Parser<'a> { maybe_whole!(self, NtStmt, |x| Some(x)); let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; + let lo = self.span; Ok(Some(if self.eat_keyword(keywords::Let) { Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Local(self.parse_local(attrs.into())?), - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), } } else if let Some(macro_def) = self.eat_macro_def(&attrs, &Visibility::Inherited)? { Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Item(macro_def), - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), } // Starts like a simple path, but not a union item. } else if self.token.is_path_start() && @@ -3796,8 +3777,8 @@ impl<'a> Parser<'a> { let expr = if self.check(&token::OpenDelim(token::Brace)) { self.parse_struct_expr(lo, pth, ThinVec::new())? } else { - let hi = self.prev_span.hi; - self.mk_expr(lo, hi, ExprKind::Path(None, pth), ThinVec::new()) + let hi = self.prev_span; + self.mk_expr(lo.to(hi), ExprKind::Path(None, pth), ThinVec::new()) }; let expr = self.with_res(Restrictions::RESTRICTION_STMT_EXPR, |this| { @@ -3808,7 +3789,7 @@ impl<'a> Parser<'a> { return Ok(Some(Stmt { id: ast::DUMMY_NODE_ID, node: StmtKind::Expr(expr), - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), })); } @@ -3839,7 +3820,7 @@ impl<'a> Parser<'a> { }; let (_, tts) = self.expect_delimited_token_tree()?; - let hi = self.prev_span.hi; + let hi = self.prev_span; let style = if delim == token::Brace { MacStmtStyle::Braces @@ -3848,7 +3829,7 @@ impl<'a> Parser<'a> { }; if id.name == keywords::Invalid.name() { - let mac = spanned(lo, hi, Mac_ { path: pth, tts: tts }); + let mac = respan(lo.to(hi), Mac_ { path: pth, tts: tts }); let node = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { StmtKind::Mac(P((mac, style, attrs.into()))) @@ -3868,14 +3849,14 @@ impl<'a> Parser<'a> { self.warn_missing_semicolon(); StmtKind::Mac(P((mac, style, attrs.into()))) } else { - let e = self.mk_mac_expr(lo, hi, mac.node, ThinVec::new()); + let e = self.mk_mac_expr(lo.to(hi), mac.node, ThinVec::new()); let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; StmtKind::Expr(e) }; Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: lo.to(hi), node: node, } } else { @@ -3890,13 +3871,14 @@ impl<'a> Parser<'a> { followed by a semicolon"); } } + let span = lo.to(hi); Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: span, node: StmtKind::Item({ self.mk_item( - lo, hi, id /*id is good here*/, - ItemKind::Mac(spanned(lo, hi, Mac_ { path: pth, tts: tts })), + span, id /*id is good here*/, + ItemKind::Mac(respan(span, Mac_ { path: pth, tts: tts })), Visibility::Inherited, attrs) }), @@ -3911,7 +3893,7 @@ impl<'a> Parser<'a> { match item { Some(i) => Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, i.span.hi), + span: lo.to(i.span), node: StmtKind::Item(i), }, None => { @@ -3942,7 +3924,7 @@ impl<'a> Parser<'a> { Restrictions::RESTRICTION_STMT_EXPR, Some(attrs.into()))?; Stmt { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, e.span.hi), + span: lo.to(e.span), node: StmtKind::Expr(e), } } @@ -3960,7 +3942,7 @@ impl<'a> Parser<'a> { pub fn parse_block(&mut self) -> PResult<'a, P<Block>> { maybe_whole!(self, NtBlock, |x| x); - let lo = self.span.lo; + let lo = self.span; if !self.eat(&token::OpenDelim(token::Brace)) { let sp = self.span; @@ -4005,7 +3987,7 @@ impl<'a> Parser<'a> { fn parse_inner_attrs_and_block(&mut self) -> PResult<'a, (Vec<Attribute>, P<Block>)> { maybe_whole!(self, NtBlock, |x| (Vec::new(), x)); - let lo = self.span.lo; + let lo = self.span; self.expect(&token::OpenDelim(token::Brace))?; Ok((self.parse_inner_attributes()?, self.parse_block_tail(lo, BlockCheckMode::Default)?)) @@ -4013,7 +3995,7 @@ impl<'a> Parser<'a> { /// Parse the rest of a block expression or function body /// Precondition: already parsed the '{'. - fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> PResult<'a, P<Block>> { + fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P<Block>> { let mut stmts = vec![]; while !self.eat(&token::CloseDelim(token::Brace)) { @@ -4031,7 +4013,7 @@ impl<'a> Parser<'a> { stmts: stmts, id: ast::DUMMY_NODE_ID, rules: s, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), })) } @@ -4086,30 +4068,32 @@ impl<'a> Parser<'a> { // BOUND = TY_BOUND | LT_BOUND // LT_BOUND = LIFETIME (e.g. `'a`) // TY_BOUND = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`) - fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> - { + fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> { let mut bounds = Vec::new(); loop { let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None }; - if let Some(lifetime) = self.eat_lifetime() { + if self.check_lifetime() { if let Some(question_span) = question { self.span_err(question_span, "`?` may only modify trait bounds, not lifetime bounds"); } - bounds.push(RegionTyParamBound(lifetime)); - } else {if self.check_keyword(keywords::For) || self.check_path() { - let poly_trait_ref = self.parse_poly_trait_ref()?; + bounds.push(RegionTyParamBound(self.expect_lifetime())); + } else if self.check_keyword(keywords::For) || self.check_path() { + let lo = self.span; + let lifetime_defs = self.parse_late_bound_lifetime_defs()?; + let path = self.parse_path(PathStyle::Type)?; + let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span)); let modifier = if question.is_some() { TraitBoundModifier::Maybe } else { TraitBoundModifier::None }; - bounds.push(TraitTyParamBound(poly_trait_ref, modifier)); + bounds.push(TraitTyParamBound(poly_trait, modifier)); } else { break - }} + } - if !self.eat(&token::BinOp(token::Plus)) { + if !allow_plus || !self.eat(&token::BinOp(token::Plus)) { break } } @@ -4117,12 +4101,16 @@ impl<'a> Parser<'a> { return Ok(bounds); } + fn parse_ty_param_bounds(&mut self) -> PResult<'a, TyParamBounds> { + self.parse_ty_param_bounds_common(true) + } + // Parse bounds of a type parameter `BOUND + BOUND + BOUND` without trailing `+`. // BOUND = LT_BOUND (e.g. `'a`) fn parse_lt_param_bounds(&mut self) -> Vec<Lifetime> { let mut lifetimes = Vec::new(); - while let Some(lifetime) = self.eat_lifetime() { - lifetimes.push(lifetime); + while self.check_lifetime() { + lifetimes.push(self.expect_lifetime()); if !self.eat(&token::BinOp(token::Plus)) { break @@ -4167,7 +4155,8 @@ impl<'a> Parser<'a> { let mut seen_ty_param = false; loop { let attrs = self.parse_outer_attributes()?; - if let Some(lifetime) = self.eat_lifetime() { + if self.check_lifetime() { + let lifetime = self.expect_lifetime(); // Parse lifetime parameter. let bounds = if self.eat(&token::Colon) { self.parse_lt_param_bounds() @@ -4183,7 +4172,7 @@ impl<'a> Parser<'a> { self.span_err(self.prev_span, "lifetime parameters must be declared prior to type parameters"); } - } else {if self.check_ident() { + } else if self.check_ident() { // Parse type parameter. ty_params.push(self.parse_ty_param(attrs)?); seen_ty_param = true; @@ -4195,7 +4184,7 @@ impl<'a> Parser<'a> { &format!("trailing attribute after {} parameters", param_kind)); } break - }} + } if !self.eat(&token::Comma) { break @@ -4214,7 +4203,7 @@ impl<'a> Parser<'a> { pub fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { maybe_whole!(self, NtGenerics, |x| x); - let span_lo = self.span.lo; + let span_lo = self.span; if self.eat_lt() { let (lifetime_defs, ty_params) = self.parse_generic_params()?; self.expect_gt()?; @@ -4225,7 +4214,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), }, - span: mk_sp(span_lo, self.prev_span.hi), + span: span_lo.to(self.prev_span), }) } else { Ok(ast::Generics::default()) @@ -4241,16 +4230,16 @@ impl<'a> Parser<'a> { let mut seen_type = false; let mut seen_binding = false; loop { - if let Some(lifetime) = self.eat_lifetime() { + if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) { // Parse lifetime argument. - lifetimes.push(lifetime); + lifetimes.push(self.expect_lifetime()); if seen_type || seen_binding { self.span_err(self.prev_span, "lifetime parameters must be declared prior to type parameters"); } - } else {if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { + } else if self.check_ident() && self.look_ahead(1, |t| t == &token::Eq) { // Parse associated type binding. - let lo = self.span.lo; + let lo = self.span; let ident = self.parse_ident()?; self.bump(); let ty = self.parse_ty()?; @@ -4258,7 +4247,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, ident: ident, ty: ty, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), }); seen_binding = true; } else if self.check_type() { @@ -4271,7 +4260,7 @@ impl<'a> Parser<'a> { seen_type = true; } else { break - }} + } if !self.eat(&token::Comma) { break @@ -4315,19 +4304,20 @@ impl<'a> Parser<'a> { } loop { - let lo = self.span.lo; - if let Some(lifetime) = self.eat_lifetime() { + let lo = self.span; + if self.check_lifetime() && self.look_ahead(1, |t| t != &token::BinOp(token::Plus)) { + let lifetime = self.expect_lifetime(); // Bounds starting with a colon are mandatory, but possibly empty. self.expect(&token::Colon)?; let bounds = self.parse_lt_param_bounds(); where_clause.predicates.push(ast::WherePredicate::RegionPredicate( ast::WhereRegionPredicate { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), lifetime: lifetime, bounds: bounds, } )); - } else {if self.check_type() { + } else if self.check_type() { // Parse optional `for<'a, 'b>`. // This `for` is parsed greedily and applies to the whole predicate, // the bounded type can have its own `for` applying only to it. @@ -4343,7 +4333,7 @@ impl<'a> Parser<'a> { let bounds = self.parse_ty_param_bounds()?; where_clause.predicates.push(ast::WherePredicate::BoundPredicate( ast::WhereBoundPredicate { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), bound_lifetimes: lifetime_defs, bounded_ty: ty, bounds: bounds, @@ -4354,7 +4344,7 @@ impl<'a> Parser<'a> { let rhs_ty = self.parse_ty()?; where_clause.predicates.push(ast::WherePredicate::EqPredicate( ast::WhereEqPredicate { - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), lhs_ty: ty, rhs_ty: rhs_ty, id: ast::DUMMY_NODE_ID, @@ -4365,7 +4355,7 @@ impl<'a> Parser<'a> { } } else { break - }} + } if !self.eat(&token::Comma) { break @@ -4405,8 +4395,12 @@ impl<'a> Parser<'a> { Ok(arg) => Ok(Some(arg)), Err(mut e) => { e.emit(); + let lo = p.prev_span; + // Skip every token until next possible arg or end. p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); - Ok(None) + // Create a placeholder argument for proper arg count (#34264). + let span = lo.to(p.prev_span); + Ok(Some(dummy_arg(span))) } } } @@ -4440,7 +4434,7 @@ impl<'a> Parser<'a> { fn parse_self_arg(&mut self) -> PResult<'a, Option<Arg>> { let expect_ident = |this: &mut Self| match this.token { // Preserve hygienic context. - token::Ident(ident) => { this.bump(); codemap::respan(this.prev_span, ident) } + token::Ident(ident) => { let sp = this.span; this.bump(); codemap::respan(sp, ident) } _ => unreachable!() }; let isolated_self = |this: &mut Self, n| { @@ -4451,7 +4445,7 @@ impl<'a> Parser<'a> { // Parse optional self parameter of a method. // Only a limited set of initial token sequences is considered self parameters, anything // else is parsed as a normal function parameter list, so some lookahead is required. - let eself_lo = self.span.lo; + let eself_lo = self.span; let (eself, eself_ident) = match self.token { token::BinOp(token::And) => { // &self @@ -4470,13 +4464,13 @@ impl<'a> Parser<'a> { } else if self.look_ahead(1, |t| t.is_lifetime()) && isolated_self(self, 2) { self.bump(); - let lt = self.eat_lifetime().expect("not a lifetime"); + let lt = self.expect_lifetime(); (SelfKind::Region(Some(lt), Mutability::Immutable), expect_ident(self)) } else if self.look_ahead(1, |t| t.is_lifetime()) && self.look_ahead(2, |t| t.is_keyword(keywords::Mut)) && isolated_self(self, 3) { self.bump(); - let lt = self.eat_lifetime().expect("not a lifetime"); + let lt = self.expect_lifetime(); self.bump(); (SelfKind::Region(Some(lt), Mutability::Mutable), expect_ident(self)) } else { @@ -4533,7 +4527,7 @@ impl<'a> Parser<'a> { _ => return Ok(None), }; - let eself = codemap::respan(mk_sp(eself_lo, self.prev_span.hi), eself); + let eself = codemap::respan(eself_lo.to(self.prev_span), eself); Ok(Some(Arg::from_self(eself, eself_ident))) } @@ -4605,8 +4599,7 @@ impl<'a> Parser<'a> { Ok((id, generics)) } - fn mk_item(&mut self, lo: BytePos, hi: BytePos, ident: Ident, - node: ItemKind, vis: Visibility, + fn mk_item(&mut self, span: Span, ident: Ident, node: ItemKind, vis: Visibility, attrs: Vec<Attribute>) -> P<Item> { P(Item { ident: ident, @@ -4614,7 +4607,7 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, node: node, vis: vis, - span: mk_sp(lo, hi) + span: span, }) } @@ -4672,8 +4665,8 @@ impl<'a> Parser<'a> { maybe_whole!(self, NtImplItem, |x| x); let mut attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; - let vis = self.parse_visibility()?; + let lo = self.span; + let vis = self.parse_visibility(false)?; let defaultness = self.parse_defaultness()?; let (name, node) = if self.eat_keyword(keywords::Type) { let name = self.parse_ident()?; @@ -4698,7 +4691,7 @@ impl<'a> Parser<'a> { Ok(ImplItem { id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, self.prev_span.hi), + span: lo.to(self.prev_span), ident: name, vis: vis, defaultness: defaultness, @@ -4707,25 +4700,30 @@ impl<'a> Parser<'a> { }) } - fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) { - match *visa { - Visibility::Inherited => (), + fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) { + if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) { + err.emit(); + } + } + + fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> { + match *vis { + Visibility::Inherited => Ok(()), _ => { let is_macro_rules: bool = match self.token { token::Ident(sid) => sid.name == Symbol::intern("macro_rules"), _ => false, }; if is_macro_rules { - self.diagnostic().struct_span_err(span, "can't qualify macro_rules \ - invocation with `pub`") - .help("did you mean #[macro_export]?") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`"); + err.help("did you mean #[macro_export]?"); + Err(err) } else { - self.diagnostic().struct_span_err(span, "can't qualify macro \ - invocation with `pub`") - .help("try adjusting the macro to put `pub` \ - inside the invocation") - .emit(); + let mut err = self.diagnostic() + .struct_span_err(sp, "can't qualify macro invocation with `pub`"); + err.help("try adjusting the macro to put `pub` inside the invocation"); + Err(err) } } } @@ -4736,14 +4734,36 @@ impl<'a> Parser<'a> { -> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> { // code copied from parse_macro_use_or_failure... abstraction! if self.token.is_path_start() { - // method macro. + // Method macro. let prev_span = self.prev_span; - self.complain_if_pub_macro(&vis, prev_span); + // Before complaining about trying to set a macro as `pub`, + // check if `!` comes after the path. + let err = self.complain_if_pub_macro_diag(&vis, prev_span); - let lo = self.span.lo; + let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; - self.expect(&token::Not)?; + let bang_err = self.expect(&token::Not); + if let Err(mut err) = err { + if let Err(mut bang_err) = bang_err { + // Given this code `pub path(`, it seems like this is not setting the + // visibility of a macro invocation, but rather a mistyped method declaration. + // Create a diagnostic pointing out that `fn` is missing. + // + // x | pub path(&self) { + // | ^ missing `fn` for method declaration + + err.cancel(); + bang_err.cancel(); + // pub path( + // ^^ `sp` below will point to this + let sp = prev_span.between(self.prev_span); + err = self.diagnostic() + .struct_span_err(sp, "missing `fn` for method declaration"); + err.span_label(sp, &"missing `fn`"); + } + return Err(err); + } // eat a matched-delimiter token tree: let (delim, tts) = self.expect_delimited_token_tree()?; @@ -4751,7 +4771,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)? } - let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts }); + let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts }); Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(mac))) } else { let (constness, unsafety, abi) = self.parse_fn_front_matter()?; @@ -4869,14 +4889,6 @@ impl<'a> Parser<'a> { } } - /// Parse a::B<String,i32> - fn parse_trait_ref(&mut self) -> PResult<'a, TraitRef> { - Ok(TraitRef { - path: self.parse_path(PathStyle::Type)?, - ref_id: ast::DUMMY_NODE_ID, - }) - } - fn parse_late_bound_lifetime_defs(&mut self) -> PResult<'a, Vec<LifetimeDef>> { if self.eat_keyword(keywords::For) { self.expect_lt()?; @@ -4892,18 +4904,6 @@ impl<'a> Parser<'a> { } } - /// Parse for<'l> a::B<String,i32> - fn parse_poly_trait_ref(&mut self) -> PResult<'a, PolyTraitRef> { - let lo = self.span.lo; - let lifetime_defs = self.parse_late_bound_lifetime_defs()?; - - Ok(PolyTraitRef { - bound_lifetimes: lifetime_defs, - trait_ref: self.parse_trait_ref()?, - span: mk_sp(lo, self.prev_span.hi), - }) - } - /// Parse struct Foo { ... } fn parse_item_struct(&mut self) -> PResult<'a, ItemInfo> { let class_name = self.parse_ident()?; @@ -5005,28 +5005,11 @@ impl<'a> Parser<'a> { SeqSep::trailing_allowed(token::Comma), |p| { let attrs = p.parse_outer_attributes()?; - let lo = p.span.lo; - let mut vis = p.parse_visibility()?; - let ty_is_interpolated = - p.token.is_interpolated() || p.look_ahead(1, |t| t.is_interpolated()); - let mut ty = p.parse_ty()?; - - // Handle `pub(path) type`, in which `vis` will be `pub` and `ty` will be `(path)`. - if vis == Visibility::Public && !ty_is_interpolated && - p.token != token::Comma && p.token != token::CloseDelim(token::Paren) { - ty = if let TyKind::Paren(ref path_ty) = ty.node { - if let TyKind::Path(None, ref path) = path_ty.node { - vis = Visibility::Restricted { path: P(path.clone()), id: path_ty.id }; - Some(p.parse_ty()?) - } else { - None - } - } else { - None - }.unwrap_or(ty); - } + let lo = p.span; + let vis = p.parse_visibility(true)?; + let ty = p.parse_ty()?; Ok(StructField { - span: mk_sp(lo, p.span.hi), + span: lo.to(p.span), vis: vis, ident: None, id: ast::DUMMY_NODE_ID, @@ -5040,7 +5023,7 @@ impl<'a> Parser<'a> { /// Parse a structure field declaration pub fn parse_single_struct_field(&mut self, - lo: BytePos, + lo: Span, vis: Visibility, attrs: Vec<Attribute> ) -> PResult<'a, StructField> { @@ -5062,19 +5045,26 @@ impl<'a> Parser<'a> { /// Parse an element of a struct definition fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> { let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; - let vis = self.parse_visibility()?; + let lo = self.span; + let vis = self.parse_visibility(false)?; self.parse_single_struct_field(lo, vis, attrs) } - // Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts - // `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`. - fn parse_visibility(&mut self) -> PResult<'a, Visibility> { + /// Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `pub(self)` for `pub(in self)` + /// and `pub(super)` for `pub(in super)`. If the following element can't be a tuple (i.e. it's + /// a function definition, it's not a tuple struct field) and the contents within the parens + /// isn't valid, emit a proper diagnostic. + fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { if !self.eat_keyword(keywords::Pub) { return Ok(Visibility::Inherited) } if self.check(&token::OpenDelim(token::Paren)) { + let start_span = self.span; + // We don't `self.bump()` the `(` yet because this might be a struct definition where + // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`. + // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so + // by the following tokens. if self.look_ahead(1, |t| t.is_keyword(keywords::Crate)) { // `pub(crate)` self.bump(); // `(` @@ -5099,6 +5089,24 @@ impl<'a> Parser<'a> { let vis = Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; self.expect(&token::CloseDelim(token::Paren))?; // `)` return Ok(vis) + } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct + // `pub(something) fn ...` or `struct X { pub(something) y: Z }` + self.bump(); // `(` + let msg = "incorrect visibility restriction"; + let suggestion = r##"some possible visibility restrictions are: +`pub(crate)`: visible only on the current crate +`pub(super)`: visible only in the current module's parent +`pub(in path::to::module)`: visible only on the specified path"##; + let path = self.parse_path(PathStyle::Mod)?; + let path_span = self.prev_span; + let help_msg = format!("to make this visible only to module `{}`, add `in` before \ + the path:", + path); + self.expect(&token::CloseDelim(token::Paren))?; // `)` + let sp = start_span.to(self.prev_span); + let mut err = self.span_fatal_help(sp, &msg, &suggestion); + err.span_suggestion(path_span, &help_msg, format!("in {}", path)); + err.emit(); // emit diagnostic, but continue with public visibility } } @@ -5115,7 +5123,7 @@ impl<'a> Parser<'a> { } /// Given a termination token, parse all of the items in a module - fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> PResult<'a, Mod> { + fn parse_mod_items(&mut self, term: &token::Token, inner_lo: Span) -> PResult<'a, Mod> { let mut items = vec![]; while let Some(item) = self.parse_item()? { items.push(item); @@ -5129,11 +5137,11 @@ impl<'a> Parser<'a> { let hi = if self.span == syntax_pos::DUMMY_SP { inner_lo } else { - self.prev_span.hi + self.prev_span }; Ok(ast::Mod { - inner: mk_sp(inner_lo, hi), + inner: inner_lo.to(hi), items: items }) } @@ -5178,11 +5186,9 @@ impl<'a> Parser<'a> { let attr = ast::Attribute { id: attr::mk_attr_id(), style: ast::AttrStyle::Outer, - value: ast::MetaItem { - name: Symbol::intern("warn_directory_ownership"), - node: ast::MetaItemKind::Word, - span: syntax_pos::DUMMY_SP, - }, + path: ast::Path::from_ident(syntax_pos::DUMMY_SP, + Ident::from_str("warn_directory_ownership")), + tokens: TokenStream::empty(), is_sugared_doc: false, span: syntax_pos::DUMMY_SP, }; @@ -5198,7 +5204,7 @@ impl<'a> Parser<'a> { let old_directory = self.directory.clone(); self.push_directory(id, &outer_attrs); self.expect(&token::OpenDelim(token::Brace))?; - let mod_inner_lo = self.span.lo; + let mod_inner_lo = self.span; let attrs = self.parse_inner_attributes()?; let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?; self.directory = old_directory; @@ -5208,22 +5214,22 @@ impl<'a> Parser<'a> { fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") { - self.directory.path.push(&*path.as_str()); + self.directory.path.push(&path.as_str()); self.directory.ownership = DirectoryOwnership::Owned; } else { - self.directory.path.push(&*id.name.as_str()); + self.directory.path.push(&id.name.as_str()); } } pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option<PathBuf> { - attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&*d.as_str())) + attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&d.as_str())) } /// Returns either a path to a module, or . pub fn default_submod_path(id: ast::Ident, dir_path: &Path, codemap: &CodeMap) -> ModulePath { let mod_name = id.to_string(); let default_path_str = format!("{}.rs", mod_name); - let secondary_path_str = format!("{}/mod.rs", mod_name); + let secondary_path_str = format!("{}{}mod.rs", mod_name, path::MAIN_SEPARATOR); let default_path = dir_path.join(&default_path_str); let secondary_path = dir_path.join(&secondary_path_str); let default_exists = codemap.file_exists(&default_path); @@ -5301,8 +5307,9 @@ impl<'a> Parser<'a> { }; err.span_note(id_sp, &format!("maybe move this module `{0}` to its own directory \ - via `{0}/mod.rs`", - this_module)); + via `{0}{1}mod.rs`", + this_module, + path::MAIN_SEPARATOR)); if paths.path_exists { err.span_note(id_sp, &format!("... or maybe `use` the module `{}` instead \ @@ -5341,7 +5348,7 @@ impl<'a> Parser<'a> { let mut p0 = new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp); p0.cfg_mods = self.cfg_mods; - let mod_inner_lo = p0.span.lo; + let mod_inner_lo = p0.span; let mod_attrs = p0.parse_inner_attributes()?; let m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?; self.sess.included_mod_stack.borrow_mut().pop(); @@ -5349,42 +5356,42 @@ impl<'a> Parser<'a> { } /// Parse a function declaration from a foreign module - fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: BytePos, - attrs: Vec<Attribute>) -> PResult<'a, ForeignItem> { + fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>) + -> PResult<'a, ForeignItem> { self.expect_keyword(keywords::Fn)?; let (ident, mut generics) = self.parse_fn_header()?; let decl = self.parse_fn_decl(true)?; generics.where_clause = self.parse_where_clause()?; - let hi = self.span.hi; + let hi = self.span; self.expect(&token::Semi)?; Ok(ast::ForeignItem { ident: ident, attrs: attrs, node: ForeignItemKind::Fn(decl, generics), id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: lo.to(hi), vis: vis }) } /// Parse a static item from a foreign module - fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: BytePos, - attrs: Vec<Attribute>) -> PResult<'a, ForeignItem> { + fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: Span, attrs: Vec<Attribute>) + -> PResult<'a, ForeignItem> { self.expect_keyword(keywords::Static)?; let mutbl = self.eat_keyword(keywords::Mut); let ident = self.parse_ident()?; self.expect(&token::Colon)?; let ty = self.parse_ty()?; - let hi = self.span.hi; + let hi = self.span; self.expect(&token::Semi)?; Ok(ForeignItem { ident: ident, attrs: attrs, node: ForeignItemKind::Static(ty, mutbl), id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), + span: lo.to(hi), vis: vis }) } @@ -5396,7 +5403,7 @@ impl<'a> Parser<'a> { /// extern crate foo; /// extern crate bar as foo; fn parse_item_extern_crate(&mut self, - lo: BytePos, + lo: Span, visibility: Visibility, attrs: Vec<Attribute>) -> PResult<'a, P<Item>> { @@ -5410,8 +5417,7 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; let prev_span = self.prev_span; - Ok(self.mk_item(lo, - prev_span.hi, + Ok(self.mk_item(lo.to(prev_span), ident, ItemKind::ExternCrate(maybe_path), visibility, @@ -5429,7 +5435,7 @@ impl<'a> Parser<'a> { /// extern "C" {} /// extern {} fn parse_item_foreign_mod(&mut self, - lo: BytePos, + lo: Span, opt_abi: Option<abi::Abi>, visibility: Visibility, mut attrs: Vec<Attribute>) @@ -5451,12 +5457,8 @@ impl<'a> Parser<'a> { abi: abi, items: foreign_items }; - Ok(self.mk_item(lo, - prev_span.hi, - keywords::Invalid.ident(), - ItemKind::ForeignMod(m), - visibility, - attrs)) + let invalid = keywords::Invalid.ident(); + Ok(self.mk_item(lo.to(prev_span), invalid, ItemKind::ForeignMod(m), visibility, attrs)) } /// Parse type Foo = Bar; @@ -5477,7 +5479,7 @@ impl<'a> Parser<'a> { let mut any_disr = None; while self.token != token::CloseDelim(token::Brace) { let variant_attrs = self.parse_outer_attributes()?; - let vlo = self.span.lo; + let vlo = self.span; let struct_def; let mut disr_expr = None; @@ -5505,7 +5507,7 @@ impl<'a> Parser<'a> { data: struct_def, disr_expr: disr_expr, }; - variants.push(spanned(vlo, self.prev_span.hi, vr)); + variants.push(respan(vlo.to(self.prev_span), vr)); if !self.eat(&token::Comma) { break; } } @@ -5575,9 +5577,9 @@ impl<'a> Parser<'a> { Some(P(item)) }); - let lo = self.span.lo; + let lo = self.span; - let visibility = self.parse_visibility()?; + let visibility = self.parse_visibility(false)?; if self.eat_keyword(keywords::Use) { // USE ITEM @@ -5585,12 +5587,8 @@ impl<'a> Parser<'a> { self.expect(&token::Semi)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, - keywords::Invalid.ident(), - item_, - visibility, - attrs); + let invalid = keywords::Invalid.ident(); + let item = self.mk_item(lo.to(prev_span), invalid, item_, visibility, attrs); return Ok(Some(item)); } @@ -5610,8 +5608,7 @@ impl<'a> Parser<'a> { respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5633,8 +5630,7 @@ impl<'a> Parser<'a> { }; let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5658,8 +5654,7 @@ impl<'a> Parser<'a> { respan(const_span, Constness::Const), Abi::Rust)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5676,8 +5671,7 @@ impl<'a> Parser<'a> { } let (ident, item_, extra_attrs) = self.parse_item_const(None)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5693,8 +5687,7 @@ impl<'a> Parser<'a> { let (ident, item_, extra_attrs) = self.parse_item_trait(ast::Unsafety::Unsafe)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5709,8 +5702,7 @@ impl<'a> Parser<'a> { self.expect_keyword(keywords::Impl)?; let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5726,8 +5718,7 @@ impl<'a> Parser<'a> { respan(fn_span, Constness::NotConst), Abi::Rust)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5750,8 +5741,7 @@ impl<'a> Parser<'a> { respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5763,8 +5753,7 @@ impl<'a> Parser<'a> { let (ident, item_, extra_attrs) = self.parse_item_mod(&attrs[..])?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5775,8 +5764,7 @@ impl<'a> Parser<'a> { // TYPE ITEM let (ident, item_, extra_attrs) = self.parse_item_type()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5787,8 +5775,7 @@ impl<'a> Parser<'a> { // ENUM ITEM let (ident, item_, extra_attrs) = self.parse_item_enum()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5800,8 +5787,7 @@ impl<'a> Parser<'a> { let (ident, item_, extra_attrs) = self.parse_item_trait(ast::Unsafety::Normal)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5812,8 +5798,7 @@ impl<'a> Parser<'a> { // IMPL ITEM let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5824,8 +5809,7 @@ impl<'a> Parser<'a> { // STRUCT ITEM let (ident, item_, extra_attrs) = self.parse_item_struct()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5837,8 +5821,7 @@ impl<'a> Parser<'a> { self.bump(); let (ident, item_, extra_attrs) = self.parse_item_union()?; let prev_span = self.prev_span; - let item = self.mk_item(lo, - prev_span.hi, + let item = self.mk_item(lo.to(prev_span), ident, item_, visibility, @@ -5855,8 +5838,8 @@ impl<'a> Parser<'a> { /// Parse a foreign item. fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> { let attrs = self.parse_outer_attributes()?; - let lo = self.span.lo; - let visibility = self.parse_visibility()?; + let lo = self.span; + let visibility = self.parse_visibility(false)?; if self.check_keyword(keywords::Static) { // FOREIGN STATIC ITEM @@ -5882,7 +5865,7 @@ impl<'a> Parser<'a> { attrs: Vec<Attribute> , macros_allowed: bool, attributes_allowed: bool, - lo: BytePos, + lo: Span, visibility: Visibility ) -> PResult<'a, Option<P<Item>>> { if macros_allowed && self.token.is_path_start() { @@ -5891,7 +5874,7 @@ impl<'a> Parser<'a> { let prev_span = self.prev_span; self.complain_if_pub_macro(&visibility, prev_span); - let mac_lo = self.span.lo; + let mac_lo = self.span; // item macro. let pth = self.parse_path(PathStyle::Mod)?; @@ -5917,9 +5900,9 @@ impl<'a> Parser<'a> { } } - let hi = self.prev_span.hi; - let mac = spanned(mac_lo, hi, Mac_ { path: pth, tts: tts }); - let item = self.mk_item(lo, hi, id, ItemKind::Mac(mac), visibility, attrs); + let hi = self.prev_span; + let mac = respan(mac_lo.to(hi), Mac_ { path: pth, tts: tts }); + let item = self.mk_item(lo.to(hi), id, ItemKind::Mac(mac), visibility, attrs); return Ok(Some(item)); } @@ -5947,7 +5930,7 @@ impl<'a> Parser<'a> { self.parse_unspanned_seq(&token::OpenDelim(token::Brace), &token::CloseDelim(token::Brace), SeqSep::trailing_allowed(token::Comma), |this| { - let lo = this.span.lo; + let lo = this.span; let ident = if this.eat_keyword(keywords::SelfValue) { keywords::SelfValue.ident() } else { @@ -5959,8 +5942,7 @@ impl<'a> Parser<'a> { rename: rename, id: ast::DUMMY_NODE_ID }; - let hi = this.prev_span.hi; - Ok(spanned(lo, hi, node)) + Ok(respan(lo.to(this.prev_span), node)) }) } @@ -5978,21 +5960,21 @@ impl<'a> Parser<'a> { /// MOD_SEP? non_global_path MOD_SEP LBRACE item_seq RBRACE /// MOD_SEP? LBRACE item_seq RBRACE fn parse_view_path(&mut self) -> PResult<'a, P<ViewPath>> { - let lo = self.span.lo; + let lo = self.span; if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) || self.is_import_coupler() { // `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`. self.eat(&token::ModSep); let prefix = ast::Path { segments: vec![PathSegment::crate_root()], - span: mk_sp(lo, self.span.hi), + span: lo.to(self.span), }; let view_path_kind = if self.eat(&token::BinOp(token::Star)) { ViewPathGlob(prefix) } else { ViewPathList(prefix, self.parse_path_list_items()?) }; - Ok(P(spanned(lo, self.span.hi, view_path_kind))) + Ok(P(respan(lo.to(self.span), view_path_kind))) } else { let prefix = self.parse_path(PathStyle::Mod)?.default_to_global(); if self.is_import_coupler() { @@ -6000,16 +5982,16 @@ impl<'a> Parser<'a> { self.bump(); if self.check(&token::BinOp(token::Star)) { self.bump(); - Ok(P(spanned(lo, self.span.hi, ViewPathGlob(prefix)))) + Ok(P(respan(lo.to(self.span), ViewPathGlob(prefix)))) } else { let items = self.parse_path_list_items()?; - Ok(P(spanned(lo, self.span.hi, ViewPathList(prefix, items)))) + Ok(P(respan(lo.to(self.span), ViewPathList(prefix, items)))) } } else { // `foo::bar` or `foo::bar as baz` let rename = self.parse_rename()?. unwrap_or(prefix.segments.last().unwrap().identifier); - Ok(P(spanned(lo, self.prev_span.hi, ViewPathSimple(rename, prefix)))) + Ok(P(respan(lo.to(self.prev_span), ViewPathSimple(rename, prefix)))) } } } @@ -6025,11 +6007,11 @@ impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main /// entry point for the parser. pub fn parse_crate_mod(&mut self) -> PResult<'a, Crate> { - let lo = self.span.lo; + let lo = self.span; Ok(ast::Crate { attrs: self.parse_inner_attributes()?, module: self.parse_mod_items(&token::Eof, lo)?, - span: mk_sp(lo, self.span.lo), + span: lo.to(self.span), }) } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 25601f2420e..74aa3984a9a 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -17,7 +17,7 @@ pub use self::Token::*; use ast::{self}; use ptr::P; use symbol::keywords; -use tokenstream; +use tokenstream::TokenTree; use std::fmt; use std::rc::Rc; @@ -103,6 +103,21 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { ].contains(&ident.name) } +fn ident_can_begin_type(ident: ast::Ident) -> bool { + let ident_token: Token = Ident(ident); + + !ident_token.is_any_keyword() || + ident_token.is_path_segment_keyword() || + [ + keywords::For.name(), + keywords::Impl.name(), + keywords::Fn.name(), + keywords::Unsafe.name(), + keywords::Extern.name(), + keywords::Typeof.name(), + ].contains(&ident.name) +} + #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)] pub enum Token { /* Expression-operator symbols. */ @@ -182,25 +197,21 @@ impl Token { /// Returns `true` if the token can appear at the start of an expression. pub fn can_begin_expr(&self) -> bool { match *self { - OpenDelim(..) => true, - Ident(ident) => ident_can_begin_expr(ident), - Literal(..) => true, - Not => true, - BinOp(Minus) => true, - BinOp(Star) => true, - BinOp(And) => true, - BinOp(Or) => true, // in lambda syntax - OrOr => true, // in lambda syntax - AndAnd => true, // double borrow + Ident(ident) => ident_can_begin_expr(ident), // value name or keyword + OpenDelim(..) => true, // tuple, array or block + Literal(..) => true, // literal + Not => true, // operator not + BinOp(Minus) => true, // unary minus + BinOp(Star) => true, // dereference + BinOp(Or) | OrOr => true, // closure + BinOp(And) => true, // reference + AndAnd => true, // double reference DotDot | DotDotDot => true, // range notation Lt | BinOp(Shl) => true, // associated path - ModSep => true, - Pound => true, // for expression attributes + ModSep => true, // global path + Pound => true, // expression attributes Interpolated(ref nt) => match **nt { - NtExpr(..) => true, - NtIdent(..) => true, - NtBlock(..) => true, - NtPath(..) => true, + NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true, _ => false, }, _ => false, @@ -210,20 +221,20 @@ impl Token { /// Returns `true` if the token can appear at the start of a type. pub fn can_begin_type(&self) -> bool { match *self { + Ident(ident) => ident_can_begin_type(ident), // type name or keyword OpenDelim(Paren) => true, // tuple OpenDelim(Bracket) => true, // array - Ident(..) => true, // type name or keyword Underscore => true, // placeholder Not => true, // never BinOp(Star) => true, // raw pointer BinOp(And) => true, // reference AndAnd => true, // double reference + Question => true, // maybe bound in trait object + Lifetime(..) => true, // lifetime bound in trait object Lt | BinOp(Shl) => true, // associated path ModSep => true, // global path Interpolated(ref nt) => match **nt { - NtTy(..) => true, - NtIdent(..) => true, - NtPath(..) => true, + NtIdent(..) | NtTy(..) | NtPath(..) => true, _ => false, }, _ => false, @@ -238,14 +249,22 @@ impl Token { } } - /// Returns `true` if the token is an identifier. - pub fn is_ident(&self) -> bool { + pub fn ident(&self) -> Option<ast::Ident> { match *self { - Ident(..) => true, - _ => false, + 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 { + self.ident().is_some() + } + /// Returns `true` if the token is a documentation comment. pub fn is_doc_comment(&self) -> bool { match *self { @@ -297,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, } } @@ -319,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, } } @@ -349,7 +363,7 @@ pub enum Nonterminal { /// Stuff inside brackets for attributes NtMeta(ast::MetaItem), NtPath(ast::Path), - NtTT(tokenstream::TokenTree), + NtTT(TokenTree), // These are not exposed to macros, but are used by quasiquote. NtArm(ast::Arm), NtImplItem(ast::ImplItem), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 83753f398a3..e7feff2b79f 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -28,7 +28,7 @@ use ptr::P; use std_inject; use symbol::{Symbol, keywords}; use syntax_pos::DUMMY_SP; -use tokenstream::{self, TokenTree}; +use tokenstream::{self, TokenStream, TokenTree}; use std::ascii; use std::io::{self, Write, Read}; @@ -329,6 +329,10 @@ pub fn tts_to_string(tts: &[tokenstream::TokenTree]) -> String { to_string(|s| s.print_tts(tts.iter().cloned().collect())) } +pub fn tokens_to_string(tokens: TokenStream) -> String { + to_string(|s| s.print_tts(tokens)) +} + pub fn stmt_to_string(stmt: &ast::Stmt) -> String { to_string(|s| s.print_stmt(stmt)) } @@ -750,7 +754,21 @@ pub trait PrintState<'a> { ast::AttrStyle::Inner => word(self.writer(), "#![")?, ast::AttrStyle::Outer => word(self.writer(), "#[")?, } - self.print_meta_item(&attr.meta())?; + if let Some(mi) = attr.meta() { + self.print_meta_item(&mi)? + } else { + for (i, segment) in attr.path.segments.iter().enumerate() { + if i > 0 { + word(self.writer(), "::")? + } + if segment.identifier.name != keywords::CrateRoot.name() && + segment.identifier.name != "$crate" { + word(self.writer(), &segment.identifier.name.as_str())?; + } + } + space(self.writer())?; + self.print_tts(attr.tokens.clone())?; + } word(self.writer(), "]") } } @@ -789,6 +807,45 @@ pub trait PrintState<'a> { self.end() } + /// This doesn't deserve to be called "pretty" printing, but it should be + /// meaning-preserving. A quick hack that might help would be to look at the + /// spans embedded in the TTs to decide where to put spaces and newlines. + /// But it'd be better to parse these according to the grammar of the + /// appropriate macro, transcribe back into the grammar we just parsed from, + /// and then pretty-print the resulting AST nodes (so, e.g., we print + /// expression arguments as expressions). It can be done! I think. + fn print_tt(&mut self, tt: tokenstream::TokenTree) -> io::Result<()> { + match tt { + TokenTree::Token(_, ref tk) => { + word(self.writer(), &token_to_string(tk))?; + match *tk { + parse::token::DocComment(..) => { + hardbreak(self.writer()) + } + _ => Ok(()) + } + } + TokenTree::Delimited(_, ref delimed) => { + word(self.writer(), &token_to_string(&delimed.open_token()))?; + space(self.writer())?; + self.print_tts(delimed.stream())?; + space(self.writer())?; + word(self.writer(), &token_to_string(&delimed.close_token())) + }, + } + } + + fn print_tts(&mut self, tts: tokenstream::TokenStream) -> io::Result<()> { + self.ibox(0)?; + for (i, tt) in tts.into_trees().enumerate() { + if i != 0 { + space(self.writer())?; + } + self.print_tt(tt)?; + } + self.end() + } + fn space_if_not_bol(&mut self) -> io::Result<()> { if !self.is_bol() { space(self.writer())?; } Ok(()) @@ -1038,6 +1095,9 @@ impl<'a> State<'a> { ast::TyKind::Infer => { word(&mut self.s, "_")?; } + ast::TyKind::Err => { + word(&mut self.s, "?")?; + } ast::TyKind::ImplicitSelf => { word(&mut self.s, "Self")?; } @@ -1458,45 +1518,6 @@ impl<'a> State<'a> { } } - /// This doesn't deserve to be called "pretty" printing, but it should be - /// meaning-preserving. A quick hack that might help would be to look at the - /// spans embedded in the TTs to decide where to put spaces and newlines. - /// But it'd be better to parse these according to the grammar of the - /// appropriate macro, transcribe back into the grammar we just parsed from, - /// and then pretty-print the resulting AST nodes (so, e.g., we print - /// expression arguments as expressions). It can be done! I think. - pub fn print_tt(&mut self, tt: tokenstream::TokenTree) -> io::Result<()> { - match tt { - TokenTree::Token(_, ref tk) => { - word(&mut self.s, &token_to_string(tk))?; - match *tk { - parse::token::DocComment(..) => { - hardbreak(&mut self.s) - } - _ => Ok(()) - } - } - TokenTree::Delimited(_, ref delimed) => { - word(&mut self.s, &token_to_string(&delimed.open_token()))?; - space(&mut self.s)?; - self.print_tts(delimed.stream())?; - space(&mut self.s)?; - word(&mut self.s, &token_to_string(&delimed.close_token())) - }, - } - } - - pub fn print_tts(&mut self, tts: tokenstream::TokenStream) -> io::Result<()> { - self.ibox(0)?; - for (i, tt) in tts.into_trees().enumerate() { - if i != 0 { - space(&mut self.s)?; - } - self.print_tt(tt)?; - } - self.end() - } - pub fn print_variant(&mut self, v: &ast::Variant) -> io::Result<()> { self.head("")?; let generics = ast::Generics::default(); diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 58750158931..15111bbba0a 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -43,6 +43,8 @@ use std::{mem, ptr, slice, vec}; use serialize::{Encodable, Decodable, Encoder, Decoder}; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; /// An owned smart pointer. #[derive(Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct P<T: ?Sized> { @@ -215,3 +217,13 @@ impl<T: Decodable> Decodable for P<[T]> { })) } } + +impl<CTX, T> HashStable<CTX> for P<T> + where T: ?Sized + HashStable<CTX> +{ + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut CTX, + hasher: &mut StableHasher<W>) { + (**self).hash_stable(hcx, hasher); + } +} diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 2192d203cdc..c7820a15fb3 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -10,28 +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> { @@ -44,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, @@ -66,15 +62,12 @@ 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, - value: ast::MetaItem { - name: Symbol::intern("prelude_import"), - node: ast::MetaItemKind::Word, - span: span, - }, + path: ast::Path::from_ident(span, ast::Ident::from_str("prelude_import")), + tokens: TokenStream::empty(), id: attr::mk_attr_id(), is_sugared_doc: false, span: span, diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs deleted file mode 100644 index 6642c60d256..00000000000 --- a/src/libsyntax/symbol.rs +++ /dev/null @@ -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)); - } -} diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index e052d2cda3a..50380626d7f 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -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 } } diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs index c6d6e6237f2..c537a0ee166 100644 --- a/src/libsyntax/test_snippet.rs +++ b/src/libsyntax/test_snippet.rs @@ -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, } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 2da442a1a53..86bfdebe42b 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -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()) } @@ -162,6 +164,12 @@ impl From<TokenTree> for TokenStream { } } +impl From<Token> for TokenStream { + fn from(token: Token) -> TokenStream { + TokenTree::Token(DUMMY_SP, token).into() + } +} + impl<T: Into<TokenStream>> iter::FromIterator<T> for TokenStream { fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self { TokenStream::concat(iter.into_iter().map(Into::into).collect::<Vec<_>>()) @@ -360,7 +368,7 @@ impl PartialEq<ThinTokenStream> for ThinTokenStream { impl fmt::Display for TokenStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&pprust::tts_to_string(&self.trees().collect::<Vec<_>>())) + f.write_str(&pprust::tokens_to_string(self.clone())) } } @@ -419,7 +427,7 @@ mod tests { Span { lo: BytePos(a), hi: BytePos(b), - expn_id: NO_EXPANSION, + ctxt: NO_EXPANSION, } } diff --git a/src/libsyntax/util/rc_slice.rs b/src/libsyntax/util/rc_slice.rs index 195fb23f9d8..2d9fd7aa875 100644 --- a/src/libsyntax/util/rc_slice.rs +++ b/src/libsyntax/util/rc_slice.rs @@ -12,6 +12,9 @@ use std::fmt; use std::ops::Deref; use std::rc::Rc; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; + #[derive(Clone)] pub struct RcSlice<T> { data: Rc<Box<[T]>>, @@ -41,3 +44,13 @@ impl<T: fmt::Debug> fmt::Debug for RcSlice<T> { fmt::Debug::fmt(self.deref(), f) } } + +impl<CTX, T> HashStable<CTX> for RcSlice<T> + where T: HashStable<CTX> +{ + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut CTX, + hasher: &mut StableHasher<W>) { + (**self).hash_stable(hcx, hasher); + } +} diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a5333f3bb6a..b5e9a1892ac 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -350,7 +350,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { TyKind::Typeof(ref expression) => { visitor.visit_expr(expression) } - TyKind::Infer | TyKind::ImplicitSelf => {} + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} TyKind::Mac(ref mac) => { visitor.visit_mac(mac) } |
