1
Fork 0

Hygienize librustc_resolve.

This commit is contained in:
Jeffrey Seyfried 2017-03-22 08:39:51 +00:00
parent 1cded8472e
commit 1f175fa35d
18 changed files with 492 additions and 190 deletions

View file

@ -393,7 +393,7 @@ impl<'a> LoweringContext<'a> {
} }
fn allow_internal_unstable(&self, reason: &'static str, mut span: Span) -> Span { fn allow_internal_unstable(&self, reason: &'static str, mut span: Span) -> Span {
let mark = Mark::fresh(); let mark = Mark::fresh(Mark::root());
mark.set_expn_info(codemap::ExpnInfo { mark.set_expn_info(codemap::ExpnInfo {
call_site: span, call_site: span,
callee: codemap::NameAndSpan { callee: codemap::NameAndSpan {

View file

@ -388,7 +388,7 @@ impl CrateStore for cstore::CStore {
attrs: attrs.iter().cloned().collect(), attrs: attrs.iter().cloned().collect(),
node: ast::ItemKind::MacroDef(ast::MacroDef { node: ast::ItemKind::MacroDef(ast::MacroDef {
tokens: body.into(), tokens: body.into(),
legacy: true, legacy: def.legacy,
}), }),
vis: ast::Visibility::Inherited, vis: ast::Visibility::Inherited,
}) })

View file

@ -1104,6 +1104,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
Entry { Entry {
kind: EntryKind::MacroDef(self.lazy(&MacroDef { kind: EntryKind::MacroDef(self.lazy(&MacroDef {
body: pprust::tts_to_string(&macro_def.body.trees().collect::<Vec<_>>()), body: pprust::tts_to_string(&macro_def.body.trees().collect::<Vec<_>>()),
legacy: macro_def.legacy,
})), })),
visibility: self.lazy(&ty::Visibility::Public), visibility: self.lazy(&ty::Visibility::Public),
span: self.lazy(&macro_def.span), span: self.lazy(&macro_def.span),

View file

@ -433,9 +433,10 @@ impl_stable_hash_for!(struct ModData { reexports });
#[derive(RustcEncodable, RustcDecodable)] #[derive(RustcEncodable, RustcDecodable)]
pub struct MacroDef { pub struct MacroDef {
pub body: String, pub body: String,
pub legacy: bool,
} }
impl_stable_hash_for!(struct MacroDef { body }); impl_stable_hash_for!(struct MacroDef { body, legacy });
#[derive(RustcEncodable, RustcDecodable)] #[derive(RustcEncodable, RustcDecodable)]
pub struct FnData { pub struct FnData {

View file

@ -23,7 +23,7 @@ use {resolve_error, resolve_struct_error, ResolutionError};
use rustc::middle::cstore::LoadedMacro; use rustc::middle::cstore::LoadedMacro;
use rustc::hir::def::*; use rustc::hir::def::*;
use rustc::hir::def_id::{CrateNum, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefId}; use rustc::hir::def_id::{BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
use rustc::ty; use rustc::ty;
use std::cell::Cell; use std::cell::Cell;
@ -150,7 +150,7 @@ impl<'a> Resolver<'a> {
view_path.span, view_path.span,
ResolutionError::SelfImportsOnlyAllowedWithin); ResolutionError::SelfImportsOnlyAllowedWithin);
} else if source_name == "$crate" && full_path.segments.len() == 1 { } else if source_name == "$crate" && full_path.segments.len() == 1 {
let crate_root = self.resolve_crate_var(source.ctxt, item.span); let crate_root = self.resolve_crate_root(source.ctxt);
let crate_name = match crate_root.kind { let crate_name = match crate_root.kind {
ModuleKind::Def(_, name) => name, ModuleKind::Def(_, name) => name,
ModuleKind::Block(..) => unreachable!(), ModuleKind::Block(..) => unreachable!(),
@ -247,7 +247,8 @@ impl<'a> Resolver<'a> {
// n.b. we don't need to look at the path option here, because cstore already did // n.b. we don't need to look at the path option here, because cstore already did
let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap(); let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap();
let module = self.get_extern_crate_root(crate_id, item.span); let module =
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
self.populate_module_if_necessary(module); self.populate_module_if_necessary(module);
let used = self.process_legacy_macro_imports(item, module, expansion); let used = self.process_legacy_macro_imports(item, module, expansion);
let binding = let binding =
@ -279,7 +280,7 @@ impl<'a> Resolver<'a> {
no_implicit_prelude: parent.no_implicit_prelude || { no_implicit_prelude: parent.no_implicit_prelude || {
attr::contains_name(&item.attrs, "no_implicit_prelude") attr::contains_name(&item.attrs, "no_implicit_prelude")
}, },
..ModuleData::new(Some(parent), module_kind, def_id, item.span) ..ModuleData::new(Some(parent), module_kind, def_id, expansion, item.span)
}); });
self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
self.module_map.insert(def_id, module); self.module_map.insert(def_id, module);
@ -317,6 +318,7 @@ impl<'a> Resolver<'a> {
let module = self.new_module(parent, let module = self.new_module(parent,
module_kind, module_kind,
parent.normal_ancestor_id, parent.normal_ancestor_id,
expansion,
item.span); item.span);
self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
@ -376,6 +378,7 @@ impl<'a> Resolver<'a> {
let module = self.new_module(parent, let module = self.new_module(parent,
module_kind, module_kind,
parent.normal_ancestor_id, parent.normal_ancestor_id,
expansion,
item.span); item.span);
self.define(parent, ident, TypeNS, (module, vis, sp, expansion)); self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
self.current_module = module; self.current_module = module;
@ -421,12 +424,13 @@ impl<'a> Resolver<'a> {
self.define(parent, item.ident, 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) { fn build_reduced_graph_for_block(&mut self, block: &Block, expansion: Mark) {
let parent = self.current_module; let parent = self.current_module;
if self.block_needs_anonymous_module(block) { if self.block_needs_anonymous_module(block) {
let module = self.new_module(parent, let module = self.new_module(parent,
ModuleKind::Block(block.id), ModuleKind::Block(block.id),
parent.normal_ancestor_id, parent.normal_ancestor_id,
expansion,
block.span); block.span);
self.block_map.insert(block.id, module); self.block_map.insert(block.id, module);
self.current_module = module; // Descend into the block. self.current_module = module; // Descend into the block.
@ -440,23 +444,24 @@ impl<'a> Resolver<'a> {
let def_id = def.def_id(); let def_id = def.def_id();
let vis = self.session.cstore.visibility(def_id); let vis = self.session.cstore.visibility(def_id);
let span = child.span; let span = child.span;
let expansion = Mark::root(); // FIXME(jseyfried) intercrate hygiene
match def { match def {
Def::Mod(..) | Def::Enum(..) => { Def::Mod(..) | Def::Enum(..) => {
let module = self.new_module(parent, let module = self.new_module(parent,
ModuleKind::Def(def, ident.name), ModuleKind::Def(def, ident.name),
def_id, def_id,
expansion,
span); span);
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root())); self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
} }
Def::Variant(..) | Def::TyAlias(..) => { Def::Variant(..) | Def::TyAlias(..) => {
self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root())); self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion));
} }
Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::VariantCtor(..) => { Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::VariantCtor(..) => {
self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root())); self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, expansion));
} }
Def::StructCtor(..) => { Def::StructCtor(..) => {
self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root())); self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, expansion));
if let Some(struct_def_id) = if let Some(struct_def_id) =
self.session.cstore.def_key(def_id).parent self.session.cstore.def_key(def_id).parent
@ -469,14 +474,15 @@ impl<'a> Resolver<'a> {
let module = self.new_module(parent, let module = self.new_module(parent,
module_kind, module_kind,
parent.normal_ancestor_id, parent.normal_ancestor_id,
expansion,
span); span);
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root())); self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion));
for child in self.session.cstore.item_children(def_id) { for child in self.session.cstore.item_children(def_id) {
let ns = if let Def::AssociatedTy(..) = child.def { TypeNS } else { ValueNS }; let ns = if let Def::AssociatedTy(..) = child.def { TypeNS } else { ValueNS };
let ident = Ident::with_empty_ctxt(child.name); let ident = Ident::with_empty_ctxt(child.name);
self.define(module, ident, ns, (child.def, ty::Visibility::Public, self.define(module, ident, ns, (child.def, ty::Visibility::Public,
DUMMY_SP, Mark::root())); DUMMY_SP, expansion));
if self.session.cstore.associated_item_cloned(child.def.def_id()) if self.session.cstore.associated_item_cloned(child.def.def_id())
.method_has_self_argument { .method_has_self_argument {
@ -486,31 +492,42 @@ impl<'a> Resolver<'a> {
module.populated.set(true); module.populated.set(true);
} }
Def::Struct(..) | Def::Union(..) => { Def::Struct(..) | Def::Union(..) => {
self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root())); self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion));
// Record field names for error reporting. // Record field names for error reporting.
let field_names = self.session.cstore.struct_field_names(def_id); let field_names = self.session.cstore.struct_field_names(def_id);
self.insert_field_names(def_id, field_names); self.insert_field_names(def_id, field_names);
} }
Def::Macro(..) => { Def::Macro(..) => {
self.define(parent, ident, MacroNS, (def, vis, DUMMY_SP, Mark::root())); self.define(parent, ident, MacroNS, (def, vis, DUMMY_SP, expansion));
} }
_ => bug!("unexpected definition: {:?}", def) _ => bug!("unexpected definition: {:?}", def)
} }
} }
fn get_extern_crate_root(&mut self, cnum: CrateNum, span: Span) -> Module<'a> { pub fn get_module(&mut self, def_id: DefId) -> Module<'a> {
let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; if def_id.krate == LOCAL_CRATE {
let name = self.session.cstore.crate_name(cnum); return self.module_map[&def_id]
let macros_only = self.session.cstore.dep_kind(cnum).macros_only(); }
let module_kind = ModuleKind::Def(Def::Mod(def_id), name);
let arenas = self.arenas; let macros_only = self.session.cstore.dep_kind(def_id.krate).macros_only();
*self.extern_crate_roots.entry((cnum, macros_only)).or_insert_with(|| { if let Some(&module) = self.extern_module_map.get(&(def_id, macros_only)) {
arenas.alloc_module(ModuleData::new(None, module_kind, def_id, span)) return module;
}) }
let (name, parent) = if def_id.index == CRATE_DEF_INDEX {
(self.session.cstore.crate_name(def_id.krate), None)
} else {
let def_key = self.session.cstore.def_key(def_id);
(def_key.disambiguated_data.data.get_opt_name().unwrap(),
Some(self.get_module(DefId { index: def_key.parent.unwrap(), ..def_id })))
};
let kind = ModuleKind::Def(Def::Mod(def_id), name);
self.arenas.alloc_module(ModuleData::new(parent, kind, def_id, Mark::root(), DUMMY_SP))
} }
pub fn macro_def_scope(&mut self, expansion: Mark, span: Span) -> Module<'a> { pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'a> {
let def_id = self.macro_defs[&expansion]; let def_id = self.macro_defs[&expansion];
if let Some(id) = self.definitions.as_local_node_id(def_id) { if let Some(id) = self.definitions.as_local_node_id(def_id) {
self.local_macro_def_scopes[&id] self.local_macro_def_scopes[&id]
@ -519,7 +536,7 @@ impl<'a> Resolver<'a> {
self.graph_root self.graph_root
} else { } else {
let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap(); let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap();
self.get_extern_crate_root(module_def_id.krate, span) self.get_module(module_def_id)
} }
} }
@ -766,7 +783,7 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
fn visit_block(&mut self, block: &'a Block) { fn visit_block(&mut self, block: &'a Block) {
let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope); let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope);
self.resolver.build_reduced_graph_for_block(block); self.resolver.build_reduced_graph_for_block(block, self.expansion);
visit::walk_block(self, block); visit::walk_block(self, block);
self.resolver.current_module = parent; self.resolver.current_module = parent;
self.legacy_scope = legacy_scope; self.legacy_scope = legacy_scope;

