]> git.lizzy.rs Git - rust.git/commitdiff
Hygienize `librustc_resolve`.
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>
Wed, 22 Mar 2017 08:39:51 +0000 (08:39 +0000)
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>
Thu, 25 May 2017 05:51:50 +0000 (05:51 +0000)
18 files changed:
src/librustc/hir/lowering.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/schema.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_resolve/resolve_imports.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/fold.rs
src/libsyntax/std_inject.rs
src/libsyntax/test.rs
src/libsyntax_ext/deriving/mod.rs
src/libsyntax_ext/proc_macro_registrar.rs
src/libsyntax_pos/hygiene.rs
src/libsyntax_pos/symbol.rs

index 5ec8dd0156ab11496fcdbfdb753020420c961de9..1e4114add814d786848b01140741d10bc44c5d14 100644 (file)
@@ -393,7 +393,7 @@ fn str_to_ident(&self, s: &'static str) -> Name {
     }
 
     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 {
             call_site: span,
             callee: codemap::NameAndSpan {
index 4e16c97ca4d86d3ece589af54ba78c342991fa81..9d098557367cd48311369dfc59557c7f5a1ee188 100644 (file)
@@ -388,7 +388,7 @@ fn load_macro(&self, id: DefId, sess: &Session) -> LoadedMacro {
             attrs: attrs.iter().cloned().collect(),
             node: ast::ItemKind::MacroDef(ast::MacroDef {
                 tokens: body.into(),
-                legacy: true,
+                legacy: def.legacy,
             }),
             vis: ast::Visibility::Inherited,
         })
index 93fcdc455e5dd3762dc7dfe7d6f78e13c4e66ea0..07c475949d4357555c41e90dc33776106bc121c1 100644 (file)
@@ -1104,6 +1104,7 @@ fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef) -> Entry<'tcx
         Entry {
             kind: EntryKind::MacroDef(self.lazy(&MacroDef {
                 body: pprust::tts_to_string(&macro_def.body.trees().collect::<Vec<_>>()),
+                legacy: macro_def.legacy,
             })),
             visibility: self.lazy(&ty::Visibility::Public),
             span: self.lazy(&macro_def.span),
index 91a22d922199da6d2e6f3e35192ec9957a9491e1..2ffe7cc02aaacec21feca4538057c9159a306b3b 100644 (file)
@@ -433,9 +433,10 @@ pub struct ModData {
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct MacroDef {
     pub body: String,
+    pub legacy: bool,
 }
 
-impl_stable_hash_for!(struct MacroDef { body });
+impl_stable_hash_for!(struct MacroDef { body, legacy });
 
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct FnData {
index 18798962df1beabf71afd46295407f6afc207c7f..72f555b47cc9a87c6ff06a6a30e49b7e1a430898 100644 (file)
@@ -23,7 +23,7 @@
 
 use rustc::middle::cstore::LoadedMacro;
 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 std::cell::Cell;
@@ -150,7 +150,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
                                           view_path.span,
                                           ResolutionError::SelfImportsOnlyAllowedWithin);
                         } 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 {
                                 ModuleKind::Def(_, name) => name,
                                 ModuleKind::Block(..) => unreachable!(),
@@ -247,7 +247,8 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
 
                 // 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 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);
                 let used = self.process_legacy_macro_imports(item, module, expansion);
                 let binding =
@@ -279,7 +280,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
                     no_implicit_prelude: parent.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.module_map.insert(def_id, module);
@@ -317,6 +318,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
                 let module = self.new_module(parent,
                                              module_kind,
                                              parent.normal_ancestor_id,
+                                             expansion,
                                              item.span);
                 self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
 
@@ -376,6 +378,7 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
                 let module = self.new_module(parent,
                                              module_kind,
                                              parent.normal_ancestor_id,
+                                             expansion,
                                              item.span);
                 self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
                 self.current_module = module;
@@ -421,12 +424,13 @@ fn build_reduced_graph_for_foreign_item(&mut self, item: &ForeignItem, 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;
         if self.block_needs_anonymous_module(block) {
             let module = self.new_module(parent,
                                          ModuleKind::Block(block.id),
                                          parent.normal_ancestor_id,
+                                         expansion,
                                          block.span);
             self.block_map.insert(block.id, module);
             self.current_module = module; // Descend into the block.
@@ -440,23 +444,24 @@ fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, chi
         let def_id = def.def_id();
         let vis = self.session.cstore.visibility(def_id);
         let span = child.span;
-
+        let expansion = Mark::root(); // FIXME(jseyfried) intercrate hygiene
         match def {
             Def::Mod(..) | Def::Enum(..) => {
                 let module = self.new_module(parent,
                                              ModuleKind::Def(def, ident.name),
                                              def_id,
+                                             expansion,
                                              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(..) => {
-                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(..) => {
-                self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
+                self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, expansion));
             }
             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) =
                         self.session.cstore.def_key(def_id).parent
@@ -469,14 +474,15 @@ fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, chi
                 let module = self.new_module(parent,
                                              module_kind,
                                              parent.normal_ancestor_id,
+                                             expansion,
                                              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) {
                     let ns = if let Def::AssociatedTy(..) = child.def { TypeNS } else { ValueNS };
                     let ident = Ident::with_empty_ctxt(child.name);
                     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())
                            .method_has_self_argument {
@@ -486,31 +492,42 @@ fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, chi
                 module.populated.set(true);
             }
             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.
                 let field_names = self.session.cstore.struct_field_names(def_id);
                 self.insert_field_names(def_id, field_names);
             }
             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)
         }
     }
 
-    fn get_extern_crate_root(&mut self, cnum: CrateNum, span: Span) -> Module<'a> {
-        let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
-        let name = self.session.cstore.crate_name(cnum);
-        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;
-        *self.extern_crate_roots.entry((cnum, macros_only)).or_insert_with(|| {
-            arenas.alloc_module(ModuleData::new(None, module_kind, def_id, span))
-        })
+    pub fn get_module(&mut self, def_id: DefId) -> Module<'a> {
+        if def_id.krate == LOCAL_CRATE {
+            return self.module_map[&def_id]
+        }
+
+        let macros_only = self.session.cstore.dep_kind(def_id.krate).macros_only();
+        if let Some(&module) = self.extern_module_map.get(&(def_id, macros_only)) {
+            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];
         if let Some(id) = self.definitions.as_local_node_id(def_id) {
             self.local_macro_def_scopes[&id]
@@ -519,7 +536,7 @@ pub fn macro_def_scope(&mut self, expansion: Mark, span: Span) -> Module<'a> {
             self.graph_root
         } else {
             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 @@ fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) {
 
     fn visit_block(&mut self, block: &'a Block) {
         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);
         self.resolver.current_module = parent;
         self.legacy_scope = legacy_scope;
index 6d8ca09935cff3ae4f1139e99bda83b28316578c..180a608e631040d75acb263f3237cd784264ae6f 100644 (file)
@@ -43,7 +43,7 @@
 use rustc::session::Session;
 use rustc::lint;
 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::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
 use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
@@ -51,7 +51,7 @@
 use syntax::ext::hygiene::{Mark, SyntaxContext};
 use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy};
 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::symbol::{Symbol, keywords};
 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: Span,
+
+    expansion: Mark,
 }
 
 pub type Module<'a> = &'a ModuleData<'a>;
