From c3427161ee05ad92e70329494a44f32389813dbf Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 30 Jun 2018 19:35:00 +0300 Subject: [PATCH 1/3] libsyntax_pos: Tweak some visibilities --- src/libsyntax_pos/hygiene.rs | 24 ++++++++++++++++-------- src/libsyntax_pos/lib.rs | 2 +- src/libsyntax_pos/span_encoding.rs | 4 ++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 33d02d0b10a7b..ff23c2fb534d5 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -27,16 +27,16 @@ use std::fmt; /// A SyntaxContext represents a chain of macro expansions (represented by marks). #[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)] -pub struct SyntaxContext(pub(super) u32); +pub struct SyntaxContext(u32); #[derive(Copy, Clone, Debug)] -pub struct SyntaxContextData { - pub outer_mark: Mark, - pub prev_ctxt: SyntaxContext, +struct SyntaxContextData { + outer_mark: Mark, + prev_ctxt: SyntaxContext, // This context, but with all transparent and semi-transparent marks filtered away. - pub opaque: SyntaxContext, + opaque: SyntaxContext, // This context, but with all transparent marks filtered away. - pub opaque_and_semitransparent: SyntaxContext, + opaque_and_semitransparent: SyntaxContext, } /// A mark is a unique id associated with a macro expansion. @@ -198,7 +198,7 @@ impl Mark { } #[derive(Debug)] -pub struct HygieneData { +crate struct HygieneData { marks: Vec, syntax_contexts: Vec, markings: HashMap<(SyntaxContext, Mark), SyntaxContext>, @@ -206,7 +206,7 @@ pub struct HygieneData { } impl HygieneData { - pub fn new() -> Self { + crate fn new() -> Self { HygieneData { marks: vec![MarkData { parent: Mark::root(), @@ -249,6 +249,14 @@ impl SyntaxContext { SyntaxContext(0) } + crate fn as_u32(self) -> u32 { + self.0 + } + + crate fn from_u32(raw: u32) -> SyntaxContext { + SyntaxContext(raw) + } + // 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 diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 491ce720f36c5..61af70af47d85 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -19,10 +19,10 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(const_fn)] +#![feature(crate_visibility_modifier)] #![feature(custom_attribute)] #![feature(non_exhaustive)] #![feature(optin_builtin_traits)] -#![allow(unused_attributes)] #![feature(specialization)] #![feature(stdsimd)] diff --git a/src/libsyntax_pos/span_encoding.rs b/src/libsyntax_pos/span_encoding.rs index 601a0273ae911..473aa1bd1b8a4 100644 --- a/src/libsyntax_pos/span_encoding.rs +++ b/src/libsyntax_pos/span_encoding.rs @@ -100,7 +100,7 @@ const INTERNED_INDEX_OFFSET: u32 = 1; #[inline] fn encode(sd: &SpanData) -> Span { - let (base, len, ctxt) = (sd.lo.0, sd.hi.0 - sd.lo.0, sd.ctxt.0); + let (base, len, ctxt) = (sd.lo.0, sd.hi.0 - sd.lo.0, sd.ctxt.as_u32()); let val = if (base >> INLINE_SIZES[BASE_INDEX]) == 0 && (len >> INLINE_SIZES[LEN_INDEX]) == 0 && @@ -132,7 +132,7 @@ fn decode(span: Span) -> SpanData { let index = extract(INTERNED_INDEX_OFFSET, INTERNED_INDEX_SIZE); return with_span_interner(|interner| *interner.get(index)); }; - SpanData { lo: BytePos(base), hi: BytePos(base + len), ctxt: SyntaxContext(ctxt) } + SpanData { lo: BytePos(base), hi: BytePos(base + len), ctxt: SyntaxContext::from_u32(ctxt) } } #[derive(Default)] From e8442a8eb68f2b049b3670a9cf1cd9f7b45804f3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 30 Jun 2018 19:53:46 +0300 Subject: [PATCH 2/3] hygiene: Decouple transparencies from expansion IDs --- src/libproc_macro/lib.rs | 19 ++--- src/librustc_resolve/lib.rs | 8 +- src/librustc_resolve/macros.rs | 11 +-- src/libsyntax/ext/base.rs | 18 ++--- src/libsyntax_pos/hygiene.rs | 76 +++++++++++-------- .../proc-macro/auxiliary/generate-mod.rs | 28 +++++++ .../ui-fulldeps/proc-macro/generate-mod.rs | 21 +++++ .../proc-macro/generate-mod.stderr | 9 +++ 8 files changed, 122 insertions(+), 68 deletions(-) create mode 100644 src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs create mode 100644 src/test/ui-fulldeps/proc-macro/generate-mod.rs create mode 100644 src/test/ui-fulldeps/proc-macro/generate-mod.stderr diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index fb5cbf473a387..876cf295acc1b 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -1351,7 +1351,7 @@ pub mod __internal { use syntax::parse::token::{self, Token}; use syntax::tokenstream; use syntax_pos::{BytePos, Loc, DUMMY_SP}; - use syntax_pos::hygiene::{Mark, SyntaxContext, Transparency}; + use syntax_pos::hygiene::{SyntaxContext, Transparency}; use super::{TokenStream, LexError, Span}; @@ -1436,20 +1436,15 @@ pub mod __internal { // No way to determine def location for a proc macro right now, so use call location. let location = cx.current_expansion.mark.expn_info().unwrap().call_site; - // Opaque mark was already created by expansion, now create its transparent twin. - // We can't use the call-site span literally here, even if it appears to provide - // correct name resolution, because it has all the `ExpnInfo` wrong, so the edition - // checks, lint macro checks, macro backtraces will all break. - let opaque_mark = cx.current_expansion.mark; - let transparent_mark = Mark::fresh_cloned(opaque_mark); - transparent_mark.set_transparency(Transparency::Transparent); - - let to_span = |mark| Span(location.with_ctxt(SyntaxContext::empty().apply_mark(mark))); + let to_span = |transparency| Span(location.with_ctxt( + SyntaxContext::empty().apply_mark_with_transparency(cx.current_expansion.mark, + transparency)) + ); p.set(ProcMacroSess { parse_sess: cx.parse_sess, data: ProcMacroData { - def_site: to_span(opaque_mark), - call_site: to_span(transparent_mark), + def_site: to_span(Transparency::Opaque), + call_site: to_span(Transparency::Transparent), }, }); f() diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 9f36f888b581b..8d07cb4d7a8a7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1996,8 +1996,8 @@ impl<'a> Resolver<'a> { let mut iter = ctxt.marks().into_iter().rev().peekable(); let mut result = None; // Find the last modern mark from the end if it exists. - while let Some(&mark) = iter.peek() { - if mark.transparency() == Transparency::Opaque { + while let Some(&(mark, transparency)) = iter.peek() { + if transparency == Transparency::Opaque { result = Some(mark); iter.next(); } else { @@ -2005,8 +2005,8 @@ impl<'a> Resolver<'a> { } } // Then find the last legacy mark from the end if it exists. - for mark in iter { - if mark.transparency() == Transparency::SemiTransparent { + for (mark, transparency) in iter { + if transparency == Transparency::SemiTransparent { result = Some(mark); } else { break; diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 0523765ea1897..9ce1e21d0d03e 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -24,7 +24,7 @@ use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator}; use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver}; use syntax::ext::expand::{self, AstFragment, AstFragmentKind, Invocation, InvocationKind}; -use syntax::ext::hygiene::{self, Mark, Transparency}; +use syntax::ext::hygiene::{self, Mark}; use syntax::ext::placeholders::placeholder; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{self, emit_feature_err, GateIssue}; @@ -331,13 +331,8 @@ impl<'a> base::Resolver for Resolver<'a> { self.unused_macros.remove(&def_id); let ext = self.get_macro(def); - if ext.is_modern() { - let transparency = - if ext.is_transparent() { Transparency::Transparent } else { Transparency::Opaque }; - invoc.expansion_data.mark.set_transparency(transparency); - } else if def_id.krate == BUILTIN_MACROS_CRATE { - invoc.expansion_data.mark.set_is_builtin(true); - } + invoc.expansion_data.mark.set_default_transparency(ext.default_transparency()); + invoc.expansion_data.mark.set_is_builtin(def_id.krate == BUILTIN_MACROS_CRATE); Ok(Some(ext)) } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index e2424de4d1449..2e9c7d6f96c45 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -17,7 +17,7 @@ use syntax_pos::{Span, MultiSpan, DUMMY_SP}; use edition::Edition; use errors::{DiagnosticBuilder, DiagnosticId}; use ext::expand::{self, AstFragment, Invocation}; -use ext::hygiene::{self, Mark, SyntaxContext}; +use ext::hygiene::{self, Mark, SyntaxContext, Transparency}; use fold::{self, Folder}; use parse::{self, parser, DirectoryOwnership}; use parse::token; @@ -673,20 +673,14 @@ impl SyntaxExtension { } } - pub fn is_modern(&self) -> bool { + pub fn default_transparency(&self) -> Transparency { match *self { - SyntaxExtension::DeclMacro { .. } | SyntaxExtension::ProcMacro { .. } | SyntaxExtension::AttrProcMacro(..) | - SyntaxExtension::ProcMacroDerive(..) => true, - _ => false, - } - } - - pub fn is_transparent(&self) -> bool { - match *self { - SyntaxExtension::DeclMacro { is_transparent, .. } => is_transparent, - _ => false, + SyntaxExtension::ProcMacroDerive(..) | + SyntaxExtension::DeclMacro { is_transparent: false, .. } => Transparency::Opaque, + SyntaxExtension::DeclMacro { is_transparent: true, .. } => Transparency::Transparent, + _ => Transparency::SemiTransparent, } } diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index ff23c2fb534d5..385174ea7fea7 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -32,6 +32,7 @@ pub struct SyntaxContext(u32); #[derive(Copy, Clone, Debug)] struct SyntaxContextData { outer_mark: Mark, + transparency: Transparency, prev_ctxt: SyntaxContext, // This context, but with all transparent and semi-transparent marks filtered away. opaque: SyntaxContext, @@ -46,14 +47,14 @@ pub struct Mark(u32); #[derive(Clone, Debug)] struct MarkData { parent: Mark, - transparency: Transparency, + default_transparency: Transparency, is_builtin: bool, expn_info: Option, } /// A property of a macro expansion that determines how identifiers /// produced by that expansion are resolved. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug)] pub enum Transparency { /// Identifier produced by a transparent expansion is always resolved at call-site. /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this. @@ -81,7 +82,7 @@ impl Mark { Mark::fresh_with_data(MarkData { parent, // By default expansions behave like `macro_rules`. - transparency: Transparency::SemiTransparent, + default_transparency: Transparency::SemiTransparent, is_builtin: false, expn_info: None, }, data) @@ -127,9 +128,11 @@ impl Mark { }) } + // FIXME: This operation doesn't really make sense when single macro expansion + // can produce tokens with different transparencies. Figure out how to avoid it. pub fn modern(mut self) -> Mark { HygieneData::with(|data| { - while data.marks[self.0 as usize].transparency != Transparency::Opaque { + while data.marks[self.0 as usize].default_transparency != Transparency::Opaque { self = data.marks[self.0 as usize].parent; } self @@ -137,24 +140,20 @@ impl Mark { } #[inline] - pub fn transparency(self) -> Transparency { - assert_ne!(self, Mark::root()); - HygieneData::with(|data| data.marks[self.0 as usize].transparency) - } - - #[inline] - pub fn set_transparency(self, transparency: Transparency) { + pub fn set_default_transparency(self, transparency: Transparency) { assert_ne!(self, Mark::root()); - HygieneData::with(|data| data.marks[self.0 as usize].transparency = transparency) + HygieneData::with(|data| data.marks[self.0 as usize].default_transparency = transparency) } #[inline] pub fn is_builtin(self) -> bool { + assert_ne!(self, Mark::root()); HygieneData::with(|data| data.marks[self.0 as usize].is_builtin) } #[inline] pub fn set_is_builtin(self, is_builtin: bool) { + assert_ne!(self, Mark::root()); HygieneData::with(|data| data.marks[self.0 as usize].is_builtin = is_builtin) } @@ -201,7 +200,7 @@ impl Mark { crate struct HygieneData { marks: Vec, syntax_contexts: Vec, - markings: HashMap<(SyntaxContext, Mark), SyntaxContext>, + markings: HashMap<(SyntaxContext, Mark, Transparency), SyntaxContext>, default_edition: Edition, } @@ -212,12 +211,13 @@ impl HygieneData { parent: Mark::root(), // If the root is opaque, then loops searching for an opaque mark // will automatically stop after reaching it. - transparency: Transparency::Opaque, + default_transparency: Transparency::Opaque, is_builtin: true, expn_info: None, }], syntax_contexts: vec![SyntaxContextData { outer_mark: Mark::root(), + transparency: Transparency::Opaque, prev_ctxt: SyntaxContext(0), opaque: SyntaxContext(0), opaque_and_semitransparent: SyntaxContext(0), @@ -267,7 +267,7 @@ impl SyntaxContext { HygieneData::with(|data| { data.marks.push(MarkData { parent: Mark::root(), - transparency: Transparency::SemiTransparent, + default_transparency: Transparency::SemiTransparent, is_builtin: false, expn_info: Some(expansion_info), }); @@ -276,6 +276,7 @@ impl SyntaxContext { data.syntax_contexts.push(SyntaxContextData { outer_mark: mark, + transparency: Transparency::SemiTransparent, prev_ctxt: SyntaxContext::empty(), opaque: SyntaxContext::empty(), opaque_and_semitransparent: SyntaxContext::empty(), @@ -284,22 +285,31 @@ impl SyntaxContext { }) } - /// Extend a syntax context with a given mark pub fn apply_mark(self, mark: Mark) -> SyntaxContext { - if mark.transparency() == Transparency::Opaque { - return self.apply_mark_internal(mark); + assert_ne!(mark, Mark::root()); + self.apply_mark_with_transparency( + mark, HygieneData::with(|data| data.marks[mark.0 as usize].default_transparency) + ) + } + + /// Extend a syntax context with a given mark and transparency + pub fn apply_mark_with_transparency(self, mark: Mark, transparency: Transparency) + -> SyntaxContext { + assert_ne!(mark, Mark::root()); + if transparency == Transparency::Opaque { + return self.apply_mark_internal(mark, transparency); } let call_site_ctxt = mark.expn_info().map_or(SyntaxContext::empty(), |info| info.call_site.ctxt()); - let call_site_ctxt = if mark.transparency() == Transparency::SemiTransparent { + let call_site_ctxt = if transparency == Transparency::SemiTransparent { call_site_ctxt.modern() } else { call_site_ctxt.modern_and_legacy() }; if call_site_ctxt == SyntaxContext::empty() { - return self.apply_mark_internal(mark); + return self.apply_mark_internal(mark, transparency); } // Otherwise, `mark` is a macros 1.0 definition and the call site is in a @@ -312,27 +322,26 @@ impl SyntaxContext { // // See the example at `test/run-pass/hygiene/legacy_interaction.rs`. let mut ctxt = call_site_ctxt; - for mark in self.marks() { - ctxt = ctxt.apply_mark_internal(mark); + for (mark, transparency) in self.marks() { + ctxt = ctxt.apply_mark_internal(mark, transparency); } - ctxt.apply_mark_internal(mark) + ctxt.apply_mark_internal(mark, transparency) } - fn apply_mark_internal(self, mark: Mark) -> SyntaxContext { + fn apply_mark_internal(self, mark: Mark, transparency: Transparency) -> SyntaxContext { HygieneData::with(|data| { let syntax_contexts = &mut data.syntax_contexts; - let transparency = data.marks[mark.0 as usize].transparency; - let mut opaque = syntax_contexts[self.0 as usize].opaque; let mut opaque_and_semitransparent = syntax_contexts[self.0 as usize].opaque_and_semitransparent; if transparency >= Transparency::Opaque { let prev_ctxt = opaque; - opaque = *data.markings.entry((prev_ctxt, mark)).or_insert_with(|| { + opaque = *data.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| { let new_opaque = SyntaxContext(syntax_contexts.len() as u32); syntax_contexts.push(SyntaxContextData { outer_mark: mark, + transparency, prev_ctxt, opaque: new_opaque, opaque_and_semitransparent: new_opaque, @@ -344,11 +353,12 @@ impl SyntaxContext { if transparency >= Transparency::SemiTransparent { let prev_ctxt = opaque_and_semitransparent; opaque_and_semitransparent = - *data.markings.entry((prev_ctxt, mark)).or_insert_with(|| { + *data.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| { let new_opaque_and_semitransparent = SyntaxContext(syntax_contexts.len() as u32); syntax_contexts.push(SyntaxContextData { outer_mark: mark, + transparency, prev_ctxt, opaque, opaque_and_semitransparent: new_opaque_and_semitransparent, @@ -358,11 +368,12 @@ impl SyntaxContext { } let prev_ctxt = self; - *data.markings.entry((prev_ctxt, mark)).or_insert_with(|| { + *data.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| { let new_opaque_and_semitransparent_and_transparent = SyntaxContext(syntax_contexts.len() as u32); syntax_contexts.push(SyntaxContextData { outer_mark: mark, + transparency, prev_ctxt, opaque, opaque_and_semitransparent, @@ -396,12 +407,13 @@ impl SyntaxContext { }) } - pub fn marks(mut self) -> Vec { + pub fn marks(mut self) -> Vec<(Mark, Transparency)> { HygieneData::with(|data| { let mut marks = Vec::new(); while self != SyntaxContext::empty() { - marks.push(data.syntax_contexts[self.0 as usize].outer_mark); - self = data.syntax_contexts[self.0 as usize].prev_ctxt; + let ctxt_data = &data.syntax_contexts[self.0 as usize]; + marks.push((ctxt_data.outer_mark, ctxt_data.transparency)); + self = ctxt_data.prev_ctxt; } marks.reverse(); marks diff --git a/src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs b/src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs new file mode 100644 index 0000000000000..1741b0eed8927 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs @@ -0,0 +1,28 @@ +// Copyright 2016 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. + +// run-pass +// no-prefer-dynamic + +#![feature(proc_macro)] +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro] +pub fn check(_: TokenStream) -> TokenStream { + " + struct Outer; + mod inner { + type Inner = Outer; // `Outer` shouldn't be available from here + } + ".parse().unwrap() +} diff --git a/src/test/ui-fulldeps/proc-macro/generate-mod.rs b/src/test/ui-fulldeps/proc-macro/generate-mod.rs new file mode 100644 index 0000000000000..509cd33d93d34 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/generate-mod.rs @@ -0,0 +1,21 @@ +// 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. + +// Modules generated by transparent proc macros still acts as barriers for names (issue #50504). + +// aux-build:generate-mod.rs + +#![feature(proc_macro, proc_macro_gen)] + +extern crate generate_mod; + +generate_mod::check!(); //~ ERROR cannot find type `Outer` in this scope + +fn main() {} diff --git a/src/test/ui-fulldeps/proc-macro/generate-mod.stderr b/src/test/ui-fulldeps/proc-macro/generate-mod.stderr new file mode 100644 index 0000000000000..80213b04dceb0 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/generate-mod.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `Outer` in this scope + --> $DIR/generate-mod.rs:19:1 + | +LL | generate_mod::check!(); //~ ERROR cannot find type `Outer` in this scope + | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. From e0c3ee5118af792dc8ba75c47cd93dbfe3ac9e4b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 30 Jun 2018 22:28:24 +0300 Subject: [PATCH 3/3] hygiene: Invert default transparency for procedural macros --- src/libsyntax/ext/base.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 2e9c7d6f96c45..1181bc3bb5d02 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -678,8 +678,8 @@ impl SyntaxExtension { SyntaxExtension::ProcMacro { .. } | SyntaxExtension::AttrProcMacro(..) | SyntaxExtension::ProcMacroDerive(..) | - SyntaxExtension::DeclMacro { is_transparent: false, .. } => Transparency::Opaque, SyntaxExtension::DeclMacro { is_transparent: true, .. } => Transparency::Transparent, + SyntaxExtension::DeclMacro { is_transparent: false, .. } => Transparency::Opaque, _ => Transparency::SemiTransparent, } }