diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2016-12-27 17:02:52 -0800 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2016-12-27 17:02:52 -0800 |
| commit | e766c465d2e4c4e3c106bfa8343cbe6f9192d445 (patch) | |
| tree | 821a7cf1e0b04ac9c0cddede6eb760bbf2d0ce62 /src/libsyntax | |
| parent | 96c52d4fd86aed6320732a511c04bcbfff7d117f (diff) | |
| parent | 314c28b729ae359b99586cc62c486c28e0d44424 (diff) | |
| download | rust-e766c465d2e4c4e3c106bfa8343cbe6f9192d445.tar.gz rust-e766c465d2e4c4e3c106bfa8343cbe6f9192d445.zip | |
Merge branch 'master' into escape-reason-docs
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 142 | ||||
| -rw-r--r-- | src/libsyntax/attr.rs | 30 | ||||
| -rw-r--r-- | src/libsyntax/ext/base.rs | 10 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 55 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 81 | ||||
| -rw-r--r-- | src/libsyntax/ext/hygiene.rs | 18 | ||||
| -rw-r--r-- | src/libsyntax/ext/placeholders.rs | 52 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/macro_parser.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/ext/tt/macro_rules.rs | 56 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 34 | ||||
| -rw-r--r-- | src/libsyntax/parse/mod.rs | 63 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 90 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 77 | ||||
| -rw-r--r-- | src/libsyntax/std_inject.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax/symbol.rs | 3 | ||||
| -rw-r--r-- | src/libsyntax/test.rs | 6 | ||||
| -rw-r--r-- | src/libsyntax/tokenstream.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 5 |
19 files changed, 294 insertions, 453 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2a911aceb9d..a5abdd922d6 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -47,10 +47,14 @@ impl 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)) - } + /// 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 { @@ -107,10 +111,8 @@ pub struct LifetimeDef { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] pub struct Path { pub span: Span, - /// A `::foo` path, is relative to the crate root rather than current - /// module (like paths in an import). - pub global: bool, /// The segments in the path: the things separated by `::`. + /// Global paths begin with `keywords::CrateRoot`. pub segments: Vec<PathSegment>, } @@ -132,14 +134,21 @@ impl Path { pub fn from_ident(s: Span, identifier: Ident) -> Path { Path { span: s, - global: false, - segments: vec![ - PathSegment { - identifier: identifier, - parameters: PathParameters::none() - } - ], + segments: vec![identifier.into()], + } + } + + pub fn default_to_global(mut self) -> Path { + let name = self.segments[0].identifier.name; + if !self.is_global() && name != "$crate" && + name != keywords::SelfValue.name() && name != keywords::Super.name() { + self.segments.insert(0, PathSegment::crate_root()); } + self + } + + pub fn is_global(&self) -> bool { + !self.segments.is_empty() && self.segments[0].identifier.name == keywords::CrateRoot.name() } } @@ -156,7 +165,24 @@ pub struct PathSegment { /// this is more than just simple syntactic sugar; the use of /// parens affects the region binding rules, so we preserve the /// distinction. - pub parameters: PathParameters, + /// The `Option<P<..>>` wrapper is purely a size optimization; + /// `None` is used to represent both `Path` and `Path<>`. + pub parameters: Option<P<PathParameters>>, +} + +impl From<Ident> for PathSegment { + fn from(id: Ident) -> Self { + PathSegment { identifier: id, parameters: None } + } +} + +impl PathSegment { + pub fn crate_root() -> Self { + PathSegment { + identifier: keywords::CrateRoot.ident(), + parameters: None, + } + } } /// Parameters of a path segment. @@ -170,79 +196,8 @@ pub enum PathParameters { Parenthesized(ParenthesizedParameterData), } -impl PathParameters { - pub fn none() -> PathParameters { - PathParameters::AngleBracketed(AngleBracketedParameterData { - lifetimes: Vec::new(), - types: P::new(), - bindings: P::new(), - }) - } - - pub fn is_empty(&self) -> bool { - match *self { - PathParameters::AngleBracketed(ref data) => data.is_empty(), - - // Even if the user supplied no types, something like - // `X()` is equivalent to `X<(),()>`. - PathParameters::Parenthesized(..) => false, - } - } - - pub fn has_lifetimes(&self) -> bool { - match *self { - PathParameters::AngleBracketed(ref data) => !data.lifetimes.is_empty(), - PathParameters::Parenthesized(_) => false, - } - } - - pub fn has_types(&self) -> bool { - match *self { - PathParameters::AngleBracketed(ref data) => !data.types.is_empty(), - PathParameters::Parenthesized(..) => true, - } - } - - /// Returns the types that the user wrote. Note that these do not necessarily map to the type - /// parameters in the parenthesized case. - pub fn types(&self) -> Vec<&P<Ty>> { - match *self { - PathParameters::AngleBracketed(ref data) => { - data.types.iter().collect() - } - PathParameters::Parenthesized(ref data) => { - data.inputs.iter() - .chain(data.output.iter()) - .collect() - } - } - } - - pub fn lifetimes(&self) -> Vec<&Lifetime> { - match *self { - PathParameters::AngleBracketed(ref data) => { - data.lifetimes.iter().collect() - } - PathParameters::Parenthesized(_) => { - Vec::new() - } - } - } - - pub fn bindings(&self) -> Vec<&TypeBinding> { - match *self { - PathParameters::AngleBracketed(ref data) => { - data.bindings.iter().collect() - } - PathParameters::Parenthesized(_) => { - Vec::new() - } - } - } -} - /// A path like `Foo<'a, T>` -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Default)] pub struct AngleBracketedParameterData { /// The lifetime parameters for this path segment. pub lifetimes: Vec<Lifetime>, @@ -254,9 +209,10 @@ pub struct AngleBracketedParameterData { pub bindings: P<[TypeBinding]>, } -impl AngleBracketedParameterData { - fn is_empty(&self) -> bool { - self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty() +impl Into<Option<P<PathParameters>>> for AngleBracketedParameterData { + fn into(self) -> Option<P<PathParameters>> { + let empty = self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty(); + if empty { None } else { Some(P(PathParameters::AngleBracketed(self))) } } } @@ -1822,10 +1778,6 @@ impl VariantData { } } -/* - FIXME (#3300): Should allow items to be anonymous. Right now - we just use dummy names for anon items. - */ /// An item /// /// The name might be a dummy name in case of anonymous items @@ -1968,8 +1920,6 @@ pub struct MacroDef { pub attrs: Vec<Attribute>, pub id: NodeId, pub span: Span, - pub imported_from: Option<Ident>, - pub allow_internal_unstable: bool, pub body: Vec<TokenTree>, } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 45c120e0b95..c31bcfbd869 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -29,7 +29,6 @@ use symbol::Symbol; use util::ThinVec; use std::cell::{RefCell, Cell}; -use std::collections::HashSet; thread_local! { static USED_ATTRS: RefCell<Vec<u64>> = RefCell::new(Vec::new()); @@ -372,16 +371,6 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute } } -pub fn mk_doc_attr_outer(id: AttrId, item: MetaItem, is_sugared_doc: bool) -> Attribute { - Attribute { - id: id, - style: ast::AttrStyle::Outer, - value: item, - is_sugared_doc: is_sugared_doc, - span: DUMMY_SP, - } -} - pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, lo: BytePos, hi: BytePos) -> Attribute { let style = doc_comment_style(&text.as_str()); @@ -421,13 +410,6 @@ pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option<S .and_then(|at| at.value_str()) } -pub fn last_meta_item_value_str_by_name(items: &[MetaItem], name: &str) -> Option<Symbol> { - items.iter() - .rev() - .find(|mi| mi.check_name(name)) - .and_then(|i| i.value_str()) -} - /* Higher-level applications */ pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> { @@ -856,18 +838,6 @@ pub fn find_deprecation(diagnostic: &Handler, attrs: &[Attribute], find_deprecation_generic(diagnostic, attrs.iter(), item_sp) } -pub fn require_unique_names(diagnostic: &Handler, metas: &[MetaItem]) { - let mut set = HashSet::new(); - for meta in metas { - let name = meta.name(); - - if !set.insert(name.clone()) { - panic!(diagnostic.span_fatal(meta.span, - &format!("duplicate meta item `{}`", name))); - } - } -} - /// Parse #[repr(...)] forms. /// diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index ddbca47429d..68d261c64f8 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -217,8 +217,7 @@ pub trait IdentMacroExpander { cx: &'cx mut ExtCtxt, sp: Span, ident: ast::Ident, - token_tree: Vec<tokenstream::TokenTree>, - attrs: Vec<ast::Attribute>) + token_tree: Vec<tokenstream::TokenTree>) -> Box<MacResult+'cx>; } @@ -234,8 +233,7 @@ impl<F> IdentMacroExpander for F cx: &'cx mut ExtCtxt, sp: Span, ident: ast::Ident, - token_tree: Vec<tokenstream::TokenTree>, - _attrs: Vec<ast::Attribute>) + token_tree: Vec<tokenstream::TokenTree>) -> Box<MacResult+'cx> { (*self)(cx, sp, ident, token_tree) @@ -518,9 +516,9 @@ pub trait Resolver { fn next_node_id(&mut self) -> ast::NodeId; fn get_module_scope(&mut self, id: ast::NodeId) -> Mark; fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item>; + fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool; fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion); - fn add_macro(&mut self, scope: Mark, def: ast::MacroDef, export: bool); fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>); fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>); @@ -542,9 +540,9 @@ impl Resolver for DummyResolver { fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID } fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() } fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> { item } + fn is_whitelisted_legacy_custom_derive(&self, _name: Name) -> bool { false } fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {} - fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef, _export: bool) {} fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {} fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec<Mark>) {} diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index a208b934d79..7584fa3916d 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -11,7 +11,7 @@ use abi::Abi; use ast::{self, Ident, Generics, Expr, BlockCheckMode, UnOp, PatKind}; use attr; -use syntax_pos::{Span, DUMMY_SP, Pos}; +use syntax_pos::{Span, DUMMY_SP}; use codemap::{dummy_spanned, respan, Spanned}; use ext::base::ExtCtxt; use ptr::P; @@ -322,24 +322,24 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: Vec<ast::TypeBinding> ) -> ast::Path { let last_identifier = idents.pop().unwrap(); - let mut segments: Vec<ast::PathSegment> = idents.into_iter() - .map(|ident| { - ast::PathSegment { - identifier: ident, - parameters: ast::PathParameters::none(), - } - }).collect(); - segments.push(ast::PathSegment { - identifier: last_identifier, - parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { + let mut segments: Vec<ast::PathSegment> = Vec::new(); + if global { + segments.push(ast::PathSegment::crate_root()); + } + + segments.extend(idents.into_iter().map(Into::into)); + let parameters = if lifetimes.is_empty() && types.is_empty() && bindings.is_empty() { + None + } else { + Some(P(ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { lifetimes: lifetimes, types: P::from_vec(types), bindings: P::from_vec(bindings), - }) - }); + }))) + }; + segments.push(ast::PathSegment { identifier: last_identifier, parameters: parameters }); ast::Path { span: sp, - global: global, segments: segments, } } @@ -367,13 +367,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: Vec<ast::TypeBinding>) -> (ast::QSelf, ast::Path) { let mut path = trait_path; + let parameters = ast::AngleBracketedParameterData { + lifetimes: lifetimes, + types: P::from_vec(types), + bindings: P::from_vec(bindings), + }; path.segments.push(ast::PathSegment { identifier: ident, - parameters: ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { - lifetimes: lifetimes, - types: P::from_vec(types), - bindings: P::from_vec(bindings), - }) + parameters: Some(P(ast::PathParameters::AngleBracketed(parameters))), }); (ast::QSelf { @@ -659,23 +660,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn expr_field_access(&self, sp: Span, expr: P<ast::Expr>, ident: ast::Ident) -> P<ast::Expr> { - let field_span = Span { - lo: sp.lo - Pos::from_usize(ident.name.as_str().len()), - hi: sp.hi, - expn_id: sp.expn_id, - }; - - let id = Spanned { node: ident, span: field_span }; + let id = Spanned { node: ident, span: sp }; self.expr(sp, ast::ExprKind::Field(expr, id)) } fn expr_tup_field_access(&self, sp: Span, expr: P<ast::Expr>, idx: usize) -> P<ast::Expr> { - let field_span = Span { - lo: sp.lo - Pos::from_usize(idx.to_string().len()), - hi: sp.hi, - expn_id: sp.expn_id, - }; - - let id = Spanned { node: idx, span: field_span }; + let id = Spanned { node: idx, span: sp }; self.expr(sp, ast::ExprKind::TupField(expr, id)) } fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index e3979926680..5d62175fbf2 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -158,7 +158,6 @@ pub struct Invocation { pub enum InvocationKind { Bang { - attrs: Vec<ast::Attribute>, mac: ast::Mac, ident: Option<Ident>, span: Span, @@ -276,7 +275,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { if expansions.len() < depth { expansions.push(Vec::new()); } - expansions[depth - 1].push((mark.as_u32(), expansion)); + expansions[depth - 1].push((mark, expansion)); if !self.cx.ecfg.single_step { invocations.extend(new_invocations.into_iter().rev()); } @@ -287,7 +286,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic); while let Some(expansions) = expansions.pop() { for (mark, expansion) in expansions.into_iter().rev() { - placeholder_expander.add(ast::NodeId::from_u32(mark), expansion); + placeholder_expander.add(mark.as_placeholder_id(), expansion); } } @@ -386,20 +385,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { /// Expand a macro invocation. Returns the result of expansion. fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) -> Expansion { let (mark, kind) = (invoc.expansion_data.mark, invoc.expansion_kind); - let (attrs, mac, ident, span) = match invoc.kind { - InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span), + let (mac, ident, span) = match invoc.kind { + InvocationKind::Bang { mac, ident, span } => (mac, ident, span), _ => unreachable!(), }; let Mac_ { path, tts, .. } = mac.node; - // Detect use of feature-gated or invalid attributes on macro invoations - // since they will not be detected after macro expansion. - for attr in attrs.iter() { - feature_gate::check_attribute(&attr, &self.cx.parse_sess, - &self.cx.parse_sess.codemap(), - &self.cx.ecfg.features.unwrap()); - } - let extname = path.segments.last().unwrap().identifier.name; let ident = ident.unwrap_or(keywords::Invalid.ident()); let marked_tts = mark_tts(&tts, mark); @@ -440,7 +431,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } }); - kind.make_from(expander.expand(self.cx, span, ident, marked_tts, attrs)) + kind.make_from(expander.expand(self.cx, span, ident, marked_tts)) } MultiDecorator(..) | MultiModifier(..) | SyntaxExtension::AttrProcMacro(..) => { @@ -595,13 +586,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { ..self.cx.current_expansion.clone() }, }); - placeholder(expansion_kind, ast::NodeId::from_u32(mark.as_u32())) + placeholder(expansion_kind, mark.as_placeholder_id()) } - fn collect_bang( - &mut self, mac: ast::Mac, attrs: Vec<ast::Attribute>, span: Span, kind: ExpansionKind, - ) -> Expansion { - self.collect(kind, InvocationKind::Bang { attrs: attrs, mac: mac, ident: None, span: span }) + fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: ExpansionKind) -> Expansion { + self.collect(kind, InvocationKind::Bang { mac: mac, ident: None, span: span }) } fn collect_attr(&mut self, attr: ast::Attribute, item: Annotatable, kind: ExpansionKind) @@ -622,6 +611,16 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> { self.cfg.configure(node) } + + // 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); + } + } } // These are pretty nasty. Ideally, we would keep the tokens around, linked from @@ -650,7 +649,7 @@ fn string_to_tts(text: String, parse_sess: &ParseSess) -> Vec<TokenTree> { .new_filemap(String::from("<macro expansion>"), None, text); let lexer = lexer::StringReader::new(&parse_sess.span_diagnostic, filemap); - let mut parser = Parser::new(parse_sess, Box::new(lexer)); + let mut parser = Parser::new(parse_sess, Box::new(lexer), None, false); panictry!(parser.parse_all_token_trees()) } @@ -660,7 +659,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { expr.node = self.cfg.configure_expr_kind(expr.node); if let ast::ExprKind::Mac(mac) = expr.node { - self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr).make_expr() + self.check_attributes(&expr.attrs); + self.collect_bang(mac, expr.span, ExpansionKind::Expr).make_expr() } else { P(noop_fold_expr(expr, self)) } @@ -671,8 +671,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { expr.node = self.cfg.configure_expr_kind(expr.node); if let ast::ExprKind::Mac(mac) = expr.node { - self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr) - .make_opt_expr() + self.check_attributes(&expr.attrs); + self.collect_bang(mac, expr.span, ExpansionKind::OptExpr).make_opt_expr() } else { Some(P(noop_fold_expr(expr, self))) } @@ -685,8 +685,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } pat.and_then(|pat| match pat.node { - PatKind::Mac(mac) => - self.collect_bang(mac, Vec::new(), pat.span, ExpansionKind::Pat).make_pat(), + PatKind::Mac(mac) => self.collect_bang(mac, pat.span, ExpansionKind::Pat).make_pat(), _ => unreachable!(), }) } @@ -707,8 +706,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { }).collect() }; - let mut placeholder = - self.collect_bang(mac, attrs.into(), stmt.span, ExpansionKind::Stmts).make_stmts(); + self.check_attributes(&attrs); + let mut placeholder = self.collect_bang(mac, stmt.span, ExpansionKind::Stmts).make_stmts(); // If this is a macro invocation with a semicolon, then apply that // semicolon to the final statement produced by expansion. @@ -740,18 +739,21 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { match item.node { ast::ItemKind::Mac(..) => { - if match item.node { - ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(), - _ => unreachable!(), - } { - return SmallVector::one(item); - } + self.check_attributes(&item.attrs); + let is_macro_def = if let ItemKind::Mac(ref mac) = item.node { + mac.node.path.segments[0].identifier.name == "macro_rules" + } else { + unreachable!() + }; - item.and_then(|item| match item.node { + item.and_then(|mut item| match item.node { + ItemKind::Mac(_) if is_macro_def => { + item.id = Mark::fresh().as_placeholder_id(); + SmallVector::one(P(item)) + } ItemKind::Mac(mac) => { self.collect(ExpansionKind::Items, InvocationKind::Bang { mac: mac, - attrs: item.attrs, ident: Some(item.ident), span: item.span, }).make_items() @@ -823,7 +825,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { match item.node { ast::TraitItemKind::Macro(mac) => { let ast::TraitItem { attrs, span, .. } = item; - self.collect_bang(mac, attrs, span, ExpansionKind::TraitItems).make_trait_items() + self.check_attributes(&attrs); + self.collect_bang(mac, span, ExpansionKind::TraitItems).make_trait_items() } _ => fold::noop_fold_trait_item(item, self), } @@ -841,7 +844,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { match item.node { ast::ImplItemKind::Macro(mac) => { let ast::ImplItem { attrs, span, .. } = item; - self.collect_bang(mac, attrs, span, ExpansionKind::ImplItems).make_impl_items() + self.check_attributes(&attrs); + self.collect_bang(mac, span, ExpansionKind::ImplItems).make_impl_items() } _ => fold::noop_fold_impl_item(item, self), } @@ -854,8 +858,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { }; match ty.node { - ast::TyKind::Mac(mac) => - self.collect_bang(mac, Vec::new(), ty.span, ExpansionKind::Ty).make_ty(), + ast::TyKind::Mac(mac) => self.collect_bang(mac, ty.span, ExpansionKind::Ty).make_ty(), _ => unreachable!(), } } diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs index 0fd72277cca..2af5c2ea999 100644 --- a/src/libsyntax/ext/hygiene.rs +++ b/src/libsyntax/ext/hygiene.rs @@ -51,7 +51,11 @@ impl Mark { Mark(id.as_u32()) } - pub fn as_u32(&self) -> u32 { + pub fn as_placeholder_id(self) -> NodeId { + NodeId::from_u32(self.0) + } + + pub fn as_u32(self) -> u32 { self.0 } } @@ -115,12 +119,12 @@ impl SyntaxContext { }) } - /// If `ident` is macro expanded, return the source ident from the macro definition - /// and the mark of the expansion that created the macro definition. - pub fn source(self) -> (Self /* source context */, Mark /* source macro */) { - let macro_def_ctxt = self.data().prev_ctxt.data(); - (macro_def_ctxt.prev_ctxt, macro_def_ctxt.outer_mark) - } + /// If `ident` is macro expanded, return the source ident from the macro definition + /// and the mark of the expansion that created the macro definition. + pub fn source(self) -> (Self /* source context */, Mark /* source macro */) { + let macro_def_ctxt = self.data().prev_ctxt.data(); + (macro_def_ctxt.prev_ctxt, macro_def_ctxt.outer_mark) + } } impl fmt::Debug for SyntaxContext { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 4fe57a8345e..66555d7d95d 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -12,9 +12,10 @@ use ast; use codemap::{DUMMY_SP, dummy_spanned}; use ext::base::ExtCtxt; use ext::expand::{Expansion, ExpansionKind}; +use ext::hygiene::Mark; use fold::*; use ptr::P; -use symbol::{Symbol, keywords}; +use symbol::keywords; use util::move_map::MoveMap; use util::small_vector::SmallVector; @@ -24,7 +25,7 @@ use std::mem; pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { fn mac_placeholder() -> ast::Mac { dummy_spanned(ast::Mac_ { - path: ast::Path { span: DUMMY_SP, global: false, segments: Vec::new() }, + path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, tts: Vec::new(), }) } @@ -68,10 +69,6 @@ pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { } } -pub fn macro_scope_placeholder() -> Expansion { - placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) -} - pub struct PlaceholderExpander<'a, 'b: 'a> { expansions: HashMap<ast::NodeId, Expansion>, cx: &'a mut ExtCtxt<'b>, @@ -100,11 +97,12 @@ 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 { - // Scope placeholder - ast::ItemKind::Mac(_) if item.id == ast::DUMMY_NODE_ID => SmallVector::one(item), - ast::ItemKind::Mac(_) => self.remove(item.id).make_items(), - _ => noop_fold_item(item, self), + ast::ItemKind::Mac(ref mac) if !mac.node.path.segments.is_empty() => {} + ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(), + _ => {} } + + noop_fold_item(item, self) } fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector<ast::TraitItem> { @@ -172,10 +170,10 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { block.stmts = block.stmts.move_flat_map(|mut stmt| { remaining_stmts -= 1; - // Scope placeholder + // `macro_rules!` macro definition if let ast::StmtKind::Item(ref item) = stmt.node { - if let ast::ItemKind::Mac(..) = item.node { - macros.push(item.ident.ctxt.data().outer_mark); + if let ast::ItemKind::Mac(_) = item.node { + macros.push(Mark::from_placeholder_id(item.id)); return None; } } @@ -208,33 +206,13 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { fn fold_mod(&mut self, module: ast::Mod) -> ast::Mod { let mut module = noop_fold_mod(module, self); module.items = module.items.move_flat_map(|item| match item.node { - ast::ItemKind::Mac(_) => None, // remove scope placeholders from modules + ast::ItemKind::Mac(_) if !self.cx.ecfg.keep_macs => None, // remove macro definitions _ => Some(item), }); module } -} -pub fn reconstructed_macro_rules(def: &ast::MacroDef) -> Expansion { - Expansion::Items(SmallVector::one(P(ast::Item { - ident: def.ident, - attrs: def.attrs.clone(), - id: ast::DUMMY_NODE_ID, - node: ast::ItemKind::Mac(ast::Mac { - span: def.span, - node: ast::Mac_ { - path: ast::Path { - span: DUMMY_SP, - global: false, - segments: vec![ast::PathSegment { - identifier: ast::Ident::with_empty_ctxt(Symbol::intern("macro_rules")), - parameters: ast::PathParameters::none(), - }], - }, - tts: def.body.clone(), - } - }), - vis: ast::Visibility::Inherited, - span: def.span, - }))) + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + mac + } } diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 39ffab4dc17..2de31166070 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -83,7 +83,7 @@ use syntax_pos::{self, BytePos, mk_sp, Span}; use codemap::Spanned; use errors::FatalError; use parse::lexer::*; //resolve bug? -use parse::ParseSess; +use parse::{Directory, ParseSess}; use parse::parser::{PathStyle, Parser}; use parse::token::{DocComment, MatchNt, SubstNt}; use parse::token::{Token, Nonterminal}; @@ -407,8 +407,9 @@ fn inner_parse_loop(cur_eis: &mut SmallVector<Box<MatcherPos>>, Success(()) } -pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree]) -> NamedParseResult { - let mut parser = Parser::new_with_doc_flag(sess, Box::new(rdr), true); +pub fn parse(sess: &ParseSess, rdr: TtReader, ms: &[TokenTree], directory: Option<Directory>) + -> NamedParseResult { + let mut parser = Parser::new(sess, Box::new(rdr), directory, true); let mut cur_eis = SmallVector::one(initial_matcher_pos(ms.to_owned(), parser.span.lo)); let mut next_eis = Vec::new(); // or proceed normally diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 4164b4a93ec..3abd24b50ba 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -10,14 +10,13 @@ use {ast, attr}; use syntax_pos::{Span, DUMMY_SP}; -use ext::base::{DummyResult, ExtCtxt, MacEager, MacResult, SyntaxExtension}; -use ext::base::{IdentMacroExpander, NormalTT, TTMacroExpander}; +use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension}; +use ext::base::{NormalTT, TTMacroExpander}; use ext::expand::{Expansion, ExpansionKind}; -use ext::placeholders; use ext::tt::macro_parser::{Success, Error, Failure}; use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; use ext::tt::macro_parser::{parse, parse_failure_msg}; -use parse::ParseSess; +use parse::{Directory, ParseSess}; use parse::lexer::new_tt_reader; use parse::parser::Parser; use parse::token::{self, NtTT, Token}; @@ -116,12 +115,13 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, // rhs has holes ( `$id` and `$(...)` that need filled) let trncbr = new_tt_reader(&cx.parse_sess.span_diagnostic, Some(named_matches), rhs); - let mut p = Parser::new(cx.parse_sess(), Box::new(trncbr)); - let module = &cx.current_expansion.module; - p.directory.path = module.directory.clone(); - p.directory.ownership = cx.current_expansion.directory_ownership; - p.root_module_name = - module.mod_path.last().map(|id| (*id.name.as_str()).to_owned()); + let directory = Directory { + path: cx.current_expansion.module.directory.clone(), + ownership: cx.current_expansion.directory_ownership, + }; + let mut p = Parser::new(cx.parse_sess(), Box::new(trncbr), Some(directory), false); + p.root_module_name = cx.current_expansion.module.mod_path.last() + .map(|id| (*id.name.as_str()).to_owned()); p.check_unknown_macro_variable(); // Let the context choose how to interpret the result. @@ -150,38 +150,6 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, cx.span_fatal(best_fail_spot.substitute_dummy(sp), &best_fail_msg); } -pub struct MacroRulesExpander; -impl IdentMacroExpander for MacroRulesExpander { - fn expand(&self, - cx: &mut ExtCtxt, - span: Span, - ident: ast::Ident, - tts: Vec<tokenstream::TokenTree>, - attrs: Vec<ast::Attribute>) - -> Box<MacResult> { - let export = attr::contains_name(&attrs, "macro_export"); - let def = ast::MacroDef { - ident: ident, - id: ast::DUMMY_NODE_ID, - span: span, - imported_from: None, - body: tts, - allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"), - attrs: attrs, - }; - - // If keep_macs is true, expands to a MacEager::items instead. - let result = if cx.ecfg.keep_macs { - MacEager::items(placeholders::reconstructed_macro_rules(&def).make_items()) - } else { - MacEager::items(placeholders::macro_scope_placeholder().make_items()) - }; - - cx.resolver.add_macro(cx.current_expansion.mark, def, export); - result - } -} - // Note that macro-by-example's input is also matched against a token tree: // $( $lhs:tt => $rhs:tt );+ // @@ -222,7 +190,7 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { // Parse the macro_rules! invocation (`none` is for no interpolations): let arg_reader = new_tt_reader(&sess.span_diagnostic, None, def.body.clone()); - let argument_map = match parse(sess, arg_reader, &argument_gram) { + let argument_map = match parse(sess, arg_reader, &argument_gram, None) { Success(m) => m, Failure(sp, tok) => { let s = parse_failure_msg(tok); @@ -281,7 +249,7 @@ pub fn compile(sess: &ParseSess, def: &ast::MacroDef) -> SyntaxExtension { valid: valid, }); - NormalTT(exp, Some(def.span), def.allow_internal_unstable) + NormalTT(exp, Some(def.span), attr::contains_name(&def.attrs, "allow_internal_unstable")) } fn check_lhs_nt_follows(sess: &ParseSess, lhs: &TokenTree) -> bool { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 77c53542dcb..e04cc11f15e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -304,6 +304,7 @@ declare_features! ( // Allows using `Self` and associated types in struct expressions and patterns. (active, more_struct_aliases, "1.14.0", Some(37544)), + // Allows #[link(..., cfg(..))] (active, link_cfg, "1.14.0", Some(37406)), @@ -314,6 +315,9 @@ declare_features! ( // Allows #[target_feature(...)] (active, target_feature, "1.15.0", None), + + // Allow safe suggestions for potential type conversions. + (active, safe_suggestion, "1.0.0", Some(37384)), ); declare_features! ( diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 6af8efb2a19..9797e0003fc 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -302,23 +302,22 @@ pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P< view_path.map(|Spanned {node, span}| Spanned { node: match node { ViewPathSimple(ident, path) => { - ViewPathSimple(ident, fld.fold_path(path)) + ViewPathSimple(fld.fold_ident(ident), fld.fold_path(path)) } ViewPathGlob(path) => { ViewPathGlob(fld.fold_path(path)) } ViewPathList(path, path_list_idents) => { - ViewPathList(fld.fold_path(path), - path_list_idents.move_map(|path_list_ident| { - Spanned { - node: PathListItem_ { - id: fld.new_id(path_list_ident.node.id), - rename: path_list_ident.node.rename, - name: path_list_ident.node.name, - }, - span: fld.new_span(path_list_ident.span) - } - })) + let path = fld.fold_path(path); + let path_list_idents = path_list_idents.move_map(|path_list_ident| Spanned { + node: PathListItem_ { + id: fld.new_id(path_list_ident.node.id), + rename: path_list_ident.node.rename.map(|ident| fld.fold_ident(ident)), + name: fld.fold_ident(path_list_ident.node.name), + }, + span: fld.new_span(path_list_ident.span) + }); + ViewPathList(path, path_list_idents) } }, span: fld.new_span(span) @@ -345,7 +344,7 @@ pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body}: Arm, fld: &mut T pub fn noop_fold_ty_binding<T: Folder>(b: TypeBinding, fld: &mut T) -> TypeBinding { TypeBinding { id: fld.new_id(b.id), - ident: b.ident, + ident: fld.fold_ident(b.ident), ty: fld.fold_ty(b.ty), span: fld.new_span(b.span), } @@ -433,12 +432,11 @@ pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize { i } -pub fn noop_fold_path<T: Folder>(Path {global, segments, span}: Path, fld: &mut T) -> Path { +pub fn noop_fold_path<T: Folder>(Path { segments, span }: Path, fld: &mut T) -> Path { Path { - global: global, segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment { identifier: fld.fold_ident(identifier), - parameters: fld.fold_path_parameters(parameters), + parameters: parameters.map(|ps| ps.map(|ps| fld.fold_path_parameters(ps))), }), span: fld.new_span(span) } @@ -673,7 +671,7 @@ pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam { .collect::<Vec<_>>() .into(), id: fld.new_id(id), - ident: ident, + ident: fld.fold_ident(ident), bounds: fld.fold_bounds(bounds), default: default.map(|x| fld.fold_ty(x)), span: span @@ -1088,7 +1086,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> { let fs = fields.move_map(|f| { Spanned { span: folder.new_span(f.span), node: ast::FieldPat { - ident: f.node.ident, + ident: folder.fold_ident(f.node.ident), pat: folder.fold_pat(f.node.pat), is_shorthand: f.node.is_shorthand, }} diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index e5b66f88958..24178e1f675 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -222,14 +222,14 @@ pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>) // it appears to me that the cfg doesn't matter here... indeed, // parsing tt's probably shouldn't require a parser at all. let srdr = lexer::StringReader::new(&sess.span_diagnostic, filemap); - let mut p1 = Parser::new(sess, Box::new(srdr)); + let mut p1 = Parser::new(sess, Box::new(srdr), None, false); panictry!(p1.parse_all_token_trees()) } /// Given tts and the ParseSess, produce a parser pub fn tts_to_parser<'a>(sess: &'a ParseSess, tts: Vec<tokenstream::TokenTree>) -> Parser<'a> { let trdr = lexer::new_tt_reader(&sess.span_diagnostic, None, tts); - let mut p = Parser::new(sess, Box::new(trdr)); + let mut p = Parser::new(sess, Box::new(trdr), None, false); p.check_unknown_macro_variable(); p } @@ -633,13 +633,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 1), - global: false, - segments: vec![ - ast::PathSegment { - identifier: Ident::from_str("a"), - parameters: ast::PathParameters::none(), - } - ], + segments: vec![Ident::from_str("a").into()], }), span: sp(0, 1), attrs: ThinVec::new(), @@ -651,19 +645,11 @@ mod tests { P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { - span: sp(0, 6), - global: true, - segments: vec![ - ast::PathSegment { - identifier: Ident::from_str("a"), - parameters: ast::PathParameters::none(), - }, - ast::PathSegment { - identifier: Ident::from_str("b"), - parameters: ast::PathParameters::none(), - } - ] - }), + span: sp(0, 6), + segments: vec![ast::PathSegment::crate_root(), + Ident::from_str("a").into(), + Ident::from_str("b").into()] + }), span: sp(0, 6), attrs: ThinVec::new(), })) @@ -771,13 +757,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node:ast::ExprKind::Path(None, ast::Path{ span: sp(7, 8), - global: false, - segments: vec![ - ast::PathSegment { - identifier: Ident::from_str("d"), - parameters: ast::PathParameters::none(), - } - ], + segments: vec![Ident::from_str("d").into()], }), span:sp(7,8), attrs: ThinVec::new(), @@ -794,13 +774,7 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span:sp(0,1), - global:false, - segments: vec![ - ast::PathSegment { - identifier: Ident::from_str("b"), - parameters: ast::PathParameters::none(), - } - ], + segments: vec![Ident::from_str("b").into()], }), span: sp(0,1), attrs: ThinVec::new()})), @@ -841,13 +815,7 @@ mod tests { ty: P(ast::Ty{id: ast::DUMMY_NODE_ID, node: ast::TyKind::Path(None, ast::Path{ span:sp(10,13), - global:false, - segments: vec![ - ast::PathSegment { - identifier: Ident::from_str("i32"), - parameters: ast::PathParameters::none(), - } - ], + segments: vec![Ident::from_str("i32").into()], }), span:sp(10,13) }), @@ -889,14 +857,7 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path{ span:sp(17,18), - global:false, - segments: vec![ - ast::PathSegment { - identifier: Ident::from_str("b"), - parameters: - ast::PathParameters::none(), - } - ], + segments: vec![Ident::from_str("b").into()], }), span: sp(17,18), attrs: ThinVec::new()})), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index bdd1606805f..a0ed50b33a4 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -267,12 +267,11 @@ impl From<P<Expr>> for LhsExpr { } impl<'a> Parser<'a> { - pub fn new(sess: &'a ParseSess, rdr: Box<Reader+'a>) -> Self { - Parser::new_with_doc_flag(sess, rdr, false) - } - - pub fn new_with_doc_flag(sess: &'a ParseSess, rdr: Box<Reader+'a>, desugar_doc_comments: bool) - -> Self { + pub fn new(sess: &'a ParseSess, + rdr: Box<Reader+'a>, + directory: Option<Directory>, + desugar_doc_comments: bool) + -> Self { let mut parser = Parser { reader: rdr, sess: sess, @@ -298,7 +297,9 @@ impl<'a> Parser<'a> { let tok = parser.next_tok(); parser.token = tok.tok; parser.span = tok.sp; - if parser.span != syntax_pos::DUMMY_SP { + if let Some(directory) = directory { + parser.directory = directory; + } else if parser.span != syntax_pos::DUMMY_SP { parser.directory.path = PathBuf::from(sess.codemap().span_to_filename(parser.span)); parser.directory.path.pop(); } @@ -1613,7 +1614,6 @@ impl<'a> Parser<'a> { } else { ast::Path { span: span, - global: false, segments: vec![] } }; @@ -1657,7 +1657,7 @@ impl<'a> Parser<'a> { // Parse any number of segments and bound sets. A segment is an // identifier followed by an optional lifetime and a set of types. // A bound set is a set of type parameter bounds. - let segments = match mode { + let mut segments = match mode { PathStyle::Type => { self.parse_path_segments_without_colons()? } @@ -1669,13 +1669,16 @@ impl<'a> Parser<'a> { } }; + if is_global { + segments.insert(0, ast::PathSegment::crate_root()); + } + // Assemble the span. let span = mk_sp(lo, self.prev_span.hi); // Assemble the result. Ok(ast::Path { span: span, - global: is_global, segments: segments, }) } @@ -1704,12 +1707,11 @@ impl<'a> Parser<'a> { // Parse types, optionally. let parameters = if self.eat_lt() { let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?; - - ast::PathParameters::AngleBracketed(ast::AngleBracketedParameterData { + ast::AngleBracketedParameterData { lifetimes: lifetimes, types: P::from_vec(types), bindings: P::from_vec(bindings), - }) + }.into() } else if self.eat(&token::OpenDelim(token::Paren)) { let lo = self.prev_span.lo; @@ -1726,18 +1728,17 @@ impl<'a> Parser<'a> { let hi = self.prev_span.hi; - ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData { + Some(P(ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData { span: mk_sp(lo, hi), inputs: inputs, output: output_ty, - }) + }))) } else { - ast::PathParameters::none() + None }; // Assemble and push the result. - segments.push(ast::PathSegment { identifier: identifier, - parameters: parameters }); + segments.push(ast::PathSegment { identifier: identifier, parameters: parameters }); // Continue only if we see a `::` if !self.eat(&token::ModSep) { @@ -1756,10 +1757,7 @@ impl<'a> Parser<'a> { // If we do not see a `::`, stop. if !self.eat(&token::ModSep) { - segments.push(ast::PathSegment { - identifier: identifier, - parameters: ast::PathParameters::none() - }); + segments.push(identifier.into()); return Ok(segments); } @@ -1767,14 +1765,13 @@ impl<'a> Parser<'a> { if self.eat_lt() { // Consumed `a::b::<`, go look for types let (lifetimes, types, bindings) = self.parse_generic_values_after_lt()?; - let parameters = ast::AngleBracketedParameterData { - lifetimes: lifetimes, - types: P::from_vec(types), - bindings: P::from_vec(bindings), - }; segments.push(ast::PathSegment { identifier: identifier, - parameters: ast::PathParameters::AngleBracketed(parameters), + parameters: ast::AngleBracketedParameterData { + lifetimes: lifetimes, + types: P::from_vec(types), + bindings: P::from_vec(bindings), + }.into(), }); // Consumed `a::b::<T,U>`, check for `::` before proceeding @@ -1783,10 +1780,7 @@ impl<'a> Parser<'a> { } } else { // Consumed `a::`, go look for `b` - segments.push(ast::PathSegment { - identifier: identifier, - parameters: ast::PathParameters::none(), - }); + segments.push(identifier.into()); } } } @@ -1801,10 +1795,7 @@ impl<'a> Parser<'a> { let identifier = self.parse_path_segment_ident()?; // Assemble and push the result. - segments.push(ast::PathSegment { - identifier: identifier, - parameters: ast::PathParameters::none() - }); + segments.push(identifier.into()); // If we do not see a `::` or see `::{`/`::*`, stop. if !self.check(&token::ModSep) || self.is_import_coupler() { @@ -4173,7 +4164,7 @@ impl<'a> Parser<'a> { })); self.bump(); } - token::ModSep | token::Ident(..) => { + _ if self.token.is_path_start() || self.token.is_keyword(keywords::For) => { let poly_trait_ref = self.parse_poly_trait_ref()?; let modifier = if ate_question { TraitBoundModifier::Maybe @@ -4377,6 +4368,23 @@ impl<'a> Parser<'a> { return Ok(where_clause); } + // This is a temporary hack. + // + // We are considering adding generics to the `where` keyword as an alternative higher-rank + // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking + // change, for now we refuse to parse `where < (ident | lifetime) (> | , | :)`. + if token::Lt == self.token { + let ident_or_lifetime = self.look_ahead(1, |t| t.is_ident() || t.is_lifetime()); + if ident_or_lifetime { + let gt_comma_or_colon = self.look_ahead(2, |t| { + *t == token::Gt || *t == token::Comma || *t == token::Colon + }); + if gt_comma_or_colon { + self.span_err(self.span, "syntax `where<T>` is reserved for future use"); + } + } + } + let mut parsed_something = false; loop { let lo = self.span.lo; @@ -5191,7 +5199,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(keywords::Crate) { pub_crate(self) } else { - let path = self.parse_path(PathStyle::Mod)?; + let path = self.parse_path(PathStyle::Mod)?.default_to_global(); self.expect(&token::CloseDelim(token::Paren))?; Ok(Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }) } @@ -6079,9 +6087,9 @@ impl<'a> Parser<'a> { 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 { - global: self.eat(&token::ModSep), - segments: Vec::new(), + segments: vec![ast::PathSegment::crate_root()], span: mk_sp(lo, self.span.hi), }; let view_path_kind = if self.eat(&token::BinOp(token::Star)) { @@ -6091,7 +6099,7 @@ impl<'a> Parser<'a> { }; Ok(P(spanned(lo, self.span.hi, view_path_kind))) } else { - let prefix = self.parse_path(PathStyle::Mod)?; + let prefix = self.parse_path(PathStyle::Mod)?.default_to_global(); if self.is_import_coupler() { // `foo::bar::{a, b}` or `foo::bar::*` self.bump(); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index c28b9d00501..7558f0256da 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -371,7 +371,7 @@ pub fn fn_block_to_string(p: &ast::FnDecl) -> String { } pub fn path_to_string(p: &ast::Path) -> String { - to_string(|s| s.print_path(p, false, 0)) + to_string(|s| s.print_path(p, false, 0, false)) } pub fn ident_to_string(id: ast::Ident) -> String { @@ -435,7 +435,8 @@ pub fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { match *vis { ast::Visibility::Public => format!("pub {}", s), ast::Visibility::Crate(_) => format!("pub(crate) {}", s), - ast::Visibility::Restricted { ref path, .. } => format!("pub({}) {}", path, s), + ast::Visibility::Restricted { ref path, .. } => + format!("pub({}) {}", to_string(|s| s.print_path(path, false, 0, true)), s), ast::Visibility::Inherited => s.to_string() } } @@ -1021,7 +1022,7 @@ impl<'a> State<'a> { &generics)); } ast::TyKind::Path(None, ref path) => { - try!(self.print_path(path, false, 0)); + try!(self.print_path(path, false, 0, false)); } ast::TyKind::Path(Some(ref qself), ref path) => { try!(self.print_qpath(path, qself, false)) @@ -1332,7 +1333,7 @@ impl<'a> State<'a> { } ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => { try!(self.print_visibility(&item.vis)); - try!(self.print_path(&node.path, false, 0)); + try!(self.print_path(&node.path, false, 0, false)); try!(word(&mut self.s, "! ")); try!(self.print_ident(item.ident)); try!(self.cbox(INDENT_UNIT)); @@ -1347,7 +1348,7 @@ impl<'a> State<'a> { } fn print_trait_ref(&mut self, t: &ast::TraitRef) -> io::Result<()> { - self.print_path(&t.path, false, 0) + self.print_path(&t.path, false, 0, false) } fn print_formal_lifetime_list(&mut self, lifetimes: &[ast::LifetimeDef]) -> io::Result<()> { @@ -1405,8 +1406,10 @@ impl<'a> State<'a> { match *vis { ast::Visibility::Public => self.word_nbsp("pub"), ast::Visibility::Crate(_) => self.word_nbsp("pub(crate)"), - ast::Visibility::Restricted { ref path, .. } => - self.word_nbsp(&format!("pub({})", path)), + ast::Visibility::Restricted { ref path, .. } => { + let path = to_string(|s| s.print_path(path, false, 0, true)); + self.word_nbsp(&format!("pub({})", path)) + } ast::Visibility::Inherited => Ok(()) } } @@ -1571,7 +1574,7 @@ impl<'a> State<'a> { } ast::TraitItemKind::Macro(codemap::Spanned { ref node, .. }) => { // code copied from ItemKind::Mac: - self.print_path(&node.path, false, 0)?; + self.print_path(&node.path, false, 0, false)?; word(&mut self.s, "! ")?; self.cbox(INDENT_UNIT)?; self.popen()?; @@ -1607,7 +1610,7 @@ impl<'a> State<'a> { } ast::ImplItemKind::Macro(codemap::Spanned { ref node, .. }) => { // code copied from ItemKind::Mac: - try!(self.print_path(&node.path, false, 0)); + try!(self.print_path(&node.path, false, 0, false)); try!(word(&mut self.s, "! ")); try!(self.cbox(INDENT_UNIT)); try!(self.popen()); @@ -1793,7 +1796,7 @@ impl<'a> State<'a> { pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken) -> io::Result<()> { - try!(self.print_path(&m.node.path, false, 0)); + try!(self.print_path(&m.node.path, false, 0, false)); try!(word(&mut self.s, "!")); match delim { token::Paren => try!(self.popen()), @@ -1885,7 +1888,7 @@ impl<'a> State<'a> { fields: &[ast::Field], wth: &Option<P<ast::Expr>>, attrs: &[Attribute]) -> io::Result<()> { - try!(self.print_path(path, true, 0)); + try!(self.print_path(path, true, 0, false)); try!(word(&mut self.s, "{")); try!(self.print_inner_attributes_inline(attrs)); try!(self.commasep_cmnt( @@ -2186,7 +2189,7 @@ impl<'a> State<'a> { } } ast::ExprKind::Path(None, ref path) => { - try!(self.print_path(path, true, 0)) + try!(self.print_path(path, true, 0, false)) } ast::ExprKind::Path(Some(ref qself), ref path) => { try!(self.print_qpath(path, qself, true)) @@ -2334,22 +2337,27 @@ impl<'a> State<'a> { fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, - depth: usize) + depth: usize, + defaults_to_global: bool) -> io::Result<()> { try!(self.maybe_print_comment(path.span.lo)); - let mut first = !path.global; - for segment in &path.segments[..path.segments.len()-depth] { - if first { - first = false - } else { + let mut segments = path.segments[..path.segments.len()-depth].iter(); + if defaults_to_global && path.is_global() { + segments.next(); + } + for (i, segment) in segments.enumerate() { + if i > 0 { try!(word(&mut self.s, "::")) } - - try!(self.print_ident(segment.identifier)); - - try!(self.print_path_parameters(&segment.parameters, colons_before_params)); + if segment.identifier.name != keywords::CrateRoot.name() && + segment.identifier.name != "$crate" { + try!(self.print_ident(segment.identifier)); + if let Some(ref parameters) = segment.parameters { + try!(self.print_path_parameters(parameters, colons_before_params)); + } + } } Ok(()) @@ -2367,13 +2375,16 @@ impl<'a> State<'a> { try!(space(&mut self.s)); try!(self.word_space("as")); let depth = path.segments.len() - qself.position; - try!(self.print_path(&path, false, depth)); + try!(self.print_path(&path, false, depth, false)); } try!(word(&mut self.s, ">")); try!(word(&mut self.s, "::")); let item_segment = path.segments.last().unwrap(); try!(self.print_ident(item_segment.identifier)); - self.print_path_parameters(&item_segment.parameters, colons_before_params) + match item_segment.parameters { + Some(ref parameters) => self.print_path_parameters(parameters, colons_before_params), + None => Ok(()), + } } fn print_path_parameters(&mut self, @@ -2381,10 +2392,6 @@ impl<'a> State<'a> { colons_before_params: bool) -> io::Result<()> { - if parameters.is_empty() { - return Ok(()); - } - if colons_before_params { try!(word(&mut self.s, "::")) } @@ -2471,7 +2478,7 @@ impl<'a> State<'a> { } } PatKind::TupleStruct(ref path, ref elts, ddpos) => { - try!(self.print_path(path, true, 0)); + try!(self.print_path(path, true, 0, false)); try!(self.popen()); if let Some(ddpos) = ddpos { try!(self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))); @@ -2489,13 +2496,13 @@ impl<'a> State<'a> { try!(self.pclose()); } PatKind::Path(None, ref path) => { - try!(self.print_path(path, true, 0)); + try!(self.print_path(path, true, 0, false)); } PatKind::Path(Some(ref qself), ref path) => { try!(self.print_qpath(path, qself, false)); } PatKind::Struct(ref path, ref fields, etc) => { - try!(self.print_path(path, true, 0)); + try!(self.print_path(path, true, 0, false)); try!(self.nbsp()); try!(self.word_space("{")); try!(self.commasep_cmnt( @@ -2842,7 +2849,7 @@ impl<'a> State<'a> { try!(self.print_lifetime_bounds(lifetime, bounds)); } ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => { - try!(self.print_path(path, false, 0)); + try!(self.print_path(path, false, 0, false)); try!(space(&mut self.s)); try!(self.word_space("=")); try!(self.print_type(&ty)); @@ -2856,7 +2863,7 @@ impl<'a> State<'a> { pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> io::Result<()> { match vp.node { ast::ViewPathSimple(ident, ref path) => { - try!(self.print_path(path, false, 0)); + try!(self.print_path(path, false, 0, true)); if path.segments.last().unwrap().identifier.name != ident.name { @@ -2869,7 +2876,7 @@ impl<'a> State<'a> { } ast::ViewPathGlob(ref path) => { - try!(self.print_path(path, false, 0)); + try!(self.print_path(path, false, 0, true)); word(&mut self.s, "::*") } @@ -2877,7 +2884,7 @@ impl<'a> State<'a> { if path.segments.is_empty() { try!(word(&mut self.s, "{")); } else { - try!(self.print_path(path, false, 0)); + try!(self.print_path(path, false, 0, true)); try!(word(&mut self.s, "::{")); } try!(self.commasep(Inconsistent, &idents[..], |s, w| { diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 6a291ad9c40..68d807b24a7 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -80,10 +80,8 @@ pub fn maybe_inject_crates_ref(sess: &ParseSess, }], vis: ast::Visibility::Inherited, node: ast::ItemKind::Use(P(codemap::dummy_spanned(ast::ViewPathGlob(ast::Path { - global: false, - segments: vec![name, "prelude", "v1"].into_iter().map(|name| ast::PathSegment { - identifier: ast::Ident::from_str(name), - parameters: ast::PathParameters::none(), + segments: ["{{root}}", name, "prelude", "v1"].into_iter().map(|name| { + ast::Ident::from_str(name).into() }).collect(), span: span, })))), diff --git a/src/libsyntax/symbol.rs b/src/libsyntax/symbol.rs index fe9a176179c..c2123ea5a07 100644 --- a/src/libsyntax/symbol.rs +++ b/src/libsyntax/symbol.rs @@ -221,6 +221,9 @@ declare_keywords! { (53, Default, "default") (54, StaticLifetime, "'static") (55, Union, "union") + + // A virtual keyword that resolves to the crate root when used in a lexical scope. + (56, CrateRoot, "{{root}}") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index fca89e265e4..b8e0b938814 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -579,11 +579,7 @@ fn nospan<T>(t: T) -> codemap::Spanned<T> { fn path_node(ids: Vec<Ident>) -> ast::Path { ast::Path { span: DUMMY_SP, - global: false, - segments: ids.into_iter().map(|identifier| ast::PathSegment { - identifier: identifier, - parameters: ast::PathParameters::none(), - }).collect() + segments: ids.into_iter().map(Into::into).collect(), } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 0d5dcaf339f..e352e7853c7 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -31,7 +31,7 @@ use ext::base; use ext::tt::macro_parser; use parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use parse::lexer; -use parse; +use parse::{self, Directory}; use parse::token::{self, Token, Lit, Nonterminal}; use print::pprust; use symbol::Symbol; @@ -218,7 +218,11 @@ impl TokenTree { let diag = &cx.parse_sess().span_diagnostic; // `None` is because we're not interpolating let arg_rdr = lexer::new_tt_reader(diag, None, tts.iter().cloned().collect()); - macro_parser::parse(cx.parse_sess(), arg_rdr, mtch) + let directory = Directory { + path: cx.current_expansion.module.directory.clone(), + ownership: cx.current_expansion.directory_ownership, + }; + macro_parser::parse(cx.parse_sess(), arg_rdr, mtch, Some(directory)) } /// Check if this TokenTree is equal to the other, regardless of span information. diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 3e0353d532d..ad29cb50a84 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -178,7 +178,6 @@ pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) { pub fn walk_macro_def<'a, V: Visitor<'a>>(visitor: &mut V, macro_def: &'a MacroDef) { visitor.visit_ident(macro_def.span, macro_def.ident); - walk_opt_ident(visitor, macro_def.span, macro_def.imported_from); walk_list!(visitor, visit_attribute, ¯o_def.attrs); } @@ -384,7 +383,9 @@ pub fn walk_path_segment<'a, V: Visitor<'a>>(visitor: &mut V, path_span: Span, segment: &'a PathSegment) { visitor.visit_ident(path_span, segment.identifier); - visitor.visit_path_parameters(path_span, &segment.parameters); + if let Some(ref parameters) = segment.parameters { + visitor.visit_path_parameters(path_span, parameters); + } } pub fn walk_path_parameters<'a, V>(visitor: &mut V, |