@@ -869,6 +871,7 @@ impl<'a> ModuleData<'a> {
     fn new(parent: Option<Module<'a>>,
            kind: ModuleKind,
            normal_ancestor_id: DefId,
+           expansion: Mark,
            span: Span) -> Self {
         ModuleData {
             parent: parent,
@@ -884,6 +887,7 @@ fn new(parent: Option<Module<'a>>,
             traits: RefCell::new(None),
             populated: Cell::new(normal_ancestor_id.is_local()),
             span: span,
+            expansion: expansion,
         }
     }
 
@@ -1165,7 +1169,7 @@ pub struct Resolver<'a> {
     // entry block for `f`.
     block_map: NodeMap<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,
     // 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)]`
 
     crate_loader: &'a mut CrateLoader,
-    macro_names: FxHashSet<Name>,
+    macro_names: FxHashSet<Ident>,
     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_defs: FxHashMap<Mark, DefId>,
     local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
@@ -1310,7 +1314,7 @@ pub fn new(session: &'a Session,
         let root_module_kind = ModuleKind::Def(Def::Mod(root_def_id), keywords::Invalid.name());
         let graph_root = arenas.alloc_module(ModuleData {
             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();
         module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root);
@@ -1364,7 +1368,7 @@ pub fn new(session: &'a Session,
             trait_map: NodeMap(),
             module_map: module_map,
             block_map: NodeMap(),
-            extern_crate_roots: FxHashMap(),
+            extern_module_map: FxHashMap(),
 
             make_glob_map: make_glob_map == MakeGlobMap::Yes,
             glob_map: NodeMap(),
@@ -1449,9 +1453,11 @@ fn new_module(
         parent: Module<'a>,
         kind: ModuleKind,
         normal_ancestor_id: DefId,
+        expansion: Mark,
         span: Span,
     ) -> 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)
@@ -1513,10 +1519,11 @@ fn resolve_ident_in_lexical_scope(&mut self,
                                       path_span: Span)
                                       -> Option<LexicalScopeBinding<'a>> {
         if ns == TypeNS {
-            ident = ident.unhygienize();
+            ident.ctxt = ident.ctxt.modern();
         }
 
         // Walk backwards up the ribs in scope.
+        let mut module = self.graph_root;
         for i in (0 .. self.ribs[ns].len()).rev() {
             if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() {
                 // The ident resolves to a type parameter or local variable.
@@ -1525,45 +1532,120 @@ fn resolve_ident_in_lexical_scope(&mut self,
                 ));
             }
 
-            if let ModuleRibKind(module) = self.ribs[ns][i].kind {
-                let item = self.resolve_ident_in_module(module, ident, ns, false,
-                                                        record_used, path_span);
-                if let Ok(binding) = item {
-                    // The ident resolves to an item.
-                    return Some(LexicalScopeBinding::Item(binding));
+            module = match self.ribs[ns][i].kind {
+                ModuleRibKind(module) => module,
+                MacroDefinition(def) if def == self.macro_defs[&ident.ctxt.outer()] => {
+                    // If an invocation of this macro created `ident`, give up on `ident`
+                    // and switch to `ident`'s source from the macro definition.
+                    ident.ctxt.remove_mark();
+                    continue
                 }
+                _ => continue,
+            };
 
-                if let ModuleKind::Block(..) = module.kind { // We can see through blocks
-                } else if !module.no_implicit_prelude {
-                    return self.prelude.and_then(|prelude| {
-                        self.resolve_ident_in_module(prelude, ident, ns, false,
-                                                     false, path_span).ok()
-                    }).map(LexicalScopeBinding::Item)
-                } else {
-                    return None;
-                }
+            let item = self.resolve_ident_in_module_unadjusted(
+                module, ident, ns, false, record_used, path_span,
+            );
+            if let Ok(binding) = item {
+                // The ident resolves to an item.
+                return Some(LexicalScopeBinding::Item(binding));
             }
 
-            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;
-                }
+            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 {
+                    None
+                };
             }
+            module = parent;
+            module_expansion = parent_expansion;
         }
 
         None
     }
 
-    fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext, span: Span) -> Module<'a> {
-        let mut ctxt_data = crate_var_ctxt.data();
-        while ctxt_data.prev_ctxt != SyntaxContext::empty() {
-            ctxt_data = ctxt_data.prev_ctxt.data();
+    fn resolve_ident_in_module(&mut self,
+                               module: Module<'a>,
+                               mut ident: Ident,
+                               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 result = self.resolve_ident_in_module_unadjusted(
+            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);
         }
-        let module = self.macro_def_scope(ctxt_data.outer_mark, span);
-        if module.is_local() { self.graph_root } else { module }
+        module
     }
 
     // AST resolution
@@ -1611,15 +1693,12 @@ fn with_scope<F>(&mut self, id: NodeId, f: F)
     fn search_label(&self, mut ident: Ident) -> Option<Def> {
         for rib in self.label_ribs.iter().rev() {
             match rib.kind {
-                NormalRibKind => {
-                    // Continue
-                }
+                NormalRibKind => {}
+                // If an invocation of this macro created `ident`, give up on `ident`
+                // and switch to `ident`'s source from the macro definition.
                 MacroDefinition(def) => {
-                    // 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;
+                    if def == self.macro_defs[&ident.ctxt.outer()] {
+                        ident.ctxt.remove_mark();
                     }
                 }
                 _ => {
@@ -1751,7 +1830,7 @@ fn with_type_parameter_rib<'b, F>(&'b mut self, type_parameters: TypeParameters<
                 let mut function_type_rib = Rib::new(rib_kind);
                 let mut seen_bindings = FxHashMap();
                 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);
 
                     if seen_bindings.contains_key(&ident) {
@@ -2504,7 +2583,7 @@ fn resolve_qpath_anywhere(&mut self,
         }
         let is_global = self.global_macros.get(&path[0].name).cloned()
             .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(
                 PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang))
@@ -2613,13 +2692,17 @@ fn resolve_path(&mut self,
             let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
 
             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
             } else if allow_super && ns == TypeNS && ident.name == keywords::Super.name() {
-                let current_module = if i == 0 { self.current_module } else { module.unwrap() };
-                let self_module = self.module_map[&current_module.normal_ancestor_id];
+                let mut ctxt = ident.ctxt.modern();
+                let self_module = match i {
+                    0 => self.resolve_self(&mut ctxt, self.current_module),
+                    _ => module.unwrap(),
+                };
                 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
                 } else {
                     let msg = "There are too many initial `super`s.".to_string();
@@ -2629,10 +2712,10 @@ fn resolve_path(&mut self,
             allow_super = false;
 
             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
             } 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
             }
 
@@ -3108,7 +3191,8 @@ fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) {
         }
     }
 
-    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);
 
         let mut found_traits = Vec::new();
@@ -3120,13 +3204,12 @@ fn get_traits_containing_item(&mut self, ident: Ident, ns: Namespace) -> Vec<Tra
             }
         }
 
