Enforce the weakened shadowing restriction.
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
//! Here we build the "reduced graph": the graph of the module tree without
|
//! Here we build the "reduced graph": the graph of the module tree without
|
||||||
//! any imports resolved.
|
//! any imports resolved.
|
||||||
|
|
||||||
|
use macros;
|
||||||
use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
|
use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
|
||||||
use {Module, ModuleS, ModuleKind};
|
use {Module, ModuleS, ModuleKind};
|
||||||
use Namespace::{self, TypeNS, ValueNS};
|
use Namespace::{self, TypeNS, ValueNS};
|
||||||
@@ -39,6 +40,7 @@ use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
|
|||||||
use syntax::ext::base::{MultiItemModifier, Resolver as SyntaxResolver};
|
use syntax::ext::base::{MultiItemModifier, Resolver as SyntaxResolver};
|
||||||
use syntax::ext::hygiene::Mark;
|
use syntax::ext::hygiene::Mark;
|
||||||
use syntax::feature_gate::{self, emit_feature_err};
|
use syntax::feature_gate::{self, emit_feature_err};
|
||||||
|
use syntax::ext::tt::macro_rules;
|
||||||
use syntax::parse::token::keywords;
|
use syntax::parse::token::keywords;
|
||||||
use syntax::visit::{self, Visitor};
|
use syntax::visit::{self, Visitor};
|
||||||
|
|
||||||
@@ -77,7 +79,7 @@ impl<'b> Resolver<'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs the reduced graph for one item.
|
/// Constructs the reduced graph for one item.
|
||||||
fn build_reduced_graph_for_item(&mut self, item: &Item) {
|
fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
|
||||||
let parent = self.current_module;
|
let parent = self.current_module;
|
||||||
let name = item.ident.name;
|
let name = item.ident.name;
|
||||||
let sp = item.span;
|
let sp = item.span;
|
||||||
@@ -188,9 +190,28 @@ impl<'b> Resolver<'b> {
|
|||||||
// We need to error on `#[macro_use] extern crate` when it isn't at the
|
// We need to error on `#[macro_use] extern crate` when it isn't at the
|
||||||
// crate root, because `$crate` won't work properly.
|
// crate root, because `$crate` won't work properly.
|
||||||
let is_crate_root = self.current_module.parent.is_none();
|
let is_crate_root = self.current_module.parent.is_none();
|
||||||
for def in self.crate_loader.load_macros(item, is_crate_root) {
|
for loaded_macro in self.crate_loader.load_macros(item, is_crate_root) {
|
||||||
match def.kind {
|
match loaded_macro.kind {
|
||||||
LoadedMacroKind::Def(def) => self.add_macro(Mark::root(), def),
|
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.expansion_data[&Mark::root()].module.macros.borrow_mut()
|
||||||
|
.insert(name, macros::NameBinding {
|
||||||
|
ext: Rc::new(ext),
|
||||||
|
expansion: expansion,
|
||||||
|
shadowing: shadowing,
|
||||||
|
span: loaded_macro.import_site,
|
||||||
|
});
|
||||||
|
self.macro_names.insert(name);
|
||||||
|
}
|
||||||
|
if def.export {
|
||||||
|
def.id = self.next_node_id();
|
||||||
|
self.exported_macros.push(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
LoadedMacroKind::CustomDerive(name, ext) => {
|
LoadedMacroKind::CustomDerive(name, ext) => {
|
||||||
self.insert_custom_derive(&name, ext, item.span);
|
self.insert_custom_derive(&name, ext, item.span);
|
||||||
}
|
}
|
||||||
@@ -527,6 +548,7 @@ impl<'b> Resolver<'b> {
|
|||||||
|
|
||||||
pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
|
pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
|
||||||
pub resolver: &'a mut Resolver<'b>,
|
pub resolver: &'a mut Resolver<'b>,
|
||||||
|
pub expansion: Mark,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
|
||||||
@@ -562,7 +584,7 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let parent = self.resolver.current_module;
|
let parent = self.resolver.current_module;
|
||||||
self.resolver.build_reduced_graph_for_item(item);
|
self.resolver.build_reduced_graph_for_item(item, self.expansion);
|
||||||
visit::walk_item(self, item);
|
visit::walk_item(self, item);
|
||||||
self.resolver.current_module = parent;
|
self.resolver.current_module = parent;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1073,6 +1073,7 @@ pub struct Resolver<'a> {
|
|||||||
|
|
||||||
privacy_errors: Vec<PrivacyError<'a>>,
|
privacy_errors: Vec<PrivacyError<'a>>,
|
||||||
ambiguity_errors: Vec<AmbiguityError<'a>>,
|
ambiguity_errors: Vec<AmbiguityError<'a>>,
|
||||||
|
macro_shadowing_errors: FnvHashSet<Span>,
|
||||||
|
|
||||||
arenas: &'a ResolverArenas<'a>,
|
arenas: &'a ResolverArenas<'a>,
|
||||||
dummy_binding: &'a NameBinding<'a>,
|
dummy_binding: &'a NameBinding<'a>,
|
||||||
@@ -1248,6 +1249,7 @@ impl<'a> Resolver<'a> {
|
|||||||
|
|
||||||
privacy_errors: Vec::new(),
|
privacy_errors: Vec::new(),
|
||||||
ambiguity_errors: Vec::new(),
|
ambiguity_errors: Vec::new(),
|
||||||
|
macro_shadowing_errors: FnvHashSet(),
|
||||||
|
|
||||||
arenas: arenas,
|
arenas: arenas,
|
||||||
dummy_binding: arenas.alloc_name_binding(NameBinding {
|
dummy_binding: arenas.alloc_name_binding(NameBinding {
|
||||||
|
|||||||
@@ -22,10 +22,14 @@ use syntax::ext::hygiene::{Mark, SyntaxContext};
|
|||||||
use syntax::ext::tt::macro_rules;
|
use syntax::ext::tt::macro_rules;
|
||||||
use syntax::parse::token::intern;
|
use syntax::parse::token::intern;
|
||||||
use syntax::util::lev_distance::find_best_match_for_name;
|
use syntax::util::lev_distance::find_best_match_for_name;
|
||||||
|
use syntax_pos::{Span, DUMMY_SP};
|
||||||
|
|
||||||
// FIXME(jseyfried) Merge with `::NameBinding`.
|
// FIXME(jseyfried) Merge with `::NameBinding`.
|
||||||
pub struct NameBinding {
|
pub struct NameBinding {
|
||||||
ext: Rc<SyntaxExtension>,
|
pub ext: Rc<SyntaxExtension>,
|
||||||
|
pub expansion: Mark,
|
||||||
|
pub shadowing: bool,
|
||||||
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -69,7 +73,7 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||||||
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
|
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
|
||||||
self.collect_def_ids(mark, expansion);
|
self.collect_def_ids(mark, expansion);
|
||||||
self.current_module = self.expansion_data[&mark].module;
|
self.current_module = self.expansion_data[&mark].module;
|
||||||
expansion.visit_with(&mut BuildReducedGraphVisitor { resolver: self });
|
expansion.visit_with(&mut BuildReducedGraphVisitor { resolver: self, expansion: mark });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
|
fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
|
||||||
@@ -77,16 +81,18 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||||||
self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
|
self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
|
||||||
}
|
}
|
||||||
if def.use_locally {
|
if def.use_locally {
|
||||||
self.macro_names.insert(def.ident.name);
|
let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope];
|
||||||
let ext = macro_rules::compile(&self.session.parse_sess, &def);
|
|
||||||
|
|
||||||
let mut module = self.expansion_data[&scope].module;
|
|
||||||
while module.macros_escape {
|
while module.macros_escape {
|
||||||
module = module.parent.unwrap();
|
module = module.parent.unwrap();
|
||||||
}
|
}
|
||||||
module.macros.borrow_mut().insert(def.ident.name, NameBinding {
|
let binding = NameBinding {
|
||||||
ext: Rc::new(ext),
|
ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
|
||||||
});
|
expansion: 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);
|
||||||
|
self.macro_names.insert(def.ident.name);
|
||||||
}
|
}
|
||||||
if def.export {
|
if def.export {
|
||||||
def.id = self.next_node_id();
|
def.id = self.next_node_id();
|
||||||
@@ -100,6 +106,9 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||||||
}
|
}
|
||||||
self.graph_root.macros.borrow_mut().insert(ident.name, NameBinding {
|
self.graph_root.macros.borrow_mut().insert(ident.name, NameBinding {
|
||||||
ext: ext,
|
ext: ext,
|
||||||
|
expansion: Mark::root(),
|
||||||
|
shadowing: false,
|
||||||
|
span: DUMMY_SP,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +147,7 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||||||
InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
|
InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.resolve_macro_name(scope, name).or_else(|| {
|
self.resolve_macro_name(scope, name, true).or_else(|| {
|
||||||
let mut err =
|
let mut err =
|
||||||
self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
|
self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
|
||||||
self.suggest_macro_name(&name.as_str(), &mut err);
|
self.suggest_macro_name(&name.as_str(), &mut err);
|
||||||
@@ -153,10 +162,28 @@ impl<'a> base::Resolver for Resolver<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Resolver<'a> {
|
impl<'a> Resolver<'a> {
|
||||||
fn resolve_macro_name(&mut self, scope: Mark, name: ast::Name) -> Option<Rc<SyntaxExtension>> {
|
pub fn resolve_macro_name(&mut self, scope: Mark, name: ast::Name, record_used: bool)
|
||||||
let mut module = self.expansion_data[&scope].module;
|
-> Option<Rc<SyntaxExtension>> {
|
||||||
|
let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope];
|
||||||
loop {
|
loop {
|
||||||
if let Some(binding) = module.macros.borrow().get(&name) {
|
if let Some(binding) = module.macros.borrow().get(&name) {
|
||||||
|
let mut backtrace = backtrace.data();
|
||||||
|
while binding.expansion != backtrace.outer_mark {
|
||||||
|
if backtrace.outer_mark != Mark::root() {
|
||||||
|
backtrace = backtrace.prev_ctxt.data();
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
return Some(binding.ext.clone());
|
return Some(binding.ext.clone());
|
||||||
}
|
}
|
||||||
match module.parent {
|
match module.parent {
|
||||||
|
|||||||
Reference in New Issue
Block a user