View file

@ -43,7 +43,7 @@ use rustc::middle::cstore::CrateLoader;
use rustc::session::Session; use rustc::session::Session;
use rustc::lint; use rustc::lint;
use rustc::hir::def::*; use rustc::hir::def::*;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
use rustc::ty; use rustc::ty;
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap}; use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
@ -51,7 +51,7 @@ use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy}; use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy};
use syntax::ext::base::SyntaxExtension; use syntax::ext::base::SyntaxExtension;
use syntax::ext::base::Determinacy::{Determined, Undetermined}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::base::MacroKind; use syntax::ext::base::MacroKind;
use syntax::symbol::{Symbol, keywords}; use syntax::symbol::{Symbol, keywords};
use syntax::util::lev_distance::find_best_match_for_name; use syntax::util::lev_distance::find_best_match_for_name;
@ -861,6 +861,8 @@ pub struct ModuleData<'a> {
/// Span of the module itself. Used for error reporting. /// Span of the module itself. Used for error reporting.
span: Span, span: Span,
expansion: Mark,
} }
pub type Module<'a> = &'a ModuleData<'a>; pub type Module<'a> = &'a ModuleData<'a>;
@ -869,6 +871,7 @@ impl<'a> ModuleData<'a> {
fn new(parent: Option<Module<'a>>, fn new(parent: Option<Module<'a>>,
kind: ModuleKind, kind: ModuleKind,
normal_ancestor_id: DefId, normal_ancestor_id: DefId,
expansion: Mark,
span: Span) -> Self { span: Span) -> Self {
ModuleData { ModuleData {
parent: parent, parent: parent,
@ -884,6 +887,7 @@ impl<'a> ModuleData<'a> {
traits: RefCell::new(None), traits: RefCell::new(None),
populated: Cell::new(normal_ancestor_id.is_local()), populated: Cell::new(normal_ancestor_id.is_local()),
span: span, span: span,
expansion: expansion,
} }
} }
@ -1165,7 +1169,7 @@ pub struct Resolver<'a> {
// entry block for `f`. // entry block for `f`.
block_map: NodeMap<Module<'a>>, block_map: NodeMap<Module<'a>>,
module_map: FxHashMap<DefId, Module<'a>>, module_map: FxHashMap<DefId, Module<'a>>,
extern_crate_roots: FxHashMap<(CrateNum, bool /* MacrosOnly? */), Module<'a>>, extern_module_map: FxHashMap<(DefId, bool /* MacrosOnly? */), Module<'a>>,
pub make_glob_map: bool, pub make_glob_map: bool,
// Maps imports to the names of items actually imported (this actually maps // Maps imports to the names of items actually imported (this actually maps
@ -1185,9 +1189,9 @@ pub struct Resolver<'a> {
use_extern_macros: bool, // true if `#![feature(use_extern_macros)]` use_extern_macros: bool, // true if `#![feature(use_extern_macros)]`
crate_loader: &'a mut CrateLoader, crate_loader: &'a mut CrateLoader,
macro_names: FxHashSet<Name>, macro_names: FxHashSet<Ident>,
global_macros: FxHashMap<Name, &'a NameBinding<'a>>, global_macros: FxHashMap<Name, &'a NameBinding<'a>>,
lexical_macro_resolutions: Vec<(Name, &'a Cell<LegacyScope<'a>>)>, lexical_macro_resolutions: Vec<(Ident, &'a Cell<LegacyScope<'a>>)>,
macro_map: FxHashMap<DefId, Rc<SyntaxExtension>>, macro_map: FxHashMap<DefId, Rc<SyntaxExtension>>,
macro_defs: FxHashMap<Mark, DefId>, macro_defs: FxHashMap<Mark, DefId>,
local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>, local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
@ -1310,7 +1314,7 @@ impl<'a> Resolver<'a> {
let root_module_kind = ModuleKind::Def(Def::Mod(root_def_id), keywords::Invalid.name()); let root_module_kind = ModuleKind::Def(Def::Mod(root_def_id), keywords::Invalid.name());
let graph_root = arenas.alloc_module(ModuleData { let graph_root = arenas.alloc_module(ModuleData {
no_implicit_prelude: attr::contains_name(&krate.attrs, "no_implicit_prelude"), no_implicit_prelude: attr::contains_name(&krate.attrs, "no_implicit_prelude"),
..ModuleData::new(None, root_module_kind, root_def_id, krate.span) ..ModuleData::new(None, root_module_kind, root_def_id, Mark::root(), krate.span)
}); });
let mut module_map = FxHashMap(); let mut module_map = FxHashMap();
module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root); module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root);
@ -1364,7 +1368,7 @@ impl<'a> Resolver<'a> {
trait_map: NodeMap(), trait_map: NodeMap(),
module_map: module_map, module_map: module_map,
block_map: NodeMap(), block_map: NodeMap(),
extern_crate_roots: FxHashMap(), extern_module_map: FxHashMap(),
make_glob_map: make_glob_map == MakeGlobMap::Yes, make_glob_map: make_glob_map == MakeGlobMap::Yes,
glob_map: NodeMap(), glob_map: NodeMap(),
@ -1449,9 +1453,11 @@ impl<'a> Resolver<'a> {
parent: Module<'a>, parent: Module<'a>,
kind: ModuleKind, kind: ModuleKind,
normal_ancestor_id: DefId, normal_ancestor_id: DefId,
expansion: Mark,
span: Span, span: Span,
) -> Module<'a> { ) -> Module<'a> {
self.arenas.alloc_module(ModuleData::new(Some(parent), kind, normal_ancestor_id, span)) let module = ModuleData::new(Some(parent), kind, normal_ancestor_id, expansion, span);
self.arenas.alloc_module(module)
} }
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span) fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
@ -1513,10 +1519,11 @@ impl<'a> Resolver<'a> {
path_span: Span) path_span: Span)
-> Option<LexicalScopeBinding<'a>> { -> Option<LexicalScopeBinding<'a>> {
if ns == TypeNS { if ns == TypeNS {
ident = ident.unhygienize(); ident.ctxt = ident.ctxt.modern();
} }
// Walk backwards up the ribs in scope. // Walk backwards up the ribs in scope.
let mut module = self.graph_root;
for i in (0 .. self.ribs[ns].len()).rev() { for i in (0 .. self.ribs[ns].len()).rev() {
if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() { if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() {
// The ident resolves to a type parameter or local variable. // The ident resolves to a type parameter or local variable.
@ -1525,45 +1532,120 @@ impl<'a> Resolver<'a> {
)); ));
} }
if let ModuleRibKind(module) = self.ribs[ns][i].kind { module = match self.ribs[ns][i].kind {
let item = self.resolve_ident_in_module(module, ident, ns, false, ModuleRibKind(module) => module,
record_used, path_span); MacroDefinition(def) if def == self.macro_defs[&ident.ctxt.outer()] => {
if let Ok(binding) = item { // If an invocation of this macro created `ident`, give up on `ident`
// The ident resolves to an item. // and switch to `ident`'s source from the macro definition.
return Some(LexicalScopeBinding::Item(binding)); ident.ctxt.remove_mark();
continue
} }
_ => continue,
};
if let ModuleKind::Block(..) = module.kind { // We can see through blocks let item = self.resolve_ident_in_module_unadjusted(
} else if !module.no_implicit_prelude { module, ident, ns, false, record_used, path_span,
return self.prelude.and_then(|prelude| { );
self.resolve_ident_in_module(prelude, ident, ns, false, if let Ok(binding) = item {
false, path_span).ok() // The ident resolves to an item.
}).map(LexicalScopeBinding::Item) return Some(LexicalScopeBinding::Item(binding));
}
match module.kind {
ModuleKind::Block(..) => {}, // We can see through blocks
_ => break,
}
}
ident.ctxt = ident.ctxt.modern();
loop {
module = unwrap_or!(self.hygienic_lexical_parent(module, &mut ident.ctxt), break);
let orig_current_module = self.current_module;
self.current_module = module; // Lexical resolutions can never be a privacy error.
let result = self.resolve_ident_in_module_unadjusted(
module, ident, ns, false, record_used, path_span,
);
self.current_module = orig_current_module;
match result {
Ok(binding) => return Some(LexicalScopeBinding::Item(binding)),
Err(Undetermined) => return None,
Err(Determined) => {}
}
}
match self.prelude {
Some(prelude) if !module.no_implicit_prelude => {
self.resolve_ident_in_module_unadjusted(prelude, ident, ns, false, false, path_span)
.ok().map(LexicalScopeBinding::Item)
}
_ => None,
}
}
fn hygienic_lexical_parent(&mut self, mut module: Module<'a>, ctxt: &mut SyntaxContext)
-> Option<Module<'a>> {
if !module.expansion.is_descendant_of(ctxt.outer()) {
return Some(self.macro_def_scope(ctxt.remove_mark()));
}
if let ModuleKind::Block(..) = module.kind {
return Some(module.parent.unwrap());
}
let mut module_expansion = module.expansion.modern(); // for backward compatability
while let Some(parent) = module.parent {
let parent_expansion = parent.expansion.modern();
if module_expansion.is_descendant_of(parent_expansion) &&
parent_expansion != module_expansion {
return if parent_expansion.is_descendant_of(ctxt.outer()) {
Some(parent)
} else { } else {
return None; None
} };
}
if let MacroDefinition(def) = self.ribs[ns][i].kind {
// If an invocation of this macro created `ident`, give up on `ident`
// and switch to `ident`'s source from the macro definition.
let ctxt_data = ident.ctxt.data();
if def == self.macro_defs[&ctxt_data.outer_mark] {
ident.ctxt = ctxt_data.prev_ctxt;
}
} }
module = parent;
module_expansion = parent_expansion;
} }
None None
} }
fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext, span: Span) -> Module<'a> { fn resolve_ident_in_module(&mut self,
let mut ctxt_data = crate_var_ctxt.data(); module: Module<'a>,
while ctxt_data.prev_ctxt != SyntaxContext::empty() { mut ident: Ident,
ctxt_data = ctxt_data.prev_ctxt.data(); ns: Namespace,
ignore_unresolved_invocations: bool,
record_used: bool,
span: Span)
-> Result<&'a NameBinding<'a>, Determinacy> {
ident.ctxt = ident.ctxt.modern();
let orig_current_module = self.current_module;
if let Some(def) = ident.ctxt.adjust(module.expansion) {
self.current_module = self.macro_def_scope(def);
} }
let module = self.macro_def_scope(ctxt_data.outer_mark, span); let result = self.resolve_ident_in_module_unadjusted(
if module.is_local() { self.graph_root } else { module } module, ident, ns, ignore_unresolved_invocations, record_used, span,
);
self.current_module = orig_current_module;
result
}
fn resolve_crate_root(&mut self, mut ctxt: SyntaxContext) -> Module<'a> {
let module = match ctxt.adjust(Mark::root()) {
Some(def) => self.macro_def_scope(def),
None => return self.graph_root,
};
self.get_module(DefId { index: CRATE_DEF_INDEX, ..module.normal_ancestor_id })
}
fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'a>) -> Module<'a> {
let mut module = self.get_module(module.normal_ancestor_id);
while module.span.ctxt.modern() != *ctxt {
let parent = module.parent.unwrap_or_else(|| self.macro_def_scope(ctxt.remove_mark()));
module = self.get_module(parent.normal_ancestor_id);
}
module
} }
// AST resolution // AST resolution
@ -1611,15 +1693,12 @@ impl<'a> Resolver<'a> {
fn search_label(&self, mut ident: Ident) -> Option<Def> { fn search_label(&self, mut ident: Ident) -> Option<Def> {
for rib in self.label_ribs.iter().rev() { for rib in self.label_ribs.iter().rev() {
match rib.kind { match rib.kind {
NormalRibKind => { NormalRibKind => {}
// Continue // If an invocation of this macro created `ident`, give up on `ident`
} // and switch to `ident`'s source from the macro definition.
MacroDefinition(def) => { MacroDefinition(def) => {
// If an invocation of this macro created `ident`, give up on `ident` if def == self.macro_defs[&ident.ctxt.outer()] {
// and switch to `ident`'s source from the macro definition. ident.ctxt.remove_mark();
let ctxt_data = ident.ctxt.data();
if def == self.macro_defs[&ctxt_data.outer_mark] {
ident.ctxt = ctxt_data.prev_ctxt;
} }
} }
_ => { _ => {
@ -1751,7 +1830,7 @@ impl<'a> Resolver<'a> {
let mut function_type_rib = Rib::new(rib_kind); let mut function_type_rib = Rib::new(rib_kind);
let mut seen_bindings = FxHashMap(); let mut seen_bindings = FxHashMap();
for type_parameter in &generics.ty_params { for type_parameter in &generics.ty_params {
let ident = type_parameter.ident.unhygienize(); let ident = type_parameter.ident.modern();
debug!("with_type_parameter_rib: {}", type_parameter.id); debug!("with_type_parameter_rib: {}", type_parameter.id);
if seen_bindings.contains_key(&ident) { if seen_bindings.contains_key(&ident) {
@ -2504,7 +2583,7 @@ impl<'a> Resolver<'a> {
} }
let is_global = self.global_macros.get(&path[0].name).cloned() let is_global = self.global_macros.get(&path[0].name).cloned()
.map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false); .map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false);
if primary_ns != MacroNS && (is_global || self.macro_names.contains(&path[0].name)) { if primary_ns != MacroNS && (is_global || self.macro_names.contains(&path[0].modern())) {
// Return some dummy definition, it's enough for error reporting. // Return some dummy definition, it's enough for error reporting.
return Some( return Some(
PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang)) PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang))
@ -2613,13 +2692,17 @@ impl<'a> Resolver<'a> {
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
if i == 0 && 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]); let mut ctxt = ident.ctxt.modern();
module = Some(self.resolve_self(&mut ctxt, self.current_module));
continue continue
} else if allow_super && ns == TypeNS && ident.name == keywords::Super.name() { } else if allow_super && ns == TypeNS && ident.name == keywords::Super.name() {
let current_module = if i == 0 { self.current_module } else { module.unwrap() }; let mut ctxt = ident.ctxt.modern();
let self_module = self.module_map[&current_module.normal_ancestor_id]; let self_module = match i {
0 => self.resolve_self(&mut ctxt, self.current_module),
_ => module.unwrap(),
};
if let Some(parent) = self_module.parent { if let Some(parent) = self_module.parent {
module = Some(self.module_map[&parent.normal_ancestor_id]); module = Some(self.resolve_self(&mut ctxt, parent));
continue continue
} else { } else {
let msg = "There are too many initial `super`s.".to_string(); let msg = "There are too many initial `super`s.".to_string();
@ -2629,10 +2712,10 @@ impl<'a> Resolver<'a> {
allow_super = false; allow_super = false;
if i == 0 && ns == TypeNS && ident.name == keywords::CrateRoot.name() { if i == 0 && ns == TypeNS && ident.name == keywords::CrateRoot.name() {
module = Some(self.graph_root); module = Some(self.resolve_crate_root(ident.ctxt.modern()));
continue continue
} else if i == 0 && ns == TypeNS && ident.name == "$crate" { } else if i == 0 && ns == TypeNS && ident.name == "$crate" {
module = Some(self.resolve_crate_var(ident.ctxt, path_span)); module = Some(self.resolve_crate_root(ident.ctxt));
continue continue
} }
@ -3108,7 +3191,8 @@ impl<'a> Resolver<'a> {
} }
} }
fn get_traits_containing_item(&mut self, ident: Ident, ns: Namespace) -> Vec<TraitCandidate> { fn get_traits_containing_item(&mut self, mut ident: Ident, ns: Namespace)
-> Vec<TraitCandidate> {
debug!("(getting traits containing item) looking for '{}'", ident.name); debug!("(getting traits containing item) looking for '{}'", ident.name);
let mut found_traits = Vec::new(); let mut found_traits = Vec::new();
@ -3120,13 +3204,12 @@ impl<'a> Resolver<'a> {
} }
} }
ident.ctxt = ident.ctxt.modern();
let mut search_module = self.current_module; let mut search_module = self.current_module;
loop { loop {
self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits); self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits);
match search_module.kind { search_module =
ModuleKind::Block(..) => search_module = search_module.parent.unwrap(), unwrap_or!(self.hygienic_lexical_parent(search_module, &mut ident.ctxt), break);
_ => break,
}
} }
if let Some(prelude) = self.prelude { if let Some(prelude) = self.prelude {
@ -3157,7 +3240,12 @@ impl<'a> Resolver<'a> {
for &(trait_name, binding) in traits.as_ref().unwrap().iter() { for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
let module = binding.module().unwrap(); let module = binding.module().unwrap();
if self.resolve_ident_in_module(module, ident, ns, false, false, module.span).is_ok() { let mut ident = ident;
if ident.ctxt.glob_adjust(module.expansion, binding.span.ctxt.modern()).is_none() {
continue
}
if self.resolve_ident_in_module_unadjusted(module, ident, ns, false, false, module.span)
.is_ok() {
let import_id = match binding.kind { let import_id = match binding.kind {
NameBindingKind::Import { directive, .. } => { NameBindingKind::Import { directive, .. } => {
self.maybe_unused_trait_imports.insert(directive.id); self.maybe_unused_trait_imports.insert(directive.id);
@ -3348,15 +3436,15 @@ impl<'a> Resolver<'a> {
} }
fn report_shadowing_errors(&mut self) { fn report_shadowing_errors(&mut self) {
for (name, scope) in replace(&mut self.lexical_macro_resolutions, Vec::new()) { for (ident, scope) in replace(&mut self.lexical_macro_resolutions, Vec::new()) {
self.resolve_legacy_scope(scope, name, true); self.resolve_legacy_scope(scope, ident, true);
} }
let mut reported_errors = FxHashSet(); let mut reported_errors = FxHashSet();
for binding in replace(&mut self.disallowed_shadowing, Vec::new()) { for binding in replace(&mut self.disallowed_shadowing, Vec::new()) {
if self.resolve_legacy_scope(&binding.parent, binding.name, false).is_some() && if self.resolve_legacy_scope(&binding.parent, binding.ident, false).is_some() &&
reported_errors.insert((binding.name, binding.span)) { reported_errors.insert((binding.ident, binding.span)) {
let msg = format!("`{}` is already in scope", binding.name); let msg = format!("`{}` is already in scope", binding.ident);
self.session.struct_span_err(binding.span, &msg) self.session.struct_span_err(binding.span, &msg)
.note("macro-expanded `macro_rules!`s may not shadow \ .note("macro-expanded `macro_rules!`s may not shadow \
existing macros (see RFC 1560)") existing macros (see RFC 1560)")

View file

@ -76,7 +76,7 @@ pub enum LegacyScope<'a> {
pub struct LegacyBinding<'a> { pub struct LegacyBinding<'a> {
pub parent: Cell<LegacyScope<'a>>, pub parent: Cell<LegacyScope<'a>>,
pub name: ast::Name, pub ident: Ident,
def_id: DefId, def_id: DefId,
pub span: Span, pub span: Span,
} }
@ -110,7 +110,7 @@ impl<'a> base::Resolver for Resolver<'a> {
} }
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark { fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
let mark = Mark::fresh(); let mark = Mark::fresh(Mark::root());
let module = self.module_map[&self.definitions.local_def_id(id)]; let module = self.module_map[&self.definitions.local_def_id(id)];
self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData { self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData {
module: Cell::new(module), module: Cell::new(module),
@ -130,7 +130,7 @@ impl<'a> base::Resolver for Resolver<'a> {
let ident = path.segments[0].identifier; let ident = path.segments[0].identifier;
if ident.name == "$crate" { if ident.name == "$crate" {
path.segments[0].identifier.name = keywords::CrateRoot.name(); path.segments[0].identifier.name = keywords::CrateRoot.name();
let module = self.0.resolve_crate_var(ident.ctxt, self.1); let module = self.0.resolve_crate_root(ident.ctxt);
if !module.is_local() { if !module.is_local() {
let span = path.segments[0].span; let span = path.segments[0].span;
path.segments.insert(1, match module.kind { path.segments.insert(1, match module.kind {
@ -292,7 +292,11 @@ impl<'a> base::Resolver for Resolver<'a> {
}; };
self.macro_defs.insert(invoc.expansion_data.mark, def.def_id()); self.macro_defs.insert(invoc.expansion_data.mark, def.def_id());
self.unused_macros.remove(&def.def_id()); self.unused_macros.remove(&def.def_id());
Ok(Some(self.get_macro(def))) let ext = self.get_macro(def);
if ext.is_modern() {
invoc.expansion_data.mark.set_modern();
}
Ok(Some(ext))
} }
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
@ -416,8 +420,7 @@ impl<'a> Resolver<'a> {
return def; return def;
} }
let name = path[0].name; let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, path[0], false);
let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, name, false);
let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution { let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution {
Ok(Def::Macro(binding.def_id, MacroKind::Bang)) Ok(Def::Macro(binding.def_id, MacroKind::Bang))
} else { } else {
@ -439,26 +442,31 @@ impl<'a> Resolver<'a> {
// Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`) // 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, pub fn resolve_lexical_macro_path_segment(&mut self,
ident: Ident, mut ident: Ident,
ns: Namespace, ns: Namespace,
record_used: bool, record_used: bool,
path_span: Span) path_span: Span)
-> Result<MacroBinding<'a>, Determinacy> { -> Result<MacroBinding<'a>, Determinacy> {
ident = ident.modern();
let mut module = Some(self.current_module); let mut module = Some(self.current_module);
let mut potential_illegal_shadower = Err(Determinacy::Determined); let mut potential_illegal_shadower = Err(Determinacy::Determined);
let determinacy = let determinacy =
if record_used { Determinacy::Determined } else { Determinacy::Undetermined }; if record_used { Determinacy::Determined } else { Determinacy::Undetermined };
loop { loop {
let orig_current_module = self.current_module;
let result = if let Some(module) = module { let result = if let Some(module) = module {
self.current_module = module; // Lexical resolutions can never be a privacy error.
// Since expanded macros may not shadow the lexical scope and // Since expanded macros may not shadow the lexical scope and
// globs may not shadow global macros (both enforced below), // globs may not shadow global macros (both enforced below),
// we resolve with restricted shadowing (indicated by the penultimate argument). // we resolve with restricted shadowing (indicated by the penultimate argument).
self.resolve_ident_in_module(module, ident, ns, true, record_used, path_span) self.resolve_ident_in_module_unadjusted(
.map(MacroBinding::Modern) module, ident, ns, true, record_used, path_span,
).map(MacroBinding::Modern)
} else { } else {
self.global_macros.get(&ident.name).cloned().ok_or(determinacy) self.global_macros.get(&ident.name).cloned().ok_or(determinacy)
.map(MacroBinding::Global) .map(MacroBinding::Global)
}; };
self.current_module = orig_current_module;
match result.map(MacroBinding::binding) { match result.map(MacroBinding::binding) {
Ok(binding) => { Ok(binding) => {
@ -491,10 +499,7 @@ impl<'a> Resolver<'a> {
} }
module = match module { module = match module {
Some(module) => match module.kind { Some(module) => self.hygienic_lexical_parent(module, &mut ident.ctxt),
ModuleKind::Block(..) => module.parent,
ModuleKind::Def(..) => None,
},
None => return potential_illegal_shadower, None => return potential_illegal_shadower,
} }
} }
@ -502,9 +507,10 @@ impl<'a> Resolver<'a> {
pub fn resolve_legacy_scope(&mut self, pub fn resolve_legacy_scope(&mut self,
mut scope: &'a Cell<LegacyScope<'a>>, mut scope: &'a Cell<LegacyScope<'a>>,
name: Name, ident: Ident,
record_used: bool) record_used: bool)
-> Option<MacroBinding<'a>> { -> Option<MacroBinding<'a>> {
let ident = ident.modern();
let mut possible_time_travel = None; let mut possible_time_travel = None;
let mut relative_depth: u32 = 0; let mut relative_depth: u32 = 0;
let mut binding = None; let mut binding = None;
@ -531,7 +537,7 @@ impl<'a> Resolver<'a> {
scope = &invocation.legacy_scope; scope = &invocation.legacy_scope;
} }
LegacyScope::Binding(potential_binding) => { LegacyScope::Binding(potential_binding) => {
if potential_binding.name == name { if potential_binding.ident == ident {
if (!self.use_extern_macros || record_used) && relative_depth > 0 { if (!self.use_extern_macros || record_used) && relative_depth > 0 {
self.disallowed_shadowing.push(potential_binding); self.disallowed_shadowing.push(potential_binding);
} }
@ -545,9 +551,9 @@ impl<'a> Resolver<'a> {
let binding = if let Some(binding) = binding { let binding = if let Some(binding) = binding {
MacroBinding::Legacy(binding) MacroBinding::Legacy(binding)
} else if let Some(binding) = self.global_macros.get(&name).cloned() { } else if let Some(binding) = self.global_macros.get(&ident.name).cloned() {
if !self.use_extern_macros { if !self.use_extern_macros {
self.record_use(Ident::with_empty_ctxt(name), MacroNS, binding, DUMMY_SP); self.record_use(ident, MacroNS, binding, DUMMY_SP);
} }
MacroBinding::Global(binding) MacroBinding::Global(binding)
} else { } else {
@ -557,7 +563,7 @@ impl<'a> Resolver<'a> {
if !self.use_extern_macros { if !self.use_extern_macros {
if let Some(scope) = possible_time_travel { if let Some(scope) = possible_time_travel {
// Check for disallowed shadowing later // Check for disallowed shadowing later
self.lexical_macro_resolutions.push((name, scope)); self.lexical_macro_resolutions.push((ident, scope));
} }
} }
@ -578,7 +584,7 @@ impl<'a> Resolver<'a> {
for &(mark, ident, span, kind) in module.legacy_macro_resolutions.borrow().iter() { for &(mark, ident, span, kind) in module.legacy_macro_resolutions.borrow().iter() {
let legacy_scope = &self.invocations[&mark].legacy_scope; let legacy_scope = &self.invocations[&mark].legacy_scope;
let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident.name, true); let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident, true);
let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, span); let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, span);
match (legacy_resolution, resolution) { match (legacy_resolution, resolution) {
(Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => { (Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => {
@ -615,7 +621,7 @@ impl<'a> Resolver<'a> {
err: &mut DiagnosticBuilder<'a>, span: Span) { err: &mut DiagnosticBuilder<'a>, span: Span) {
// First check if this is a locally-defined bang macro. // First check if this is a locally-defined bang macro.
let suggestion = if let MacroKind::Bang = kind { let suggestion = if let MacroKind::Bang = kind {
find_best_match_for_name(self.macro_names.iter(), name, None) find_best_match_for_name(self.macro_names.iter().map(|ident| &ident.name), name, None)
} else { } else {
None None
// Then check global macros. // Then check global macros.
@ -705,9 +711,10 @@ impl<'a> Resolver<'a> {
let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() }; let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() };
if def.legacy { if def.legacy {
self.macro_names.insert(ident.name); let ident = ident.modern();
self.macro_names.insert(ident);
*legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding { *legacy_scope = LegacyScope::Binding(self.arenas.alloc_legacy_binding(LegacyBinding {
parent: Cell::new(*legacy_scope), name: ident.name, def_id: def_id, span: item.span, parent: Cell::new(*legacy_scope), ident: ident, def_id: def_id, span: item.span,
})); }));
if attr::contains_name(&item.attrs, "macro_export") { if attr::contains_name(&item.attrs, "macro_export") {
let def = Def::Macro(def_id, MacroKind::Bang); let def = Def::Macro(def_id, MacroKind::Bang);

View file

@ -134,21 +134,20 @@ impl<'a> NameResolution<'a> {
impl<'a> Resolver<'a> { impl<'a> Resolver<'a> {
fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace) fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
-> &'a RefCell<NameResolution<'a>> { -> &'a RefCell<NameResolution<'a>> {
let ident = ident.unhygienize(); *module.resolutions.borrow_mut().entry((ident.modern(), ns))
*module.resolutions.borrow_mut().entry((ident, ns))
.or_insert_with(|| self.arenas.alloc_name_resolution()) .or_insert_with(|| self.arenas.alloc_name_resolution())
} }
/// Attempts to resolve `ident` in namespaces `ns` of `module`. /// Attempts to resolve `ident` in namespaces `ns` of `module`.
/// Invariant: if `record_used` is `Some`, import resolution must be complete. /// Invariant: if `record_used` is `Some`, import resolution must be complete.
pub fn resolve_ident_in_module(&mut self, pub fn resolve_ident_in_module_unadjusted(&mut self,
module: Module<'a>, module: Module<'a>,
ident: Ident, ident: Ident,
ns: Namespace, ns: Namespace,
restricted_shadowing: bool, restricted_shadowing: bool,
record_used: bool, record_used: bool,
path_span: Span) path_span: Span)
-> Result<&'a NameBinding<'a>, Determinacy> { -> Result<&'a NameBinding<'a>, Determinacy> {
self.populate_module_if_necessary(module); self.populate_module_if_necessary(module);
let resolution = self.resolution(module, ident, ns) let resolution = self.resolution(module, ident, ns)
@ -233,20 +232,22 @@ impl<'a> Resolver<'a> {
return Err(Determined); return Err(Determined);
} }
for directive in module.globs.borrow().iter() { for directive in module.globs.borrow().iter() {
if self.is_accessible(directive.vis.get()) { if !self.is_accessible(directive.vis.get()) {
if let Some(module) = directive.imported_module.get() { continue
let result = self.resolve_ident_in_module(module, }
ident, let module = unwrap_or!(directive.imported_module.get(), return Err(Undetermined));
ns, let (orig_current_module, mut ident) = (self.current_module, ident.modern());
false, match ident.ctxt.glob_adjust(module.expansion, directive.span.ctxt.modern()) {
false, Some(Some(def)) => self.current_module = self.macro_def_scope(def),
path_span); Some(None) => {}
if let Err(Undetermined) = result { None => continue,
return Err(Undetermined); };
} let result = self.resolve_ident_in_module_unadjusted(
} else { module, ident, ns, false, false, path_span,
return Err(Undetermined); );
} self.current_module = orig_current_module;
if let Err(Undetermined) = result {
return Err(Undetermined);
} }
} }
@ -394,7 +395,14 @@ impl<'a> Resolver<'a> {
// Define `binding` in `module`s glob importers. // Define `binding` in `module`s glob importers.
for directive in module.glob_importers.borrow_mut().iter() { for directive in module.glob_importers.borrow_mut().iter() {
if self.is_accessible_from(binding.vis, directive.parent) { let mut ident = ident.modern();
let scope = match ident.ctxt.reverse_glob_adjust(module.expansion,
directive.span.ctxt.modern()) {
Some(Some(def)) => self.macro_def_scope(def),
Some(None) => directive.parent,
None => continue,
};
if self.is_accessible_from(binding.vis, scope) {
let imported_binding = self.import(binding, directive); let imported_binding = self.import(binding, directive);
let _ = self.try_define(directive.parent, ident, ns, imported_binding); let _ = self.try_define(directive.parent, ident, ns, imported_binding);
} }
@ -767,8 +775,14 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
let bindings = module.resolutions.borrow().iter().filter_map(|(&ident, resolution)| { let bindings = module.resolutions.borrow().iter().filter_map(|(&ident, resolution)| {
resolution.borrow().binding().map(|binding| (ident, binding)) resolution.borrow().binding().map(|binding| (ident, binding))
}).collect::<Vec<_>>(); }).collect::<Vec<_>>();
for ((ident, ns), binding) in bindings { for ((mut ident, ns), binding) in bindings {
if binding.pseudo_vis() == ty::Visibility::Public || self.is_accessible(binding.vis) { let scope = match ident.ctxt.reverse_glob_adjust(module.expansion,
directive.span.ctxt.modern()) {
Some(Some(def)) => self.macro_def_scope(def),
Some(None) => self.current_module,
None => continue,
};
if self.is_accessible_from(binding.pseudo_vis(), scope) {
let imported_binding = self.import(binding, directive); let imported_binding = self.import(binding, directive);
let _ = self.try_define(directive.parent, ident, ns, imported_binding); let _ = self.try_define(directive.parent, ident, ns, imported_binding);
} }

View file

@ -550,12 +550,16 @@ pub enum SyntaxExtension {
/// An attribute-like procedural macro that derives a builtin trait. /// An attribute-like procedural macro that derives a builtin trait.
BuiltinDerive(BuiltinDeriveFn), BuiltinDerive(BuiltinDeriveFn),
/// A declarative macro, e.g. `macro m() {}`.
DeclMacro(Box<TTMacroExpander>, Option<Span> /* definition site span */),
} }
impl SyntaxExtension { impl SyntaxExtension {
/// Return which kind of macro calls this syntax extension. /// Return which kind of macro calls this syntax extension.
pub fn kind(&self) -> MacroKind { pub fn kind(&self) -> MacroKind {
match *self { match *self {
SyntaxExtension::DeclMacro(..) |
SyntaxExtension::NormalTT(..) | SyntaxExtension::NormalTT(..) |
SyntaxExtension::IdentTT(..) | SyntaxExtension::IdentTT(..) |
SyntaxExtension::ProcMacro(..) => SyntaxExtension::ProcMacro(..) =>
@ -569,6 +573,13 @@ impl SyntaxExtension {
MacroKind::Derive, MacroKind::Derive,
} }
} }
pub fn is_modern(&self) -> bool {
match *self {
SyntaxExtension::DeclMacro(..) => true,
_ => false,
}
}
} }
pub type NamedSyntaxExtension = (Name, SyntaxExtension); pub type NamedSyntaxExtension = (Name, SyntaxExtension);

View file

@ -288,7 +288,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new); let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new);
for path in &traits { for path in &traits {
let mark = Mark::fresh(); let mark = Mark::fresh(self.cx.current_expansion.mark);
derives.push(mark); derives.push(mark);
let item = match self.cx.resolver.resolve_macro( let item = match self.cx.resolver.resolve_macro(
Mark::root(), path, MacroKind::Derive, false) { Mark::root(), path, MacroKind::Derive, false) {
@ -455,25 +455,37 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
let path = &mac.node.path; let path = &mac.node.path;
let ident = ident.unwrap_or_else(|| keywords::Invalid.ident()); let ident = ident.unwrap_or_else(|| keywords::Invalid.ident());
let validate_and_set_expn_info = |def_site_span, allow_internal_unstable| {
if ident.name != keywords::Invalid.name() {
return Err(format!("macro {}! expects no ident argument, given '{}'", path, ident));
}
mark.set_expn_info(ExpnInfo {
call_site: span,
callee: NameAndSpan {
format: MacroBang(Symbol::intern(&format!("{}", path))),
span: def_site_span,
allow_internal_unstable: allow_internal_unstable,
},
});
Ok(())
};
let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker(mark)); let marked_tts = noop_fold_tts(mac.node.stream(), &mut Marker(mark));
let opt_expanded = match *ext { let opt_expanded = match *ext {
NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { SyntaxExtension::DeclMacro(ref expand, def_site_span) => {
if ident.name != keywords::Invalid.name() { if let Err(msg) = validate_and_set_expn_info(def_site_span, false) {
let msg =
format!("macro {}! expects no ident argument, given '{}'", path, ident);
self.cx.span_err(path.span, &msg); self.cx.span_err(path.span, &msg);
return kind.dummy(span); return kind.dummy(span);
} }
kind.make_from(expand.expand(self.cx, span, marked_tts))
}
invoc.expansion_data.mark.set_expn_info(ExpnInfo { NormalTT(ref expandfun, def_info, allow_internal_unstable) => {
call_site: span, if let Err(msg) = validate_and_set_expn_info(def_info.map(|(_, s)| s),
callee: NameAndSpan { allow_internal_unstable) {
format: MacroBang(Symbol::intern(&format!("{}", path))), self.cx.span_err(path.span, &msg);
span: exp_span.map(|(_, s)| s), return kind.dummy(span);
allow_internal_unstable: allow_internal_unstable, }
},
});
kind.make_from(expandfun.expand(self.cx, span, marked_tts)) kind.make_from(expandfun.expand(self.cx, span, marked_tts))
} }
@ -687,7 +699,7 @@ macro_rules! fully_configure {
impl<'a, 'b> InvocationCollector<'a, 'b> { impl<'a, 'b> InvocationCollector<'a, 'b> {
fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion { fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion {
let mark = Mark::fresh(); let mark = Mark::fresh(self.cx.current_expansion.mark);
self.invocations.push(Invocation { self.invocations.push(Invocation {
kind: kind, kind: kind,
expansion_kind: expansion_kind, expansion_kind: expansion_kind,

View file

@ -253,9 +253,12 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)
valid: valid, valid: valid,
}); });
NormalTT(exp, if body.legacy {
Some((def.id, def.span)), let allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable");
attr::contains_name(&def.attrs, "allow_internal_unstable")) NormalTT(exp, Some((def.id, def.span)), allow_internal_unstable)
} else {
SyntaxExtension::DeclMacro(exp, Some(def.span))
}
} }
fn check_lhs_nt_follows(sess: &ParseSess, fn check_lhs_nt_follows(sess: &ParseSess,

View file

@ -428,7 +428,7 @@ pub fn noop_fold_global_asm<T: Folder>(ga: P<GlobalAsm>,
pub fn noop_fold_variant<T: Folder>(v: Variant, fld: &mut T) -> Variant { pub fn noop_fold_variant<T: Folder>(v: Variant, fld: &mut T) -> Variant {
Spanned { Spanned {
node: Variant_ { node: Variant_ {
name: v.node.name, name: fld.fold_ident(v.node.name),
attrs: fold_attrs(v.node.attrs, fld), attrs: fold_attrs(v.node.attrs, fld),
data: fld.fold_variant_data(v.node.data), data: fld.fold_variant_data(v.node.data),
disr_expr: v.node.disr_expr.map(|e| fld.fold_expr(e)), disr_expr: v.node.disr_expr.map(|e| fld.fold_expr(e)),

View file

@ -21,7 +21,7 @@ use tokenstream::TokenStream;
/// call to codemap's `is_internal` check. /// call to codemap's `is_internal` check.
/// The expanded code uses the unstable `#[prelude_import]` attribute. /// The expanded code uses the unstable `#[prelude_import]` attribute.
fn ignored_span(sp: Span) -> Span { fn ignored_span(sp: Span) -> Span {
let mark = Mark::fresh(); let mark = Mark::fresh(Mark::root());
mark.set_expn_info(ExpnInfo { mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP, call_site: DUMMY_SP,
callee: NameAndSpan { callee: NameAndSpan {

View file

@ -276,7 +276,7 @@ fn generate_test_harness(sess: &ParseSess,
let mut cleaner = EntryPointCleaner { depth: 0 }; let mut cleaner = EntryPointCleaner { depth: 0 };
let krate = cleaner.fold_crate(krate); let krate = cleaner.fold_crate(krate);
let mark = Mark::fresh(); let mark = Mark::fresh(Mark::root());
let mut cx: TestCtxt = TestCtxt { let mut cx: TestCtxt = TestCtxt {
sess: sess, sess: sess,
span_diagnostic: sd, span_diagnostic: sd,

View file

@ -162,7 +162,7 @@ fn call_intrinsic(cx: &ExtCtxt,
} else { // Avoid instability errors with user defined curstom derives, cc #36316 } else { // Avoid instability errors with user defined curstom derives, cc #36316
let mut info = cx.current_expansion.mark.expn_info().unwrap(); let mut info = cx.current_expansion.mark.expn_info().unwrap();
info.callee.allow_internal_unstable = true; info.callee.allow_internal_unstable = true;
let mark = Mark::fresh(); let mark = Mark::fresh(Mark::root());
mark.set_expn_info(info); mark.set_expn_info(info);
span.ctxt = SyntaxContext::empty().apply_mark(mark); span.ctxt = SyntaxContext::empty().apply_mark(mark);
} }

View file

@ -361,7 +361,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
custom_derives: &[ProcMacroDerive], custom_derives: &[ProcMacroDerive],
custom_attrs: &[ProcMacroDef], custom_attrs: &[ProcMacroDef],
custom_macros: &[ProcMacroDef]) -> P<ast::Item> { custom_macros: &[ProcMacroDef]) -> P<ast::Item> {
let mark = Mark::fresh(); let mark = Mark::fresh(Mark::root());
mark.set_expn_info(ExpnInfo { mark.set_expn_info(ExpnInfo {
call_site: DUMMY_SP, call_site: DUMMY_SP,
callee: NameAndSpan { callee: NameAndSpan {

View file

@ -24,23 +24,31 @@ use std::collections::HashMap;
use std::fmt; use std::fmt;
/// A SyntaxContext represents a chain of macro expansions (represented by marks). /// A SyntaxContext represents a chain of macro expansions (represented by marks).
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
pub struct SyntaxContext(u32); pub struct SyntaxContext(u32);
#[derive(Copy, Clone)] #[derive(Copy, Clone, Default)]
pub struct SyntaxContextData { pub struct SyntaxContextData {
pub outer_mark: Mark, pub outer_mark: Mark,
pub prev_ctxt: SyntaxContext, pub prev_ctxt: SyntaxContext,
pub modern: SyntaxContext,
} }
/// A mark is a unique id associated with a macro expansion. /// A mark is a unique id associated with a macro expansion.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable, RustcDecodable)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable, RustcDecodable)]
pub struct Mark(u32); pub struct Mark(u32);
#[derive(Default)]
struct MarkData {
parent: Mark,
modern: bool,
expn_info: Option<ExpnInfo>,
}
impl Mark { impl Mark {
pub fn fresh() -> Self { pub fn fresh(parent: Mark) -> Self {
HygieneData::with(|data| { HygieneData::with(|data| {
data.marks.push(None); data.marks.push(MarkData { parent: parent, modern: false, expn_info: None });
Mark(data.marks.len() as u32 - 1) Mark(data.marks.len() as u32 - 1)
}) })
} }
@ -59,16 +67,43 @@ impl Mark {
} }
pub fn expn_info(self) -> Option<ExpnInfo> { pub fn expn_info(self) -> Option<ExpnInfo> {
HygieneData::with(|data| data.marks[self.0 as usize].clone()) HygieneData::with(|data| data.marks[self.0 as usize].expn_info.clone())
} }
pub fn set_expn_info(self, info: ExpnInfo) { pub fn set_expn_info(self, info: ExpnInfo) {
HygieneData::with(|data| data.marks[self.0 as usize] = Some(info)) HygieneData::with(|data| data.marks[self.0 as usize].expn_info = Some(info))
}
pub fn modern(mut self) -> Mark {
HygieneData::with(|data| {
loop {
if self == Mark::root() || data.marks[self.0 as usize].modern {
return self;
}
self = data.marks[self.0 as usize].parent;
}
})
}
pub fn set_modern(self) {
HygieneData::with(|data| data.marks[self.0 as usize].modern = true)
}
pub fn is_descendant_of(mut self, ancestor: Mark) -> bool {
HygieneData::with(|data| {
while self != ancestor {
if self == Mark::root() {
return false;
}
self = data.marks[self.0 as usize].parent;
}
true
})
} }
} }
struct HygieneData { struct HygieneData {
marks: Vec<Option<ExpnInfo>>, marks: Vec<MarkData>,
syntax_contexts: Vec<SyntaxContextData>, syntax_contexts: Vec<SyntaxContextData>,
markings: HashMap<(SyntaxContext, Mark), SyntaxContext>, markings: HashMap<(SyntaxContext, Mark), SyntaxContext>,
} }
@ -76,11 +111,8 @@ struct HygieneData {
impl HygieneData { impl HygieneData {
fn new() -> Self { fn new() -> Self {
HygieneData { HygieneData {
marks: vec![None], marks: vec![MarkData::default()],
syntax_contexts: vec![SyntaxContextData { syntax_contexts: vec![SyntaxContextData::default()],
outer_mark: Mark::root(),
prev_ctxt: SyntaxContext::empty(),
}],
markings: HashMap::new(), markings: HashMap::new(),
} }
} }
@ -102,30 +134,146 @@ impl SyntaxContext {
SyntaxContext(0) SyntaxContext(0)
} }
pub fn data(self) -> SyntaxContextData {
HygieneData::with(|data| data.syntax_contexts[self.0 as usize])
}
/// Extend a syntax context with a given mark /// Extend a syntax context with a given mark
pub fn apply_mark(self, mark: Mark) -> SyntaxContext { pub fn apply_mark(self, mark: Mark) -> SyntaxContext {
// Applying the same mark twice is a no-op
let ctxt_data = self.data();
if mark == ctxt_data.outer_mark {
return ctxt_data.prev_ctxt;
}
HygieneData::with(|data| { HygieneData::with(|data| {
let syntax_contexts = &mut data.syntax_contexts; let syntax_contexts = &mut data.syntax_contexts;
let ctxt_data = syntax_contexts[self.0 as usize];
if mark == ctxt_data.outer_mark {
return ctxt_data.prev_ctxt;
}
let modern = if data.marks[mark.0 as usize].modern {
*data.markings.entry((ctxt_data.modern, mark)).or_insert_with(|| {
let modern = SyntaxContext(syntax_contexts.len() as u32);
syntax_contexts.push(SyntaxContextData {
outer_mark: mark,
prev_ctxt: ctxt_data.modern,
modern: modern,
});
modern
})
} else {
ctxt_data.modern
};
*data.markings.entry((self, mark)).or_insert_with(|| { *data.markings.entry((self, mark)).or_insert_with(|| {
syntax_contexts.push(SyntaxContextData { syntax_contexts.push(SyntaxContextData {
outer_mark: mark, outer_mark: mark,
prev_ctxt: self, prev_ctxt: self,
modern: modern,
}); });
SyntaxContext(syntax_contexts.len() as u32 - 1) SyntaxContext(syntax_contexts.len() as u32 - 1)
}) })
}) })
} }
pub fn remove_mark(&mut self) -> Mark {
HygieneData::with(|data| {
let outer_mark = data.syntax_contexts[self.0 as usize].outer_mark;
*self = data.syntax_contexts[self.0 as usize].prev_ctxt;
outer_mark
})
}
/// Adjust this context for resolution in a scope created by the given expansion.
/// For example, consider the following three resolutions of `f`:
/// ```rust
/// mod foo { pub fn f() {} } // `f`'s `SyntaxContext` is empty.
/// m!(f);
/// macro m($f:ident) {
/// mod bar {
/// pub fn f() {} // `f`'s `SyntaxContext` has a single `Mark` from `m`.
/// pub fn $f() {} // `$f`'s `SyntaxContext` is empty.
/// }
/// foo::f(); // `f`'s `SyntaxContext` has a single `Mark` from `m`
/// //^ Since `mod foo` is outside this expansion, `adjust` removes the mark from `f`,
/// //| and it resolves to `::foo::f`.
/// bar::f(); // `f`'s `SyntaxContext` has a single `Mark` from `m`
/// //^ Since `mod bar` not outside this expansion, `adjust` does not change `f`,
/// //| and it resolves to `::bar::f`.
/// bar::$f(); // `f`'s `SyntaxContext` is empty.
/// //^ Since `mod bar` is not outside this expansion, `adjust` does not change `$f`,
/// //| and it resolves to `::bar::$f`.
/// }
/// ```
/// This returns the expansion whose definition scope we use to privacy check the resolution,
/// or `None` if we privacy check as usual (i.e. not w.r.t. a macro definition scope).
pub fn adjust(&mut self, expansion: Mark) -> Option<Mark> {
let mut scope = None;
while !expansion.is_descendant_of(self.outer()) {
scope = Some(self.remove_mark());
}
scope
}
/// Adjust this context for resolution in a scope created by the given expansion
/// via a glob import with the given `SyntaxContext`.
/// For example,
/// ```rust
/// m!(f);
/// macro m($i:ident) {
/// mod foo {
/// pub fn f() {} // `f`'s `SyntaxContext` has a single `Mark` from `m`.
/// pub fn $i() {} // `$i`'s `SyntaxContext` is empty.
/// }
/// n(f);
/// macro n($j:ident) {
/// use foo::*;
/// f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n`
/// //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::f`.
/// $i(); // `$i`'s `SyntaxContext` has a mark from `n`
/// //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::$i`.
/// $j(); // `$j`'s `SyntaxContext` has a mark from `m`
/// //^ This cannot be glob-adjusted, so this is a resolution error.
/// }
/// }
/// ```
/// This returns `None` if the context cannot be glob-adjusted.
/// Otherwise, it returns the scope to use when privacy checking (see `adjust` for details).
pub fn glob_adjust(&mut self, expansion: Mark, mut glob_ctxt: SyntaxContext)
-> Option<Option<Mark>> {
let mut scope = None;
while !expansion.is_descendant_of(glob_ctxt.outer()) {
scope = Some(glob_ctxt.remove_mark());
if self.remove_mark() != scope.unwrap() {
return None;
}
}
if self.adjust(expansion).is_some() {
return None;
}
Some(scope)
}
/// Undo `glob_adjust` if possible:
/// ```rust
/// if let Some(privacy_checking_scope) = self.reverse_glob_adjust(expansion, glob_ctxt) {
/// assert!(self.glob_adjust(expansion, glob_ctxt) == Some(privacy_checking_scope));
/// }
/// ```
pub fn reverse_glob_adjust(&mut self, expansion: Mark, mut glob_ctxt: SyntaxContext)
-> Option<Option<Mark>> {
if self.adjust(expansion).is_some() {
return None;
}
let mut marks = Vec::new();
while !expansion.is_descendant_of(glob_ctxt.outer()) {
marks.push(glob_ctxt.remove_mark());
}
let scope = marks.last().cloned();
while let Some(mark) = marks.pop() {
*self = self.apply_mark(mark);
}
Some(scope)
}
pub fn modern(self) -> SyntaxContext {
HygieneData::with(|data| data.syntax_contexts[self.0 as usize].modern)
}
pub fn outer(self) -> Mark { pub fn outer(self) -> Mark {
HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark) HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark)
} }

View file

@ -35,8 +35,8 @@ impl Ident {
Ident::with_empty_ctxt(Symbol::intern(string)) Ident::with_empty_ctxt(Symbol::intern(string))
} }
pub fn unhygienize(self) -> Ident { pub fn modern(self) -> Ident {
Ident { name: self.name, ctxt: SyntaxContext::empty() } Ident { name: self.name, ctxt: self.ctxt.modern() }
} }
} }