+        ident.ctxt = ident.ctxt.modern();
         let mut search_module = self.current_module;
         loop {
             self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits);
-            match search_module.kind {
-                ModuleKind::Block(..) => search_module = search_module.parent.unwrap(),
-                _ => break,
-            }
+            search_module =
+                unwrap_or!(self.hygienic_lexical_parent(search_module, &mut ident.ctxt), break);
         }
 
         if let Some(prelude) = self.prelude {
@@ -3157,7 +3240,12 @@ fn get_traits_in_module_containing_item(&mut self,
 
         for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
             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 {
                     NameBindingKind::Import { directive, .. } => {
                         self.maybe_unused_trait_imports.insert(directive.id);
@@ -3348,15 +3436,15 @@ fn report_errors(&mut self) {
     }
 
     fn report_shadowing_errors(&mut self) {
-        for (name, scope) in replace(&mut self.lexical_macro_resolutions, Vec::new()) {
-            self.resolve_legacy_scope(scope, name, true);
+        for (ident, scope) in replace(&mut self.lexical_macro_resolutions, Vec::new()) {
+            self.resolve_legacy_scope(scope, ident, true);
         }
 
         let mut reported_errors = FxHashSet();
         for binding in replace(&mut self.disallowed_shadowing, Vec::new()) {
-            if self.resolve_legacy_scope(&binding.parent, binding.name, false).is_some() &&
-               reported_errors.insert((binding.name, binding.span)) {
-                let msg = format!("`{}` is already in scope", binding.name);
+            if self.resolve_legacy_scope(&binding.parent, binding.ident, false).is_some() &&
+               reported_errors.insert((binding.ident, binding.span)) {
+                let msg = format!("`{}` is already in scope", binding.ident);
                 self.session.struct_span_err(binding.span, &msg)
                     .note("macro-expanded `macro_rules!`s may not shadow \
                            existing macros (see RFC 1560)")
index bf21344330bcaf3c663077e6e30e67a2f2e396b1..9aba892e0ff5eb3df58eca83329b29f44fbd0071 100644 (file)
@@ -76,7 +76,7 @@ pub enum LegacyScope<'a> {
 
 pub struct LegacyBinding<'a> {
     pub parent: Cell<LegacyScope<'a>>,
-    pub name: ast::Name,
+    pub ident: Ident,
     def_id: DefId,
     pub span: Span,
 }
@@ -110,7 +110,7 @@ fn next_node_id(&mut self) -> ast::NodeId {
     }
 
     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)];
         self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData {
             module: Cell::new(module),
@@ -130,7 +130,7 @@ fn fold_path(&mut self, mut path: ast::Path) -> ast::Path {
                 let ident = path.segments[0].identifier;
                 if ident.name == "$crate" {
                     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() {
                         let span = path.segments[0].span;
                         path.segments.insert(1, match module.kind {
@@ -292,7 +292,11 @@ fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
         };
         self.macro_defs.insert(invoc.expansion_data.mark, 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)
@@ -416,8 +420,7 @@ fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKin
             return def;
         }
 
-        let name = path[0].name;
-        let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, name, false);
+        let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, path[0], false);
         let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution {
             Ok(Def::Macro(binding.def_id, MacroKind::Bang))
         } else {
@@ -439,26 +442,31 @@ fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKin
 
     // 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,
-                                              ident: Ident,
+                                              mut ident: Ident,
                                               ns: Namespace,
                                               record_used: bool,
                                               path_span: Span)
                                               -> Result<MacroBinding<'a>, Determinacy> {
+        ident = ident.modern();
         let mut module = Some(self.current_module);
         let mut potential_illegal_shadower = Err(Determinacy::Determined);
         let determinacy =
             if record_used { Determinacy::Determined } else { Determinacy::Undetermined };
         loop {
+            let orig_current_module = self.current_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
                 // globs may not shadow global macros (both enforced below),
                 // we resolve with restricted shadowing (indicated by the penultimate argument).
-                self.resolve_ident_in_module(module, ident, ns, true, record_used, path_span)
-                    .map(MacroBinding::Modern)
+                self.resolve_ident_in_module_unadjusted(
+                    module, ident, ns, true, record_used, path_span,
+                ).map(MacroBinding::Modern)
             } else {
                 self.global_macros.get(&ident.name).cloned().ok_or(determinacy)
                     .map(MacroBinding::Global)
             };
+            self.current_module = orig_current_module;
 
             match result.map(MacroBinding::binding) {
                 Ok(binding) => {
@@ -491,10 +499,7 @@ pub fn resolve_lexical_macro_path_segment(&mut self,
             }
 
             module = match module {
-                Some(module) => match module.kind {
-                    ModuleKind::Block(..) => module.parent,
-                    ModuleKind::Def(..) => None,
-                },
+                Some(module) => self.hygienic_lexical_parent(module, &mut ident.ctxt),
                 None => return potential_illegal_shadower,
             }
         }
@@ -502,9 +507,10 @@ pub fn resolve_lexical_macro_path_segment(&mut self,
 
     pub fn resolve_legacy_scope(&mut self,
                                 mut scope: &'a Cell<LegacyScope<'a>>,
-                                name: Name,
+                                ident: Ident,
                                 record_used: bool)
                                 -> Option<MacroBinding<'a>> {
+        let ident = ident.modern();
         let mut possible_time_travel = None;
         let mut relative_depth: u32 = 0;
         let mut binding = None;
@@ -531,7 +537,7 @@ pub fn resolve_legacy_scope(&mut self,
                     scope = &invocation.legacy_scope;
                 }
                 LegacyScope::Binding(potential_binding) => {
-                    if potential_binding.name == name {
+                    if potential_binding.ident == ident {
                         if (!self.use_extern_macros || record_used) && relative_depth > 0 {
                             self.disallowed_shadowing.push(potential_binding);
                         }
@@ -545,9 +551,9 @@ pub fn resolve_legacy_scope(&mut self,
 
         let binding = if let Some(binding) = 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 {
-                self.record_use(Ident::with_empty_ctxt(name), MacroNS, binding, DUMMY_SP);
+                self.record_use(ident, MacroNS, binding, DUMMY_SP);
             }
             MacroBinding::Global(binding)
         } else {
@@ -557,7 +563,7 @@ pub fn resolve_legacy_scope(&mut self,
         if !self.use_extern_macros {
             if let Some(scope) = possible_time_travel {
                 // Check for disallowed shadowing later
-                self.lexical_macro_resolutions.push((name, scope));
+                self.lexical_macro_resolutions.push((ident, scope));
             }
         }
 
@@ -578,7 +584,7 @@ pub fn finalize_current_module_macro_resolutions(&mut self) {
 
         for &(mark, ident, span, kind) in module.legacy_macro_resolutions.borrow().iter() {
             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);
             match (legacy_resolution, resolution) {
                 (Some(MacroBinding::Legacy(legacy_binding)), Ok(MacroBinding::Modern(binding))) => {
@@ -615,7 +621,7 @@ fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
                           err: &mut DiagnosticBuilder<'a>, span: Span) {
         // First check if this is a locally-defined bang macro.
         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 {
             None
         // Then check global macros.
@@ -705,9 +711,10 @@ pub fn define_macro(&mut self,
 
         let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() };
         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 {
-                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") {
                 let def = Def::Macro(def_id, MacroKind::Bang);
index fdca931ad4784c6b9c216c6664d90ac18d715e14..f304aad4638cead713a6b555c1dbeebe91af3e98 100644 (file)
@@ -134,21 +134,20 @@ fn binding(&self) -> Option<&'a NameBinding<'a>> {
 impl<'a> Resolver<'a> {
     fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
                   -> &'a RefCell<NameResolution<'a>> {
-        let ident = ident.unhygienize();
-        *module.resolutions.borrow_mut().entry((ident, ns))
+        *module.resolutions.borrow_mut().entry((ident.modern(), ns))
                .or_insert_with(|| self.arenas.alloc_name_resolution())
     }
 
     /// Attempts to resolve `ident` in namespaces `ns` of `module`.
     /// Invariant: if `record_used` is `Some`, import resolution must be complete.
-    pub fn resolve_ident_in_module(&mut self,
-                                   module: Module<'a>,
-                                   ident: Ident,
-                                   ns: Namespace,
-                                   restricted_shadowing: bool,
-                                   record_used: bool,
-                                   path_span: Span)
-                                   -> Result<&'a NameBinding<'a>, Determinacy> {
+    pub fn resolve_ident_in_module_unadjusted(&mut self,
+                                              module: Module<'a>,
+                                              ident: Ident,
+                                              ns: Namespace,
+                                              restricted_shadowing: bool,
+                                              record_used: bool,
+                                              path_span: Span)
+                                              -> Result<&'a NameBinding<'a>, Determinacy> {
         self.populate_module_if_necessary(module);
 
         let resolution = self.resolution(module, ident, ns)
@@ -233,20 +232,22 @@ pub fn resolve_ident_in_module(&mut self,
             return Err(Determined);
         }
         for directive in module.globs.borrow().iter() {
-            if self.is_accessible(directive.vis.get()) {
-                if let Some(module) = directive.imported_module.get() {
-                    let result = self.resolve_ident_in_module(module,
-                                                              ident,
-                                                              ns,
-                                                              false,
-                                                              false,
-                                                              path_span);
-                    if let Err(Undetermined) = result {
-                        return Err(Undetermined);
-                    }
-                } else {
-                    return Err(Undetermined);
-                }
+            if !self.is_accessible(directive.vis.get()) {
+                continue
+            }
+            let module = unwrap_or!(directive.imported_module.get(), return Err(Undetermined));
+            let (orig_current_module, mut ident) = (self.current_module, ident.modern());
+            match ident.ctxt.glob_adjust(module.expansion, directive.span.ctxt.modern()) {
+                Some(Some(def)) => self.current_module = self.macro_def_scope(def),
+                Some(None) => {}
+                None => continue,
+            };
+            let result = self.resolve_ident_in_module_unadjusted(
+                module, ident, ns, false, false, path_span,
+            );
+            self.current_module = orig_current_module;
+            if let Err(Undetermined) = result {
+                return Err(Undetermined);
             }
         }
 
@@ -394,7 +395,14 @@ fn update_resolution<T, F>(&mut self, module: Module<'a>, ident: Ident, ns: Name
 
         // Define `binding` in `module`s glob importers.
         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 _ = self.try_define(directive.parent, ident, ns, imported_binding);
             }
@@ -767,8 +775,14 @@ fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) {
         let bindings = module.resolutions.borrow().iter().filter_map(|(&ident, resolution)| {
             resolution.borrow().binding().map(|binding| (ident, binding))
         }).collect::<Vec<_>>();
-        for ((ident, ns), binding) in bindings {
-            if binding.pseudo_vis() == ty::Visibility::Public || self.is_accessible(binding.vis) {
+        for ((mut ident, ns), binding) in bindings {
+            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 _ = self.try_define(directive.parent, ident, ns, imported_binding);
             }
index 1930f61121bb028113f2dc37d5b037f6ca9f2a47..71dc81c37592322da76ee9bddf245d21577ec2ae 100644 (file)
@@ -550,12 +550,16 @@ pub enum SyntaxExtension {
 
     /// An attribute-like procedural macro that derives a builtin trait.
     BuiltinDerive(BuiltinDeriveFn),
+
+    /// A declarative macro, e.g. `macro m() {}`.
+    DeclMacro(Box<TTMacroExpander>, Option<Span> /* definition site span */),
 }
 
 impl SyntaxExtension {
     /// Return which kind of macro calls this syntax extension.
     pub fn kind(&self) -> MacroKind {
         match *self {
+            SyntaxExtension::DeclMacro(..) |
             SyntaxExtension::NormalTT(..) |
             SyntaxExtension::IdentTT(..) |
             SyntaxExtension::ProcMacro(..) =>
@@ -569,6 +573,13 @@ pub fn kind(&self) -> MacroKind {
                 MacroKind::Derive,
         }
     }
+
+    pub fn is_modern(&self) -> bool {
+        match *self {
+            SyntaxExtension::DeclMacro(..) => true,
+            _ => false,
+        }
+    }
 }
 
 pub type NamedSyntaxExtension = (Name, SyntaxExtension);
index 25e0aed220ab3fb036e5fb37b890b95bb448d671..be077b481113f12c17fad392137df5465040e1b2 100644 (file)
@@ -288,7 +288,7 @@ fn expand(&mut self, expansion: Expansion) -> Expansion {
                     let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new);
 
                     for path in &traits {
-                        let mark = Mark::fresh();
+                        let mark = Mark::fresh(self.cx.current_expansion.mark);
                         derives.push(mark);
                         let item = match self.cx.resolver.resolve_macro(
                                 Mark::root(), path, MacroKind::Derive, false) {
@@ -455,25 +455,37 @@ fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc<SyntaxExtension>) ->
         let path = &mac.node.path;
 
         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 opt_expanded = match *ext {
-            NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
-                if ident.name != keywords::Invalid.name() {
-                    let msg =
-                        format!("macro {}! expects no ident argument, given '{}'", path, ident);
+            SyntaxExtension::DeclMacro(ref expand, def_site_span) => {
+                if let Err(msg) = validate_and_set_expn_info(def_site_span, false) {
                     self.cx.span_err(path.span, &msg);
                     return kind.dummy(span);
                 }
+                kind.make_from(expand.expand(self.cx, span, marked_tts))
+            }
 
-                invoc.expansion_data.mark.set_expn_info(ExpnInfo {
-                    call_site: span,
-                    callee: NameAndSpan {
-                        format: MacroBang(Symbol::intern(&format!("{}", path))),
-                        span: exp_span.map(|(_, s)| s),
-                        allow_internal_unstable: allow_internal_unstable,
-                    },
-                });
-
+            NormalTT(ref expandfun, def_info, allow_internal_unstable) => {
+                if let Err(msg) = validate_and_set_expn_info(def_info.map(|(_, s)| s),
+                                                             allow_internal_unstable) {
+                    self.cx.span_err(path.span, &msg);
+                    return kind.dummy(span);
+                }
                 kind.make_from(expandfun.expand(self.cx, span, marked_tts))
             }
 
@@ -687,7 +699,7 @@ macro_rules! fully_configure {
 
 impl<'a, 'b> InvocationCollector<'a, 'b> {
     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 {
             kind: kind,
             expansion_kind: expansion_kind,
index ad09d5837341297105b83532b61916dddc5c1ae5..a9252d0818e38039a1152589515cc821b1a156d3 100644 (file)
@@ -253,9 +253,12 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)
         valid: valid,
     });
 
-    NormalTT(exp,
-             Some((def.id, def.span)),
-             attr::contains_name(&def.attrs, "allow_internal_unstable"))
+    if body.legacy {
+        let 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,
index 1d1e46cf576d1a32571da2dfef635c1a47b0346b..5bbda5f2689d308a91e048026e5bf6df7b9e11e0 100644 (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 {
     Spanned {
         node: Variant_ {
-            name: v.node.name,
+            name: fld.fold_ident(v.node.name),
             attrs: fold_attrs(v.node.attrs, fld),
             data: fld.fold_variant_data(v.node.data),
             disr_expr: v.node.disr_expr.map(|e| fld.fold_expr(e)),
index 8e257102e1c13367d281d01cce701e94bb0bacf5..a8a9ae556f1084509a43ecd8c961ca7d3d93346e 100644 (file)
@@ -21,7 +21,7 @@
 /// call to codemap's `is_internal` check.
 /// The expanded code uses the unstable `#[prelude_import]` attribute.
 fn ignored_span(sp: Span) -> Span {
-    let mark = Mark::fresh();
+    let mark = Mark::fresh(Mark::root());
     mark.set_expn_info(ExpnInfo {
         call_site: DUMMY_SP,
         callee: NameAndSpan {
index bb1a6ff65a596018a263bc7aa94e941e24da1b78..3df61fadc350382dd31a3d146e48c70969420bed 100644 (file)
@@ -276,7 +276,7 @@ fn generate_test_harness(sess: &ParseSess,
     let mut cleaner = EntryPointCleaner { depth: 0 };
     let krate = cleaner.fold_crate(krate);
 
-    let mark = Mark::fresh();
+    let mark = Mark::fresh(Mark::root());
     let mut cx: TestCtxt = TestCtxt {
         sess: sess,
         span_diagnostic: sd,
index 31c7cc33676776487a41e6247add158c0edf673a..00dcfc7a587069a2294d750d2a92a2a2ecba14ae 100644 (file)
@@ -162,7 +162,7 @@ fn call_intrinsic(cx: &ExtCtxt,
     } else { // Avoid instability errors with user defined curstom derives, cc #36316
         let mut info = cx.current_expansion.mark.expn_info().unwrap();
         info.callee.allow_internal_unstable = true;
-        let mark = Mark::fresh();
+        let mark = Mark::fresh(Mark::root());
         mark.set_expn_info(info);
         span.ctxt = SyntaxContext::empty().apply_mark(mark);
     }
index 6318abec69f06526c158e74da6454a12fa36b364..ab6d73e5061a0a5252834ca345137a95c3b46dc2 100644 (file)
@@ -361,7 +361,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
                 custom_derives: &[ProcMacroDerive],
                 custom_attrs: &[ProcMacroDef],
                 custom_macros: &[ProcMacroDef]) -> P<ast::Item> {
-    let mark = Mark::fresh();
+    let mark = Mark::fresh(Mark::root());
     mark.set_expn_info(ExpnInfo {
         call_site: DUMMY_SP,
         callee: NameAndSpan {
index 8a9ff647b3ea1b9a4504aa55f3ccd4f0766a212c..24a21faa7eb9ad45b0e1e8c53d128bd2070a1cad 100644 (file)
 use std::fmt;
 
 /// 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);
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Default)]
 pub struct SyntaxContextData {
     pub outer_mark: Mark,
     pub prev_ctxt: SyntaxContext,
+    pub modern: SyntaxContext,
 }
 
 /// A mark is a unique id associated with a macro expansion.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable, RustcDecodable)]
 pub struct Mark(u32);
 
+#[derive(Default)]
+struct MarkData {
+    parent: Mark,
+    modern: bool,
+    expn_info: Option<ExpnInfo>,
+}
+
 impl Mark {
-    pub fn fresh() -> Self {
+    pub fn fresh(parent: Mark) -> Self {
         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)
         })
     }
@@ -59,16 +67,43 @@ pub fn from_u32(raw: u32) -> Mark {
     }
 
     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) {
-        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 {
-    marks: Vec<Option<ExpnInfo>>,
+    marks: Vec<MarkData>,
     syntax_contexts: Vec<SyntaxContextData>,
     markings: HashMap<(SyntaxContext, Mark), SyntaxContext>,
 }
@@ -76,11 +111,8 @@ struct HygieneData {
 impl HygieneData {
     fn new() -> Self {
         HygieneData {
-            marks: vec![None],
-            syntax_contexts: vec![SyntaxContextData {
-                outer_mark: Mark::root(),
-                prev_ctxt: SyntaxContext::empty(),
-            }],
+            marks: vec![MarkData::default()],
+            syntax_contexts: vec![SyntaxContextData::default()],
             markings: HashMap::new(),
         }
     }
@@ -102,30 +134,146 @@ pub const fn empty() -> Self {
         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
     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| {
             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(|| {
                 syntax_contexts.push(SyntaxContextData {
                     outer_mark: mark,
                     prev_ctxt: self,
+                    modern: modern,
                 });
                 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 {
         HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark)
     }
index b866652c49f854c67d7ab415c2753cc508bb4710..070fab57afa82814454b3c85a226f17c0b8e945b 100644 (file)
@@ -35,8 +35,8 @@ pub fn from_str(string: &str) -> Ident {
         Ident::with_empty_ctxt(Symbol::intern(string))
     }
 
-    pub fn unhygienize(self) -> Ident {
-        Ident { name: self.name, ctxt: SyntaxContext::empty() }
+    pub fn modern(self) -> Ident {
+        Ident { name: self.name, ctxt: self.ctxt.modern() }
     }
 }