diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index befc1ba064aa2..bb201e238e901 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -123,7 +123,7 @@ impl FromStr for TokenStream { let expn_info = mark.expn_info().unwrap(); let call_site = expn_info.call_site; // notify the expansion info that it is unhygienic - let mark = Mark::fresh(mark); + let mark = Mark::fresh(); mark.set_expn_info(expn_info); let span = call_site.with_ctxt(SyntaxContext::empty().apply_mark(mark)); let stream = parse::parse_stream_from_source_str(name, src, sess, Some(span)); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 35d580d1c159b..f579bf66e994f 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -580,7 +580,7 @@ impl<'a> LoweringContext<'a> { } fn allow_internal_unstable(&self, reason: CompilerDesugaringKind, span: Span) -> Span { - let mark = Mark::fresh(Mark::root()); + let mark = Mark::fresh(); mark.set_expn_info(codemap::ExpnInfo { call_site: span, callee: codemap::NameAndSpan { diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 497d5fdcac702..4d892ca9ba04a 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -78,7 +78,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { } self.found = true; - let mark = Mark::fresh(Mark::root()); + let mark = Mark::fresh(); mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index fe6909f759159..e37f5088a9c36 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -123,7 +123,7 @@ impl<'a> base::Resolver for Resolver<'a> { } fn get_module_scope(&mut self, id: ast::NodeId) -> Mark { - let mark = Mark::fresh(Mark::root()); + let mark = Mark::fresh(); 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), diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 29030783ca6b8..efae7ee9aaa4a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -347,7 +347,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let derives = derives.entry(invoc.expansion_data.mark).or_insert_with(Vec::new); for path in &traits { - let mark = Mark::fresh(self.cx.current_expansion.mark); + let mark = Mark::fresh(); derives.push(mark); let item = match self.cx.resolver.resolve_macro( Mark::root(), path, MacroKind::Derive, false) { @@ -999,7 +999,7 @@ struct InvocationCollector<'a, 'b: 'a> { impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion { - let mark = Mark::fresh(self.cx.current_expansion.mark); + let mark = Mark::fresh(); self.invocations.push(Invocation { kind, expansion_kind, diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index e9cd7adb9c166..cd0a764f1e077 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -22,7 +22,7 @@ use tokenstream::TokenStream; /// 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(Mark::root()); + let mark = Mark::fresh(); mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 0c7f70a578a26..cfcf2b06426b6 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -275,7 +275,7 @@ fn generate_test_harness(sess: &ParseSess, let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); - let mark = Mark::fresh(Mark::root()); + let mark = Mark::fresh(); let mut econfig = ExpansionConfig::default("test".to_string()); econfig.features = Some(features); diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index a5b348a661a78..fc3d19478b4e5 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -159,7 +159,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(Mark::root()); + let mark = Mark::fresh(); mark.set_expn_info(info); span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark)); } diff --git a/src/libsyntax_ext/proc_macro_registrar.rs b/src/libsyntax_ext/proc_macro_registrar.rs index 3593165023a54..b7d614169dcb8 100644 --- a/src/libsyntax_ext/proc_macro_registrar.rs +++ b/src/libsyntax_ext/proc_macro_registrar.rs @@ -361,7 +361,7 @@ fn mk_registrar(cx: &mut ExtCtxt, custom_derives: &[ProcMacroDerive], custom_attrs: &[ProcMacroDef], custom_macros: &[ProcMacroDef]) -> P { - let mark = Mark::fresh(Mark::root()); + let mark = Mark::fresh(); mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, callee: NameAndSpan { diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 1365ac396ffdf..a0f9a374bc58b 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -41,7 +41,6 @@ pub struct SyntaxContextData { pub struct Mark(u32); struct MarkData { - parent: Mark, kind: MarkKind, expn_info: Option, } @@ -54,9 +53,9 @@ pub enum MarkKind { } impl Mark { - pub fn fresh(parent: Mark) -> Self { + pub fn fresh() -> Self { HygieneData::with(|data| { - data.marks.push(MarkData { parent: parent, kind: MarkKind::Legacy, expn_info: None }); + data.marks.push(MarkData { kind: MarkKind::Legacy, expn_info: None }); Mark(data.marks.len() as u32 - 1) }) } @@ -93,7 +92,7 @@ impl Mark { if self == Mark::root() || data.marks[self.0 as usize].kind == MarkKind::Modern { return self; } - self = data.marks[self.0 as usize].parent; + self = self.call_site_mark(data); } }) } @@ -114,7 +113,7 @@ impl Mark { if self == Mark::root() { return false; } - self = data.marks[self.0 as usize].parent; + self = self.call_site_mark(data); } true }) @@ -134,17 +133,24 @@ impl Mark { let mut a_path = FxHashSet::(); while a != Mark::root() { a_path.insert(a); - a = data.marks[a.0 as usize].parent; + a = a.call_site_mark(data); } // While the path from b to the root hasn't intersected, move up the tree while !a_path.contains(&b) { - b = data.marks[b.0 as usize].parent; + b = b.call_site_mark(data); } b }) } + + /// Private helpers not acquiring a lock around global data + fn call_site_mark(self, data: &HygieneData) -> Mark { + data.marks[self.0 as usize].expn_info.as_ref() + .map(|einfo| data.syntax_contexts[einfo.call_site.ctxt().0 as usize].outer_mark) + .unwrap_or(Mark::root()) + } } pub struct HygieneData { @@ -159,7 +165,6 @@ impl HygieneData { pub fn new() -> Self { HygieneData { marks: vec![MarkData { - parent: Mark::root(), kind: MarkKind::Builtin, expn_info: None, }], @@ -198,14 +203,13 @@ impl SyntaxContext { // Allocate a new SyntaxContext with the given ExpnInfo. This is used when // deserializing Spans from the incr. comp. cache. - // FIXME(mw): This method does not restore MarkData::parent or - // SyntaxContextData::prev_ctxt or SyntaxContextData::modern. These things + // FIXME(mw): This method does not restore SyntaxContextData::prev_ctxt or + // SyntaxContextData::modern. These things // don't seem to be used after HIR lowering, so everything should be fine // as long as incremental compilation does not kick in before that. pub fn allocate_directly(expansion_info: ExpnInfo) -> Self { HygieneData::with(|data| { data.marks.push(MarkData { - parent: Mark::root(), kind: MarkKind::Legacy, expn_info: Some(expansion_info) }); diff --git a/src/test/ui/hygiene/call-site-parent-vs-expansion-parent.rs b/src/test/ui/hygiene/call-site-parent-vs-expansion-parent.rs new file mode 100644 index 0000000000000..8423e25722f04 --- /dev/null +++ b/src/test/ui/hygiene/call-site-parent-vs-expansion-parent.rs @@ -0,0 +1,52 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +#![feature(decl_macro)] + +macro_rules! define_field { + () => { + struct S { field: u8 } + }; + ($field: ident) => { + struct Z { $field: u8 } + }; +} + +mod modern { + macro use_field($define_field1: item, $define_field2: item) { + $define_field1 + $define_field2 + + // OK, both struct name `S` and field `name` resolve to definitions + // produced by `define_field` and living in the "root" context + // that is in scope at `use_field`'s def-site. + fn f() { S { field: 0 }; } + fn g() { Z { field: 0 }; } + } + + use_field!(define_field!{}, define_field!{ field }); +} + +mod legacy { + macro_rules! use_field {($define_field1: item, $define_field2: item) => { + $define_field1 + $define_field2 + + // OK, everything is at the same call-site. + fn f() { S { field: 0 }; } + fn g() { Z { field: 0 }; } + }} + + use_field!(define_field!{}, define_field!{ field }); +} + +fn main() {}