From 2df25adbed10c4f12e3a0b2d092c6d06c3746454 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 28 Sep 2016 22:28:19 +0000 Subject: [PATCH 01/13] Combine `std_inject::{no_core, no_std}` into `std_inject::injected_crate_name`. --- src/librustc/hir/lowering.rs | 8 +------- src/libsyntax/ext/base.rs | 8 +------- src/libsyntax/print/pprust.rs | 2 +- src/libsyntax/std_inject.rs | 22 ++++++++++++---------- 4 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index f56a27b9ae04a..2290428264221 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -95,13 +95,7 @@ pub fn lower_crate(sess: &Session, let _ignore = sess.dep_graph.in_ignore(); LoweringContext { - crate_root: if std_inject::no_core(krate) { - None - } else if std_inject::no_std(krate) { - Some("core") - } else { - Some("std") - }, + crate_root: std_inject::injected_crate_name(krate), sess: sess, parent_def: None, resolver: resolver, diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index b56018e1e9dcd..ece4f057b34ef 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -739,13 +739,7 @@ impl<'a> ExtCtxt<'a> { } pub fn initialize(&mut self, user_exts: Vec, krate: &ast::Crate) { - if std_inject::no_core(&krate) { - self.crate_root = None; - } else if std_inject::no_std(&krate) { - self.crate_root = Some("core"); - } else { - self.crate_root = Some("std"); - } + self.crate_root = std_inject::injected_crate_name(krate); for (name, extension) in user_exts { let ident = ast::Ident::with_empty_ctxt(name); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3c106970232cd..ecb437f31a5ad 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -112,7 +112,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap, out, ann, is_expanded); - if is_expanded && !std_inject::no_std(krate) { + if is_expanded && !std_inject::injected_crate_name(krate).is_none() { // We need to print `#![no_std]` (and its feature gate) so that // compiling pretty-printed source won't inject libstd again. // However we don't want these attributes in the AST because diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index d1454ab06cbc8..1b63a2b70763a 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -34,23 +34,25 @@ fn ignored_span(sess: &ParseSess, sp: Span) -> Span { return sp; } -pub fn no_core(krate: &ast::Crate) -> bool { - attr::contains_name(&krate.attrs, "no_core") -} - -pub fn no_std(krate: &ast::Crate) -> bool { - attr::contains_name(&krate.attrs, "no_std") || no_core(krate) +pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> { + if attr::contains_name(&krate.attrs, "no_core") { + None + } else if attr::contains_name(&krate.attrs, "no_std") { + Some("core") + } else { + Some("std") + } } pub fn maybe_inject_crates_ref(sess: &ParseSess, mut krate: ast::Crate, alt_std_name: Option) -> ast::Crate { - if no_core(&krate) { - return krate; - } + let name = match injected_crate_name(&krate) { + Some(name) => name, + None => return krate, + }; - let name = if no_std(&krate) { "core" } else { "std" }; let crate_name = token::intern(&alt_std_name.unwrap_or(name.to_string())); krate.module.items.insert(0, P(ast::Item { From 09e41b6784fcc67c4dc3ab681d3d751cc768ca89 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 28 Sep 2016 22:48:55 +0000 Subject: [PATCH 02/13] Add macros from plugins in `libsyntax_ext::register_builtins`. --- src/librustc_driver/driver.rs | 4 ++-- src/libsyntax/ext/base.rs | 7 +------ src/libsyntax/ext/expand.rs | 12 ++++-------- src/libsyntax_ext/lib.rs | 21 ++++++++++++++------- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 8059ef61eab83..84bd2bab76ce1 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -649,7 +649,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, let resolver_arenas = Resolver::arenas(); let mut resolver = Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas); - syntax_ext::register_builtins(&mut resolver, sess.features.borrow().quote); + syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote); krate = time(time_passes, "expansion", || { // Windows dlls do not have rpaths, so they don't know how to find their @@ -686,7 +686,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string()) }; let mut ecx = ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, &mut resolver); - let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate); + let ret = syntax::ext::expand::expand_crate(&mut ecx, krate); if cfg!(windows) { env::set_var("PATH", &old_path); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index ece4f057b34ef..ad1d65c8c5418 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -738,14 +738,9 @@ impl<'a> ExtCtxt<'a> { token::intern(st) } - pub fn initialize(&mut self, user_exts: Vec, krate: &ast::Crate) { + pub fn initialize(&mut self, krate: &ast::Crate) { self.crate_root = std_inject::injected_crate_name(krate); - for (name, extension) in user_exts { - let ident = ast::Ident::with_empty_ctxt(name); - self.resolver.add_ext(ident, Rc::new(extension)); - } - let mut module = ModuleData { mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)], directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)), diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index b1d828d0e3e49..16e53d270f02e 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -866,19 +866,15 @@ impl<'feat> ExpansionConfig<'feat> { } } -pub fn expand_crate(cx: &mut ExtCtxt, - user_exts: Vec, - c: Crate) -> Crate { - cx.initialize(user_exts, &c); +pub fn expand_crate(cx: &mut ExtCtxt, c: Crate) -> Crate { + cx.initialize(&c); cx.monotonic_expander().expand_crate(c) } // Expands crate using supplied MacroExpander - allows for // non-standard expansion behaviour (e.g. step-wise). -pub fn expand_crate_with_expander(expander: &mut MacroExpander, - user_exts: Vec, - c: Crate) -> Crate { - expander.cx.initialize(user_exts, &c); +pub fn expand_crate_with_expander(expander: &mut MacroExpander, c: Crate) -> Crate { + expander.cx.initialize(&c); expander.expand_crate(c) } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 6e4f3dde4bd24..195ad424adb06 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -50,20 +50,23 @@ pub mod deriving; use std::rc::Rc; use syntax::ast; -use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier}; +use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier, NamedSyntaxExtension}; use syntax::ext::tt::macro_rules::MacroRulesExpander; use syntax::parse::token::intern; -pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) { +pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, + user_exts: Vec, + enable_quotes: bool) { let mut register = |name, ext| { - resolver.add_ext(ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext)); + resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext)); }; - register("macro_rules", IdentTT(Box::new(MacroRulesExpander), None, false)); + register(intern("macro_rules"), IdentTT(Box::new(MacroRulesExpander), None, false)); macro_rules! register { ($( $name:ident: $f:expr, )*) => { $( - register(stringify!($name), NormalTT(Box::new($f as MacroExpanderFn), None, false)); + register(intern(stringify!($name)), + NormalTT(Box::new($f as MacroExpanderFn), None, false)); )* } } @@ -108,7 +111,11 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quot } // format_args uses `unstable` things internally. - register("format_args", NormalTT(Box::new(format::expand_format_args), None, true)); + register(intern("format_args"), NormalTT(Box::new(format::expand_format_args), None, true)); - register("derive", MultiModifier(Box::new(deriving::expand_derive))); + register(intern("derive"), MultiModifier(Box::new(deriving::expand_derive))); + + for (name, ext) in user_exts { + register(name, ext); + } } From 21b43693229d72441872cad96842b5bcd6ba9f1b Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 29 Sep 2016 00:22:46 +0000 Subject: [PATCH 03/13] Refactor away `ext::expand::{expand_crate, expand_crate_with_expander}`. --- src/librustc_driver/driver.rs | 10 ++++++++-- src/libsyntax/ext/base.rs | 12 ------------ src/libsyntax/ext/expand.rs | 29 ++++++++++------------------- 3 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 84bd2bab76ce1..a3b7b32f1b52d 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -686,11 +686,17 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string()) }; let mut ecx = ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, &mut resolver); - let ret = syntax::ext::expand::expand_crate(&mut ecx, krate); + let err_count = ecx.parse_sess.span_diagnostic.err_count(); + + let krate = ecx.monotonic_expander().expand_crate(krate); + + if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count { + ecx.parse_sess.span_diagnostic.abort_if_errors(); + } if cfg!(windows) { env::set_var("PATH", &old_path); } - ret + krate }); krate.exported_macros = mem::replace(&mut resolver.exported_macros, Vec::new()); diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index ad1d65c8c5418..923d5d05439e4 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -22,7 +22,6 @@ use parse::{self, parser}; use parse::token; use parse::token::{InternedString, str_to_ident}; use ptr::P; -use std_inject; use util::small_vector::SmallVector; use std::path::PathBuf; @@ -737,17 +736,6 @@ impl<'a> ExtCtxt<'a> { pub fn name_of(&self, st: &str) -> ast::Name { token::intern(st) } - - pub fn initialize(&mut self, krate: &ast::Crate) { - self.crate_root = std_inject::injected_crate_name(krate); - - let mut module = ModuleData { - mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)], - directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)), - }; - module.directory.pop(); - self.current_expansion.module = Rc::new(module); - } } /// Extract a string literal from the macro expanded version of `expr`, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 16e53d270f02e..745afb473f994 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast::{Block, Crate, Ident, Mac_, PatKind}; +use ast::{Block, Ident, Mac_, PatKind}; use ast::{Name, MacStmtStyle, StmtKind, ItemKind}; use ast; use ext::hygiene::Mark; @@ -26,6 +26,7 @@ use parse::parser::Parser; use parse::token::{self, intern, keywords}; use print::pprust; use ptr::P; +use std_inject; use tokenstream::{TokenTree, TokenStream}; use util::small_vector::SmallVector; use visit::Visitor; @@ -186,8 +187,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { MacroExpander { cx: cx, monotonic: monotonic } } - fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { - let err_count = self.cx.parse_sess.span_diagnostic.err_count(); + pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { + self.cx.crate_root = std_inject::injected_crate_name(&krate); + let mut module = ModuleData { + mod_path: vec![token::str_to_ident(&self.cx.ecfg.crate_name)], + directory: PathBuf::from(self.cx.codemap().span_to_filename(krate.span)), + }; + module.directory.pop(); + self.cx.current_expansion.module = Rc::new(module); let krate_item = Expansion::Items(SmallVector::one(P(ast::Item { attrs: krate.attrs, @@ -206,10 +213,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => unreachable!(), }; - if self.cx.parse_sess.span_diagnostic.err_count() - self.cx.resolve_err_count > err_count { - self.cx.parse_sess.span_diagnostic.abort_if_errors(); - } - krate } @@ -866,18 +869,6 @@ impl<'feat> ExpansionConfig<'feat> { } } -pub fn expand_crate(cx: &mut ExtCtxt, c: Crate) -> Crate { - cx.initialize(&c); - cx.monotonic_expander().expand_crate(c) -} - -// Expands crate using supplied MacroExpander - allows for -// non-standard expansion behaviour (e.g. step-wise). -pub fn expand_crate_with_expander(expander: &mut MacroExpander, c: Crate) -> Crate { - expander.cx.initialize(&c); - expander.expand_crate(c) -} - // A Marker adds the given mark to the syntax context and // sets spans' `expn_id` to the given expn_id (unless it is `None`). struct Marker { mark: Mark, expn_id: Option } From f3c7333f51cac1e492f3d6d229149f14c160d662 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 26 Sep 2016 22:54:36 +0000 Subject: [PATCH 04/13] Cleanup `depth`s. --- src/libsyntax/ext/expand.rs | 16 +++++++++------- src/libsyntax/ext/placeholders.rs | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 745afb473f994..b5cd9f53d6915 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -224,7 +224,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let (expansion, mut invocations) = self.collect_invocations(expansion); invocations.reverse(); - let mut expansions = vec![vec![(0, expansion)]]; + let mut expansions = Vec::new(); while let Some(invoc) = invocations.pop() { let ExpansionData { depth, mark, .. } = invoc.expansion_data; self.cx.current_expansion = invoc.expansion_data.clone(); @@ -236,13 +236,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { None => invoc.expansion_kind.dummy(invoc.span()), }; - self.cx.current_expansion.depth = depth + 1; let (expansion, new_invocations) = self.collect_invocations(expansion); - if expansions.len() == depth { + if expansions.len() < depth { expansions.push(Vec::new()); } - expansions[depth].push((mark.as_u32(), expansion)); + expansions[depth - 1].push((mark.as_u32(), expansion)); if !self.cx.ecfg.single_step { invocations.extend(new_invocations.into_iter().rev()); } @@ -253,12 +252,11 @@ 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() { - let expansion = expansion.fold_with(&mut placeholder_expander); placeholder_expander.add(ast::NodeId::from_u32(mark), expansion); } } - placeholder_expander.remove(ast::NodeId::from_u32(0)) + expansion.fold_with(&mut placeholder_expander) } fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec) { @@ -541,7 +539,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.invocations.push(Invocation { kind: kind, expansion_kind: expansion_kind, - expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() }, + expansion_data: ExpansionData { + mark: mark, + depth: self.cx.current_expansion.depth + 1, + ..self.cx.current_expansion.clone() + }, }); placeholder(expansion_kind, ast::NodeId::from_u32(mark.as_u32())) } diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 0ede6dd98e5b8..e323dd2f62327 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -88,10 +88,11 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> { } pub fn add(&mut self, id: ast::NodeId, expansion: Expansion) { + let expansion = expansion.fold_with(self); self.expansions.insert(id, expansion); } - pub fn remove(&mut self, id: ast::NodeId) -> Expansion { + fn remove(&mut self, id: ast::NodeId) -> Expansion { self.expansions.remove(&id).unwrap() } } From 2cf964967c48376c97fa6e2288ca26f8081f78c3 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 16 Sep 2016 08:50:34 +0000 Subject: [PATCH 05/13] Immutable `ExpansionData`. --- src/librustc_resolve/build_reduced_graph.rs | 6 +-- src/librustc_resolve/lib.rs | 11 +++++- src/librustc_resolve/macros.rs | 43 ++++++++++++--------- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 321b814238cfd..79f133770b367 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -203,7 +203,7 @@ impl<'b> Resolver<'b> { let ext = macro_rules::compile(&self.session.parse_sess, &def); let shadowing = self.resolve_macro_name(Mark::root(), name, false).is_some(); - self.expansion_data[&Mark::root()].module.macros.borrow_mut() + self.expansion_data[&Mark::root()].module.get().macros.borrow_mut() .insert(name, macros::NameBinding { ext: Rc::new(ext), expansion: expansion, @@ -525,8 +525,8 @@ pub struct BuildReducedGraphVisitor<'a, 'b: 'a> { impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { fn visit_invoc(&mut self, id: ast::NodeId) { - self.resolver.expansion_data.get_mut(&Mark::from_placeholder_id(id)).unwrap().module = - self.resolver.current_module; + let mark = Mark::from_placeholder_id(id); + self.resolver.expansion_data[&mark].module.set(self.resolver.current_module); } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 4f41dfc8b6455..a03d23a939415 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -77,6 +77,7 @@ use std::mem::replace; use std::rc::Rc; use resolve_imports::{ImportDirective, NameResolution}; +use macros::ExpansionData; // NB: This module needs to be declared first so diagnostics are // registered before they are used. @@ -1088,7 +1089,7 @@ pub struct Resolver<'a> { macro_names: FnvHashSet, // Maps the `Mark` of an expansion to its containing module or block. - expansion_data: FnvHashMap>, + expansion_data: FnvHashMap>, } pub struct ResolverArenas<'a> { @@ -1097,6 +1098,7 @@ pub struct ResolverArenas<'a> { name_bindings: arena::TypedArena>, import_directives: arena::TypedArena>, name_resolutions: arena::TypedArena>>, + expansion_data: arena::TypedArena>, } impl<'a> ResolverArenas<'a> { @@ -1120,6 +1122,9 @@ impl<'a> ResolverArenas<'a> { fn alloc_name_resolution(&'a self) -> &'a RefCell> { self.name_resolutions.alloc(Default::default()) } + fn alloc_expansion_data(&'a self, expansion_data: ExpansionData<'a>) -> &'a ExpansionData<'a> { + self.expansion_data.alloc(expansion_data) + } } impl<'a> ty::NodeIdTree for Resolver<'a> { @@ -1206,7 +1211,8 @@ impl<'a> Resolver<'a> { DefCollector::new(&mut definitions).collect_root(); let mut expansion_data = FnvHashMap(); - expansion_data.insert(Mark::root(), macros::ExpansionData::root(graph_root)); + expansion_data.insert(Mark::root(), + arenas.alloc_expansion_data(ExpansionData::root(graph_root))); Resolver { session: session, @@ -1277,6 +1283,7 @@ impl<'a> Resolver<'a> { name_bindings: arena::TypedArena::new(), import_directives: arena::TypedArena::new(), name_resolutions: arena::TypedArena::new(), + expansion_data: arena::TypedArena::new(), } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 3f6c69278bee8..ee3edbccabca5 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -12,6 +12,7 @@ use {Module, Resolver}; use build_reduced_graph::BuildReducedGraphVisitor; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex}; use rustc::hir::map::{self, DefCollector}; +use std::cell::Cell; use std::rc::Rc; use syntax::ast; use syntax::errors::DiagnosticBuilder; @@ -35,7 +36,7 @@ pub struct NameBinding { #[derive(Clone)] pub struct ExpansionData<'a> { backtrace: SyntaxContext, - pub module: Module<'a>, + pub module: Cell>, def_index: DefIndex, // True if this expansion is in a `const_integer` position, for example `[u32; m!()]`. // c.f. `DefCollector::visit_ast_const_integer`. @@ -46,7 +47,7 @@ impl<'a> ExpansionData<'a> { pub fn root(graph_root: Module<'a>) -> Self { ExpansionData { backtrace: SyntaxContext::empty(), - module: graph_root, + module: Cell::new(graph_root), def_index: CRATE_DEF_INDEX, const_integer: false, } @@ -61,18 +62,18 @@ impl<'a> base::Resolver for Resolver<'a> { fn get_module_scope(&mut self, id: ast::NodeId) -> Mark { let mark = Mark::fresh(); let module = self.module_map[&id]; - self.expansion_data.insert(mark, ExpansionData { + self.expansion_data.insert(mark, self.arenas.alloc_expansion_data(ExpansionData { backtrace: SyntaxContext::empty(), - module: module, + module: Cell::new(module), def_index: module.def_id().unwrap().index, const_integer: false, - }); + })); mark } fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) { self.collect_def_ids(mark, expansion); - self.current_module = self.expansion_data[&mark].module; + self.current_module = self.expansion_data[&mark].module.get(); expansion.visit_with(&mut BuildReducedGraphVisitor { resolver: self, expansion: mark }); } @@ -81,13 +82,14 @@ impl<'a> base::Resolver for Resolver<'a> { self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`"); } if def.use_locally { - let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope]; + let expansion_data = self.expansion_data[&scope]; + let mut module = expansion_data.module.get(); while module.macros_escape { module = module.parent.unwrap(); } let binding = NameBinding { ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)), - expansion: backtrace.data().prev_ctxt.data().outer_mark, + expansion: expansion_data.backtrace.data().prev_ctxt.data().outer_mark, shadowing: self.resolve_macro_name(scope, def.ident.name, false).is_some(), span: def.span, }; @@ -119,7 +121,7 @@ impl<'a> base::Resolver for Resolver<'a> { fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option { for i in 0..attrs.len() { let name = intern(&attrs[i].name()); - match self.expansion_data[&Mark::root()].module.macros.borrow().get(&name) { + match self.expansion_data[&Mark::root()].module.get().macros.borrow().get(&name) { Some(binding) => match *binding.ext { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) @@ -164,10 +166,11 @@ impl<'a> base::Resolver for Resolver<'a> { impl<'a> Resolver<'a> { pub fn resolve_macro_name(&mut self, scope: Mark, name: ast::Name, record_used: bool) -> Option> { - let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope]; + let expansion_data = self.expansion_data[&scope]; + let mut module = expansion_data.module.get(); loop { if let Some(binding) = module.macros.borrow().get(&name) { - let mut backtrace = backtrace.data(); + let mut backtrace = expansion_data.backtrace.data(); while binding.expansion != backtrace.outer_mark { if backtrace.outer_mark != Mark::root() { backtrace = backtrace.prev_ctxt.data(); @@ -205,14 +208,18 @@ impl<'a> Resolver<'a> { } fn collect_def_ids(&mut self, mark: Mark, expansion: &Expansion) { - let expansion_data = &mut self.expansion_data; - let ExpansionData { backtrace, def_index, const_integer, module } = expansion_data[&mark]; + let Resolver { ref mut expansion_data, arenas, graph_root, .. } = *self; + let ExpansionData { def_index, const_integer, backtrace, .. } = + expansion_data[&mark].clone(); + let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| { - expansion_data.entry(invoc.mark).or_insert(ExpansionData { - backtrace: backtrace.apply_mark(invoc.mark), - def_index: invoc.def_index, - const_integer: invoc.const_integer, - module: module, + expansion_data.entry(invoc.mark).or_insert_with(|| { + arenas.alloc_expansion_data(ExpansionData { + backtrace: backtrace.apply_mark(invoc.mark), + def_index: invoc.def_index, + const_integer: invoc.const_integer, + module: Cell::new(graph_root), + }) }); }; From a23bdd27695bb5a3bcef34aac9ef7d2ffc952928 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 3 Oct 2016 23:48:19 +0000 Subject: [PATCH 06/13] Rename `resolve::macros::{ExpansionData -> InvocationData}`. --- src/librustc_resolve/build_reduced_graph.rs | 4 +-- src/librustc_resolve/lib.rs | 21 ++++++------- src/librustc_resolve/macros.rs | 33 ++++++++++----------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 79f133770b367..6d9786c8109e4 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -203,7 +203,7 @@ impl<'b> Resolver<'b> { let ext = macro_rules::compile(&self.session.parse_sess, &def); let shadowing = self.resolve_macro_name(Mark::root(), name, false).is_some(); - self.expansion_data[&Mark::root()].module.get().macros.borrow_mut() + self.invocations[&Mark::root()].module.get().macros.borrow_mut() .insert(name, macros::NameBinding { ext: Rc::new(ext), expansion: expansion, @@ -526,7 +526,7 @@ pub struct BuildReducedGraphVisitor<'a, 'b: 'a> { impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { fn visit_invoc(&mut self, id: ast::NodeId) { let mark = Mark::from_placeholder_id(id); - self.resolver.expansion_data[&mark].module.set(self.resolver.current_module); + self.resolver.invocations[&mark].module.set(self.resolver.current_module); } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a03d23a939415..2507d747452f0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -77,7 +77,7 @@ use std::mem::replace; use std::rc::Rc; use resolve_imports::{ImportDirective, NameResolution}; -use macros::ExpansionData; +use macros::InvocationData; // NB: This module needs to be declared first so diagnostics are // registered before they are used. @@ -1089,7 +1089,7 @@ pub struct Resolver<'a> { macro_names: FnvHashSet, // Maps the `Mark` of an expansion to its containing module or block. - expansion_data: FnvHashMap>, + invocations: FnvHashMap>, } pub struct ResolverArenas<'a> { @@ -1098,7 +1098,7 @@ pub struct ResolverArenas<'a> { name_bindings: arena::TypedArena>, import_directives: arena::TypedArena>, name_resolutions: arena::TypedArena>>, - expansion_data: arena::TypedArena>, + invocation_data: arena::TypedArena>, } impl<'a> ResolverArenas<'a> { @@ -1122,8 +1122,9 @@ impl<'a> ResolverArenas<'a> { fn alloc_name_resolution(&'a self) -> &'a RefCell> { self.name_resolutions.alloc(Default::default()) } - fn alloc_expansion_data(&'a self, expansion_data: ExpansionData<'a>) -> &'a ExpansionData<'a> { - self.expansion_data.alloc(expansion_data) + fn alloc_invocation_data(&'a self, expansion_data: InvocationData<'a>) + -> &'a InvocationData<'a> { + self.invocation_data.alloc(expansion_data) } } @@ -1210,9 +1211,9 @@ impl<'a> Resolver<'a> { let mut definitions = Definitions::new(); DefCollector::new(&mut definitions).collect_root(); - let mut expansion_data = FnvHashMap(); - expansion_data.insert(Mark::root(), - arenas.alloc_expansion_data(ExpansionData::root(graph_root))); + let mut invocations = FnvHashMap(); + invocations.insert(Mark::root(), + arenas.alloc_invocation_data(InvocationData::root(graph_root))); Resolver { session: session, @@ -1272,7 +1273,7 @@ impl<'a> Resolver<'a> { derive_modes: FnvHashMap(), crate_loader: crate_loader, macro_names: FnvHashSet(), - expansion_data: expansion_data, + invocations: invocations, } } @@ -1283,7 +1284,7 @@ impl<'a> Resolver<'a> { name_bindings: arena::TypedArena::new(), import_directives: arena::TypedArena::new(), name_resolutions: arena::TypedArena::new(), - expansion_data: arena::TypedArena::new(), + invocation_data: arena::TypedArena::new(), } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index ee3edbccabca5..650642cee7032 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -34,7 +34,7 @@ pub struct NameBinding { } #[derive(Clone)] -pub struct ExpansionData<'a> { +pub struct InvocationData<'a> { backtrace: SyntaxContext, pub module: Cell>, def_index: DefIndex, @@ -43,9 +43,9 @@ pub struct ExpansionData<'a> { const_integer: bool, } -impl<'a> ExpansionData<'a> { +impl<'a> InvocationData<'a> { pub fn root(graph_root: Module<'a>) -> Self { - ExpansionData { + InvocationData { backtrace: SyntaxContext::empty(), module: Cell::new(graph_root), def_index: CRATE_DEF_INDEX, @@ -62,7 +62,7 @@ impl<'a> base::Resolver for Resolver<'a> { fn get_module_scope(&mut self, id: ast::NodeId) -> Mark { let mark = Mark::fresh(); let module = self.module_map[&id]; - self.expansion_data.insert(mark, self.arenas.alloc_expansion_data(ExpansionData { + self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData { backtrace: SyntaxContext::empty(), module: Cell::new(module), def_index: module.def_id().unwrap().index, @@ -73,7 +73,7 @@ impl<'a> base::Resolver for Resolver<'a> { fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) { self.collect_def_ids(mark, expansion); - self.current_module = self.expansion_data[&mark].module.get(); + self.current_module = self.invocations[&mark].module.get(); expansion.visit_with(&mut BuildReducedGraphVisitor { resolver: self, expansion: mark }); } @@ -82,14 +82,14 @@ impl<'a> base::Resolver for Resolver<'a> { self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`"); } if def.use_locally { - let expansion_data = self.expansion_data[&scope]; - let mut module = expansion_data.module.get(); + let invocation = self.invocations[&scope]; + let mut module = invocation.module.get(); while module.macros_escape { module = module.parent.unwrap(); } let binding = NameBinding { ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)), - expansion: expansion_data.backtrace.data().prev_ctxt.data().outer_mark, + expansion: invocation.backtrace.data().prev_ctxt.data().outer_mark, shadowing: self.resolve_macro_name(scope, def.ident.name, false).is_some(), span: def.span, }; @@ -121,7 +121,7 @@ impl<'a> base::Resolver for Resolver<'a> { fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option { for i in 0..attrs.len() { let name = intern(&attrs[i].name()); - match self.expansion_data[&Mark::root()].module.get().macros.borrow().get(&name) { + match self.invocations[&Mark::root()].module.get().macros.borrow().get(&name) { Some(binding) => match *binding.ext { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) @@ -166,11 +166,11 @@ impl<'a> base::Resolver for Resolver<'a> { impl<'a> Resolver<'a> { pub fn resolve_macro_name(&mut self, scope: Mark, name: ast::Name, record_used: bool) -> Option> { - let expansion_data = self.expansion_data[&scope]; - let mut module = expansion_data.module.get(); + let invocation = self.invocations[&scope]; + let mut module = invocation.module.get(); loop { if let Some(binding) = module.macros.borrow().get(&name) { - let mut backtrace = expansion_data.backtrace.data(); + let mut backtrace = invocation.backtrace.data(); while binding.expansion != backtrace.outer_mark { if backtrace.outer_mark != Mark::root() { backtrace = backtrace.prev_ctxt.data(); @@ -208,13 +208,12 @@ impl<'a> Resolver<'a> { } fn collect_def_ids(&mut self, mark: Mark, expansion: &Expansion) { - let Resolver { ref mut expansion_data, arenas, graph_root, .. } = *self; - let ExpansionData { def_index, const_integer, backtrace, .. } = - expansion_data[&mark].clone(); + let Resolver { ref mut invocations, arenas, graph_root, .. } = *self; + let InvocationData { def_index, const_integer, backtrace, .. } = invocations[&mark].clone(); let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| { - expansion_data.entry(invoc.mark).or_insert_with(|| { - arenas.alloc_expansion_data(ExpansionData { + invocations.entry(invoc.mark).or_insert_with(|| { + arenas.alloc_invocation_data(InvocationData { backtrace: backtrace.apply_mark(invoc.mark), def_index: invoc.def_index, const_integer: invoc.const_integer, From fbc96e18ad0c2a3f5be7e4ef003c720146b0a52d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 6 Oct 2016 08:04:30 +0000 Subject: [PATCH 07/13] Persistent macro scopes. --- src/librustc_resolve/build_reduced_graph.rs | 69 ++++---- src/librustc_resolve/lib.rs | 15 +- src/librustc_resolve/macros.rs | 182 +++++++++++++------- 3 files changed, 167 insertions(+), 99 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 6d9786c8109e4..c1c582320549d 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -13,7 +13,7 @@ //! Here we build the "reduced graph": the graph of the module tree without //! any imports resolved. -use macros; +use macros::{InvocationData, LegacyImports, LegacyScope}; use resolve_imports::ImportDirectiveSubclass::{self, GlobImport}; use {Module, ModuleS, ModuleKind}; use Namespace::{self, TypeNS, ValueNS}; @@ -84,7 +84,7 @@ impl<'b> Resolver<'b> { } /// Constructs the reduced graph for one item. - fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) { + fn build_reduced_graph_for_item(&mut self, item: &Item, legacy_imports: &mut LegacyImports) { let parent = self.current_module; let name = item.ident.name; let sp = item.span; @@ -200,16 +200,9 @@ impl<'b> Resolver<'b> { LoadedMacroKind::Def(mut def) => { let name = def.ident.name; if def.use_locally { - let ext = macro_rules::compile(&self.session.parse_sess, &def); - let shadowing = - self.resolve_macro_name(Mark::root(), name, false).is_some(); - self.invocations[&Mark::root()].module.get().macros.borrow_mut() - .insert(name, macros::NameBinding { - ext: Rc::new(ext), - expansion: expansion, - shadowing: shadowing, - span: loaded_macro.import_site, - }); + let ext = + Rc::new(macro_rules::compile(&self.session.parse_sess, &def)); + legacy_imports.insert(name, (ext, loaded_macro.import_site)); self.macro_names.insert(name); } if def.export { @@ -250,7 +243,6 @@ impl<'b> Resolver<'b> { attr::contains_name(&item.attrs, "no_implicit_prelude") }, normal_ancestor_id: Some(item.id), - macros_escape: self.contains_macro_use(&item.attrs), ..ModuleS::new(Some(parent), ModuleKind::Def(def, name)) }); self.define(parent, name, TypeNS, (module, sp, vis)); @@ -520,22 +512,26 @@ impl<'b> Resolver<'b> { pub struct BuildReducedGraphVisitor<'a, 'b: 'a> { pub resolver: &'a mut Resolver<'b>, - pub expansion: Mark, + pub legacy_scope: LegacyScope<'b>, + pub legacy_imports: LegacyImports, } impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { - fn visit_invoc(&mut self, id: ast::NodeId) { - let mark = Mark::from_placeholder_id(id); - self.resolver.invocations[&mark].module.set(self.resolver.current_module); + fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> { + let invocation = self.resolver.invocations[&Mark::from_placeholder_id(id)]; + invocation.module.set(self.resolver.current_module); + invocation.legacy_scope.set(self.legacy_scope); + invocation } } macro_rules! method { ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => { fn $visit(&mut self, node: &$ty) { - match node.node { - $invoc(..) => self.visit_invoc(node.id), - _ => visit::$walk(self, node), + if let $invoc(..) = node.node { + self.visit_invoc(node.id); + } else { + visit::$walk(self, node); } } } @@ -543,22 +539,35 @@ macro_rules! method { impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item); - method!(visit_stmt: ast::Stmt, ast::StmtKind::Mac, walk_stmt); method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr); method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat); method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty); fn visit_item(&mut self, item: &Item) { - match item.node { + let macro_use = match item.node { ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => return, // Scope placeholder - ItemKind::Mac(..) => return self.visit_invoc(item.id), - _ => {} - } + ItemKind::Mac(..) => { + return self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id)); + } + ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs), + _ => false, + }; - let parent = self.resolver.current_module; - self.resolver.build_reduced_graph_for_item(item, self.expansion); + let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope); + self.resolver.build_reduced_graph_for_item(item, &mut self.legacy_imports); visit::walk_item(self, item); self.resolver.current_module = parent; + if !macro_use { + self.legacy_scope = legacy_scope; + } + } + + fn visit_stmt(&mut self, stmt: &ast::Stmt) { + if let ast::StmtKind::Mac(..) = stmt.node { + self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(stmt.id)); + } else { + visit::walk_stmt(self, stmt); + } } fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) { @@ -567,10 +576,11 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { } fn visit_block(&mut self, block: &Block) { - let parent = self.resolver.current_module; + let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope); self.resolver.build_reduced_graph_for_block(block); visit::walk_block(self, block); self.resolver.current_module = parent; + self.legacy_scope = legacy_scope; } fn visit_trait_item(&mut self, item: &TraitItem) { @@ -578,7 +588,8 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { let def_id = parent.def_id().unwrap(); if let TraitItemKind::Macro(_) = item.node { - return self.visit_invoc(item.id); + self.visit_invoc(item.id); + return } // Add the item to the trait info. diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 2507d747452f0..219c2abff2c3f 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -57,6 +57,7 @@ use syntax::ext::base::MultiItemModifier; use syntax::ext::hygiene::Mark; use syntax::ast::{self, FloatTy}; use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy}; +use syntax::ext::base::SyntaxExtension; use syntax::parse::token::{self, keywords}; use syntax::util::lev_distance::find_best_match_for_name; @@ -77,7 +78,7 @@ use std::mem::replace; use std::rc::Rc; use resolve_imports::{ImportDirective, NameResolution}; -use macros::InvocationData; +use macros::{InvocationData, LegacyBinding}; // NB: This module needs to be declared first so diagnostics are // registered before they are used. @@ -792,9 +793,6 @@ pub struct ModuleS<'a> { // access the children must be preceded with a // `populate_module_if_necessary` call. populated: Cell, - - macros: RefCell>, - macros_escape: bool, } pub type Module<'a> = &'a ModuleS<'a>; @@ -812,8 +810,6 @@ impl<'a> ModuleS<'a> { globs: RefCell::new((Vec::new())), traits: RefCell::new(None), populated: Cell::new(true), - macros: RefCell::new(FnvHashMap()), - macros_escape: false, } } @@ -1087,6 +1083,7 @@ pub struct Resolver<'a> { pub derive_modes: FnvHashMap>, crate_loader: &'a mut CrateLoader, macro_names: FnvHashSet, + builtin_macros: FnvHashMap>, // Maps the `Mark` of an expansion to its containing module or block. invocations: FnvHashMap>, @@ -1099,6 +1096,7 @@ pub struct ResolverArenas<'a> { import_directives: arena::TypedArena>, name_resolutions: arena::TypedArena>>, invocation_data: arena::TypedArena>, + legacy_bindings: arena::TypedArena>, } impl<'a> ResolverArenas<'a> { @@ -1126,6 +1124,9 @@ impl<'a> ResolverArenas<'a> { -> &'a InvocationData<'a> { self.invocation_data.alloc(expansion_data) } + fn alloc_legacy_binding(&'a self, binding: LegacyBinding<'a>) -> &'a LegacyBinding<'a> { + self.legacy_bindings.alloc(binding) + } } impl<'a> ty::NodeIdTree for Resolver<'a> { @@ -1273,6 +1274,7 @@ impl<'a> Resolver<'a> { derive_modes: FnvHashMap(), crate_loader: crate_loader, macro_names: FnvHashSet(), + builtin_macros: FnvHashMap(), invocations: invocations, } } @@ -1285,6 +1287,7 @@ impl<'a> Resolver<'a> { import_directives: arena::TypedArena::new(), name_resolutions: arena::TypedArena::new(), invocation_data: arena::TypedArena::new(), + legacy_bindings: arena::TypedArena::new(), } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 650642cee7032..31b0180f6f122 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -12,6 +12,7 @@ use {Module, Resolver}; use build_reduced_graph::BuildReducedGraphVisitor; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex}; use rustc::hir::map::{self, DefCollector}; +use rustc::util::nodemap::FnvHashMap; use std::cell::Cell; use std::rc::Rc; use syntax::ast; @@ -19,41 +20,58 @@ use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier}; use syntax::ext::base::{NormalTT, SyntaxExtension}; use syntax::ext::expand::{Expansion, Invocation, InvocationKind}; -use syntax::ext::hygiene::{Mark, SyntaxContext}; +use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; use syntax::parse::token::intern; use syntax::util::lev_distance::find_best_match_for_name; -use syntax_pos::{Span, DUMMY_SP}; - -// FIXME(jseyfried) Merge with `::NameBinding`. -pub struct NameBinding { - pub ext: Rc, - pub expansion: Mark, - pub shadowing: bool, - pub span: Span, -} +use syntax_pos::Span; #[derive(Clone)] pub struct InvocationData<'a> { - backtrace: SyntaxContext, pub module: Cell>, def_index: DefIndex, // True if this expansion is in a `const_integer` position, for example `[u32; m!()]`. // c.f. `DefCollector::visit_ast_const_integer`. const_integer: bool, + // The scope in which the invocation path is resolved. + pub legacy_scope: Cell>, + // The smallest scope that includes this invocation's expansion, + // or `Empty` if this invocation has not been expanded yet. + pub expansion: Cell>, } impl<'a> InvocationData<'a> { pub fn root(graph_root: Module<'a>) -> Self { InvocationData { - backtrace: SyntaxContext::empty(), module: Cell::new(graph_root), def_index: CRATE_DEF_INDEX, const_integer: false, + legacy_scope: Cell::new(LegacyScope::Empty), + expansion: Cell::new(LegacyScope::Empty), } } } +#[derive(Copy, Clone)] +pub enum LegacyScope<'a> { + Empty, + Invocation(&'a InvocationData<'a>), // The scope of the invocation, not including its expansion + Expansion(&'a InvocationData<'a>), // The scope of the invocation, including its expansion + Binding(&'a LegacyBinding<'a>), +} + +pub struct LegacyBinding<'a> { + parent: LegacyScope<'a>, + kind: LegacyBindingKind, +} + +pub enum LegacyBindingKind { + MacroRules(ast::Name, Rc, Span), + MacroUse(LegacyImports), +} + +pub type LegacyImports = FnvHashMap, Span)>; + impl<'a> base::Resolver for Resolver<'a> { fn next_node_id(&mut self) -> ast::NodeId { self.session.next_node_id() @@ -63,18 +81,36 @@ impl<'a> base::Resolver for Resolver<'a> { let mark = Mark::fresh(); let module = self.module_map[&id]; self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData { - backtrace: SyntaxContext::empty(), module: Cell::new(module), def_index: module.def_id().unwrap().index, const_integer: false, + legacy_scope: Cell::new(LegacyScope::Empty), + expansion: Cell::new(LegacyScope::Empty), })); mark } fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) { - self.collect_def_ids(mark, expansion); - self.current_module = self.invocations[&mark].module.get(); - expansion.visit_with(&mut BuildReducedGraphVisitor { resolver: self, expansion: mark }); + let invocation = self.invocations[&mark]; + self.collect_def_ids(invocation, expansion); + + self.current_module = invocation.module.get(); + let mut visitor = BuildReducedGraphVisitor { + resolver: self, + legacy_scope: LegacyScope::Invocation(invocation), + legacy_imports: FnvHashMap(), + }; + expansion.visit_with(&mut visitor); + invocation.expansion.set(visitor.legacy_scope); + + if !visitor.legacy_imports.is_empty() { + invocation.legacy_scope.set({ + LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding { + parent: invocation.legacy_scope.get(), + kind: LegacyBindingKind::MacroUse(visitor.legacy_imports), + })) + }); + } } fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) { @@ -83,17 +119,12 @@ impl<'a> base::Resolver for Resolver<'a> { } if def.use_locally { let invocation = self.invocations[&scope]; - let mut module = invocation.module.get(); - while module.macros_escape { - module = module.parent.unwrap(); - } - let binding = NameBinding { - ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)), - expansion: invocation.backtrace.data().prev_ctxt.data().outer_mark, - shadowing: self.resolve_macro_name(scope, def.ident.name, false).is_some(), - span: def.span, - }; - module.macros.borrow_mut().insert(def.ident.name, binding); + let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, &def)); + let binding = self.arenas.alloc_legacy_binding(LegacyBinding { + parent: invocation.legacy_scope.get(), + kind: LegacyBindingKind::MacroRules(def.ident.name, ext, def.span), + }); + invocation.legacy_scope.set(LegacyScope::Binding(binding)); self.macro_names.insert(def.ident.name); } if def.export { @@ -106,12 +137,7 @@ impl<'a> base::Resolver for Resolver<'a> { if let NormalTT(..) = *ext { self.macro_names.insert(ident.name); } - self.graph_root.macros.borrow_mut().insert(ident.name, NameBinding { - ext: ext, - expansion: Mark::root(), - shadowing: false, - span: DUMMY_SP, - }); + self.builtin_macros.insert(ident.name, ext); } fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec) { @@ -121,8 +147,8 @@ impl<'a> base::Resolver for Resolver<'a> { fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option { for i in 0..attrs.len() { let name = intern(&attrs[i].name()); - match self.invocations[&Mark::root()].module.get().macros.borrow().get(&name) { - Some(binding) => match *binding.ext { + match self.builtin_macros.get(&name) { + Some(ext) => match **ext { MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => { return Some(attrs.remove(i)) } @@ -149,6 +175,7 @@ impl<'a> base::Resolver for Resolver<'a> { InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span), }; + let scope = self.invocations[&scope].legacy_scope.get(); self.resolve_macro_name(scope, name, true).or_else(|| { let mut err = self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name)); @@ -164,37 +191,63 @@ impl<'a> base::Resolver for Resolver<'a> { } impl<'a> Resolver<'a> { - pub fn resolve_macro_name(&mut self, scope: Mark, name: ast::Name, record_used: bool) - -> Option> { - let invocation = self.invocations[&scope]; - let mut module = invocation.module.get(); + fn resolve_macro_name(&mut self, + mut scope: LegacyScope<'a>, + name: ast::Name, + record_used: bool) + -> Option> { + let check_shadowing = |this: &mut Self, relative_depth, scope, span| { + if record_used && relative_depth > 0 && + this.resolve_macro_name(scope, name, false).is_some() && + this.macro_shadowing_errors.insert(span) { + let msg = format!("`{}` is already in scope", name); + this.session.struct_span_err(span, &msg) + .note("macro-expanded `macro_rules!`s and `#[macro_use]`s \ + may not shadow existing macros (see RFC 1560)") + .emit(); + } + }; + + let mut relative_depth: u32 = 0; loop { - if let Some(binding) = module.macros.borrow().get(&name) { - let mut backtrace = invocation.backtrace.data(); - while binding.expansion != backtrace.outer_mark { - if backtrace.outer_mark != Mark::root() { - backtrace = backtrace.prev_ctxt.data(); - continue + scope = match scope { + LegacyScope::Empty => break, + LegacyScope::Expansion(invocation) => { + if let LegacyScope::Empty = invocation.expansion.get() { + invocation.legacy_scope.get() + } else { + relative_depth += 1; + invocation.expansion.get() } - - if record_used && binding.shadowing && - self.macro_shadowing_errors.insert(binding.span) { - let msg = format!("`{}` is already in scope", name); - self.session.struct_span_err(binding.span, &msg) - .note("macro-expanded `macro_rules!`s and `#[macro_use]`s \ - may not shadow existing macros (see RFC 1560)") - .emit(); + } + LegacyScope::Invocation(invocation) => { + let new_relative_depth = relative_depth.saturating_sub(1); + let mut scope = invocation.legacy_scope.get(); + if let LegacyScope::Binding(binding) = scope { + match binding.kind { + LegacyBindingKind::MacroUse(ref imports) => { + if let Some(&(ref ext, span)) = imports.get(&name) { + check_shadowing(self, relative_depth, binding.parent, span); + return Some(ext.clone()); + } + }, + LegacyBindingKind::MacroRules(name_, ref ext, span) => { + if name_ == name { + check_shadowing(self, new_relative_depth, binding.parent, span); + return Some(ext.clone()); + } + } + } + scope = binding.parent } - break + relative_depth = new_relative_depth; + scope } - return Some(binding.ext.clone()); - } - match module.parent { - Some(parent) => module = parent, - None => break, - } + _ => unreachable!(), + }; } - None + + self.builtin_macros.get(&name).cloned() } fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) { @@ -207,17 +260,18 @@ impl<'a> Resolver<'a> { } } - fn collect_def_ids(&mut self, mark: Mark, expansion: &Expansion) { + fn collect_def_ids(&mut self, invocation: &'a InvocationData<'a>, expansion: &Expansion) { let Resolver { ref mut invocations, arenas, graph_root, .. } = *self; - let InvocationData { def_index, const_integer, backtrace, .. } = invocations[&mark].clone(); + let InvocationData { def_index, const_integer, .. } = *invocation; let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| { invocations.entry(invoc.mark).or_insert_with(|| { arenas.alloc_invocation_data(InvocationData { - backtrace: backtrace.apply_mark(invoc.mark), def_index: invoc.def_index, const_integer: invoc.const_integer, module: Cell::new(graph_root), + expansion: Cell::new(LegacyScope::Empty), + legacy_scope: Cell::new(LegacyScope::Empty), }) }); }; From 53fd3b0acc42c8c038382bcbc5e4ba7869178228 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 8 Oct 2016 00:30:24 +0000 Subject: [PATCH 08/13] Avoid quadratic complexity. --- src/librustc_resolve/macros.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 31b0180f6f122..4ee07036edb7f 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -60,6 +60,19 @@ pub enum LegacyScope<'a> { Binding(&'a LegacyBinding<'a>), } +impl<'a> LegacyScope<'a> { + fn simplify_expansion(mut invoc: &'a InvocationData<'a>) -> Self { + while let LegacyScope::Invocation(_) = invoc.expansion.get() { + match invoc.legacy_scope.get() { + LegacyScope::Expansion(new_invoc) => invoc = new_invoc, + LegacyScope::Binding(_) => break, + scope @ _ => return scope, + } + } + LegacyScope::Expansion(invoc) + } +} + pub struct LegacyBinding<'a> { parent: LegacyScope<'a>, kind: LegacyBindingKind, @@ -175,8 +188,11 @@ impl<'a> base::Resolver for Resolver<'a> { InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span), }; - let scope = self.invocations[&scope].legacy_scope.get(); - self.resolve_macro_name(scope, name, true).or_else(|| { + let invocation = self.invocations[&scope]; + if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() { + invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent)); + } + self.resolve_macro_name(invocation.legacy_scope.get(), name, true).or_else(|| { let mut err = self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name)); self.suggest_macro_name(&name.as_str(), &mut err); From 6808b0a2b77448585dff3e0bfdd72a16ed5dab9b Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 11 Oct 2016 03:21:40 +0000 Subject: [PATCH 09/13] Check for shadowing errors after all invocations have been expanded. --- src/librustc_resolve/lib.rs | 23 +++++++++++++++++++---- src/librustc_resolve/macros.rs | 20 +++++++------------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 219c2abff2c3f..fb18615263cf3 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -78,7 +78,7 @@ use std::mem::replace; use std::rc::Rc; use resolve_imports::{ImportDirective, NameResolution}; -use macros::{InvocationData, LegacyBinding}; +use macros::{InvocationData, LegacyBinding, LegacyScope}; // NB: This module needs to be declared first so diagnostics are // registered before they are used. @@ -1073,7 +1073,7 @@ pub struct Resolver<'a> { privacy_errors: Vec>, ambiguity_errors: Vec>, - macro_shadowing_errors: FnvHashSet, + disallowed_shadowing: Vec<(Name, Span, LegacyScope<'a>)>, arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, @@ -1260,7 +1260,7 @@ impl<'a> Resolver<'a> { privacy_errors: Vec::new(), ambiguity_errors: Vec::new(), - macro_shadowing_errors: FnvHashSet(), + disallowed_shadowing: Vec::new(), arenas: arenas, dummy_binding: arenas.alloc_name_binding(NameBinding { @@ -3353,7 +3353,8 @@ impl<'a> Resolver<'a> { vis.is_accessible_from(module.normal_ancestor_id.unwrap(), self) } - fn report_errors(&self) { + fn report_errors(&mut self) { + self.report_shadowing_errors(); let mut reported_spans = FnvHashSet(); for &AmbiguityError { span, name, b1, b2 } in &self.ambiguity_errors { @@ -3381,6 +3382,20 @@ impl<'a> Resolver<'a> { } } + fn report_shadowing_errors(&mut self) { + let mut reported_errors = FnvHashSet(); + for (name, span, scope) in replace(&mut self.disallowed_shadowing, Vec::new()) { + if self.resolve_macro_name(scope, name, false).is_some() && + reported_errors.insert((name, span)) { + let msg = format!("`{}` is already in scope", name); + self.session.struct_span_err(span, &msg) + .note("macro-expanded `macro_rules!`s and `#[macro_use]`s \ + may not shadow existing macros (see RFC 1560)") + .emit(); + } + } + } + fn report_conflict(&self, parent: Module, name: Name, diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 4ee07036edb7f..1c36b2452a4ea 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -207,20 +207,14 @@ impl<'a> base::Resolver for Resolver<'a> { } impl<'a> Resolver<'a> { - fn resolve_macro_name(&mut self, - mut scope: LegacyScope<'a>, - name: ast::Name, - record_used: bool) - -> Option> { + pub fn resolve_macro_name(&mut self, + mut scope: LegacyScope<'a>, + name: ast::Name, + record_used: bool) + -> Option> { let check_shadowing = |this: &mut Self, relative_depth, scope, span| { - if record_used && relative_depth > 0 && - this.resolve_macro_name(scope, name, false).is_some() && - this.macro_shadowing_errors.insert(span) { - let msg = format!("`{}` is already in scope", name); - this.session.struct_span_err(span, &msg) - .note("macro-expanded `macro_rules!`s and `#[macro_use]`s \ - may not shadow existing macros (see RFC 1560)") - .emit(); + if record_used && relative_depth > 0 { + this.disallowed_shadowing.push((name, span, scope)); } }; From 31e0e12e6986ca369e9e27fa713c40b174c4d573 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 11 Oct 2016 03:41:48 +0000 Subject: [PATCH 10/13] Add support for undetermined macro invocations. --- src/librustc_resolve/macros.rs | 11 +++++----- src/librustc_resolve/resolve_imports.rs | 8 +------ src/libsyntax/ext/base.rs | 14 +++++++++--- src/libsyntax/ext/expand.rs | 29 ++++++++++++++++++++++--- 4 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 1c36b2452a4ea..ca0958e085af0 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -17,7 +17,7 @@ use std::cell::Cell; use std::rc::Rc; use syntax::ast; use syntax::errors::DiagnosticBuilder; -use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier}; +use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator, MultiItemModifier}; use syntax::ext::base::{NormalTT, SyntaxExtension}; use syntax::ext::expand::{Expansion, Invocation, InvocationKind}; use syntax::ext::hygiene::Mark; @@ -173,7 +173,8 @@ impl<'a> base::Resolver for Resolver<'a> { None } - fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option> { + fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, _force: bool) + -> Result, Determinacy> { let (name, span) = match invoc.kind { InvocationKind::Bang { ref mac, .. } => { let path = &mac.node.path; @@ -181,7 +182,7 @@ impl<'a> base::Resolver for Resolver<'a> { !path.segments[0].parameters.is_empty() { self.session.span_err(path.span, "expected macro name without module separators"); - return None; + return Err(Determinacy::Determined); } (path.segments[0].identifier.name, path.span) } @@ -192,12 +193,12 @@ impl<'a> base::Resolver for Resolver<'a> { if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() { invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent)); } - self.resolve_macro_name(invocation.legacy_scope.get(), name, true).or_else(|| { + self.resolve_macro_name(invocation.legacy_scope.get(), name, true).ok_or_else(|| { let mut err = self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name)); self.suggest_macro_name(&name.as_str(), &mut err); err.emit(); - None + Determinacy::Determined }) } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 4689c4ded5c0a..a72a660a5c411 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use self::Determinacy::*; use self::ImportDirectiveSubclass::*; use Module; @@ -26,6 +25,7 @@ use rustc::lint::builtin::PRIVATE_IN_PUBLIC; use rustc::hir::def::*; use syntax::ast::{NodeId, Name}; +use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; @@ -37,12 +37,6 @@ impl<'a> Resolver<'a> { } } -#[derive(Copy, Clone, Debug)] -pub enum Determinacy { - Determined, - Undetermined, -} - /// Contains data for specific types of import directives. #[derive(Clone, Debug)] pub enum ImportDirectiveSubclass<'a> { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 923d5d05439e4..f7c88073c9d40 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -522,10 +522,17 @@ pub trait Resolver { fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec); fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option; - fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option>; + fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool) + -> Result, Determinacy>; fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option>; } +#[derive(Copy, Clone, Debug)] +pub enum Determinacy { + Determined, + Undetermined, +} + pub struct DummyResolver; impl Resolver for DummyResolver { @@ -539,8 +546,9 @@ impl Resolver for DummyResolver { fn find_attr_invoc(&mut self, _attrs: &mut Vec) -> Option { None } fn resolve_derive_mode(&mut self, _ident: ast::Ident) -> Option> { None } - fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation) -> Option> { - None + fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation, _force: bool) + -> Result, Determinacy> { + Err(Determinacy::Determined) } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index ab7ffe36673ac..363ceebf0f475 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -225,13 +225,36 @@ impl<'a, 'b> MacroExpander<'a, 'b> { invocations.reverse(); let mut expansions = Vec::new(); - while let Some(invoc) = invocations.pop() { + let mut undetermined_invocations = Vec::new(); + let (mut progress, mut force) = (false, !self.monotonic); + loop { + let invoc = if let Some(invoc) = invocations.pop() { + invoc + } else if undetermined_invocations.is_empty() { + break + } else { + invocations = mem::replace(&mut undetermined_invocations, Vec::new()); + force = !mem::replace(&mut progress, false); + continue + }; + + let scope = + if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; + let ext = match self.cx.resolver.resolve_invoc(scope, &invoc, force) { + Ok(ext) => Some(ext), + Err(Determinacy::Determined) => None, + Err(Determinacy::Undetermined) => { + undetermined_invocations.push(invoc); + continue + } + }; + + progress = true; let ExpansionData { depth, mark, .. } = invoc.expansion_data; self.cx.current_expansion = invoc.expansion_data.clone(); - let scope = if self.monotonic { mark } else { orig_expansion_data.mark }; self.cx.current_expansion.mark = scope; - let expansion = match self.cx.resolver.resolve_invoc(scope, &invoc) { + let expansion = match ext { Some(ext) => self.expand_invoc(invoc, ext), None => invoc.expansion_kind.dummy(invoc.span()), }; From 111caef9a32e37e89b3503b3c08cdb9f309268e4 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 11 Oct 2016 03:42:06 +0000 Subject: [PATCH 11/13] Clean up the scopes of expanded `#[macro_use]` imports. --- src/librustc_resolve/build_reduced_graph.rs | 17 +++++++++---- src/librustc_resolve/lib.rs | 4 +-- src/librustc_resolve/macros.rs | 27 +++++++++------------ src/test/compile-fail/macro-shadowing.rs | 15 +++++------- 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 12e5613159713..5600669d45fb9 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -13,7 +13,7 @@ //! Here we build the "reduced graph": the graph of the module tree without //! any imports resolved. -use macros::{InvocationData, LegacyImports, LegacyScope}; +use macros::{InvocationData, LegacyScope}; use resolve_imports::ImportDirectiveSubclass::{self, GlobImport}; use {Module, ModuleS, ModuleKind}; use Namespace::{self, TypeNS, ValueNS}; @@ -84,7 +84,7 @@ impl<'b> Resolver<'b> { } /// Constructs the reduced graph for one item. - fn build_reduced_graph_for_item(&mut self, item: &Item, legacy_imports: &mut LegacyImports) { + fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) { let parent = self.current_module; let name = item.ident.name; let sp = item.span; @@ -202,7 +202,14 @@ impl<'b> Resolver<'b> { if def.use_locally { let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, &def)); - legacy_imports.insert(name, (ext, loaded_macro.import_site)); + if self.builtin_macros.insert(name, ext).is_some() && + expansion != Mark::root() { + let msg = format!("`{}` is already in scope", name); + self.session.struct_span_err(loaded_macro.import_site, &msg) + .note("macro-expanded `#[macro_use]`s may not shadow \ + existing macros (see RFC 1560)") + .emit(); + } self.macro_names.insert(name); } if def.export { @@ -513,7 +520,7 @@ impl<'b> Resolver<'b> { pub struct BuildReducedGraphVisitor<'a, 'b: 'a> { pub resolver: &'a mut Resolver<'b>, pub legacy_scope: LegacyScope<'b>, - pub legacy_imports: LegacyImports, + pub expansion: Mark, } impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { @@ -554,7 +561,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> { }; let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope); - self.resolver.build_reduced_graph_for_item(item, &mut self.legacy_imports); + self.resolver.build_reduced_graph_for_item(item, self.expansion); visit::walk_item(self, item); self.resolver.current_module = parent; if !macro_use { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index fb18615263cf3..38a042735ff85 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3389,8 +3389,8 @@ impl<'a> Resolver<'a> { reported_errors.insert((name, span)) { let msg = format!("`{}` is already in scope", name); self.session.struct_span_err(span, &msg) - .note("macro-expanded `macro_rules!`s and `#[macro_use]`s \ - may not shadow existing macros (see RFC 1560)") + .note("macro-expanded `macro_rules!`s may not shadow \ + existing macros (see RFC 1560)") .emit(); } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index ca0958e085af0..6b00ebf3d05fc 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -111,19 +111,10 @@ impl<'a> base::Resolver for Resolver<'a> { let mut visitor = BuildReducedGraphVisitor { resolver: self, legacy_scope: LegacyScope::Invocation(invocation), - legacy_imports: FnvHashMap(), + expansion: mark, }; expansion.visit_with(&mut visitor); invocation.expansion.set(visitor.legacy_scope); - - if !visitor.legacy_imports.is_empty() { - invocation.legacy_scope.set({ - LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding { - parent: invocation.legacy_scope.get(), - kind: LegacyBindingKind::MacroUse(visitor.legacy_imports), - })) - }); - } } fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) { @@ -173,7 +164,7 @@ impl<'a> base::Resolver for Resolver<'a> { None } - fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, _force: bool) + fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool) -> Result, Determinacy> { let (name, span) = match invoc.kind { InvocationKind::Bang { ref mac, .. } => { @@ -194,11 +185,15 @@ impl<'a> base::Resolver for Resolver<'a> { invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent)); } self.resolve_macro_name(invocation.legacy_scope.get(), name, true).ok_or_else(|| { - let mut err = - self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name)); - self.suggest_macro_name(&name.as_str(), &mut err); - err.emit(); - Determinacy::Determined + if force { + let mut err = + self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name)); + self.suggest_macro_name(&name.as_str(), &mut err); + err.emit(); + Determinacy::Determined + } else { + Determinacy::Undetermined + } }) } diff --git a/src/test/compile-fail/macro-shadowing.rs b/src/test/compile-fail/macro-shadowing.rs index 22463825ef98f..8381dc34a6a15 100644 --- a/src/test/compile-fail/macro-shadowing.rs +++ b/src/test/compile-fail/macro-shadowing.rs @@ -12,31 +12,28 @@ macro_rules! foo { () => {} } macro_rules! macro_one { () => {} } +#[macro_use(macro_two)] extern crate two_macros; macro_rules! m1 { () => { macro_rules! foo { () => {} } //~ ERROR `foo` is already in scope - //~^ NOTE macro-expanded `macro_rules!`s and `#[macro_use]`s may not shadow existing macros + //~^ NOTE macro-expanded `macro_rules!`s may not shadow existing macros - #[macro_use] //~ ERROR `macro_one` is already in scope - //~^ NOTE macro-expanded `macro_rules!`s and `#[macro_use]`s may not shadow existing macros - extern crate two_macros; + #[macro_use] //~ ERROR `macro_two` is already in scope + //~^ NOTE macro-expanded `#[macro_use]`s may not shadow existing macros + extern crate two_macros as __; }} m1!(); //~ NOTE in this expansion //~| NOTE in this expansion //~| NOTE in this expansion //~| NOTE in this expansion -fn f() { macro_one!(); } foo!(); macro_rules! m2 { () => { macro_rules! foo { () => {} } - #[macro_use] extern crate two_macros as __; - - fn g() { macro_one!(); } foo!(); }} m2!(); -//^ Since `foo` and `macro_one` are not used outside this expansion, they are not shadowing errors. +//^ Since `foo` is not used outside this expansion, it is not a shadowing error. fn main() {} From a4c0daab6d0995fe7d553f1c59e438a634628fe4 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 11 Oct 2016 03:48:54 +0000 Subject: [PATCH 12/13] Remove `LegacyBindingKind::MacroUse`. --- src/librustc_resolve/macros.rs | 49 +++++++++++----------------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 6b00ebf3d05fc..86ab077191eef 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -75,12 +75,9 @@ impl<'a> LegacyScope<'a> { pub struct LegacyBinding<'a> { parent: LegacyScope<'a>, - kind: LegacyBindingKind, -} - -pub enum LegacyBindingKind { - MacroRules(ast::Name, Rc, Span), - MacroUse(LegacyImports), + name: ast::Name, + ext: Rc, + span: Span, } pub type LegacyImports = FnvHashMap, Span)>; @@ -123,10 +120,11 @@ impl<'a> base::Resolver for Resolver<'a> { } if def.use_locally { let invocation = self.invocations[&scope]; - let ext = Rc::new(macro_rules::compile(&self.session.parse_sess, &def)); let binding = self.arenas.alloc_legacy_binding(LegacyBinding { parent: invocation.legacy_scope.get(), - kind: LegacyBindingKind::MacroRules(def.ident.name, ext, def.span), + 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); @@ -208,12 +206,6 @@ impl<'a> Resolver<'a> { name: ast::Name, record_used: bool) -> Option> { - let check_shadowing = |this: &mut Self, relative_depth, scope, span| { - if record_used && relative_depth > 0 { - this.disallowed_shadowing.push((name, span, scope)); - } - }; - let mut relative_depth: u32 = 0; loop { scope = match scope { @@ -227,29 +219,18 @@ impl<'a> Resolver<'a> { } } LegacyScope::Invocation(invocation) => { - let new_relative_depth = relative_depth.saturating_sub(1); - let mut scope = invocation.legacy_scope.get(); - if let LegacyScope::Binding(binding) = scope { - match binding.kind { - LegacyBindingKind::MacroUse(ref imports) => { - if let Some(&(ref ext, span)) = imports.get(&name) { - check_shadowing(self, relative_depth, binding.parent, span); - return Some(ext.clone()); - } - }, - LegacyBindingKind::MacroRules(name_, ref ext, span) => { - if name_ == name { - check_shadowing(self, new_relative_depth, binding.parent, span); - return Some(ext.clone()); - } - } + relative_depth = relative_depth.saturating_sub(1); + invocation.legacy_scope.get() + } + LegacyScope::Binding(binding) => { + if binding.name == name { + if record_used && relative_depth > 0 { + self.disallowed_shadowing.push((name, binding.span, binding.parent)); } - scope = binding.parent + return Some(binding.ext.clone()); } - relative_depth = new_relative_depth; - scope + binding.parent } - _ => unreachable!(), }; } From 829bd8c9b9519d7e4f769ad752b5da0ebe60e3ad Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 11 Oct 2016 05:13:40 +0000 Subject: [PATCH 13/13] Add test. --- src/test/compile-fail/macro-use-scope.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/compile-fail/macro-use-scope.rs b/src/test/compile-fail/macro-use-scope.rs index 5256396a242c9..9d389413ba9ad 100644 --- a/src/test/compile-fail/macro-use-scope.rs +++ b/src/test/compile-fail/macro-use-scope.rs @@ -19,10 +19,10 @@ fn f() { #[macro_use(macro_one)] // Check that this macro is usable in the above function extern crate two_macros; +fn g() { + macro_two!(); +} macro_rules! m { () => { - fn g() { - macro_two!(); - } #[macro_use(macro_two)] // Check that this macro is usable in the above function extern crate two_macros as _two_macros; } }