From 0ddf61890bc68409b8e72352a83520940c228b29 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Wed, 31 Aug 2016 13:25:00 -0400 Subject: Don't perform span mangling when building field/tup access nodes There are no guarantees that the two spans used to create the new one come from the same place or are even valid. Fixes #36081. --- src/libsyntax/ext/build.rs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index a208b934d79..6c0d40b69d3 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; @@ -659,23 +659,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> { } fn expr_field_access(&self, sp: Span, expr: P, ident: ast::Ident) -> P { - 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, idx: usize) -> P { - 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) -> P { -- cgit 1.4.1-3-g733a5 From fd98a8d795b17b76ea6d1edcae55d4450efd466f Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 7 Dec 2016 00:28:51 +0000 Subject: macros: fix the expected paths for a non-inline module matched by an `item` fragment. --- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/ext/tt/macro_parser.rs | 7 ++++--- src/libsyntax/ext/tt/macro_rules.rs | 17 +++++++++-------- src/libsyntax/parse/mod.rs | 4 ++-- src/libsyntax/parse/parser.rs | 15 ++++++++------- src/libsyntax/tokenstream.rs | 8 ++++++-- src/test/run-pass/auxiliary/issue_38190.rs | 12 ++++++++++++ src/test/run-pass/issue-38190.rs | 21 +++++++++++++++++++++ 8 files changed, 63 insertions(+), 23 deletions(-) create mode 100644 src/test/run-pass/auxiliary/issue_38190.rs create mode 100644 src/test/run-pass/issue-38190.rs (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 4138acafac6..89865d89bae 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -650,7 +650,7 @@ fn string_to_tts(text: String, parse_sess: &ParseSess) -> Vec { .new_filemap(String::from(""), 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()) } 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>, 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) + -> 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..ca18e580ecd 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -17,7 +17,7 @@ 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 +116,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. @@ -222,7 +223,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); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index bfaf00a3d3f..9263e5e3e4d 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) // 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) -> 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 } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index bdd1606805f..4367f933485 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -267,12 +267,11 @@ impl From> for LhsExpr { } impl<'a> Parser<'a> { - pub fn new(sess: &'a ParseSess, rdr: Box) -> Self { - Parser::new_with_doc_flag(sess, rdr, false) - } - - pub fn new_with_doc_flag(sess: &'a ParseSess, rdr: Box, desugar_doc_comments: bool) - -> Self { + pub fn new(sess: &'a ParseSess, + rdr: Box, + directory: Option, + 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(); } 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/test/run-pass/auxiliary/issue_38190.rs b/src/test/run-pass/auxiliary/issue_38190.rs new file mode 100644 index 00000000000..7fc4390d6dc --- /dev/null +++ b/src/test/run-pass/auxiliary/issue_38190.rs @@ -0,0 +1,12 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_export] +macro_rules! m { ([$i:item]) => {} } diff --git a/src/test/run-pass/issue-38190.rs b/src/test/run-pass/issue-38190.rs new file mode 100644 index 00000000000..ed9bf9e8095 --- /dev/null +++ b/src/test/run-pass/issue-38190.rs @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue_38190.rs +// ignore-pretty issue #37195 + +#[macro_use] +extern crate issue_38190; + +mod auxiliary { + m!([mod issue_38190;]); +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From 90f6219f496596233d504244cfbbdbded7df5a30 Mon Sep 17 00:00:00 2001 From: Without Boats Date: Fri, 9 Dec 2016 10:54:05 -0800 Subject: Prevent where < ident > from parsing. In order to be forward compatible with `where<'a>` syntax for higher rank parameters, prevent potential conflicts with UFCS from parsing correctly for the near term. --- src/libsyntax/parse/parser.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index bdd1606805f..f6cebdc372f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4377,6 +4377,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`. 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 { + return Err(self.fatal("TODO How to even explain this error?")); + } + } + } + let mut parsed_something = false; loop { let lo = self.span.lo; -- cgit 1.4.1-3-g733a5 From ddae271b78b08f2700c839eb220b21654e405f7b Mon Sep 17 00:00:00 2001 From: Without Boats Date: Fri, 9 Dec 2016 20:39:42 -0800 Subject: Improve error message. --- src/libsyntax/parse/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index f6cebdc372f..2c6e6e3fea3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4389,7 +4389,7 @@ impl<'a> Parser<'a> { *t == token::Gt || *t == token::Comma || *t == token::Colon }); if gt_comma_or_colon { - return Err(self.fatal("TODO How to even explain this error?")); + self.err("syntax `where` is reserved for future use"); } } } -- cgit 1.4.1-3-g733a5 From 14e4b00933c13a4c419f2192df11b135d5bb0c85 Mon Sep 17 00:00:00 2001 From: Without Boats Date: Fri, 9 Dec 2016 21:17:58 -0800 Subject: Fix mistake. --- src/libsyntax/parse/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2c6e6e3fea3..53377ee0236 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4389,7 +4389,7 @@ impl<'a> Parser<'a> { *t == token::Gt || *t == token::Comma || *t == token::Colon }); if gt_comma_or_colon { - self.err("syntax `where` is reserved for future use"); + self.span_err(self.span, "syntax `where` is reserved for future use"); } } } -- cgit 1.4.1-3-g733a5 From 12a6cf1123890fcc7ee4934422e4d344c5857923 Mon Sep 17 00:00:00 2001 From: Kalita Alexey Date: Fri, 16 Dec 2016 14:16:46 +0300 Subject: Allow path fragments to be parsed as type parameter bounds in macro expansion --- src/libsyntax/parse/parser.rs | 2 +- src/test/run-pass/issue-8521.rs | 34 ++++++++++++++++++++++ src/test/ui/macros/macro_path_as_generic_bound.rs | 19 ++++++++++++ .../ui/macros/macro_path_as_generic_bound.stderr | 11 +++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-8521.rs create mode 100644 src/test/ui/macros/macro_path_as_generic_bound.rs create mode 100644 src/test/ui/macros/macro_path_as_generic_bound.stderr (limited to 'src/libsyntax') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index bdd1606805f..8ea59a5cbab 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4173,7 +4173,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 diff --git a/src/test/run-pass/issue-8521.rs b/src/test/run-pass/issue-8521.rs new file mode 100644 index 00000000000..ce362c4bcd1 --- /dev/null +++ b/src/test/run-pass/issue-8521.rs @@ -0,0 +1,34 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo1 {} + +trait A {} + +macro_rules! foo1(($t:path) => { + impl Foo1 for T {} +}); + +foo1!(A); + +trait Foo2 {} + +trait B {} + +#[allow(unused)] +struct C {} + +macro_rules! foo2(($t:path) => { + impl Foo2 for T {} +}); + +foo2!(B); + +fn main() {} diff --git a/src/test/ui/macros/macro_path_as_generic_bound.rs b/src/test/ui/macros/macro_path_as_generic_bound.rs new file mode 100644 index 00000000000..781ea30ed8b --- /dev/null +++ b/src/test/ui/macros/macro_path_as_generic_bound.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo {} + +macro_rules! foo(($t:path) => { + impl Foo for T {} +}); + +foo!(m::m2::A); + +fn main() {} diff --git a/src/test/ui/macros/macro_path_as_generic_bound.stderr b/src/test/ui/macros/macro_path_as_generic_bound.stderr new file mode 100644 index 00000000000..96635032105 --- /dev/null +++ b/src/test/ui/macros/macro_path_as_generic_bound.stderr @@ -0,0 +1,11 @@ +error[E0433]: failed to resolve. Use of undeclared type or module `m` + --> $DIR/macro_path_as_generic_bound.rs:17:6 + | +17 | foo!(m::m2::A); + | -----^^^^^^^^-- + | | | + | | Use of undeclared type or module `m` + | in this macro invocation + +error: cannot continue compilation due to previous error + -- cgit 1.4.1-3-g733a5 From 83ab9f7faccddee23545e12d323791f9e2d06380 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 29 Nov 2016 02:07:02 +0000 Subject: Remove some unused functions and fix formatting. --- src/libsyntax/attr.rs | 30 ------------------------------ src/libsyntax/ext/hygiene.rs | 12 ++++++------ 2 files changed, 6 insertions(+), 36 deletions(-) (limited to 'src/libsyntax') 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> = 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 Option { - 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 { @@ -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/hygiene.rs b/src/libsyntax/ext/hygiene.rs index 0fd72277cca..8842cb55b1e 100644 --- a/src/libsyntax/ext/hygiene.rs +++ b/src/libsyntax/ext/hygiene.rs @@ -115,12 +115,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 { -- cgit 1.4.1-3-g733a5 From 59de7f8f04d9122dd776f2edd73eb77a4fc94054 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 29 Nov 2016 02:07:12 +0000 Subject: Add `ident.unhygienize()` and use `Ident` more instead of `Name` in `resolve`. --- src/librustc_resolve/build_reduced_graph.rs | 108 +++++++++++++-------------- src/librustc_resolve/lib.rs | 51 ++++++------- src/librustc_resolve/macros.rs | 23 +++--- src/librustc_resolve/resolve_imports.rs | 112 ++++++++++++++-------------- src/libsyntax/ast.rs | 12 ++- 5 files changed, 156 insertions(+), 150 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 25a37931ba3..4aa04dc34fe 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -28,7 +28,7 @@ use rustc::ty; use std::cell::Cell; use std::rc::Rc; -use syntax::ast::Name; +use syntax::ast::{Name, Ident}; use syntax::attr; use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind}; @@ -76,12 +76,12 @@ struct LegacyMacroImports { impl<'b> Resolver<'b> { /// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined; /// otherwise, reports an error. - fn define(&mut self, parent: Module<'b>, name: Name, ns: Namespace, def: T) + fn define(&mut self, parent: Module<'b>, ident: Ident, ns: Namespace, def: T) where T: ToNameBinding<'b>, { let binding = def.to_name_binding(); - if let Err(old_binding) = self.try_define(parent, name, ns, binding.clone()) { - self.report_conflict(parent, name, ns, old_binding, &binding); + if let Err(old_binding) = self.try_define(parent, ident, ns, binding.clone()) { + self.report_conflict(parent, ident, ns, old_binding, &binding); } } @@ -102,7 +102,7 @@ impl<'b> Resolver<'b> { /// Constructs the reduced graph for one item. fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) { let parent = self.current_module; - let name = item.ident.name; + let ident = item.ident; let sp = item.span; let vis = self.resolve_visibility(&item.vis); @@ -157,8 +157,8 @@ impl<'b> Resolver<'b> { } let subclass = SingleImport { - target: binding.name, - source: source.name, + target: binding, + source: source, result: self.per_ns(|_, _| Cell::new(Err(Undetermined))), }; self.add_import_directive( @@ -187,13 +187,13 @@ impl<'b> Resolver<'b> { for source_item in source_items { let node = source_item.node; - let (module_path, name, rename) = { + let (module_path, ident, rename) = { if node.name.name != keywords::SelfValue.name() { - let rename = node.rename.unwrap_or(node.name).name; - (module_path.clone(), node.name.name, rename) + let rename = node.rename.unwrap_or(node.name); + (module_path.clone(), node.name, rename) } else { - let name = match module_path.last() { - Some(ident) => ident.name, + let ident = match module_path.last() { + Some(&ident) => ident, None => { resolve_error( self, @@ -205,13 +205,13 @@ impl<'b> Resolver<'b> { } }; let module_path = module_path.split_last().unwrap().1; - let rename = node.rename.map(|i| i.name).unwrap_or(name); - (module_path.to_vec(), name, rename) + let rename = node.rename.unwrap_or(ident); + (module_path.to_vec(), ident, rename) } }; let subclass = SingleImport { target: rename, - source: name, + source: ident, result: self.per_ns(|_, _| Cell::new(Err(Undetermined))), }; let id = source_item.node.id; @@ -251,7 +251,7 @@ impl<'b> Resolver<'b> { expansion: expansion, }); let imported_binding = self.import(binding, directive); - self.define(parent, name, TypeNS, imported_binding); + self.define(parent, ident, TypeNS, imported_binding); self.populate_module_if_necessary(module); self.process_legacy_macro_imports(item, module, expansion); } @@ -265,9 +265,9 @@ impl<'b> Resolver<'b> { attr::contains_name(&item.attrs, "no_implicit_prelude") }, normal_ancestor_id: Some(item.id), - ..ModuleS::new(Some(parent), ModuleKind::Def(def, name)) + ..ModuleS::new(Some(parent), ModuleKind::Def(def, ident.name)) }); - self.define(parent, name, TypeNS, (module, vis, sp, expansion)); + self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.module_map.insert(item.id, module); // Descend into the module. @@ -280,27 +280,27 @@ impl<'b> Resolver<'b> { ItemKind::Static(_, m, _) => { let mutbl = m == Mutability::Mutable; let def = Def::Static(self.definitions.local_def_id(item.id), mutbl); - self.define(parent, name, ValueNS, (def, vis, sp, expansion)); + self.define(parent, ident, ValueNS, (def, vis, sp, expansion)); } ItemKind::Const(..) => { let def = Def::Const(self.definitions.local_def_id(item.id)); - self.define(parent, name, ValueNS, (def, vis, sp, expansion)); + self.define(parent, ident, ValueNS, (def, vis, sp, expansion)); } ItemKind::Fn(..) => { let def = Def::Fn(self.definitions.local_def_id(item.id)); - self.define(parent, name, ValueNS, (def, vis, sp, expansion)); + self.define(parent, ident, ValueNS, (def, vis, sp, expansion)); } // These items live in the type namespace. ItemKind::Ty(..) => { let def = Def::TyAlias(self.definitions.local_def_id(item.id)); - self.define(parent, name, TypeNS, (def, vis, sp, expansion)); + self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); } ItemKind::Enum(ref enum_definition, _) => { let def = Def::Enum(self.definitions.local_def_id(item.id)); - let module = self.new_module(parent, ModuleKind::Def(def, name), true); - self.define(parent, name, TypeNS, (module, vis, sp, expansion)); + let module = self.new_module(parent, ModuleKind::Def(def, ident.name), true); + self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); for variant in &(*enum_definition).variants { self.build_reduced_graph_for_variant(variant, module, vis, expansion); @@ -311,14 +311,14 @@ impl<'b> Resolver<'b> { ItemKind::Struct(ref struct_def, _) => { // Define a name in the type namespace. let def = Def::Struct(self.definitions.local_def_id(item.id)); - self.define(parent, name, TypeNS, (def, vis, sp, expansion)); + self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); // If this is a tuple or unit struct, define a name // in the value namespace as well. if !struct_def.is_struct() { let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()), CtorKind::from_ast(struct_def)); - self.define(parent, name, ValueNS, (ctor_def, vis, sp, expansion)); + self.define(parent, ident, ValueNS, (ctor_def, vis, sp, expansion)); } // Record field names for error reporting. @@ -332,7 +332,7 @@ impl<'b> Resolver<'b> { ItemKind::Union(ref vdata, _) => { let def = Def::Union(self.definitions.local_def_id(item.id)); - self.define(parent, name, TypeNS, (def, vis, sp, expansion)); + self.define(parent, ident, TypeNS, (def, vis, sp, expansion)); // Record field names for error reporting. let field_names = vdata.fields().iter().filter_map(|field| { @@ -350,8 +350,8 @@ impl<'b> Resolver<'b> { // Add all the items within to a new module. let module = - self.new_module(parent, ModuleKind::Def(Def::Trait(def_id), name), true); - self.define(parent, name, TypeNS, (module, vis, sp, expansion)); + self.new_module(parent, ModuleKind::Def(Def::Trait(def_id), ident.name), true); + self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.current_module = module; } ItemKind::Mac(_) => panic!("unexpanded macro in resolve!"), @@ -365,26 +365,23 @@ impl<'b> Resolver<'b> { parent: Module<'b>, vis: ty::Visibility, expansion: Mark) { - let name = variant.node.name.name; + let ident = variant.node.name; let def_id = self.definitions.local_def_id(variant.node.data.id()); // Define a name in the type namespace. let def = Def::Variant(def_id); - self.define(parent, name, TypeNS, (def, vis, variant.span, expansion)); + self.define(parent, ident, TypeNS, (def, vis, variant.span, expansion)); // Define a constructor name in the value namespace. // Braced variants, unlike structs, generate unusable names in // value namespace, they are reserved for possible future use. let ctor_kind = CtorKind::from_ast(&variant.node.data); let ctor_def = Def::VariantCtor(def_id, ctor_kind); - self.define(parent, name, ValueNS, (ctor_def, vis, variant.span, expansion)); + self.define(parent, ident, ValueNS, (ctor_def, vis, variant.span, expansion)); } /// Constructs the reduced graph for one foreign item. fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, expansion: Mark) { - let parent = self.current_module; - let name = item.ident.name; - let def = match item.node { ForeignItemKind::Fn(..) => { Def::Fn(self.definitions.local_def_id(item.id)) @@ -393,8 +390,9 @@ impl<'b> Resolver<'b> { Def::Static(self.definitions.local_def_id(item.id), m) } }; + let parent = self.current_module; let vis = self.resolve_visibility(&item.vis); - self.define(parent, name, ValueNS, (def, vis, item.span, expansion)); + self.define(parent, item.ident, ValueNS, (def, vis, item.span, expansion)); } fn build_reduced_graph_for_block(&mut self, block: &Block) { @@ -414,7 +412,7 @@ impl<'b> Resolver<'b> { /// Builds the reduced graph for a single item in an external crate. fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, child: Export) { - let name = child.name; + let ident = Ident::with_empty_ctxt(child.name); let def = child.def; let def_id = def.def_id(); let vis = match def { @@ -425,25 +423,25 @@ impl<'b> Resolver<'b> { match def { Def::Mod(..) | Def::Enum(..) => { - let module = self.new_module(parent, ModuleKind::Def(def, name), false); - self.define(parent, name, TypeNS, (module, vis, DUMMY_SP, Mark::root())); + let module = self.new_module(parent, ModuleKind::Def(def, ident.name), false); + self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root())); } Def::Variant(..) => { - self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root())); + self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root())); } Def::VariantCtor(..) => { - self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root())); + self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => { - self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root())); + self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Trait(..) => { - let module = self.new_module(parent, ModuleKind::Def(def, name), false); - self.define(parent, name, TypeNS, (module, vis, DUMMY_SP, Mark::root())); + let module = self.new_module(parent, ModuleKind::Def(def, ident.name), false); + self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root())); // If this is a trait, add all the trait item names to the trait info. let trait_item_def_ids = self.session.cstore.associated_item_def_ids(def_id); @@ -455,27 +453,27 @@ impl<'b> Resolver<'b> { } } Def::TyAlias(..) | Def::AssociatedTy(..) => { - self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root())); + self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Struct(..) => { - self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root())); + self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root())); // Record field names for error reporting. let field_names = self.session.cstore.struct_field_names(def_id); self.insert_field_names(def_id, field_names); } Def::StructCtor(..) => { - self.define(parent, name, ValueNS, (def, vis, DUMMY_SP, Mark::root())); + self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Union(..) => { - self.define(parent, name, TypeNS, (def, vis, DUMMY_SP, Mark::root())); + self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root())); // Record field names for error reporting. let field_names = self.session.cstore.struct_field_names(def_id); self.insert_field_names(def_id, field_names); } Def::Macro(..) => { - self.define(parent, name, MacroNS, (def, vis, DUMMY_SP, Mark::root())); + self.define(parent, ident, MacroNS, (def, vis, DUMMY_SP, Mark::root())); } Def::Local(..) | Def::PrimTy(..) | @@ -574,12 +572,13 @@ impl<'b> Resolver<'b> { } if let Some(span) = legacy_imports.import_all { - module.for_each_child(|name, ns, binding| if ns == MacroNS { - self.legacy_import_macro(name, binding, span, allow_shadowing); + module.for_each_child(|ident, ns, binding| if ns == MacroNS { + self.legacy_import_macro(ident.name, binding, span, allow_shadowing); }); } else { for (name, span) in legacy_imports.imports { - let result = self.resolve_name_in_module(module, name, MacroNS, false, None); + let ident = Ident::with_empty_ctxt(name); + let result = self.resolve_ident_in_module(module, ident, MacroNS, false, None); if let Ok(binding) = result { self.legacy_import_macro(name, binding, span, allow_shadowing); } else { @@ -591,7 +590,8 @@ impl<'b> Resolver<'b> { let krate = module.def_id().unwrap().krate; self.used_crates.insert(krate); self.session.cstore.export_macros(krate); - let result = self.resolve_name_in_module(module, name, MacroNS, false, None); + let ident = Ident::with_empty_ctxt(name); + let result = self.resolve_ident_in_module(module, ident, MacroNS, false, None); if let Ok(binding) = result { self.macro_exports.push(Export { name: name, def: binding.def() }); } else { @@ -759,7 +759,7 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { self.resolver.trait_item_map.insert((item.ident.name, def_id), is_static_method); let vis = ty::Visibility::Public; - self.resolver.define(parent, item.ident.name, ns, (def, vis, item.span, self.expansion)); + self.resolver.define(parent, item.ident, ns, (def, vis, item.span, self.expansion)); self.resolver.current_module = parent.parent.unwrap(); // nearest normal ancestor visit::walk_trait_item(self, item); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 509ee704e2e..4d4f4629c75 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -781,8 +781,8 @@ pub struct ModuleS<'a> { // The node id of the closest normal module (`mod`) ancestor (including this module). normal_ancestor_id: Option, - resolutions: RefCell>>>, - legacy_macro_resolutions: RefCell>, + resolutions: RefCell>>>, + legacy_macro_resolutions: RefCell>, macro_resolutions: RefCell, PathScope, Span)>>, // Macro invocations that can expand into items in this module. @@ -794,7 +794,7 @@ pub struct ModuleS<'a> { globs: RefCell>>, // Used to memoize the traits in this module for faster searches through all traits in scope. - traits: RefCell)]>>>, + traits: RefCell)]>>>, // Whether this module is populated. If not populated, any attempt to // access the children must be preceded with a @@ -822,9 +822,9 @@ impl<'a> ModuleS<'a> { } } - fn for_each_child)>(&self, mut f: F) { - for (&(name, ns), name_resolution) in self.resolutions.borrow().iter() { - name_resolution.borrow().binding.map(|binding| f(name, ns, binding)); + fn for_each_child)>(&self, mut f: F) { + for (&(ident, ns), name_resolution) in self.resolutions.borrow().iter() { + name_resolution.borrow().binding.map(|binding| f(ident, ns, binding)); } } @@ -1334,7 +1334,7 @@ impl<'a> Resolver<'a> { }) } - fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span) + fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span) -> bool /* true if an error was reported */ { // track extern crates for unused_extern_crate lint if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) { @@ -1345,13 +1345,13 @@ impl<'a> Resolver<'a> { NameBindingKind::Import { directive, binding, ref used } if !used.get() => { used.set(true); self.used_imports.insert((directive.id, ns)); - self.add_to_glob_map(directive.id, name); - self.record_use(name, ns, binding, span) + self.add_to_glob_map(directive.id, ident); + self.record_use(ident, ns, binding, span) } NameBindingKind::Import { .. } => false, NameBindingKind::Ambiguity { b1, b2 } => { self.ambiguity_errors.push(AmbiguityError { - span: span, name: name, lexical: false, b1: b1, b2: b2, + span: span, name: ident.name, lexical: false, b1: b1, b2: b2, }); true } @@ -1359,9 +1359,9 @@ impl<'a> Resolver<'a> { } } - fn add_to_glob_map(&mut self, id: NodeId, name: Name) { + fn add_to_glob_map(&mut self, id: NodeId, ident: Ident) { if self.make_glob_map { - self.glob_map.entry(id).or_insert_with(FxHashSet).insert(name); + self.glob_map.entry(id).or_insert_with(FxHashSet).insert(ident.name); } } @@ -1388,7 +1388,7 @@ impl<'a> Resolver<'a> { record_used: Option) -> Option> { if ns == TypeNS { - ident = Ident::with_empty_ctxt(ident.name); + ident = ident.unhygienize(); } // Walk backwards up the ribs in scope. @@ -1403,8 +1403,7 @@ impl<'a> Resolver<'a> { } if let ModuleRibKind(module) = self.ribs[ns][i].kind { - let name = ident.name; - let item = self.resolve_name_in_module(module, name, ns, false, record_used); + let item = self.resolve_ident_in_module(module, ident, ns, false, record_used); if let Ok(binding) = item { // The ident resolves to an item. return Some(LexicalScopeBinding::Item(binding)); @@ -1413,7 +1412,7 @@ impl<'a> Resolver<'a> { if let ModuleKind::Block(..) = module.kind { // We can see through blocks } else if !module.no_implicit_prelude { return self.prelude.and_then(|prelude| { - self.resolve_name_in_module(prelude, name, ns, false, None).ok() + self.resolve_ident_in_module(prelude, ident, ns, false, None).ok() }).map(LexicalScopeBinding::Item) } else { return None; @@ -2183,8 +2182,7 @@ impl<'a> Resolver<'a> { Def::VariantCtor(_, CtorKind::Const) | Def::Const(..) if !always_binding => { // A unit struct/variant or constant pattern. - let name = ident.node.name; - self.record_use(name, ValueNS, binding.unwrap(), ident.span); + self.record_use(ident.node, ValueNS, binding.unwrap(), ident.span); Some(PathResolution::new(def)) } Def::StructCtor(..) | Def::VariantCtor(..) | @@ -2363,9 +2361,9 @@ impl<'a> Resolver<'a> { allow_super = false; let binding = if let Some(module) = module { - self.resolve_name_in_module(module, ident.name, ns, false, record_used) + self.resolve_ident_in_module(module, ident, ns, false, record_used) } else if opt_ns == Some(MacroNS) { - self.resolve_lexical_macro_path_segment(ident.name, ns, record_used) + self.resolve_lexical_macro_path_segment(ident, ns, record_used) } else { match self.resolve_ident_in_lexical_scope(ident, ns, record_used) { Some(LexicalScopeBinding::Item(binding)) => Ok(binding), @@ -2953,16 +2951,15 @@ impl<'a> Resolver<'a> { in_module_is_extern)) = worklist.pop() { self.populate_module_if_necessary(in_module); - in_module.for_each_child(|name, ns, name_binding| { + in_module.for_each_child(|ident, ns, name_binding| { // avoid imports entirely if name_binding.is_import() && !name_binding.is_extern_crate() { return; } // collect results based on the filter function - if name == lookup_name && ns == namespace { + if ident.name == lookup_name && ns == namespace { if filter_fn(name_binding.def()) { // create the path - let ident = Ident::with_empty_ctxt(name); let params = PathParameters::none(); let segment = PathSegment { identifier: ident, @@ -2994,7 +2991,7 @@ impl<'a> Resolver<'a> { // form the path let mut path_segments = path_segments.clone(); path_segments.push(PathSegment { - identifier: Ident::with_empty_ctxt(name), + identifier: ident, parameters: PathParameters::none(), }); @@ -3124,13 +3121,13 @@ impl<'a> Resolver<'a> { fn report_conflict(&mut self, parent: Module, - name: Name, + ident: Ident, ns: Namespace, binding: &NameBinding, old_binding: &NameBinding) { // Error on the second of two conflicting names if old_binding.span.lo > binding.span.lo { - return self.report_conflict(parent, name, ns, old_binding, binding); + return self.report_conflict(parent, ident, ns, old_binding, binding); } let container = match parent.kind { @@ -3145,7 +3142,7 @@ impl<'a> Resolver<'a> { false => ("defined", "definition"), }; - let span = binding.span; + let (name, span) = (ident.name, binding.span); if let Some(s) = self.name_already_seen.get(&name) { if s == &span { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 6c02967672d..b2e31d54909 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -19,7 +19,7 @@ use rustc::hir::map::{self, DefCollector}; use rustc::ty; use std::cell::Cell; use std::rc::Rc; -use syntax::ast::{self, Name}; +use syntax::ast::{self, Name, Ident}; use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator}; use syntax::ext::base::{NormalTT, SyntaxExtension}; @@ -246,7 +246,7 @@ impl<'a> base::Resolver for Resolver<'a> { let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) { Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()), Some(MacroBinding::Modern(binding)) => Ok(binding.get_macro(self)), - None => match self.resolve_lexical_macro_path_segment(name, MacroNS, None) { + None => match self.resolve_lexical_macro_path_segment(path[0], MacroNS, None) { Ok(binding) => Ok(binding.get_macro(self)), Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined), _ => { @@ -260,7 +260,7 @@ impl<'a> base::Resolver for Resolver<'a> { }; if self.use_extern_macros { - self.current_module.legacy_macro_resolutions.borrow_mut().push((scope, name, span)); + self.current_module.legacy_macro_resolutions.borrow_mut().push((scope, path[0], span)); } result } @@ -269,7 +269,7 @@ impl<'a> base::Resolver for Resolver<'a> { impl<'a> Resolver<'a> { // Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`) pub fn resolve_lexical_macro_path_segment(&mut self, - name: Name, + ident: Ident, ns: Namespace, record_used: Option) -> Result<&'a NameBinding<'a>, Determinacy> { @@ -278,7 +278,7 @@ impl<'a> Resolver<'a> { loop { // Since expanded macros may not shadow the lexical scope (enforced below), // we can ignore unresolved invocations (indicated by the penultimate argument). - match self.resolve_name_in_module(module, name, ns, true, record_used) { + match self.resolve_ident_in_module(module, ident, ns, true, record_used) { Ok(binding) => { let span = match record_used { Some(span) => span, @@ -286,6 +286,7 @@ impl<'a> Resolver<'a> { }; match potential_expanded_shadower { Some(shadower) if shadower.def() != binding.def() => { + let name = ident.name; self.ambiguity_errors.push(AmbiguityError { span: span, name: name, b1: shadower, b2: binding, lexical: true, }); @@ -383,10 +384,10 @@ impl<'a> Resolver<'a> { } } - for &(mark, name, span) in module.legacy_macro_resolutions.borrow().iter() { + for &(mark, ident, span) in module.legacy_macro_resolutions.borrow().iter() { let legacy_scope = &self.invocations[&mark].legacy_scope; - let legacy_resolution = self.resolve_legacy_scope(legacy_scope, name, true); - let resolution = self.resolve_lexical_macro_path_segment(name, MacroNS, Some(span)); + let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident.name, true); + let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, Some(span)); let (legacy_resolution, resolution) = match (legacy_resolution, resolution) { (Some(legacy_resolution), Ok(resolution)) => (legacy_resolution, resolution), _ => continue, @@ -396,9 +397,9 @@ impl<'a> Resolver<'a> { MacroBinding::Modern(binding) => (binding.span, "imported"), MacroBinding::Legacy(binding) => (binding.span, "defined"), }; - let msg1 = format!("`{}` could resolve to the macro {} here", name, participle); - let msg2 = format!("`{}` could also resolve to the macro imported here", name); - self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) + let msg1 = format!("`{}` could resolve to the macro {} here", ident, participle); + let msg2 = format!("`{}` could also resolve to the macro imported here", ident); + self.session.struct_span_err(span, &format!("`{}` is ambiguous", ident)) .span_note(legacy_span, &msg1) .span_note(resolution.span, &msg2) .emit(); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 64a8e21f9e0..7c7908d2401 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -21,7 +21,7 @@ use rustc::ty; use rustc::lint::builtin::PRIVATE_IN_PUBLIC; use rustc::hir::def::*; -use syntax::ast::{Ident, NodeId, Name}; +use syntax::ast::{Ident, NodeId}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::hygiene::Mark; use syntax::symbol::keywords; @@ -35,8 +35,8 @@ use std::mem; #[derive(Clone, Debug)] pub enum ImportDirectiveSubclass<'a> { SingleImport { - target: Name, - source: Name, + target: Ident, + source: Ident, result: PerNS, Determinacy>>>, }, GlobImport { @@ -126,31 +126,32 @@ impl<'a> NameResolution<'a> { } impl<'a> Resolver<'a> { - fn resolution(&self, module: Module<'a>, name: Name, ns: Namespace) + fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace) -> &'a RefCell> { - *module.resolutions.borrow_mut().entry((name, ns)) + *module.resolutions.borrow_mut().entry((ident, ns)) .or_insert_with(|| self.arenas.alloc_name_resolution()) } - /// Attempts to resolve the supplied name in the given module for the given namespace. - /// If successful, returns the binding corresponding to the name. + /// Attempts to resolve `ident` in namespaces `ns` of `module`. /// Invariant: if `record_used` is `Some`, import resolution must be complete. - pub fn resolve_name_in_module(&mut self, - module: Module<'a>, - name: Name, - ns: Namespace, - ignore_unresolved_invocations: bool, - record_used: Option) - -> Result<&'a NameBinding<'a>, Determinacy> { + pub fn resolve_ident_in_module(&mut self, + module: Module<'a>, + ident: Ident, + ns: Namespace, + ignore_unresolved_invocations: bool, + record_used: Option) + -> Result<&'a NameBinding<'a>, Determinacy> { + let ident = ident.unhygienize(); self.populate_module_if_necessary(module); - let resolution = self.resolution(module, name, ns) + let resolution = self.resolution(module, ident, ns) .try_borrow_mut() .map_err(|_| Determined)?; // This happens when there is a cycle of imports if let Some(span) = record_used { if let Some(binding) = resolution.binding { if let Some(shadowed_glob) = resolution.shadows_glob { + let name = ident.name; // If we ignore unresolved invocations, we must forbid // expanded shadowing to avoid time travel. if ignore_unresolved_invocations && @@ -162,11 +163,11 @@ impl<'a> Resolver<'a> { }); } } - if self.record_use(name, ns, binding, span) { + if self.record_use(ident, ns, binding, span) { return Ok(self.dummy_binding); } if !self.is_accessible(binding.vis) { - self.privacy_errors.push(PrivacyError(span, name, binding)); + self.privacy_errors.push(PrivacyError(span, ident.name, binding)); } } @@ -194,11 +195,11 @@ impl<'a> Resolver<'a> { Some(module) => module, None => return Err(Undetermined), }; - let name = match directive.subclass { + let ident = match directive.subclass { SingleImport { source, .. } => source, _ => unreachable!(), }; - match self.resolve_name_in_module(module, name, ns, false, None) { + match self.resolve_ident_in_module(module, ident, ns, false, None) { Err(Determined) => {} _ => return Err(Undetermined), } @@ -220,7 +221,7 @@ impl<'a> Resolver<'a> { for directive in module.globs.borrow().iter() { if self.is_accessible(directive.vis.get()) { if let Some(module) = directive.imported_module.get() { - let result = self.resolve_name_in_module(module, name, ns, false, None); + let result = self.resolve_ident_in_module(module, ident, ns, false, None); if let Err(Undetermined) = result { return Err(Undetermined); } @@ -299,12 +300,13 @@ impl<'a> Resolver<'a> { } // Define the name or return the existing binding if there is a collision. - pub fn try_define(&mut self, module: Module<'a>, name: Name, ns: Namespace, binding: T) + pub fn try_define(&mut self, module: Module<'a>, ident: Ident, ns: Namespace, binding: T) -> Result<(), &'a NameBinding<'a>> where T: ToNameBinding<'a> { + let ident = ident.unhygienize(); let binding = self.arenas.alloc_name_binding(binding.to_name_binding()); - self.update_resolution(module, name, ns, |this, resolution| { + self.update_resolution(module, ident, ns, |this, resolution| { if let Some(old_binding) = resolution.binding { if binding.is_glob_import() { if !old_binding.is_glob_import() && @@ -347,13 +349,14 @@ impl<'a> Resolver<'a> { // Use `f` to mutate the resolution of the name in the module. // If the resolution becomes a success, define it in the module's glob importers. - fn update_resolution(&mut self, module: Module<'a>, name: Name, ns: Namespace, f: F) -> T + fn update_resolution(&mut self, module: Module<'a>, ident: Ident, ns: Namespace, f: F) + -> T where F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T { // Ensure that `resolution` isn't borrowed when defining in the module's glob importers, // during which the resolution might end up getting re-defined via a glob cycle. let (binding, t) = { - let mut resolution = &mut *self.resolution(module, name, ns).borrow_mut(); + let mut resolution = &mut *self.resolution(module, ident, ns).borrow_mut(); let old_binding = resolution.binding(); let t = f(self, resolution); @@ -372,7 +375,7 @@ impl<'a> Resolver<'a> { for directive in module.glob_importers.borrow_mut().iter() { if self.is_accessible_from(binding.vis, directive.parent) { let imported_binding = self.import(binding, directive); - let _ = self.try_define(directive.parent, name, ns, imported_binding); + let _ = self.try_define(directive.parent, ident, ns, imported_binding); } } @@ -508,7 +511,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let mut indeterminate = false; self.per_ns(|this, ns| { if let Err(Undetermined) = result[ns].get() { - result[ns].set(this.resolve_name_in_module(module, source, ns, false, None)); + result[ns].set(this.resolve_ident_in_module(module, source, ns, false, None)); } else { return }; @@ -564,7 +567,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { _ => return None, }; - let (name, result) = match directive.subclass { + let (ident, result) = match directive.subclass { SingleImport { source, ref result, .. } => (source, result), GlobImport { .. } if module.def_id() == directive.parent.def_id() => { // Importing a module into itself is not allowed. @@ -586,8 +589,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.per_ns(|this, ns| { if let Ok(binding) = result[ns].get() { all_ns_err = false; - if this.record_use(name, ns, binding, directive.span) { - this.resolution(module, name, ns).borrow_mut().binding = + if this.record_use(ident, ns, binding, directive.span) { + this.resolution(module, ident, ns).borrow_mut().binding = Some(this.dummy_binding); } } @@ -596,7 +599,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if all_ns_err { let mut all_ns_failed = true; self.per_ns(|this, ns| { - match this.resolve_name_in_module(module, name, ns, false, Some(span)) { + match this.resolve_ident_in_module(module, ident, ns, false, Some(span)) { Ok(_) => all_ns_failed = false, _ => {} } @@ -604,27 +607,28 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { return if all_ns_failed { let resolutions = module.resolutions.borrow(); - let names = resolutions.iter().filter_map(|(&(ref n, _), resolution)| { - if *n == name { return None; } // Never suggest the same name + let names = resolutions.iter().filter_map(|(&(ref i, _), resolution)| { + if *i == ident { return None; } // Never suggest the same name match *resolution.borrow() { - NameResolution { binding: Some(_), .. } => Some(n), + NameResolution { binding: Some(_), .. } => Some(&i.name), NameResolution { single_imports: SingleImports::None, .. } => None, - _ => Some(n), + _ => Some(&i.name), } }); - let lev_suggestion = match find_best_match_for_name(names, &name.as_str(), None) { - Some(name) => format!(". Did you mean to use `{}`?", name), - None => "".to_owned(), - }; + let lev_suggestion = + match find_best_match_for_name(names, &ident.name.as_str(), None) { + Some(name) => format!(". Did you mean to use `{}`?", name), + None => "".to_owned(), + }; let module_str = module_to_string(module); let msg = if &module_str == "???" { - format!("no `{}` in the root{}", name, lev_suggestion) + format!("no `{}` in the root{}", ident, lev_suggestion) } else { - format!("no `{}` in `{}`{}", name, module_str, lev_suggestion) + format!("no `{}` in `{}`{}", ident, module_str, lev_suggestion) }; Some(msg) } else { - // `resolve_name_in_module` reported a privacy error. + // `resolve_ident_in_module` reported a privacy error. self.import_dummy_binding(directive); None } @@ -649,18 +653,18 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if ns == TypeNS && binding.is_extern_crate() { let msg = format!("extern crate `{}` is private, and cannot be reexported \ (error E0364), consider declaring with `pub`", - name); + ident); self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); } else if ns == TypeNS { struct_span_err!(self.session, directive.span, E0365, - "`{}` is private, and cannot be reexported", name) - .span_label(directive.span, &format!("reexport of private `{}`", name)) - .note(&format!("consider declaring type or module `{}` with `pub`", name)) + "`{}` is private, and cannot be reexported", ident) + .span_label(directive.span, &format!("reexport of private `{}`", ident)) + .note(&format!("consider declaring type or module `{}` with `pub`", ident)) .emit(); } else { - let msg = format!("`{}` is private, and cannot be reexported", name); + let msg = format!("`{}` is private, and cannot be reexported", ident); let note_msg = - format!("consider marking `{}` as `pub` in the imported module", name); + format!("consider marking `{}` as `pub` in the imported module", ident); struct_span_err!(self.session, directive.span, E0364, "{}", &msg) .span_note(directive.span, ¬e_msg) .emit(); @@ -697,13 +701,13 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // Ensure that `resolutions` isn't borrowed during `try_define`, // since it might get updated via a glob cycle. - let bindings = module.resolutions.borrow().iter().filter_map(|(name, resolution)| { - resolution.borrow().binding().map(|binding| (*name, binding)) + let bindings = module.resolutions.borrow().iter().filter_map(|(&ident, resolution)| { + resolution.borrow().binding().map(|binding| (ident, binding)) }).collect::>(); - for ((name, ns), binding) in bindings { + for ((ident, ns), binding) in bindings { if binding.pseudo_vis() == ty::Visibility::Public || self.is_accessible(binding.vis) { let imported_binding = self.import(binding, directive); - let _ = self.try_define(directive.parent, name, ns, imported_binding); + let _ = self.try_define(directive.parent, ident, ns, imported_binding); } } @@ -722,7 +726,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { reexports = mem::replace(&mut self.macro_exports, Vec::new()); } - for (&(name, ns), resolution) in module.resolutions.borrow().iter() { + for (&(ident, ns), resolution) in module.resolutions.borrow().iter() { let resolution = resolution.borrow(); let binding = match resolution.binding { Some(binding) => binding, @@ -736,7 +740,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if !def.def_id().is_local() { self.session.cstore.export_macros(def.def_id().krate); } - reexports.push(Export { name: name, def: def }); + reexports.push(Export { name: ident.name, def: def }); } } @@ -745,7 +749,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { !orig_binding.vis.is_at_least(binding.vis, self) { let msg = format!("variant `{}` is private, and cannot be reexported \ (error E0364), consider declaring its enum as `pub`", - name); + ident); self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, binding.span, msg); } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2a911aceb9d..2369cc5714e 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 { -- cgit 1.4.1-3-g733a5 From e80d1a8faf2da8df494828e2772e2d2043282fed Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 29 Nov 2016 23:36:27 +0000 Subject: Remove `MacroDef`'s fields `imported_from` and `allow_internal_unstable`, remove `export` argument of `resolver.add_macro()`. --- src/librustc/hir/intravisit.rs | 1 - src/librustc/hir/lowering.rs | 2 -- src/librustc/hir/mod.rs | 2 -- src/librustc/middle/stability.rs | 8 ++------ src/librustc_metadata/cstore_impl.rs | 2 -- src/librustc_resolve/macros.rs | 5 +++-- src/librustdoc/visit_ast.rs | 5 +++-- src/libsyntax/ast.rs | 2 -- src/libsyntax/ext/base.rs | 4 ++-- src/libsyntax/ext/tt/macro_rules.rs | 7 ++----- src/libsyntax/visit.rs | 1 - 11 files changed, 12 insertions(+), 27 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 625bde2ca8b..186d6f62650 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -365,7 +365,6 @@ pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) { pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) { visitor.visit_id(macro_def.id); visitor.visit_name(macro_def.span, macro_def.name); - walk_opt_name(visitor, macro_def.span, macro_def.imported_from); walk_list!(visitor, visit_attribute, ¯o_def.attrs); } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 74876eb59ee..f5773d35178 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -987,8 +987,6 @@ impl<'a> LoweringContext<'a> { attrs: self.lower_attrs(&m.attrs), id: m.id, span: m.span, - imported_from: m.imported_from.map(|x| x.name), - allow_internal_unstable: m.allow_internal_unstable, body: m.body.clone().into(), } } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 4fd8f96ba04..f52ee35e175 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -475,8 +475,6 @@ pub struct MacroDef { pub attrs: HirVec, pub id: NodeId, pub span: Span, - pub imported_from: Option, - pub allow_internal_unstable: bool, pub body: HirVec, } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 3e32957aecf..f45e86f2f4b 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -302,9 +302,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) { - if md.imported_from.is_none() { - self.annotate(md.id, &md.attrs, md.span, AnnotationKind::Required, |_| {}); - } + self.annotate(md.id, &md.attrs, md.span, AnnotationKind::Required, |_| {}); } } @@ -373,9 +371,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> { } fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) { - if md.imported_from.is_none() { - self.check_missing_stability(md.id, md.span); - } + self.check_missing_stability(md.id, md.span); } } diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 1a1bb1432ee..ac830318ce9 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -418,8 +418,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { ident: ast::Ident::with_empty_ctxt(name), id: ast::DUMMY_NODE_ID, span: local_span, - imported_from: None, // FIXME - allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"), attrs: attrs, body: body, }) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index b2e31d54909..5e356878ba8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -20,6 +20,7 @@ use rustc::ty; use std::cell::Cell; use std::rc::Rc; use syntax::ast::{self, Name, Ident}; +use syntax::attr; use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator}; use syntax::ext::base::{NormalTT, SyntaxExtension}; @@ -138,7 +139,7 @@ impl<'a> base::Resolver for Resolver<'a> { invocation.expansion.set(visitor.legacy_scope); } - fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef, export: bool) { + fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) { if def.ident.name == "macro_rules" { self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`"); } @@ -153,7 +154,7 @@ impl<'a> base::Resolver for Resolver<'a> { invocation.legacy_scope.set(LegacyScope::Binding(binding)); self.macro_names.insert(def.ident.name); - if export { + if attr::contains_name(&def.attrs, "macro_export") { def.id = self.next_node_id(); DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| { collector.visit_macro_def(&def) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 4087b9a761f..e5410c6341f 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -201,6 +201,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { if def_id.krate == LOCAL_CRATE { continue // These are `krate.exported_macros`, handled in `self.visit()`. } + let imported_from = self.cx.sess().cstore.original_crate_name(def_id.krate); let def = match self.cx.sess().cstore.load_macro(def_id, self.cx.sess()) { LoadedMacro::MacroRules(macro_rules) => macro_rules, // FIXME(jseyfried): document proc macro reexports @@ -217,7 +218,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { matchers: matchers, stab: self.stability(def.id), depr: self.deprecation(def.id), - imported_from: def.imported_from.map(|ident| ident.name), + imported_from: Some(imported_from), }) } } @@ -525,7 +526,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { matchers: matchers, stab: self.stability(def.id), depr: self.deprecation(def.id), - imported_from: def.imported_from, + imported_from: None, } } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2369cc5714e..39d78cd8776 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1972,8 +1972,6 @@ pub struct MacroDef { pub attrs: Vec, pub id: NodeId, pub span: Span, - pub imported_from: Option, - pub allow_internal_unstable: bool, pub body: Vec, } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index ddbca47429d..508c5eaed8c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -520,7 +520,7 @@ pub trait Resolver { fn eliminate_crate_var(&mut self, item: P) -> P; fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion); - fn add_macro(&mut self, scope: Mark, def: ast::MacroDef, export: bool); + fn add_macro(&mut self, scope: Mark, def: ast::MacroDef); fn add_ext(&mut self, ident: ast::Ident, ext: Rc); fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec); @@ -544,7 +544,7 @@ impl Resolver for DummyResolver { fn eliminate_crate_var(&mut self, item: P) -> P { item } fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {} - fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef, _export: bool) {} + fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef) {} fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc) {} fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec) {} diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index ca18e580ecd..5a028594a21 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -160,14 +160,11 @@ impl IdentMacroExpander for MacroRulesExpander { tts: Vec, attrs: Vec) -> Box { - 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, }; @@ -178,7 +175,7 @@ impl IdentMacroExpander for MacroRulesExpander { MacEager::items(placeholders::macro_scope_placeholder().make_items()) }; - cx.resolver.add_macro(cx.current_expansion.mark, def, export); + cx.resolver.add_macro(cx.current_expansion.mark, def); result } } @@ -282,7 +279,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/visit.rs b/src/libsyntax/visit.rs index 3e0353d532d..c1391d0b1c2 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); } -- cgit 1.4.1-3-g733a5 From 421c5d11c1b4bb591bb429577c7b89cba59acefa Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 1 Dec 2016 11:20:04 +0000 Subject: Remove scope placeholders, remove method `add_macro` of `ext::base::Resolver`. --- src/librustc_resolve/build_reduced_graph.rs | 10 ++-- src/librustc_resolve/macros.rs | 75 +++++++++++++++++------------ src/libsyntax/ext/base.rs | 2 - src/libsyntax/ext/expand.rs | 37 ++++++++------ src/libsyntax/ext/placeholders.rs | 50 ++++++------------- src/libsyntax/ext/tt/macro_rules.rs | 34 +------------ src/libsyntax_ext/lib.rs | 5 +- 7 files changed, 91 insertions(+), 122 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 02a4d8db095..9f85580b93e 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -697,9 +697,13 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> { fn visit_item(&mut self, item: &'a Item) { let macro_use = match item.node { - ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => return, // Scope placeholder - ItemKind::Mac(..) => { - return self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id)); + ItemKind::Mac(ref mac) => { + if mac.node.path.segments.is_empty() { + self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id)); + } else { + self.resolver.define_macro(item, &mut self.legacy_scope); + } + return } ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs), _ => false, diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 5e356878ba8..ce92a4446f9 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -23,8 +23,8 @@ use syntax::ast::{self, Name, Ident}; use syntax::attr; use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator}; -use syntax::ext::base::{NormalTT, SyntaxExtension}; -use syntax::ext::expand::Expansion; +use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension}; +use syntax::ext::expand::{Expansion, mark_tts}; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{emit_feature_err, GateIssue}; @@ -139,34 +139,6 @@ impl<'a> base::Resolver for Resolver<'a> { invocation.expansion.set(visitor.legacy_scope); } - fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) { - if def.ident.name == "macro_rules" { - self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`"); - } - - let invocation = self.invocations[&scope]; - let binding = self.arenas.alloc_legacy_binding(LegacyBinding { - parent: Cell::new(invocation.legacy_scope.get()), - name: def.ident.name, - ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)), - span: def.span, - }); - invocation.legacy_scope.set(LegacyScope::Binding(binding)); - self.macro_names.insert(def.ident.name); - - if attr::contains_name(&def.attrs, "macro_export") { - def.id = self.next_node_id(); - DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| { - collector.visit_macro_def(&def) - }); - self.macro_exports.push(Export { - name: def.ident.name, - def: Def::Macro(self.definitions.local_def_id(def.id)), - }); - self.exported_macros.push(def); - } - } - fn add_ext(&mut self, ident: ast::Ident, ext: Rc) { if let NormalTT(..) = *ext { self.macro_names.insert(ident.name); @@ -444,4 +416,47 @@ impl<'a> Resolver<'a> { expansion.visit_with(def_collector) }); } + + pub fn define_macro(&mut self, item: &ast::Item, legacy_scope: &mut LegacyScope<'a>) { + let tts = match item.node { + ast::ItemKind::Mac(ref mac) => &mac.node.tts, + _ => unreachable!(), + }; + + if item.ident.name == "macro_rules" { + self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`"); + } + + let mark = Mark::from_placeholder_id(item.id); + let invocation = self.invocations[&mark]; + invocation.module.set(self.current_module); + + let mut def = ast::MacroDef { + ident: item.ident, + attrs: item.attrs.clone(), + id: ast::DUMMY_NODE_ID, + span: item.span, + body: mark_tts(tts, mark), + }; + + *legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding { + parent: Cell::new(*legacy_scope), + name: def.ident.name, + ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)), + span: def.span, + })); + self.macro_names.insert(def.ident.name); + + if attr::contains_name(&def.attrs, "macro_export") { + def.id = self.next_node_id(); + DefCollector::new(&mut self.definitions).with_parent(CRATE_DEF_INDEX, |collector| { + collector.visit_macro_def(&def) + }); + self.macro_exports.push(Export { + name: def.ident.name, + def: Def::Macro(self.definitions.local_def_id(def.id)), + }); + self.exported_macros.push(def); + } + } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 508c5eaed8c..f9364f39ab7 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -520,7 +520,6 @@ pub trait Resolver { fn eliminate_crate_var(&mut self, item: P) -> P; fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion); - fn add_macro(&mut self, scope: Mark, def: ast::MacroDef); fn add_ext(&mut self, ident: ast::Ident, ext: Rc); fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec); @@ -544,7 +543,6 @@ impl Resolver for DummyResolver { fn eliminate_crate_var(&mut self, item: P) -> P { item } fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {} - fn add_macro(&mut self, _scope: Mark, _def: ast::MacroDef) {} fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc) {} fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec) {} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 19545e2e642..05501b5434a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -392,14 +392,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; 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); @@ -601,6 +593,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect_bang( &mut self, mac: ast::Mac, attrs: Vec, span: Span, kind: ExpansionKind, ) -> Expansion { + self.check_attributes(&attrs); self.collect(kind, InvocationKind::Bang { attrs: attrs, mac: mac, ident: None, span: span }) } @@ -622,6 +615,16 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn configure(&mut self, node: T) -> Option { 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 @@ -740,14 +743,18 @@ 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 = ast::NodeId::from_u32(Mark::fresh().as_u32()); + SmallVector::one(P(item)) + } ItemKind::Mac(mac) => { self.collect(ExpansionKind::Items, InvocationKind::Bang { mac: mac, diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 4fe57a8345e..eb4b6144c8d 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; @@ -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, 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) -> SmallVector> { 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 { @@ -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_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 5a028594a21..3abd24b50ba 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -10,10 +10,9 @@ 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}; @@ -151,35 +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, - attrs: Vec) - -> Box { - let def = ast::MacroDef { - ident: ident, - id: ast::DUMMY_NODE_ID, - span: span, - body: tts, - 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); - result - } -} - // Note that macro-by-example's input is also matched against a token tree: // $( $lhs:tt => $rhs:tt );+ // diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 66d6c0570ac..e31b29d5cc1 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -50,8 +50,7 @@ pub mod deriving; use std::rc::Rc; use syntax::ast; -use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier, NamedSyntaxExtension}; -use syntax::ext::tt::macro_rules::MacroRulesExpander; +use syntax::ext::base::{MacroExpanderFn, NormalTT, MultiModifier, NamedSyntaxExtension}; use syntax::symbol::Symbol; pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, @@ -61,8 +60,6 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext)); }; - register(Symbol::intern("macro_rules"), IdentTT(Box::new(MacroRulesExpander), None, false)); - macro_rules! register { ($( $name:ident: $f:expr, )*) => { $( register(Symbol::intern(stringify!($name)), -- cgit 1.4.1-3-g733a5 From 6f040b48ef3f8bce0706d838f5672ca8a3e07880 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 1 Dec 2016 11:54:01 +0000 Subject: Avoid including attributes in bang macro invocations. --- src/libsyntax/ext/base.rs | 6 ++---- src/libsyntax/ext/expand.rs | 38 +++++++++++++++++--------------------- 2 files changed, 19 insertions(+), 25 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index f9364f39ab7..8e63f73fdaa 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, - attrs: Vec) + token_tree: Vec) -> Box; } @@ -234,8 +233,7 @@ impl IdentMacroExpander for F cx: &'cx mut ExtCtxt, sp: Span, ident: ast::Ident, - token_tree: Vec, - _attrs: Vec) + token_tree: Vec) -> Box { (*self)(cx, sp, ident, token_tree) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 05501b5434a..e6782884f38 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, mac: ast::Mac, ident: Option, span: Span, @@ -386,8 +385,8 @@ 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) -> 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; @@ -432,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(..) => { @@ -590,11 +589,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { placeholder(expansion_kind, ast::NodeId::from_u32(mark.as_u32())) } - fn collect_bang( - &mut self, mac: ast::Mac, attrs: Vec, span: Span, kind: ExpansionKind, - ) -> Expansion { - self.check_attributes(&attrs); - 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) @@ -663,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)) } @@ -674,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))) } @@ -688,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!(), }) } @@ -710,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. @@ -758,7 +754,6 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { ItemKind::Mac(mac) => { self.collect(ExpansionKind::Items, InvocationKind::Bang { mac: mac, - attrs: item.attrs, ident: Some(item.ident), span: item.span, }).make_items() @@ -830,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), } @@ -848,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), } @@ -861,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!(), } } -- cgit 1.4.1-3-g733a5 From 745ddf2aa78e4515d6a41e34a301d97afbde33ba Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 1 Dec 2016 22:49:32 +0000 Subject: Refactor out `mark.as_placeholder_id()`. --- src/libsyntax/ext/expand.rs | 8 ++++---- src/libsyntax/ext/hygiene.rs | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index e6782884f38..5d62175fbf2 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -275,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()); } @@ -286,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); } } @@ -586,7 +586,7 @@ 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, span: Span, kind: ExpansionKind) -> Expansion { @@ -748,7 +748,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { item.and_then(|mut item| match item.node { ItemKind::Mac(_) if is_macro_def => { - item.id = ast::NodeId::from_u32(Mark::fresh().as_u32()); + item.id = Mark::fresh().as_placeholder_id(); SmallVector::one(P(item)) } ItemKind::Mac(mac) => { diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs index 8842cb55b1e..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 } } -- cgit 1.4.1-3-g733a5 From 8e61ff25d85dcdc81c55f51ba2a777e13e561a25 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 10 Dec 2016 06:45:58 +0000 Subject: Optimize `ast::PathSegment`. --- src/librustc/hir/lowering.rs | 18 ++++--- src/librustc_passes/ast_validation.rs | 4 +- src/librustc_resolve/lib.rs | 14 ++--- src/librustc_resolve/macros.rs | 4 +- src/libsyntax/ast.rs | 97 ++++++----------------------------- src/libsyntax/ext/build.rs | 31 +++++------ src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/mod.rs | 53 ++++--------------- src/libsyntax/parse/parser.rs | 40 +++++---------- src/libsyntax/print/pprust.rs | 13 ++--- src/libsyntax/std_inject.rs | 5 +- src/libsyntax/test.rs | 5 +- src/libsyntax/visit.rs | 4 +- src/libsyntax_ext/concat_idents.rs | 6 +-- 14 files changed, 86 insertions(+), 210 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index f5773d35178..e8c3492705a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -433,13 +433,19 @@ impl<'a> LoweringContext<'a> { segment: &PathSegment, param_mode: ParamMode) -> hir::PathSegment { - let parameters = match segment.parameters { - PathParameters::AngleBracketed(ref data) => { - let data = self.lower_angle_bracketed_parameter_data(data, param_mode); - hir::AngleBracketedParameters(data) + let parameters = if let Some(ref parameters) = segment.parameters { + match **parameters { + PathParameters::AngleBracketed(ref data) => { + let data = self.lower_angle_bracketed_parameter_data(data, param_mode); + hir::AngleBracketedParameters(data) + } + PathParameters::Parenthesized(ref data) => { + hir::ParenthesizedParameters(self.lower_parenthesized_parameter_data(data)) + } } - PathParameters::Parenthesized(ref data) => - hir::ParenthesizedParameters(self.lower_parenthesized_parameter_data(data)), + } else { + let data = self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode); + hir::AngleBracketedParameters(data) }; hir::PathSegment { diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 2d0f0864752..bc150b84778 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -171,7 +171,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match item.node { ItemKind::Use(ref view_path) => { let path = view_path.node.path(); - if !path.segments.iter().all(|segment| segment.parameters.is_empty()) { + if path.segments.iter().any(|segment| segment.parameters.is_some()) { self.err_handler() .span_err(path.span, "type or lifetime parameters in import path"); } @@ -275,7 +275,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_vis(&mut self, vis: &'a Visibility) { match *vis { Visibility::Restricted { ref path, .. } => { - if !path.segments.iter().all(|segment| segment.parameters.is_empty()) { + if !path.segments.iter().all(|segment| segment.parameters.is_none()) { self.err_handler() .span_err(path.span, "type or lifetime parameters in visibility path"); } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d87e04f7b97..821820df838 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -62,7 +62,7 @@ use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind}; use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, Generics}; use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; use syntax::ast::{Local, Mutability, Pat, PatKind, Path}; -use syntax::ast::{PathSegment, PathParameters, QSelf, TraitItemKind, TraitRef, Ty, TyKind}; +use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind}; use syntax_pos::{Span, DUMMY_SP}; use errors::DiagnosticBuilder; @@ -2960,14 +2960,9 @@ impl<'a> Resolver<'a> { if ident.name == lookup_name && ns == namespace { if filter_fn(name_binding.def()) { // create the path - let params = PathParameters::none(); - let segment = PathSegment { - identifier: ident, - parameters: params, - }; let span = name_binding.span; let mut segms = path_segments.clone(); - segms.push(segment); + segms.push(ident.into()); let path = Path { span: span, global: false, @@ -2990,10 +2985,7 @@ impl<'a> Resolver<'a> { if let Some(module) = name_binding.module() { // form the path let mut path_segments = path_segments.clone(); - path_segments.push(PathSegment { - identifier: ident, - parameters: PathParameters::none(), - }); + path_segments.push(ident.into()); if !in_module_is_extern || name_binding.vis == ty::Visibility::Public { // add the module to the lookup diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index ce92a4446f9..6399a266fcf 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -183,9 +183,9 @@ impl<'a> base::Resolver for Resolver<'a> { fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) -> Result, Determinacy> { let ast::Path { ref segments, global, span } = *path; - if segments.iter().any(|segment| !segment.parameters.is_empty()) { + if segments.iter().any(|segment| segment.parameters.is_some()) { let kind = - if segments.last().unwrap().parameters.is_empty() { "module" } else { "macro" }; + if segments.last().unwrap().parameters.is_some() { "macro" } else { "module" }; let msg = format!("type parameters are not allowed on {}s", kind); self.session.span_err(path.span, &msg); return Err(Determinacy::Determined); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 39d78cd8776..fdd82225b97 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -137,12 +137,7 @@ impl Path { Path { span: s, global: false, - segments: vec![ - PathSegment { - identifier: identifier, - parameters: PathParameters::none() - } - ], + segments: vec![identifier.into()], } } } @@ -160,7 +155,15 @@ 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>` wrapper is purely a size optimization; + /// `None` is used to represent both `Path` and `Path<>`. + pub parameters: Option>, +} + +impl From for PathSegment { + fn from(id: Ident) -> Self { + PathSegment { identifier: id, parameters: None } + } } /// Parameters of a path segment. @@ -174,79 +177,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> { - 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, @@ -258,9 +190,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>> for AngleBracketedParameterData { + fn into(self) -> Option> { + let empty = self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty(); + if empty { None } else { Some(P(PathParameters::AngleBracketed(self))) } } } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index a208b934d79..c0dfb900240 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -322,21 +322,17 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: Vec ) -> ast::Path { let last_identifier = idents.pop().unwrap(); - let mut segments: Vec = 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 = idents.into_iter().map(Into::into).collect(); + 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, @@ -367,13 +363,14 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: Vec) -> (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 { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 6af8efb2a19..b3753e3e977 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -438,7 +438,7 @@ pub fn noop_fold_path(Path {global, segments, span}: Path, fld: &mut 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) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index c982205f0ec..b9e6605639e 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -634,12 +634,7 @@ mod tests { 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 +646,10 @@ 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), + global: true, + segments: vec![Ident::from_str("a").into(), Ident::from_str("b").into()], + }), span: sp(0, 6), attrs: ThinVec::new(), })) @@ -772,12 +758,7 @@ mod tests { 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(), @@ -795,12 +776,7 @@ mod tests { 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()})), @@ -842,12 +818,7 @@ mod tests { 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) }), @@ -890,13 +861,7 @@ mod tests { 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 a1d4ad9d629..72462b74e68 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1705,12 +1705,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; @@ -1727,18 +1726,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) { @@ -1757,10 +1755,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); } @@ -1768,14 +1763,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::`, check for `::` before proceeding @@ -1784,10 +1778,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()); } } } @@ -1802,10 +1793,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() { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index c28b9d00501..22e8391de93 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2349,7 +2349,9 @@ impl<'a> State<'a> { try!(self.print_ident(segment.identifier)); - try!(self.print_path_parameters(&segment.parameters, colons_before_params)); + if let Some(ref parameters) = segment.parameters { + try!(self.print_path_parameters(parameters, colons_before_params)) + } } Ok(()) @@ -2373,7 +2375,10 @@ impl<'a> State<'a> { 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 +2386,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, "::")) } diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 6a291ad9c40..4ad760a3caf 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -81,9 +81,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: vec![name, "prelude", "v1"].into_iter().map(|name| { + ast::Ident::from_str(name).into() }).collect(), span: span, })))), diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index fca89e265e4..7709d3bd1cf 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -580,10 +580,7 @@ fn path_node(ids: Vec) -> 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/visit.rs b/src/libsyntax/visit.rs index c1391d0b1c2..ad29cb50a84 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -383,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, diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index b26e33eb384..1381490efa1 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -59,14 +59,10 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, impl Result { fn path(&self) -> ast::Path { - let segment = ast::PathSegment { - identifier: self.ident, - parameters: ast::PathParameters::none(), - }; ast::Path { span: self.span, global: false, - segments: vec![segment], + segments: vec![self.ident.into()], } } } -- cgit 1.4.1-3-g733a5 From 164f0105bb65f31b89e5fb7f368c9e6f5833a3f8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 25 Oct 2016 22:19:19 +0200 Subject: Add safe_suggestion attribute --- src/libcollections/lib.rs | 1 + src/libcollections/string.rs | 1 + src/librustc/infer/error_reporting.rs | 29 ++++++++++++++++++++++++----- src/libsyntax/feature_gate.rs | 9 +++++++++ 4 files changed, 35 insertions(+), 5 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 68b067012d3..673a717b5f8 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -28,6 +28,7 @@ #![cfg_attr(test, allow(deprecated))] // rand #![cfg_attr(not(stage0), deny(warnings))] +#![cfg_attr(not(stage0), feature(safe_suggestion))] #![feature(alloc)] #![feature(allow_internal_unstable)] diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index b4c41a99a6b..a5017d5d701 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1231,6 +1231,7 @@ impl String { /// assert_eq!(a.len(), 3); /// ``` #[inline] + #[cfg_attr(not(stage0), safe_suggestion)] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { self.vec.len() diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index d50853e3a0e..98cbd742b10 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -587,19 +587,29 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // look for expected with found id self.tcx.populate_inherent_implementations_for_type_if_necessary(found); if let Some(impl_infos) = self.tcx.inherent_impls.borrow().get(&found) { - let mut methods = Vec::new(); + let mut methods: Vec<(Option, DefId, ImplOrTraitItem<'tcx>)> = Vec::new(); for impl_ in impl_infos { methods.append(&mut self.tcx .impl_or_trait_items(*impl_) .iter() - .map(|&did| self.tcx.impl_or_trait_item(did)) - .filter(|x| { + .map(|&did| (None, did, self.tcx.impl_or_trait_item(did))) + .filter(|&(_, _, ref x)| { self.matches_return_type(x, &expected_ty) }) .collect()); } - for method in methods { - println!("==> {:?}", method.name()); + let safe_suggestions: Vec<_> = methods.iter() + .map(|&(_, ref id, ref x)| (self.find_attr(*id, "safe_suggestion"), id, x)) + .filter(|&(ref res, _, _)| res.is_some()) + .collect(); + if safe_suggestions.len() > 0 { + for (_, _, method) in safe_suggestions { + println!("safe ==> {:?}", method.name()); + } + } else { + for &(_, _, ref method) in methods.iter() { + println!("not safe ==> {:?}", method.name()); + } } } } @@ -615,6 +625,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.note_and_explain_type_err(diag, terr, span); } + fn find_attr(&self, def_id: DefId, attr_name: &str) -> Option { + for item in self.tcx.get_attrs(def_id).iter() { + if item.check_name(attr_name) { + return Some(item.clone()); + } + } + None + } + pub fn report_and_explain_type_error(&self, trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 77c53542dcb..dbb31b0e56c 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! ( @@ -648,6 +652,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "internal implementation detail", cfg_fn!(rustc_attrs))), + ("safe_suggestion", Whitelisted, Gated("safe_suggestion", + "the `#[safe_suggestion]` attribute \ + is an experimental feature", + cfg_fn!(safe_suggestion))), + // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted, Ungated), -- cgit 1.4.1-3-g733a5 From b2d0ec0eb4cb468fefb66da7af67b9cf8132373e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 28 Oct 2016 01:04:16 +0200 Subject: Fix coercion ICE --- src/librustc_typeck/check/method/mod.rs | 21 ----------------- src/librustc_typeck/check/method/probe.rs | 39 +++++++++++++++++-------------- src/libsyntax/feature_gate.rs | 3 ++- 3 files changed, 24 insertions(+), 39 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 334ef30487a..bd240c74133 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -354,25 +354,4 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -> Option { self.tcx.associated_items(def_id).find(|item| item.name == item_name) } - - pub fn matches_return_type(&self, method: &ty::ImplOrTraitItem<'tcx>, - expected: ty::Ty<'tcx>) -> bool { - match *method { - ty::ImplOrTraitItem::MethodTraitItem(ref x) => { - self.can_sub_types(x.fty.sig.skip_binder().output, expected).is_ok() - } - _ => false, - } - } - - pub fn impl_or_return_item(&self, - def_id: DefId, - return_type: ty::Ty<'tcx>) - -> Option> { - self.tcx - .impl_or_trait_items(def_id) - .iter() - .map(|&did| self.tcx.impl_or_trait_item(did)) - .find(|m| self.matches_return_type(m, return_type)) - } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 85a2fcd2ba1..e735360274e 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -21,7 +21,8 @@ use rustc::ty::subst::{Subst, Substs}; use rustc::traits::{self, ObligationCause}; use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable}; use rustc::infer::type_variable::TypeVariableOrigin; -use rustc::util::nodemap::FxHashSet; +use rustc::util::nodemap::{FnvHashSet, FxHashSet}; +use rustc::infer::{self, InferOk, TypeOrigin}; use syntax::ast; use syntax_pos::Span; use rustc::hir; @@ -626,27 +627,27 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { Ok(()) } + pub fn matches_return_type(&self, method: &ty::ImplOrTraitItem<'tcx>, + expected: ty::Ty<'tcx>) -> bool { + match *method { + ty::ImplOrTraitItem::MethodTraitItem(ref x) => { + self.probe(|_| { + let output = self.replace_late_bound_regions_with_fresh_var( + self.span, infer::FnCall, &x.fty.sig.output()); + self.can_sub_types(output.0, expected).is_ok() + }) + } + _ => false, + } + } + fn assemble_extension_candidates_for_trait(&mut self, trait_def_id: DefId) -> Result<(), MethodError<'tcx>> { debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id); - // Check whether `trait_def_id` defines a method with suitable name: - let trait_items = self.tcx.associated_items(trait_def_id); - let maybe_item = match self.looking_for { - LookingFor::MethodName(item_name) => { - trait_items.iter() - .find(|item| item.name == item_name) - } - LookingFor::ReturnType(item_ty) => { - trait_items.iter() - .find(|item| { - self.fcx.matches_return_type(item, &item_ty) - }) - } - }; - let item = match maybe_item { + let item = match self.impl_or_trait_item(trait_def_id) { Some(i) => i, None => { return Ok(()); @@ -1351,7 +1352,11 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.fcx.impl_or_trait_item(def_id, name) } LookingFor::ReturnType(return_ty) => { - self.fcx.impl_or_return_item(def_id, return_ty) + self.tcx + .impl_or_trait_items(def_id) + .iter() + .map(|&did| self.tcx.impl_or_trait_item(did)) + .find(|m| self.matches_return_type(m, return_ty)) } } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index dbb31b0e56c..a176a1ddede 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -652,7 +652,8 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "internal implementation detail", cfg_fn!(rustc_attrs))), - ("safe_suggestion", Whitelisted, Gated("safe_suggestion", + ("safe_suggestion", Whitelisted, Gated(Stability::Unstable, + "safe_suggestion", "the `#[safe_suggestion]` attribute \ is an experimental feature", cfg_fn!(safe_suggestion))), -- cgit 1.4.1-3-g733a5 From c11fe553df269d6f47b4c48f5c47c08efdd373dc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 28 Oct 2016 14:27:42 +0200 Subject: Create check_ref method to allow to check coercion with & types --- src/libcollections/lib.rs | 1 - src/libcollections/string.rs | 1 - src/librustc/infer/error_reporting.rs | 2 +- src/librustc_typeck/check/demand.rs | 116 +++++++++++++++------------- src/librustc_typeck/check/method/probe.rs | 16 ++-- src/libsyntax/feature_gate.rs | 6 -- src/test/compile-fail/coerce_suggestions.rs | 41 ++++++++++ 7 files changed, 114 insertions(+), 69 deletions(-) create mode 100644 src/test/compile-fail/coerce_suggestions.rs (limited to 'src/libsyntax') diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 673a717b5f8..68b067012d3 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -28,7 +28,6 @@ #![cfg_attr(test, allow(deprecated))] // rand #![cfg_attr(not(stage0), deny(warnings))] -#![cfg_attr(not(stage0), feature(safe_suggestion))] #![feature(alloc)] #![feature(allow_internal_unstable)] diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index a5017d5d701..b4c41a99a6b 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1231,7 +1231,6 @@ impl String { /// assert_eq!(a.len(), 3); /// ``` #[inline] - #[cfg_attr(not(stage0), safe_suggestion)] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { self.vec.len() diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index a67af1d5dcc..90d752ae6ee 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -549,7 +549,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { let expected_found = match values { None => None, - Some(ref values) => match self.values_str(&values) { + Some(values) => match self.values_str(&values) { Some((expected, found)) => Some((expected, found)), None => { // Derived error. Cancel the emitter. diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 01a961949bc..6246e95faeb 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -19,28 +19,10 @@ use syntax_pos::{self, Span}; use rustc::hir; use rustc::ty::{self, ImplOrTraitItem}; -use hir::def_id::DefId; - use std::rc::Rc; use super::method::probe; -struct MethodInfo<'tcx> { - ast: Option, - id: DefId, - item: Rc>, -} - -impl<'tcx> MethodInfo<'tcx> { - fn new(ast: Option, id: DefId, item: Rc>) -> MethodInfo { - MethodInfo { - ast: ast, - id: id, - item: item, - } - } -} - impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Requires that the two types unify, and prints an error message if // they don't. @@ -79,6 +61,46 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + fn check_ref(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, + expected: Ty<'tcx>) -> Option { + match (&checked_ty.sty, &expected.sty) { + (&ty::TyRef(_, x_mutability), &ty::TyRef(_, y_mutability)) => { + // check if there is a mutability difference + if x_mutability.mutbl == hir::Mutability::MutImmutable && + x_mutability.mutbl != y_mutability.mutbl && + self.can_sub_types(&x_mutability.ty, y_mutability.ty).is_ok() { + if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) { + return Some(format!("try with `&mut {}`", &src.replace("&", ""))); + } + } + None + } + (_, &ty::TyRef(_, mutability)) => { + // check if it can work when put into a ref + let ref_ty = match mutability.mutbl { + hir::Mutability::MutMutable => self.tcx.mk_mut_ref( + self.tcx.mk_region(ty::ReStatic), + checked_ty), + hir::Mutability::MutImmutable => self.tcx.mk_imm_ref( + self.tcx.mk_region(ty::ReStatic), + checked_ty), + }; + if self.try_coerce(expr, ref_ty, expected).is_ok() { + if let Ok(src) = self.tcx.sess.codemap().span_to_snippet(expr.span) { + return Some(format!("try with `{}{}`", + match mutability.mutbl { + hir::Mutability::MutMutable => "&mut ", + hir::Mutability::MutImmutable => "&", + }, + &src)); + } + } + None + } + _ => None, + } + } + // Checks that the type of `expr` can be coerced to `expected`. pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) { let expected = self.resolve_type_vars_with_obligations(expected); @@ -86,34 +108,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let cause = self.misc(expr.span); let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); let mode = probe::Mode::MethodCall; - let suggestions = - if let Ok(methods) = self.probe_return(syntax_pos::DUMMY_SP, mode, expected, - checked_ty, ast::DUMMY_NODE_ID) { + let suggestions = if let Some(s) = self.check_ref(expr, checked_ty, expected) { + Some(s) + } else if let Ok(methods) = self.probe_return(syntax_pos::DUMMY_SP, + mode, + expected, + checked_ty, + ast::DUMMY_NODE_ID) { let suggestions: Vec<_> = methods.iter() - .filter_map(|ref x| { - if let Some(id) = self.get_impl_id(&x.item) { - Some(MethodInfo::new(None, id, Rc::new(x.item.clone()))) - } else { - None - }}) + .map(|ref x| { + Rc::new(x.item.clone()) + }) .collect(); if suggestions.len() > 0 { - let safe_suggestions: Vec<_> = - suggestions.iter() - .map(|ref x| MethodInfo::new( - self.find_attr(x.id, "safe_suggestion"), - x.id, - x.item.clone())) - .filter(|ref x| x.ast.is_some()) - .collect(); - Some(if safe_suggestions.len() > 0 { - self.get_best_match(&safe_suggestions) - } else { - format!("no safe suggestion found, here are functions which match your \ - needs but be careful:\n - {}", - self.get_best_match(&suggestions)) - }) + Some(format!("here are some functions which \ + might fulfill your needs:\n - {}", + self.get_best_match(&suggestions))) } else { None } @@ -132,34 +143,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn get_best_match(&self, methods: &[MethodInfo<'tcx>]) -> String { + fn get_best_match(&self, methods: &[Rc>]) -> String { if methods.len() == 1 { - return format!(" - {}", methods[0].item.name()); + return format!(" - {}", methods[0].name()); } - let no_argument_methods: Vec<&MethodInfo> = + let no_argument_methods: Vec<&Rc>> = methods.iter() - .filter(|ref x| self.has_not_input_arg(&*x.item)) + .filter(|ref x| self.has_not_input_arg(&*x)) .collect(); if no_argument_methods.len() > 0 { no_argument_methods.iter() - .map(|method| format!("{}", method.item.name())) + .take(5) + .map(|method| format!("{}", method.name())) .collect::>() .join("\n - ") } else { methods.iter() - .map(|method| format!("{}", method.item.name())) + .take(5) + .map(|method| format!("{}", method.name())) .collect::>() .join("\n - ") } } - fn get_impl_id(&self, impl_: &ImplOrTraitItem<'tcx>) -> Option { - match *impl_ { - ty::ImplOrTraitItem::MethodTraitItem(ref m) => Some((*m).def_id), - _ => None, - } - } - fn has_not_input_arg(&self, method: &ImplOrTraitItem<'tcx>) -> bool { match *method { ImplOrTraitItem::MethodTraitItem(ref x) => { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index e735360274e..4a63c967920 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -194,7 +194,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // think cause spurious errors. Really though this part should // take place in the `self.probe` below. let steps = if mode == Mode::MethodCall { - match self.create_steps(span, self_ty) { + match self.create_steps(span, self_ty, &looking_for) { Some(steps) => steps, None => { return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), @@ -247,7 +247,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn create_steps(&self, span: Span, - self_ty: Ty<'tcx>) + self_ty: Ty<'tcx>, + looking_for: &LookingFor<'tcx>) -> Option>> { // FIXME: we don't need to create the entire steps in one pass @@ -262,7 +263,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) .collect(); - let final_ty = autoderef.unambiguous_final_ty(); + let final_ty = match looking_for { + &LookingFor::MethodName(_) => autoderef.unambiguous_final_ty(), + &LookingFor::ReturnType(_) => self_ty, + }; match final_ty.sty { ty::TyArray(elem_ty, _) => { let dereferences = steps.len() - 1; @@ -628,13 +632,15 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } pub fn matches_return_type(&self, method: &ty::ImplOrTraitItem<'tcx>, - expected: ty::Ty<'tcx>) -> bool { + expected: ty::Ty<'tcx>) -> bool { match *method { ty::ImplOrTraitItem::MethodTraitItem(ref x) => { self.probe(|_| { let output = self.replace_late_bound_regions_with_fresh_var( self.span, infer::FnCall, &x.fty.sig.output()); - self.can_sub_types(output.0, expected).is_ok() + let substs = self.fresh_substs_for_item(self.span, method.def_id()); + let output = output.0.subst(self.tcx, substs); + self.can_sub_types(output, expected).is_ok() }) } _ => false, diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index a176a1ddede..e04cc11f15e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -652,12 +652,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "internal implementation detail", cfg_fn!(rustc_attrs))), - ("safe_suggestion", Whitelisted, Gated(Stability::Unstable, - "safe_suggestion", - "the `#[safe_suggestion]` attribute \ - is an experimental feature", - cfg_fn!(safe_suggestion))), - // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted, Ungated), diff --git a/src/test/compile-fail/coerce_suggestions.rs b/src/test/compile-fail/coerce_suggestions.rs new file mode 100644 index 00000000000..decd589e6f4 --- /dev/null +++ b/src/test/compile-fail/coerce_suggestions.rs @@ -0,0 +1,41 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn test(_x: &mut String) {} +fn test2(_x: &mut i32) {} + +fn main() { + let x: usize = String::new(); + //^ ERROR E0308 + //| NOTE expected type `usize` + //| NOTE found type `std::string::String` + //| NOTE here are some functions which might fulfill your needs: + let x: &str = String::new(); + //^ ERROR E0308 + //| NOTE expected type `&str` + //| NOTE found type `std::string::String` + //| NOTE try with `&String::new()` + let y = String::new(); + test(&y); + //^ ERROR E0308 + //| NOTE expected type `&mut std::string::String` + //| NOTE found type `&std::string::String` + //| NOTE try with `&mut y` + test2(&y); + //^ ERROR E0308 + //| NOTE expected type `&mut i32` + //| NOTE found type `&std::string::String` + //| NOTE try with `&mut y` + let f; + f = box f; + //^ ERROR E0308 + //| NOTE expected type `_` + //| NOTE found type `Box<_>` +} -- cgit 1.4.1-3-g733a5 From f10f50b42639718b2580d10802f05f2b6ff209d5 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Dec 2016 03:51:11 +0000 Subject: Refactor how global paths are represented (for both ast and hir). --- src/librustc/hir/lowering.rs | 46 +++++------ src/librustc/hir/mod.rs | 9 +- src/librustc/hir/print.rs | 28 +++---- src/librustc/infer/error_reporting.rs | 1 - src/librustc_const_eval/_match.rs | 1 - .../calculate_svh/svh_visitor.rs | 2 - src/librustc_lint/bad_style.rs | 2 +- src/librustc_passes/ast_validation.rs | 4 +- src/librustc_resolve/build_reduced_graph.rs | 31 ++++--- src/librustc_resolve/lib.rs | 96 +++++++++------------- src/librustc_resolve/macros.rs | 28 +++---- src/librustc_resolve/resolve_imports.rs | 21 +++-- src/librustc_save_analysis/dump_visitor.rs | 49 ++++------- src/librustdoc/clean/mod.rs | 27 +++--- src/libsyntax/ast.rs | 27 +++++- src/libsyntax/ext/build.rs | 8 +- src/libsyntax/ext/placeholders.rs | 2 +- src/libsyntax/fold.rs | 3 +- src/libsyntax/parse/mod.rs | 10 +-- src/libsyntax/parse/parser.rs | 16 ++-- src/libsyntax/print/pprust.rs | 67 ++++++++------- src/libsyntax/std_inject.rs | 3 +- src/libsyntax/symbol.rs | 3 + src/libsyntax/test.rs | 1 - src/libsyntax_ext/concat_idents.rs | 1 - src/libsyntax_ext/deriving/generic/mod.rs | 11 +-- .../compile-fail/resolve-primitive-fallback.rs | 2 +- 27 files changed, 242 insertions(+), 257 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index e8c3492705a..1cf5e35a095 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -81,7 +81,7 @@ pub struct LoweringContext<'a> { } pub trait Resolver { - // Resolve a global hir path generated by the lowerer when expanding `for`, `if let`, etc. + // Resolve a hir path generated by the lowerer when expanding `for`, `if let`, etc. fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool); // Obtain the resolution for a node id @@ -337,7 +337,6 @@ impl<'a> LoweringContext<'a> { let proj_start = p.segments.len() - resolution.depth; let path = P(hir::Path { - global: p.global, def: resolution.base_def, segments: p.segments[..proj_start].iter().enumerate().map(|(i, segment)| { let param_mode = match (qself_position, param_mode) { @@ -404,12 +403,17 @@ impl<'a> LoweringContext<'a> { id: NodeId, p: &Path, name: Option, - param_mode: ParamMode) + param_mode: ParamMode, + defaults_to_global: bool) -> hir::Path { + let mut segments = p.segments.iter(); + if defaults_to_global && p.is_global() { + segments.next(); + } + hir::Path { - global: p.global, def: self.expect_full_def(id), - segments: p.segments.iter().map(|segment| { + segments: segments.map(|segment| { self.lower_path_segment(segment, param_mode) }).chain(name.map(|name| { hir::PathSegment { @@ -424,9 +428,10 @@ impl<'a> LoweringContext<'a> { fn lower_path(&mut self, id: NodeId, p: &Path, - param_mode: ParamMode) + param_mode: ParamMode, + defaults_to_global: bool) -> hir::Path { - self.lower_path_extra(id, p, None, param_mode) + self.lower_path_extra(id, p, None, param_mode, defaults_to_global) } fn lower_path_segment(&mut self, @@ -602,8 +607,8 @@ impl<'a> LoweringContext<'a> { // Check if the where clause type is a plain type parameter. match bound_pred.bounded_ty.node { TyKind::Path(None, ref path) - if !path.global && path.segments.len() == 1 && - bound_pred.bound_lifetimes.is_empty() => { + if path.segments.len() == 1 && + bound_pred.bound_lifetimes.is_empty() => { if let Some(Def::TyParam(def_id)) = self.resolver.get_resolution(bound_pred.bounded_ty.id) .map(|d| d.base_def) { @@ -677,7 +682,7 @@ impl<'a> LoweringContext<'a> { span}) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { id: id, - path: self.lower_path(id, path, ParamMode::Explicit), + path: self.lower_path(id, path, ParamMode::Explicit, false), ty: self.lower_ty(ty), span: span, }) @@ -707,7 +712,7 @@ impl<'a> LoweringContext<'a> { fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef { hir::TraitRef { - path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit), + path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit, false), ref_id: p.ref_id, } } @@ -800,7 +805,7 @@ impl<'a> LoweringContext<'a> { }; let mut path = self.lower_path_extra(import.id, path, suffix, - ParamMode::Explicit); + ParamMode::Explicit, true); path.span = span; self.items.insert(import.id, hir::Item { id: import.id, @@ -814,7 +819,7 @@ impl<'a> LoweringContext<'a> { path } }; - let path = P(self.lower_path(id, path, ParamMode::Explicit)); + let path = P(self.lower_path(id, path, ParamMode::Explicit, true)); let kind = match view_path.node { ViewPathSimple(ident, _) => { *name = ident.name; @@ -1135,7 +1140,6 @@ impl<'a> LoweringContext<'a> { Some(def) => { hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path { span: pth1.span, - global: false, def: def, segments: hir_vec![ hir::PathSegment::from_name(pth1.node.name) @@ -1878,7 +1882,7 @@ impl<'a> LoweringContext<'a> { Visibility::Crate(_) => hir::Visibility::Crate, Visibility::Restricted { ref path, id } => { hir::Visibility::Restricted { - path: P(self.lower_path(id, path, ParamMode::Explicit)), + path: P(self.lower_path(id, path, ParamMode::Explicit, true)), id: id } } @@ -1971,7 +1975,6 @@ impl<'a> LoweringContext<'a> { let expr_path = hir::ExprPath(hir::QPath::Resolved(None, P(hir::Path { span: span, - global: false, def: def, segments: hir_vec![hir::PathSegment::from_name(id)], }))); @@ -2139,17 +2142,12 @@ impl<'a> LoweringContext<'a> { /// `fld.cx.use_std`, and `::core::b::c::d` otherwise. /// The path is also resolved according to `is_value`. fn std_path(&mut self, span: Span, components: &[&str], is_value: bool) -> hir::Path { - let idents = self.crate_root.iter().chain(components); - - let segments: Vec<_> = idents.map(|name| { - hir::PathSegment::from_name(Symbol::intern(name)) - }).collect(); - let mut path = hir::Path { span: span, - global: true, def: Def::Err, - segments: segments.into(), + segments: iter::once(keywords::CrateRoot.name()).chain({ + self.crate_root.into_iter().chain(components.iter().cloned()).map(Symbol::intern) + }).map(hir::PathSegment::from_name).collect(), }; self.resolver.resolve_hir_path(&mut path, is_value); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f52ee35e175..a0039f612b9 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -105,15 +105,18 @@ 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 definition that the path resolved to. pub def: Def, /// The segments in the path: the things separated by `::`. pub segments: HirVec, } +impl Path { + pub fn is_global(&self) -> bool { + !self.segments.is_empty() && self.segments[0].name == keywords::CrateRoot.name() + } +} + impl fmt::Debug for Path { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "path({})", print::path_to_string(self)) diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 74920b13280..de4047df81c 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1643,17 +1643,14 @@ impl<'a> State<'a> { -> io::Result<()> { self.maybe_print_comment(path.span.lo)?; - let mut first = !path.global; - for segment in &path.segments { - if first { - first = false - } else { + for (i, segment) in path.segments.iter().enumerate() { + if i > 0 { word(&mut self.s, "::")? } - - self.print_name(segment.name)?; - - self.print_path_parameters(&segment.parameters, colons_before_params)?; + if segment.name != keywords::CrateRoot.name() { + self.print_name(segment.name)?; + self.print_path_parameters(&segment.parameters, colons_before_params)?; + } } Ok(()) @@ -1673,15 +1670,14 @@ impl<'a> State<'a> { space(&mut self.s)?; self.word_space("as")?; - let mut first = !path.global; - for segment in &path.segments[..path.segments.len() - 1] { - if first { - first = false - } else { + for (i, segment) in path.segments[..path.segments.len() - 1].iter().enumerate() { + if i > 0 { word(&mut self.s, "::")? } - self.print_name(segment.name)?; - self.print_path_parameters(&segment.parameters, colons_before_params)?; + if segment.name != keywords::CrateRoot.name() { + self.print_name(segment.name)?; + self.print_path_parameters(&segment.parameters, colons_before_params)?; + } } word(&mut self.s, ">")?; diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 90d752ae6ee..9d48fbca53e 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -1620,7 +1620,6 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { new_segs.push(new_seg); hir::Path { span: path.span, - global: path.global, def: path.def, segments: new_segs.into() } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 23771f4bae3..ebe10349011 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -324,7 +324,6 @@ impl Witness { let v = ctor.variant_for_adt(adt); let qpath = hir::QPath::Resolved(None, P(hir::Path { span: DUMMY_SP, - global: false, def: Def::Err, segments: vec![hir::PathSegment::from_name(v.name)].into(), })); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index ec44e19df10..bd865d10efc 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -189,7 +189,6 @@ enum SawAbiComponent<'a> { SawStructField, SawVariant, SawQPath, - SawPath(bool), SawPathSegment, SawPathParameters, SawBlock, @@ -678,7 +677,6 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) { debug!("visit_path: st={:?}", self.st); - SawPath(path.global).hash(self.st); hash_span!(self, path.span); visit::walk_path(self, path) } diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 2aa74407afc..1d384741d96 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -382,7 +382,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) { // Lint for constants that look like binding identifiers (#7526) if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node { - if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() { + if path.segments.len() == 1 && path.segments[0].parameters.is_empty() { if let Def::Const(..) = path.def { NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern", diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index bc150b84778..52bdd014933 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -154,8 +154,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_path(&mut self, path: &'a Path, id: NodeId) { - if path.global && path.segments.len() > 0 { - let ident = path.segments[0].identifier; + if path.segments.len() >= 2 && path.is_global() { + let ident = path.segments[1].identifier; if token::Ident(ident).is_path_segment_keyword() { self.session.add_lint(lint::builtin::SUPER_OR_SELF_IN_GLOBAL_PATH, id, diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index cd2a2767979..09f438953ec 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -40,6 +40,7 @@ use syntax::ext::base::Determinacy::Undetermined; use syntax::ext::expand::mark_tts; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; +use syntax::parse::token; use syntax::symbol::keywords; use syntax::visit::{self, Visitor}; @@ -112,7 +113,7 @@ impl<'a> Resolver<'a> { // Extract and intern the module part of the path. For // globs and lists, the path is found directly in the AST; // for simple paths we have to munge the path a little. - let module_path: Vec<_> = match view_path.node { + let mut module_path: Vec<_> = match view_path.node { ViewPathSimple(_, ref full_path) => { full_path.segments .split_last() @@ -132,6 +133,12 @@ impl<'a> Resolver<'a> { } }; + // This can be removed once warning cycle #36888 is complete. + if module_path.len() >= 2 && module_path[0].name == keywords::CrateRoot.name() && + token::Ident(module_path[1]).is_path_segment_keyword() { + module_path.remove(0); + } + // Build up the import directives. let is_prelude = attr::contains_name(&item.attrs, "prelude_import"); @@ -193,18 +200,16 @@ impl<'a> Resolver<'a> { let rename = node.rename.unwrap_or(node.name); (module_path.clone(), node.name, rename) } else { - let ident = match module_path.last() { - Some(&ident) => ident, - None => { - resolve_error( - self, - source_item.span, - ResolutionError:: - SelfImportOnlyInImportListWithNonEmptyPrefix - ); - continue; - } - }; + let ident = *module_path.last().unwrap(); + if ident.name == keywords::CrateRoot.name() { + resolve_error( + self, + source_item.span, + ResolutionError:: + SelfImportOnlyInImportListWithNonEmptyPrefix + ); + continue; + } let module_path = module_path.split_last().unwrap().1; let rename = node.rename.unwrap_or(ident); (module_path.to_vec(), ident, rename) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f73227681c5..7f91576f6d6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -578,9 +578,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { fn visit_poly_trait_ref(&mut self, tref: &'tcx ast::PolyTraitRef, m: &'tcx ast::TraitBoundModifier) { - let ast::Path { ref segments, span, global } = tref.trait_ref.path; + let ast::Path { ref segments, span } = tref.trait_ref.path; let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); - let def = self.resolve_trait_reference(&path, global, None, span); + let def = self.resolve_trait_reference(&path, None, span); self.record_def(tref.trait_ref.ref_id, def); visit::walk_poly_trait_ref(self, tref, m); } @@ -753,13 +753,6 @@ impl<'a> LexicalScopeBinding<'a> { } } -#[derive(Copy, Clone, PartialEq)] -enum PathScope { - Global, - Lexical, - Import, -} - #[derive(Clone)] enum PathResult<'a> { Module(Module<'a>), @@ -783,7 +776,7 @@ pub struct ModuleData<'a> { resolutions: RefCell>>>, legacy_macro_resolutions: RefCell>, - macro_resolutions: RefCell, PathScope, Span)>>, + macro_resolutions: RefCell, Span)>>, // Macro invocations that can expand into items in this module. unresolved_invocations: RefCell>, @@ -1174,13 +1167,12 @@ impl<'a> ty::NodeIdTree for Resolver<'a> { impl<'a> hir::lowering::Resolver for Resolver<'a> { fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) { let namespace = if is_value { ValueNS } else { TypeNS }; - let hir::Path { ref segments, span, global, ref mut def } = *path; + let hir::Path { ref segments, span, ref mut def } = *path; let path: Vec<_> = segments.iter().map(|seg| Ident::with_empty_ctxt(seg.name)).collect(); - let scope = if global { PathScope::Global } else { PathScope::Lexical }; - match self.resolve_path(&path, scope, Some(namespace), Some(span)) { + match self.resolve_path(&path, Some(namespace), Some(span)) { PathResult::Module(module) => *def = module.def().unwrap(), PathResult::NonModule(path_res) if path_res.depth == 0 => *def = path_res.base_def, - PathResult::NonModule(..) => match self.resolve_path(&path, scope, None, Some(span)) { + PathResult::NonModule(..) => match self.resolve_path(&path, None, Some(span)) { PathResult::Failed(msg, _) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); } @@ -1601,17 +1593,16 @@ impl<'a> Resolver<'a> { prefix.segments.iter().map(|seg| seg.identifier).collect(); // Resolve prefix of an import with empty braces (issue #28388) if items.is_empty() && !prefix.segments.is_empty() { - let (scope, span) = (PathScope::Import, prefix.span); + let span = prefix.span; // FIXME(#38012) This should be a module path, not anything in TypeNS. - let result = - self.resolve_path(&path, scope, Some(TypeNS), Some(span)); + let result = self.resolve_path(&path, Some(TypeNS), Some(span)); let (def, msg) = match result { PathResult::Module(module) => (module.def().unwrap(), None), PathResult::NonModule(res) if res.depth == 0 => (res.base_def, None), PathResult::NonModule(_) => { // Resolve a module path for better errors - match self.resolve_path(&path, scope, None, Some(span)) { + match self.resolve_path(&path, None, Some(span)) { PathResult::Failed(msg, _) => (Def::Err, Some(msg)), _ => unreachable!(), } @@ -1698,19 +1689,17 @@ impl<'a> Resolver<'a> { fn resolve_trait_reference(&mut self, path: &[Ident], - global: bool, generics: Option<&Generics>, span: Span) -> PathResolution { - let scope = if global { PathScope::Global } else { PathScope::Lexical }; - let def = match self.resolve_path(path, scope, None, Some(span)) { + let def = match self.resolve_path(path, None, Some(span)) { PathResult::Module(module) => Some(module.def().unwrap()), PathResult::NonModule(..) => return err_path_resolution(), PathResult::Failed(msg, false) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); return err_path_resolution(); } - _ => match self.resolve_path(path, scope, Some(TypeNS), None) { + _ => match self.resolve_path(path, Some(TypeNS), None) { PathResult::NonModule(path_resolution) => Some(path_resolution.base_def), _ => None, }, @@ -1766,9 +1755,9 @@ impl<'a> Resolver<'a> { let mut new_val = None; let mut new_id = None; if let Some(trait_ref) = opt_trait_ref { - let ast::Path { ref segments, span, global } = trait_ref.path; + let ast::Path { ref segments, span } = trait_ref.path; let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); - let path_res = self.resolve_trait_reference(&path, global, generics, span); + let path_res = self.resolve_trait_reference(&path, generics, span); assert!(path_res.depth == 0); self.record_def(trait_ref.ref_id, path_res); if path_res.base_def != Def::Err { @@ -2260,9 +2249,8 @@ impl<'a> Resolver<'a> { path: &Path, ns: Namespace) -> Option { - let ast::Path { ref segments, global, span } = *path; + let ast::Path { ref segments, span } = *path; let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); - let scope = if global { PathScope::Global } else { PathScope::Lexical }; if let Some(qself) = maybe_qself { if qself.position == 0 { @@ -2273,10 +2261,10 @@ impl<'a> Resolver<'a> { }); } // Make sure the trait is valid. - self.resolve_trait_reference(&path[..qself.position], global, None, span); + self.resolve_trait_reference(&path[..qself.position], None, span); } - let result = match self.resolve_path(&path, scope, Some(ns), Some(span)) { + let result = match self.resolve_path(&path, Some(ns), Some(span)) { PathResult::NonModule(path_res) => match path_res.base_def { Def::Trait(..) if maybe_qself.is_some() => return None, _ => path_res, @@ -2297,7 +2285,7 @@ impl<'a> Resolver<'a> { // Such behavior is required for backward compatibility. // The same fallback is used when `a` resolves to nothing. PathResult::Module(..) | PathResult::Failed(..) - if scope == PathScope::Lexical && (ns == TypeNS || path.len() > 1) && + if (ns == TypeNS || path.len() > 1) && self.primitive_type_table.primitive_types.contains_key(&path[0].name) => { PathResolution { base_def: Def::PrimTy(self.primitive_type_table.primitive_types[&path[0].name]), @@ -2317,7 +2305,7 @@ impl<'a> Resolver<'a> { } let unqualified_result = { - match self.resolve_path(&[*path.last().unwrap()], PathScope::Lexical, Some(ns), None) { + match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) { PathResult::NonModule(path_res) => path_res.base_def, PathResult::Module(module) => module.def().unwrap(), _ => return Some(result), @@ -2333,27 +2321,19 @@ impl<'a> Resolver<'a> { fn resolve_path(&mut self, path: &[Ident], - scope: PathScope, opt_ns: Option, // `None` indicates a module path record_used: Option) -> PathResult<'a> { - let (mut module, allow_self) = match scope { - PathScope::Lexical => (None, true), - PathScope::Import => (Some(self.graph_root), true), - PathScope::Global => (Some(self.graph_root), false), - }; - let mut allow_super = allow_self; + let mut module = None; + let mut allow_super = true; for (i, &ident) in path.iter().enumerate() { let is_last = i == path.len() - 1; let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; - if i == 0 && allow_self && ns == TypeNS && ident.name == keywords::SelfValue.name() { + if i == 0 && ns == TypeNS && ident.name == keywords::SelfValue.name() { module = Some(self.module_map[&self.current_module.normal_ancestor_id.unwrap()]); continue - } else if i == 0 && allow_self && ns == TypeNS && ident.name == "$crate" { - module = Some(self.resolve_crate_var(ident.ctxt)); - continue } else if allow_super && ns == TypeNS && ident.name == keywords::Super.name() { let current_module = if i == 0 { self.current_module } else { module.unwrap() }; let self_module = self.module_map[¤t_module.normal_ancestor_id.unwrap()]; @@ -2367,6 +2347,14 @@ impl<'a> Resolver<'a> { } allow_super = false; + if i == 0 && ns == TypeNS && ident.name == keywords::CrateRoot.name() { + module = Some(self.graph_root); + continue + } else if i == 0 && ns == TypeNS && ident.name == "$crate" { + module = Some(self.resolve_crate_var(ident.ctxt)); + continue + } + let binding = if let Some(module) = module { self.resolve_ident_in_module(module, ident, ns, false, record_used) } else if opt_ns == Some(MacroNS) { @@ -2430,7 +2418,7 @@ impl<'a> Resolver<'a> { } } - PathResult::Module(module.unwrap()) + PathResult::Module(module.unwrap_or(self.graph_root)) } // Resolve a local definition, potentially adjusting for closures. @@ -2665,10 +2653,8 @@ impl<'a> Resolver<'a> { } else { // Be helpful if the name refers to a struct let path_name = path_names_to_string(path, 0); - let ast::Path { ref segments, global, .. } = *path; - let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); - let scope = if global { PathScope::Global } else { PathScope::Lexical }; - let type_res = match self.resolve_path(&path, scope, Some(TypeNS), None) { + let path: Vec<_> = path.segments.iter().map(|seg| seg.identifier).collect(); + let type_res = match self.resolve_path(&path, Some(TypeNS), None) { PathResult::NonModule(type_res) => Some(type_res), _ => None, }; @@ -2738,7 +2724,7 @@ impl<'a> Resolver<'a> { } else { // we display a help message if this is a module if let PathResult::Module(module) = - self.resolve_path(&path, scope, None, None) { + self.resolve_path(&path, None, None) { def = module.def().unwrap(); context = UnresolvedNameContext::PathIsMod(parent); } @@ -2964,7 +2950,6 @@ impl<'a> Resolver<'a> { segms.push(ident.into()); let path = Path { span: span, - global: false, segments: segms, }; // the entity is accessible in the following cases: @@ -3022,7 +3007,7 @@ impl<'a> Resolver<'a> { let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); let mut path_resolution = err_path_resolution(); - let vis = match self.resolve_path(&path, PathScope::Import, None, Some(span)) { + let vis = match self.resolve_path(&path, None, Some(span)) { PathResult::Module(module) => { path_resolution = PathResolution::new(module.def().unwrap()); ty::Visibility::Restricted(module.normal_ancestor_id.unwrap()) @@ -3190,15 +3175,14 @@ impl<'a> Resolver<'a> { } fn names_to_string(names: &[Ident]) -> String { - let mut first = true; let mut result = String::new(); - for ident in names { - if first { - first = false - } else { - result.push_str("::") + for (i, ident) in names.iter().enumerate() { + if i > 0 { + result.push_str("::"); + } + if ident.name != keywords::CrateRoot.name() { + result.push_str(&ident.name.as_str()); } - result.push_str(&ident.name.as_str()); } result } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 204d1127fc4..ff3c5836293 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -9,7 +9,7 @@ // except according to those terms. use {AmbiguityError, Resolver, ResolutionError, resolve_error}; -use {Module, ModuleKind, NameBinding, NameBindingKind, PathScope, PathResult}; +use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult}; use Namespace::{self, MacroNS}; use build_reduced_graph::BuildReducedGraphVisitor; use resolve_imports::ImportResolver; @@ -30,6 +30,7 @@ use syntax::ext::tt::macro_rules; use syntax::feature_gate::{emit_feature_err, GateIssue}; use syntax::fold::Folder; use syntax::ptr::P; +use syntax::symbol::keywords; use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit::Visitor; use syntax_pos::{Span, DUMMY_SP}; @@ -105,15 +106,13 @@ impl<'a> base::Resolver for Resolver<'a> { fn fold_path(&mut self, mut path: ast::Path) -> ast::Path { let ident = path.segments[0].identifier; if ident.name == "$crate" { - path.global = true; + path.segments[0].identifier.name = keywords::CrateRoot.name(); let module = self.0.resolve_crate_var(ident.ctxt); - if module.is_local() { - path.segments.remove(0); - } else { - path.segments[0].identifier = match module.kind { - ModuleKind::Def(_, name) => ast::Ident::with_empty_ctxt(name), + if !module.is_local() { + path.segments.insert(1, match module.kind { + ModuleKind::Def(_, name) => ast::Ident::with_empty_ctxt(name).into(), _ => unreachable!(), - }; + }) } } path @@ -182,7 +181,7 @@ impl<'a> base::Resolver for Resolver<'a> { fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool) -> Result, Determinacy> { - let ast::Path { ref segments, global, span } = *path; + let ast::Path { ref segments, span } = *path; if segments.iter().any(|segment| segment.parameters.is_some()) { let kind = if segments.last().unwrap().parameters.is_some() { "macro" } else { "module" }; @@ -191,12 +190,11 @@ impl<'a> base::Resolver for Resolver<'a> { return Err(Determinacy::Determined); } - let path_scope = if global { PathScope::Global } else { PathScope::Lexical }; let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect(); let invocation = self.invocations[&scope]; self.current_module = invocation.module.get(); - if path.len() > 1 || global { + if path.len() > 1 { if !self.use_extern_macros { let msg = "non-ident macro paths are experimental"; let feature = "use_extern_macros"; @@ -204,7 +202,7 @@ impl<'a> base::Resolver for Resolver<'a> { return Err(Determinacy::Determined); } - let ext = match self.resolve_path(&path, path_scope, Some(MacroNS), None) { + let ext = match self.resolve_path(&path, Some(MacroNS), None) { PathResult::NonModule(path_res) => match path_res.base_def { Def::Err => Err(Determinacy::Determined), def @ _ => Ok(self.get_macro(def)), @@ -214,7 +212,7 @@ impl<'a> base::Resolver for Resolver<'a> { _ => Err(Determinacy::Determined), }; self.current_module.macro_resolutions.borrow_mut() - .push((path.into_boxed_slice(), path_scope, span)); + .push((path.into_boxed_slice(), span)); return ext; } @@ -351,8 +349,8 @@ impl<'a> Resolver<'a> { pub fn finalize_current_module_macro_resolutions(&mut self) { let module = self.current_module; - for &(ref path, scope, span) in module.macro_resolutions.borrow().iter() { - match self.resolve_path(path, scope, Some(MacroNS), Some(span)) { + for &(ref path, span) in module.macro_resolutions.borrow().iter() { + match self.resolve_path(path, Some(MacroNS), Some(span)) { PathResult::NonModule(_) => {}, PathResult::Failed(msg, _) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 8bc0bfb41ff..f62974b30d1 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -12,7 +12,7 @@ use self::ImportDirectiveSubclass::*; use {AmbiguityError, Module, PerNS}; use Namespace::{self, TypeNS, MacroNS}; -use {NameBinding, NameBindingKind, PathResult, PathScope, PrivacyError}; +use {NameBinding, NameBindingKind, PathResult, PrivacyError}; use Resolver; use {names_to_string, module_to_string}; use {resolve_error, ResolutionError}; @@ -24,6 +24,7 @@ use rustc::hir::def::*; use syntax::ast::{Ident, NodeId}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::hygiene::Mark; +use syntax::parse::token; use syntax::symbol::keywords; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; @@ -490,7 +491,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // For better failure detection, pretend that the import will not define any names // while resolving its module path. directive.vis.set(ty::Visibility::PrivateExternal); - let result = self.resolve_path(&directive.module_path, PathScope::Import, None, None); + let result = self.resolve_path(&directive.module_path, None, None); directive.vis.set(vis); match result { @@ -553,15 +554,17 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.current_module = directive.parent; let ImportDirective { ref module_path, span, .. } = *directive; - let module_result = self.resolve_path(&module_path, PathScope::Import, None, Some(span)); + let module_result = self.resolve_path(&module_path, None, Some(span)); let module = match module_result { PathResult::Module(module) => module, PathResult::Failed(msg, _) => { - let mut path = vec![keywords::SelfValue.ident()]; - path.extend(module_path); - let result = self.resolve_path(&path, PathScope::Import, None, None); - return if let PathResult::Module(..) = result { - Some(format!("Did you mean `self::{}`?", &names_to_string(module_path))) + let (mut self_path, mut self_result) = (module_path.clone(), None); + if !self_path.is_empty() && !token::Ident(self_path[0]).is_path_segment_keyword() { + self_path[0].name = keywords::SelfValue.name(); + self_result = Some(self.resolve_path(&self_path, None, None)); + } + return if let Some(PathResult::Module(..)) = self_result { + Some(format!("Did you mean `{}`?", names_to_string(&self_path))) } else { Some(msg) }; @@ -787,6 +790,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } fn import_path_to_string(names: &[Ident], subclass: &ImportDirectiveSubclass) -> String { + let global = !names.is_empty() && names[0].name == keywords::CrateRoot.name(); + let names = if global { &names[1..] } else { names }; if names.is_empty() { import_directive_subclass_to_string(subclass) } else { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index afa78a05a63..65372d4dca9 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -143,19 +143,20 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // a str representation of the entire prefix. fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> { let spans = self.span.spans_for_path_segments(path); + let segments = &path.segments[if path.is_global() { 1 } else { 0 }..]; // Paths to enums seem to not match their spans - the span includes all the // variants too. But they seem to always be at the end, so I hope we can cope with // always using the first ones. So, only error out if we don't have enough spans. // What could go wrong...? - if spans.len() < path.segments.len() { + if spans.len() < segments.len() { if generated_code(path.span) { return vec![]; } error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:", path_to_string(path), spans.len(), - path.segments.len()); + segments.len()); for s in &spans { let loc = self.sess.codemap().lookup_char_pos(s.lo); error!(" '{}' in {}, line {}", @@ -170,14 +171,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { let mut result: Vec<(Span, String)> = vec![]; let mut segs = vec![]; - for (i, (seg, span)) in path.segments.iter().zip(&spans).enumerate() { + for (i, (seg, span)) in segments.iter().zip(&spans).enumerate() { segs.push(seg.clone()); let sub_path = ast::Path { span: *span, // span for the last segment - global: path.global, segments: segs, }; - let qualname = if i == 0 && path.global { + let qualname = if i == 0 && path.is_global() { format!("::{}", path_to_string(&sub_path)) } else { path_to_string(&sub_path) @@ -189,20 +189,11 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { result } - // The global arg allows us to override the global-ness of the path (which - // actually means 'does the path start with `::`', rather than 'is the path - // semantically global). We use the override for `use` imports (etc.) where - // the syntax is non-global, but the semantics are global. - fn write_sub_paths(&mut self, path: &ast::Path, global: bool) { + fn write_sub_paths(&mut self, path: &ast::Path) { let sub_paths = self.process_path_prefixes(path); - for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() { - let qualname = if i == 0 && global && !path.global { - format!("::{}", qualname) - } else { - qualname.clone() - }; + for (span, qualname) in sub_paths { self.dumper.mod_ref(ModRefData { - span: *span, + span: span, qualname: qualname, scope: self.cur_scope, ref_id: None @@ -212,22 +203,16 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // As write_sub_paths, but does not process the last ident in the path (assuming it // will be processed elsewhere). See note on write_sub_paths about global. - fn write_sub_paths_truncated(&mut self, path: &ast::Path, global: bool) { + fn write_sub_paths_truncated(&mut self, path: &ast::Path) { let sub_paths = self.process_path_prefixes(path); let len = sub_paths.len(); if len <= 1 { return; } - let sub_paths = &sub_paths[..len-1]; - for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() { - let qualname = if i == 0 && global && !path.global { - format!("::{}", qualname) - } else { - qualname.clone() - }; + for (span, qualname) in sub_paths.into_iter().take(len - 1) { self.dumper.mod_ref(ModRefData { - span: *span, + span: span, qualname: qualname, scope: self.cur_scope, ref_id: None @@ -935,7 +920,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { Def::Union(..) | Def::Variant(..) | Def::TyAlias(..) | - Def::AssociatedTy(..) => self.write_sub_paths_truncated(path, false), + Def::AssociatedTy(..) => self.write_sub_paths_truncated(path), _ => {} } } @@ -946,7 +931,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { fields: &'l [ast::Field], variant: &'l ty::VariantDef, base: &'l Option>) { - self.write_sub_paths_truncated(path, false); + self.write_sub_paths_truncated(path); if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) { down_cast_data!(struct_lit_data, TypeRefData, ex.span); @@ -1201,7 +1186,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, visibility: From::from(&item.vis), }.lower(self.tcx)); } - self.write_sub_paths_truncated(path, true); + self.write_sub_paths_truncated(path); } ast::ViewPathGlob(ref path) => { // Make a comma-separated list of names of imported modules. @@ -1225,7 +1210,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, visibility: From::from(&item.vis), }.lower(self.tcx)); } - self.write_sub_paths(path, true); + self.write_sub_paths(path); } ast::ViewPathList(ref path, ref list) => { for plid in list { @@ -1237,7 +1222,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, } } - self.write_sub_paths(path, true); + self.write_sub_paths(path); } } } @@ -1340,7 +1325,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, }.lower(self.tcx)); } - self.write_sub_paths_truncated(path, false); + self.write_sub_paths_truncated(path); visit::walk_path(self, path); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 123516dc89d..fdbd2f3647c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1737,7 +1737,6 @@ impl Clean for hir::Ty { segments.pop(); let trait_path = hir::Path { span: p.span, - global: p.global, def: Def::Trait(cx.tcx.associated_item(p.def.def_id()).container.id()), segments: segments.into(), }; @@ -1756,7 +1755,6 @@ impl Clean for hir::Ty { } let trait_path = hir::Path { span: self.span, - global: false, def: def, segments: vec![].into(), }; @@ -2213,9 +2211,9 @@ impl Path { impl Clean for hir::Path { fn clean(&self, cx: &DocContext) -> Path { Path { - global: self.global, + global: self.is_global(), def: self.def, - segments: self.segments.clean(cx), + segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx), } } } @@ -2270,24 +2268,19 @@ impl Clean for hir::PathSegment { } fn qpath_to_string(p: &hir::QPath) -> String { - let (segments, global) = match *p { - hir::QPath::Resolved(_, ref path) => { - (&path.segments, path.global) - } - hir::QPath::TypeRelative(_, ref segment) => { - return segment.name.to_string() - } + let segments = match *p { + hir::QPath::Resolved(_, ref path) => &path.segments, + hir::QPath::TypeRelative(_, ref segment) => return segment.name.to_string(), }; let mut s = String::new(); - let mut first = true; - for i in segments.iter().map(|x| x.name.as_str()) { - if !first || global { + for (i, seg) in segments.iter().enumerate() { + if i > 0 { s.push_str("::"); - } else { - first = false; } - s.push_str(&i); + if seg.name != keywords::CrateRoot.name() { + s.push_str(&*seg.name.as_str()); + } } s } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index fdd82225b97..648a82ffb76 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -111,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, } @@ -136,10 +134,22 @@ impl Path { pub fn from_ident(s: Span, identifier: Ident) -> Path { Path { span: s, - global: false, 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() + } } /// A segment of a path: an identifier, an optional lifetime, and a set of types. @@ -166,6 +176,15 @@ impl From for PathSegment { } } +impl PathSegment { + pub fn crate_root() -> Self { + PathSegment { + identifier: keywords::CrateRoot.ident(), + parameters: None, + } + } +} + /// Parameters of a path segment. /// /// E.g. `` as in `Foo` or `(A, B)` as in `Foo(A, B)` diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index c3dc64f9124..7584fa3916d 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -322,7 +322,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> { bindings: Vec ) -> ast::Path { let last_identifier = idents.pop().unwrap(); - let mut segments: Vec = idents.into_iter().map(Into::into).collect(); + let mut segments: Vec = 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 { @@ -335,7 +340,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { segments.push(ast::PathSegment { identifier: last_identifier, parameters: parameters }); ast::Path { span: sp, - global: global, segments: segments, } } diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index eb4b6144c8d..66555d7d95d 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -25,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(), }) } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index b3753e3e977..bf10d45add4 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -433,9 +433,8 @@ pub fn noop_fold_usize(i: usize, _: &mut T) -> usize { i } -pub fn noop_fold_path(Path {global, segments, span}: Path, fld: &mut T) -> Path { +pub fn noop_fold_path(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: parameters.map(|ps| ps.map(|ps| fld.fold_path_parameters(ps))), diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b9e6605639e..24178e1f675 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -633,7 +633,6 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 1), - global: false, segments: vec![Ident::from_str("a").into()], }), span: sp(0, 1), @@ -647,8 +646,9 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span: sp(0, 6), - global: true, - segments: vec![Ident::from_str("a").into(), Ident::from_str("b").into()], + segments: vec![ast::PathSegment::crate_root(), + Ident::from_str("a").into(), + Ident::from_str("b").into()] }), span: sp(0, 6), attrs: ThinVec::new(), @@ -757,7 +757,6 @@ mod tests { id: ast::DUMMY_NODE_ID, node:ast::ExprKind::Path(None, ast::Path{ span: sp(7, 8), - global: false, segments: vec![Ident::from_str("d").into()], }), span:sp(7,8), @@ -775,7 +774,6 @@ mod tests { id: ast::DUMMY_NODE_ID, node: ast::ExprKind::Path(None, ast::Path { span:sp(0,1), - global:false, segments: vec![Ident::from_str("b").into()], }), span: sp(0,1), @@ -817,7 +815,6 @@ 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![Ident::from_str("i32").into()], }), span:sp(10,13) @@ -860,7 +857,6 @@ mod tests { node: ast::ExprKind::Path(None, ast::Path{ span:sp(17,18), - global:false, segments: vec![Ident::from_str("b").into()], }), span: sp(17,18), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 72462b74e68..cd4f255b5e3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1614,7 +1614,6 @@ impl<'a> Parser<'a> { } else { ast::Path { span: span, - global: false, segments: vec![] } }; @@ -1658,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()? } @@ -1670,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, }) } @@ -5180,7 +5182,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 }) } @@ -6068,9 +6070,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)) { @@ -6080,7 +6082,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 22e8391de93..e9c1cbcba61 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>, 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,23 +2337,25 @@ 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)); - - if let Some(ref parameters) = segment.parameters { - try!(self.print_path_parameters(parameters, colons_before_params)) + if segment.identifier.name != keywords::CrateRoot.name() { + try!(self.print_ident(segment.identifier)); + if let Some(ref parameters) = segment.parameters { + try!(self.print_path_parameters(parameters, colons_before_params)); + } } } @@ -2369,7 +2374,7 @@ 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, "::")); @@ -2472,7 +2477,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))); @@ -2490,13 +2495,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( @@ -2843,7 +2848,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)); @@ -2857,7 +2862,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 { @@ -2870,7 +2875,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, "::*") } @@ -2878,7 +2883,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 4ad760a3caf..68d807b24a7 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -80,8 +80,7 @@ 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| { + 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 7709d3bd1cf..b8e0b938814 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -579,7 +579,6 @@ fn nospan(t: T) -> codemap::Spanned { fn path_node(ids: Vec) -> ast::Path { ast::Path { span: DUMMY_SP, - global: false, segments: ids.into_iter().map(Into::into).collect(), } } diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index 1381490efa1..1fc1bdff593 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -61,7 +61,6 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, fn path(&self) -> ast::Path { ast::Path { span: self.span, - global: false, segments: vec![self.ident.into()], } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 51199819dfc..7f187d8d1c1 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -363,15 +363,12 @@ fn find_type_parameters(ty: &ast::Ty, impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { fn visit_ty(&mut self, ty: &'a ast::Ty) { - match ty.node { - ast::TyKind::Path(_, ref path) if !path.global => { - if let Some(segment) = path.segments.first() { - if self.ty_param_names.contains(&segment.identifier.name) { - self.types.push(P(ty.clone())); - } + if let ast::TyKind::Path(_, ref path) = ty.node { + if let Some(segment) = path.segments.first() { + if self.ty_param_names.contains(&segment.identifier.name) { + self.types.push(P(ty.clone())); } } - _ => {} } visit::walk_ty(self, ty) diff --git a/src/test/compile-fail/resolve-primitive-fallback.rs b/src/test/compile-fail/resolve-primitive-fallback.rs index 1e43933ad0a..3c585680eab 100644 --- a/src/test/compile-fail/resolve-primitive-fallback.rs +++ b/src/test/compile-fail/resolve-primitive-fallback.rs @@ -16,5 +16,5 @@ fn main() { // Make sure primitive type fallback doesn't work with global paths let _: ::u8; - //~^ ERROR type name `u8` is undefined or not in scope + //~^ ERROR type name `::u8` is undefined or not in scope } -- cgit 1.4.1-3-g733a5 From 8a1acb2c690eeb11b5c3f2a26bf2d68741ed5844 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 21 Dec 2016 05:31:07 +0000 Subject: Pretty-print `$crate::foo::bar` as `::foo::bar`. --- src/librustc/hir/print.rs | 4 ++-- src/libsyntax/print/pprust.rs | 3 ++- src/test/pretty/issue-4264.pp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index de4047df81c..100e344d941 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1647,7 +1647,7 @@ impl<'a> State<'a> { if i > 0 { word(&mut self.s, "::")? } - if segment.name != keywords::CrateRoot.name() { + if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" { self.print_name(segment.name)?; self.print_path_parameters(&segment.parameters, colons_before_params)?; } @@ -1674,7 +1674,7 @@ impl<'a> State<'a> { if i > 0 { word(&mut self.s, "::")? } - if segment.name != keywords::CrateRoot.name() { + if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" { self.print_name(segment.name)?; self.print_path_parameters(&segment.parameters, colons_before_params)?; } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index e9c1cbcba61..7558f0256da 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2351,7 +2351,8 @@ impl<'a> State<'a> { if i > 0 { try!(word(&mut self.s, "::")) } - if segment.identifier.name != keywords::CrateRoot.name() { + 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)); diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index fdb7f9c68b9..6c74e7758c4 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -39,7 +39,7 @@ pub fn bar() ({ - (($crate::fmt::format as + ((::fmt::format as fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((<::std::fmt::Arguments>::new_v1 as fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({ -- cgit 1.4.1-3-g733a5 From 39d6483bc1156190b0c3296049e887b0f4adfd8c Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Thu, 22 Dec 2016 00:38:10 -0800 Subject: Remove outdated FIXME comment Removed FIXME comment referencing #3300. --- src/librustc/hir/mod.rs | 2 -- src/libsyntax/ast.rs | 4 ---- 2 files changed, 6 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f52ee35e175..ad6a3191675 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1531,8 +1531,6 @@ pub struct ItemId { pub id: NodeId, } -// 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 diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index fdd82225b97..eb409b6cc11 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1759,10 +1759,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 -- cgit 1.4.1-3-g733a5 From 31d9cc3833a30b0cd4c1554102402af68eebeeef Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 23 Dec 2016 02:16:31 +0000 Subject: Fix import resolution bug and fold all idents in the AST. --- src/librustc_resolve/resolve_imports.rs | 3 +-- src/libsyntax/fold.rs | 29 ++++++++++++++--------------- src/test/run-pass/issue-38556.rs | 22 ++++++++++++++++++++++ 3 files changed, 37 insertions(+), 17 deletions(-) create mode 100644 src/test/run-pass/issue-38556.rs (limited to 'src/libsyntax') diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 8bc0bfb41ff..5972f2d87c4 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -128,6 +128,7 @@ impl<'a> NameResolution<'a> { impl<'a> Resolver<'a> { fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace) -> &'a RefCell> { + let ident = ident.unhygienize(); *module.resolutions.borrow_mut().entry((ident, ns)) .or_insert_with(|| self.arenas.alloc_name_resolution()) } @@ -141,7 +142,6 @@ impl<'a> Resolver<'a> { ignore_unresolved_invocations: bool, record_used: Option) -> Result<&'a NameBinding<'a>, Determinacy> { - let ident = ident.unhygienize(); self.populate_module_if_necessary(module); let resolution = self.resolution(module, ident, ns) @@ -307,7 +307,6 @@ impl<'a> Resolver<'a> { ns: Namespace, binding: &'a NameBinding<'a>) -> Result<(), &'a NameBinding<'a>> { - let ident = ident.unhygienize(); self.update_resolution(module, ident, ns, |this, resolution| { if let Some(old_binding) = resolution.binding { if binding.is_glob_import() { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index b3753e3e977..6f938197275 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -302,23 +302,22 @@ pub fn noop_fold_view_path(view_path: P, 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(Arm {attrs, pats, guard, body}: Arm, fld: &mut T pub fn noop_fold_ty_binding(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), } @@ -673,7 +672,7 @@ pub fn noop_fold_ty_param(tp: TyParam, fld: &mut T) -> TyParam { .collect::>() .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 +1087,7 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { 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/test/run-pass/issue-38556.rs b/src/test/run-pass/issue-38556.rs new file mode 100644 index 00000000000..f6f334f650b --- /dev/null +++ b/src/test/run-pass/issue-38556.rs @@ -0,0 +1,22 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct Foo; + +macro_rules! reexport { + () => { use Foo as Bar; } +} + +reexport!(); + +fn main() { + use Bar; + fn f(_: Bar) {} +} -- cgit 1.4.1-3-g733a5 From c12fc66a9d643a6942d0bf4175d1a046e8d808de Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 22 Dec 2016 06:03:19 +0000 Subject: Allow legacy custom derive authors to disable warnings in downstream crates. --- src/librustc_driver/driver.rs | 2 ++ src/librustc_plugin/registry.rs | 18 ++++++++++++++++++ src/librustc_resolve/lib.rs | 2 ++ src/librustc_resolve/macros.rs | 4 ++++ src/libsyntax/ext/base.rs | 2 ++ src/libsyntax_ext/deriving/mod.rs | 4 +++- .../auxiliary/custom_derive_plugin.rs | 2 +- 7 files changed, 32 insertions(+), 2 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 360933c6b66..8da9a23f4fa 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -592,6 +592,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, } }); + let whitelisted_legacy_custom_derives = registry.take_whitelisted_custom_derives(); let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups, llvm_passes, attributes, mir_passes, .. } = registry; @@ -631,6 +632,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, let resolver_arenas = Resolver::arenas(); let mut resolver = Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas); + resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives; syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote); krate = time(time_passes, "expansion", || { diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index fe2f9713d1b..3700d0295e9 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -64,6 +64,8 @@ pub struct Registry<'a> { #[doc(hidden)] pub attributes: Vec<(String, AttributeType)>, + + whitelisted_custom_derives: Vec, } impl<'a> Registry<'a> { @@ -80,6 +82,7 @@ impl<'a> Registry<'a> { llvm_passes: vec![], attributes: vec![], mir_passes: Vec::new(), + whitelisted_custom_derives: Vec::new(), } } @@ -115,6 +118,21 @@ impl<'a> Registry<'a> { })); } + /// This can be used in place of `register_syntax_extension` to register legacy custom derives + /// (i.e. attribute syntax extensions whose name begins with `derive_`). Legacy custom + /// derives defined by this function do not trigger deprecation warnings when used. + #[unstable(feature = "rustc_private", issue = "27812")] + #[rustc_deprecated(since = "1.15.0", reason = "replaced by macros 1.1 (RFC 1861)")] + pub fn register_custom_derive(&mut self, name: ast::Name, extension: SyntaxExtension) { + assert!(name.as_str().starts_with("derive_")); + self.whitelisted_custom_derives.push(name); + self.register_syntax_extension(name, extension); + } + + pub fn take_whitelisted_custom_derives(&mut self) -> Vec { + ::std::mem::replace(&mut self.whitelisted_custom_derives, Vec::new()) + } + /// Register a macro of the usual kind. /// /// This is a convenience wrapper for `register_syntax_extension`. diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f73227681c5..fa9e67bb40a 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1111,6 +1111,7 @@ pub struct Resolver<'a> { lexical_macro_resolutions: Vec<(Name, &'a Cell>)>, macro_map: FxHashMap>, macro_exports: Vec, + pub whitelisted_legacy_custom_derives: Vec, // Maps the `Mark` of an expansion to its containing module or block. invocations: FxHashMap>, @@ -1292,6 +1293,7 @@ impl<'a> Resolver<'a> { macro_exports: Vec::new(), invocations: invocations, name_already_seen: FxHashMap(), + whitelisted_legacy_custom_derives: Vec::new(), } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 204d1127fc4..cdff84c8b8a 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -123,6 +123,10 @@ impl<'a> base::Resolver for Resolver<'a> { EliminateCrateVar(self).fold_item(item).expect_one("") } + fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool { + self.whitelisted_legacy_custom_derives.contains(&name) + } + fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) { let invocation = self.invocations[&mark]; self.collect_def_ids(invocation, expansion); diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 8e63f73fdaa..68d261c64f8 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -516,6 +516,7 @@ 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) -> P; + fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool; fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion); fn add_ext(&mut self, ident: ast::Ident, ext: Rc); @@ -539,6 +540,7 @@ 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) -> P { item } + fn is_whitelisted_legacy_custom_derive(&self, _name: Name) -> bool { false } fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {} fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc) {} diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 535d7de19e3..0511b0d252b 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -175,8 +175,10 @@ pub fn expand_derive(cx: &mut ExtCtxt, feature_gate::GateIssue::Language, feature_gate::EXPLAIN_CUSTOM_DERIVE); } else { - cx.span_warn(titem.span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE); let name = Symbol::intern(&format!("derive_{}", tname)); + if !cx.resolver.is_whitelisted_legacy_custom_derive(name) { + cx.span_warn(titem.span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE); + } let mitem = cx.meta_word(titem.span, name); new_attributes.push(cx.attribute(mitem.span, mitem)); } diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs index 07f7d6bad7b..e46e4fb3766 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs @@ -31,7 +31,7 @@ use rustc_plugin::Registry; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension( + reg.register_custom_derive( Symbol::intern("derive_TotalSum"), MultiDecorator(box expand)); } -- cgit 1.4.1-3-g733a5