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/hir/def.rs b/src/librustc/hir/def.rs index 7c10292061f75..7a26a239aeffa 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -129,6 +129,16 @@ pub enum Namespace { MacroNS, } +impl Namespace { + pub fn descr(self) -> &'static str { + match self { + TypeNS => "type", + ValueNS => "value", + MacroNS => "macro", + } + } +} + /// Just a helper ‒ separate structure for each namespace. #[derive(Copy, Clone, Default, Debug)] pub struct PerNS { diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 328cb8225478b..49a4a1b78a1a8 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -153,6 +153,7 @@ impl Decodable for DefPathTable { /// The definition table containing node definitions. /// It holds the DefPathTable for local DefIds/DefPaths and it also stores a /// mapping from NodeIds to local DefIds. +#[derive(Clone)] pub struct Definitions { table: DefPathTable, node_to_def_index: NodeMap, @@ -161,34 +162,12 @@ pub struct Definitions { /// If `Mark` is an ID of some macro expansion, /// then `DefId` is the normal module (`mod`) in which the expanded macro was defined. parent_modules_of_macro_defs: FxHashMap, - /// Item with a given `DefIndex` was defined during opaque macro expansion with ID `Mark`. - /// It can actually be defined during transparent macro expansions inside that opaque expansion, - /// but transparent expansions are ignored here. - opaque_expansions_that_defined: FxHashMap, + /// Item with a given `DefIndex` was defined during macro expansion with ID `Mark`. + expansions_that_defined: FxHashMap, next_disambiguator: FxHashMap<(DefIndex, DefPathData), u32>, def_index_to_span: FxHashMap, } -// Unfortunately we have to provide a manual impl of Clone because of the -// fixed-sized array field. -impl Clone for Definitions { - fn clone(&self) -> Self { - Definitions { - table: self.table.clone(), - node_to_def_index: self.node_to_def_index.clone(), - def_index_to_node: [ - self.def_index_to_node[0].clone(), - self.def_index_to_node[1].clone(), - ], - node_to_hir_id: self.node_to_hir_id.clone(), - parent_modules_of_macro_defs: self.parent_modules_of_macro_defs.clone(), - opaque_expansions_that_defined: self.opaque_expansions_that_defined.clone(), - next_disambiguator: self.next_disambiguator.clone(), - def_index_to_span: self.def_index_to_span.clone(), - } - } -} - /// A unique identifier that we can use to lookup a definition /// precisely. It combines the index of the definition's parent (if /// any) with a `DisambiguatedDefPathData`. @@ -409,7 +388,7 @@ impl Definitions { def_index_to_node: [vec![], vec![]], node_to_hir_id: IndexVec::new(), parent_modules_of_macro_defs: FxHashMap(), - opaque_expansions_that_defined: FxHashMap(), + expansions_that_defined: FxHashMap(), next_disambiguator: FxHashMap(), def_index_to_span: FxHashMap(), } @@ -584,9 +563,8 @@ impl Definitions { self.node_to_def_index.insert(node_id, index); } - let expansion = expansion.modern(); if expansion != Mark::root() { - self.opaque_expansions_that_defined.insert(index, expansion); + self.expansions_that_defined.insert(index, expansion); } // The span is added if it isn't dummy @@ -606,8 +584,8 @@ impl Definitions { self.node_to_hir_id = mapping; } - pub fn opaque_expansion_that_defined(&self, index: DefIndex) -> Mark { - self.opaque_expansions_that_defined.get(&index).cloned().unwrap_or(Mark::root()) + pub fn expansion_that_defined(&self, index: DefIndex) -> Mark { + self.expansions_that_defined.get(&index).cloned().unwrap_or(Mark::root()) } pub fn parent_module_of_macro_def(&self, mark: Mark) -> DefId { diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index a6bbd93750575..efc2d9311c1dc 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -316,6 +316,12 @@ declare_lint! { "checks the object safety of where clauses" } +declare_lint! { + pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + Warn, + "detects proc macro derives using inaccessible names from parent modules" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -372,6 +378,7 @@ impl LintPass for HardwiredLints { DUPLICATE_MACRO_EXPORTS, INTRA_DOC_LINK_RESOLUTION_FAILURE, WHERE_CLAUSES_OBJECT_SAFETY, + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, ) } } @@ -384,6 +391,7 @@ pub enum BuiltinLintDiagnostics { BareTraitObject(Span, /* is_global */ bool), AbsPathWithModule(Span), DuplicatedMacroExports(ast::Ident, Span, Span), + ProcMacroDeriveResolutionFallback(Span), } impl BuiltinLintDiagnostics { @@ -420,6 +428,10 @@ impl BuiltinLintDiagnostics { db.span_label(later_span, format!("`{}` already exported", ident)); db.span_note(earlier_span, "previous macro export is now shadowed"); } + BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(span) => { + db.span_label(span, "names from parent modules are not \ + accessible without an explicit import"); + } } } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 98042f6389db6..4a76cc683f680 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2724,7 +2724,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn adjust_ident(self, mut ident: Ident, scope: DefId, block: NodeId) -> (Ident, DefId) { ident = ident.modern(); let target_expansion = match scope.krate { - LOCAL_CRATE => self.hir.definitions().opaque_expansion_that_defined(scope.index), + LOCAL_CRATE => self.hir.definitions().expansion_that_defined(scope.index), _ => Mark::root(), }; let scope = match ident.span.adjust(target_expansion) { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index adc700506ffc0..27e51ad8961df 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -293,6 +293,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { reference: "issue #50589 ", edition: None, }, + FutureIncompatibleInfo { + id: LintId::of(PROC_MACRO_DERIVE_RESOLUTION_FALLBACK), + reference: "issue #50504 ", + edition: None, + }, ]); // Register renamed and removed lints diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b8dfd21e54076..ad63a43fead5c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -55,7 +55,7 @@ use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit::{self, FnKind, Visitor}; use syntax::attr; -use syntax::ast::{Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind}; +use syntax::ast::{CRATE_NODE_ID, Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind}; use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics}; use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path}; @@ -1891,7 +1891,12 @@ impl<'a> Resolver<'a> { ident.span = ident.span.modern(); loop { - module = unwrap_or!(self.hygienic_lexical_parent(module, &mut ident.span), break); + let (opt_module, poisoned) = if record_used { + self.hygienic_lexical_parent_with_compatibility_fallback(module, &mut ident.span) + } else { + (self.hygienic_lexical_parent(module, &mut ident.span), false) + }; + module = unwrap_or!(opt_module, 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( @@ -1900,7 +1905,19 @@ impl<'a> Resolver<'a> { self.current_module = orig_current_module; match result { - Ok(binding) => return Some(LexicalScopeBinding::Item(binding)), + Ok(binding) => { + if poisoned { + self.session.buffer_lint_with_diagnostic( + lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + CRATE_NODE_ID, ident.span, + &format!("cannot find {} `{}` in this scope", ns.descr(), ident), + lint::builtin::BuiltinLintDiagnostics:: + ProcMacroDeriveResolutionFallback(ident.span), + ); + } + return Some(LexicalScopeBinding::Item(binding)) + } + _ if poisoned => break, Err(Undetermined) => return None, Err(Determined) => {} } @@ -1935,7 +1952,7 @@ impl<'a> Resolver<'a> { None } - fn hygienic_lexical_parent(&mut self, mut module: Module<'a>, span: &mut Span) + fn hygienic_lexical_parent(&mut self, module: Module<'a>, span: &mut Span) -> Option> { if !module.expansion.is_descendant_of(span.ctxt().outer()) { return Some(self.macro_def_scope(span.remove_mark())); @@ -1945,22 +1962,41 @@ impl<'a> Resolver<'a> { return Some(module.parent.unwrap()); } - let mut module_expansion = module.expansion.modern(); // for backward compatibility - 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(span.ctxt().outer()) { - Some(parent) - } else { - None - }; + None + } + + fn hygienic_lexical_parent_with_compatibility_fallback( + &mut self, module: Module<'a>, span: &mut Span) -> (Option>, /* poisoned */ bool + ) { + if let module @ Some(..) = self.hygienic_lexical_parent(module, span) { + return (module, false); + } + + // We need to support the next case under a deprecation warning + // ``` + // struct MyStruct; + // ---- begin: this comes from a proc macro derive + // mod implementation_details { + // // Note that `MyStruct` is not in scope here. + // impl SomeTrait for MyStruct { ... } + // } + // ---- end + // ``` + // So we have to fall back to the module's parent during lexical resolution in this case. + if let Some(parent) = module.parent { + // Inner module is inside the macro, parent module is outside of the macro. + if module.expansion != parent.expansion && + module.expansion.is_descendant_of(parent.expansion) { + // The macro is a proc macro derive + if module.expansion.looks_like_proc_macro_derive() { + if parent.expansion.is_descendant_of(span.ctxt().outer()) { + return (module.parent, true); + } + } } - module = parent; - module_expansion = parent_expansion; } - None + (None, false) } fn resolve_ident_in_module(&mut self, @@ -1996,8 +2032,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 +2041,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; @@ -4037,8 +4073,9 @@ impl<'a> Resolver<'a> { let mut search_module = self.current_module; loop { self.get_traits_in_module_containing_item(ident, ns, search_module, &mut found_traits); - search_module = - unwrap_or!(self.hygienic_lexical_parent(search_module, &mut ident.span), break); + search_module = unwrap_or!( + self.hygienic_lexical_parent(search_module, &mut ident.span), break + ); } if let Some(prelude) = self.prelude { @@ -4395,12 +4432,6 @@ impl<'a> Resolver<'a> { (TypeNS, _) => "type", }; - let namespace = match ns { - ValueNS => "value", - MacroNS => "macro", - TypeNS => "type", - }; - let msg = format!("the name `{}` is defined multiple times", name); let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) { @@ -4418,7 +4449,7 @@ impl<'a> Resolver<'a> { err.note(&format!("`{}` must be defined only once in the {} namespace of this {}", name, - namespace, + ns.descr(), container)); err.span_label(span, format!("`{}` re{} here", name, new_participle)); 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 33d02d0b10a7b..c7076478332f4 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -27,16 +27,17 @@ 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, + transparency: Transparency, + 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. @@ -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. @@ -71,26 +72,16 @@ pub enum Transparency { } impl Mark { - fn fresh_with_data(mark_data: MarkData, data: &mut HygieneData) -> Self { - data.marks.push(mark_data); - Mark(data.marks.len() as u32 - 1) - } - pub fn fresh(parent: Mark) -> Self { HygieneData::with(|data| { - Mark::fresh_with_data(MarkData { + data.marks.push(MarkData { parent, // By default expansions behave like `macro_rules`. - transparency: Transparency::SemiTransparent, + default_transparency: Transparency::SemiTransparent, is_builtin: false, expn_info: None, - }, data) - }) - } - - pub fn fresh_cloned(clone_from: Mark) -> Self { - HygieneData::with(|data| { - Mark::fresh_with_data(data.marks[clone_from.0 as usize].clone(), data) + }); + Mark(data.marks.len() as u32 - 1) }) } @@ -127,34 +118,21 @@ impl Mark { }) } - pub fn modern(mut self) -> Mark { - HygieneData::with(|data| { - while data.marks[self.0 as usize].transparency != Transparency::Opaque { - self = data.marks[self.0 as usize].parent; - } - self - }) - } - - #[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) } @@ -195,29 +173,48 @@ impl Mark { b }) } + + // Used for enabling some compatibility fallback in resolve. + #[inline] + pub fn looks_like_proc_macro_derive(self) -> bool { + HygieneData::with(|data| { + let mark_data = &data.marks[self.0 as usize]; + if mark_data.default_transparency == Transparency::Opaque { + if let Some(expn_info) = &mark_data.expn_info { + if let ExpnFormat::MacroAttribute(name) = expn_info.format { + if name.as_str().starts_with("derive(") { + return true; + } + } + } + } + false + }) + } } #[derive(Debug)] -pub struct HygieneData { +crate struct HygieneData { marks: Vec, syntax_contexts: Vec, - markings: HashMap<(SyntaxContext, Mark), SyntaxContext>, + markings: HashMap<(SyntaxContext, Mark, Transparency), SyntaxContext>, default_edition: Edition, } impl HygieneData { - pub fn new() -> Self { + crate fn new() -> Self { HygieneData { marks: vec![MarkData { 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), @@ -249,6 +246,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 @@ -259,7 +264,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), }); @@ -268,6 +273,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(), @@ -276,22 +282,32 @@ impl SyntaxContext { }) } - /// Extend a syntax context with a given mark + /// Extend a syntax context with a given mark and default transparency for that 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 @@ -304,27 +320,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, @@ -336,11 +351,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, @@ -350,11 +366,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, @@ -388,12 +405,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/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)] 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..6a8d545db49b9 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/auxiliary/generate-mod.rs @@ -0,0 +1,54 @@ +// 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 { + " + type Alias = FromOutside; // OK + struct Outer; + mod inner { + type Alias = FromOutside; // `FromOutside` shouldn't be available from here + type Inner = Outer; // `Outer` shouldn't be available from here + } + ".parse().unwrap() +} + +#[proc_macro_attribute] +pub fn check_attr(_: TokenStream, _: TokenStream) -> TokenStream { + " + type AliasAttr = FromOutside; // OK + struct OuterAttr; + mod inner_attr { + type Alias = FromOutside; // `FromOutside` shouldn't be available from here + type Inner = OuterAttr; // `OuterAttr` shouldn't be available from here + } + ".parse().unwrap() +} + +#[proc_macro_derive(CheckDerive)] +pub fn check_derive(_: TokenStream) -> TokenStream { + " + type AliasDerive = FromOutside; // OK + struct OuterDerive; + mod inner_derive { + type Alias = FromOutside; // `FromOutside` shouldn't be available from here + type Inner = OuterDerive; // `OuterDerive` 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..ff64421047fb8 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/generate-mod.rs @@ -0,0 +1,34 @@ +// 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, proc_macro_path_invoc)] + +extern crate generate_mod; + +struct FromOutside; + +generate_mod::check!(); //~ ERROR cannot find type `FromOutside` in this scope + //~| ERROR cannot find type `Outer` in this scope + +#[generate_mod::check_attr] //~ ERROR cannot find type `FromOutside` in this scope + //~| ERROR cannot find type `OuterAttr` in this scope +struct S; + +#[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope + //~| WARN cannot find type `OuterDerive` in this scope + //~| WARN this was previously accepted + //~| WARN this was previously accepted +struct Z; + +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..c024aeffbb086 --- /dev/null +++ b/src/test/ui-fulldeps/proc-macro/generate-mod.stderr @@ -0,0 +1,46 @@ +error[E0412]: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:21:1 + | +LL | generate_mod::check!(); //~ ERROR cannot find type `FromOutside` in this scope + | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `Outer` in this scope + --> $DIR/generate-mod.rs:21:1 + | +LL | generate_mod::check!(); //~ ERROR cannot find type `FromOutside` in this scope + | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:24:1 + | +LL | #[generate_mod::check_attr] //~ ERROR cannot find type `FromOutside` in this scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `OuterAttr` in this scope + --> $DIR/generate-mod.rs:24:1 + | +LL | #[generate_mod::check_attr] //~ ERROR cannot find type `FromOutside` in this scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + +warning: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:28:10 + | +LL | #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = note: #[warn(proc_macro_derive_resolution_fallback)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #50504 + +warning: cannot find type `OuterDerive` in this scope + --> $DIR/generate-mod.rs:28:10 + | +LL | #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope + | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #50504 + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/run-pass/hygiene/arguments.rs b/src/test/ui/hygiene/arguments.rs similarity index 92% rename from src/test/run-pass/hygiene/arguments.rs rename to src/test/ui/hygiene/arguments.rs index 5d9e1863847da..958133e7ec589 100644 --- a/src/test/run-pass/hygiene/arguments.rs +++ b/src/test/ui/hygiene/arguments.rs @@ -23,5 +23,5 @@ macro m($t:ty, $e:expr) { fn main() { struct S; - m!(S, S); + m!(S, S); //~ ERROR cannot find type `S` in this scope } diff --git a/src/test/ui/hygiene/arguments.stderr b/src/test/ui/hygiene/arguments.stderr new file mode 100644 index 0000000000000..1b0c23eff297e --- /dev/null +++ b/src/test/ui/hygiene/arguments.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `S` in this scope + --> $DIR/arguments.rs:26:8 + | +LL | m!(S, S); //~ ERROR cannot find type `S` in this scope + | ^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/hygiene/generate-mod.rs b/src/test/ui/hygiene/generate-mod.rs index 90409857deadc..2b2108558a0f3 100644 --- a/src/test/ui/hygiene/generate-mod.rs +++ b/src/test/ui/hygiene/generate-mod.rs @@ -12,13 +12,46 @@ #![feature(decl_macro, rustc_attrs)] +macro genmod($FromOutside: ident, $Outer: ident) { + type A = $FromOutside; + struct $Outer; + mod inner { + type A = $FromOutside; // `FromOutside` shouldn't be available from here + type Inner = $Outer; // `Outer` shouldn't be available from here + } +} + #[rustc_transparent_macro] -macro genmod() { - mod m { - type A = S; //~ ERROR cannot find type `S` in this scope +macro genmod_transparent() { + type A = FromOutside; + struct Outer; + mod inner { + type A = FromOutside; //~ ERROR cannot find type `FromOutside` in this scope + type Inner = Outer; //~ ERROR cannot find type `Outer` in this scope } } -struct S; +macro_rules! genmod_legacy { () => { + type A = FromOutside; + struct Outer; + mod inner { + type A = FromOutside; //~ ERROR cannot find type `FromOutside` in this scope + type Inner = Outer; //~ ERROR cannot find type `Outer` in this scope + } +}} -genmod!(); +fn check() { + struct FromOutside; + genmod!(FromOutside, Outer); //~ ERROR cannot find type `FromOutside` in this scope + //~| ERROR cannot find type `Outer` in this scope +} + +fn check_transparent() { + struct FromOutside; + genmod_transparent!(); +} + +fn check_legacy() { + struct FromOutside; + genmod_legacy!(); +} diff --git a/src/test/ui/hygiene/generate-mod.stderr b/src/test/ui/hygiene/generate-mod.stderr index e79f8528c2cd7..0c5905c5acb4f 100644 --- a/src/test/ui/hygiene/generate-mod.stderr +++ b/src/test/ui/hygiene/generate-mod.stderr @@ -1,17 +1,56 @@ -error[E0412]: cannot find type `S` in this scope - --> $DIR/generate-mod.rs:18:18 +error[E0412]: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:45:13 | -LL | type A = S; //~ ERROR cannot find type `S` in this scope - | ^ did you mean `A`? +LL | genmod!(FromOutside, Outer); //~ ERROR cannot find type `FromOutside` in this scope + | ^^^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `Outer` in this scope + --> $DIR/generate-mod.rs:45:26 + | +LL | genmod!(FromOutside, Outer); //~ ERROR cannot find type `FromOutside` in this scope + | ^^^^^ not found in this scope + +error[E0412]: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:29:18 + | +LL | type A = FromOutside; //~ ERROR cannot find type `FromOutside` in this scope + | ^^^^^^^^^^^ not found in this scope +... +LL | genmod_transparent!(); + | ---------------------- in this macro invocation + +error[E0412]: cannot find type `Outer` in this scope + --> $DIR/generate-mod.rs:30:22 + | +LL | type Inner = Outer; //~ ERROR cannot find type `Outer` in this scope + | ^^^^^ not found in this scope +... +LL | genmod_transparent!(); + | ---------------------- in this macro invocation + +error[E0412]: cannot find type `FromOutside` in this scope + --> $DIR/generate-mod.rs:38:18 + | +LL | type A = FromOutside; //~ ERROR cannot find type `FromOutside` in this scope + | ^^^^^^^^^^^ not found in this scope +... +LL | genmod_legacy!(); + | ----------------- in this macro invocation + +error[E0412]: cannot find type `Outer` in this scope + --> $DIR/generate-mod.rs:39:22 + | +LL | type Inner = Outer; //~ ERROR cannot find type `Outer` in this scope + | ^^^^^ not found in this scope ... -LL | genmod!(); - | ---------- in this macro invocation +LL | genmod_legacy!(); + | ----------------- in this macro invocation error[E0601]: `main` function not found in crate `generate_mod` | = note: consider adding a `main` function to `$DIR/generate-mod.rs` -error: aborting due to 2 previous errors +error: aborting due to 7 previous errors Some errors occurred: E0412, E0601. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/hygiene/globs.rs b/src/test/ui/hygiene/globs.rs index 7ba217061c66e..9785ce6c0048e 100644 --- a/src/test/ui/hygiene/globs.rs +++ b/src/test/ui/hygiene/globs.rs @@ -57,12 +57,26 @@ macro n($i:ident) { } } } + macro n_with_super($j:ident) { + mod test { + use super::*; + fn g() { + let _: u32 = $i(); + let _: () = f(); + super::$j(); + } + } + } - n!(f); + n!(f); //~ ERROR cannot find function `f` in this scope + n_with_super!(f); mod test2 { super::n! { f //~ ERROR cannot find function `f` in this scope } + super::n_with_super! { + f + } } } } diff --git a/src/test/ui/hygiene/globs.stderr b/src/test/ui/hygiene/globs.stderr index d77242e135dde..7df2e31f9a752 100644 --- a/src/test/ui/hygiene/globs.stderr +++ b/src/test/ui/hygiene/globs.stderr @@ -30,13 +30,23 @@ LL | use bar::g; | LL | use foo::test2::test::g; | -LL | use foo::test::g; +LL | use foo::test2::test::g; | LL | use foo::test::g; | +and 2 other candidates + +error[E0425]: cannot find function `f` in this scope + --> $DIR/globs.rs:71:12 + | +LL | n!(f); + | ------ in this macro invocation +... +LL | n!(f); //~ ERROR cannot find function `f` in this scope + | ^ not found in this scope error[E0425]: cannot find function `f` in this scope - --> $DIR/globs.rs:64:17 + --> $DIR/globs.rs:75:17 | LL | n!(f); | ------ in this macro invocation @@ -44,6 +54,6 @@ LL | n!(f); LL | f //~ ERROR cannot find function `f` in this scope | ^ not found in this scope -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0425`.