diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 3baafee46125d..4eaee7bf6e854 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1935,7 +1935,7 @@ declare_lint! { Warn, "detects proc macro derives using inaccessible names from parent modules", @future_incompatible = FutureIncompatibleInfo { - reference: "issue #50504 ", + reference: "issue #83583 ", edition: None, }; } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d402fa4f8494f..327beca218e1d 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -606,7 +606,7 @@ impl<'a> Resolver<'a> { /// Lookup typo candidate in scope for a macro or import. fn early_lookup_typo_candidate( &mut self, - scope_set: ScopeSet, + scope_set: ScopeSet<'a>, parent_scope: &ParentScope<'a>, ident: Ident, filter_fn: &impl Fn(Res) -> bool, @@ -662,7 +662,7 @@ impl<'a> Resolver<'a> { let root_module = this.resolve_crate_root(root_ident); this.add_module_candidates(root_module, &mut suggestions, filter_fn); } - Scope::Module(module) => { + Scope::Module(module, _) => { this.add_module_candidates(module, &mut suggestions, filter_fn); } Scope::RegisteredAttrs => { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8210da7b6ce3c..fe5078f26bd98 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -26,7 +26,6 @@ use Determinacy::*; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; use rustc_ast::ptr::P; -use rustc_ast::unwrap_or; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, NodeId}; use rustc_ast::{Crate, CRATE_NODE_ID}; @@ -43,7 +42,7 @@ use rustc_hir::def::Namespace::*; use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; -use rustc_hir::{PrimTy, TraitCandidate}; +use rustc_hir::TraitCandidate; use rustc_index::vec::IndexVec; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::hir::exports::ExportMap; @@ -109,7 +108,9 @@ enum Scope<'a> { DeriveHelpersCompat, MacroRules(MacroRulesScopeRef<'a>), CrateRoot, - Module(Module<'a>), + // The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` + // lint if it should be reported. + Module(Module<'a>, Option), RegisteredAttrs, MacroUsePrelude, BuiltinAttrs, @@ -123,13 +124,17 @@ enum Scope<'a> { /// with different restrictions when looking up the resolution. /// This enum is currently used only for early resolution (imports and macros), /// but not for late resolution yet. -enum ScopeSet { +#[derive(Clone, Copy)] +enum ScopeSet<'a> { /// All scopes with the given namespace. All(Namespace, /*is_import*/ bool), /// Crate root, then extern prelude (used for mixed 2015-2018 mode in macros). AbsolutePath(Namespace), /// All scopes with macro namespace and the given macro kind restriction. Macro(MacroKind), + /// All scopes with the given namespace, used for partially performing late resolution. + /// The node id enables lints and is used for reporting them. + Late(Namespace, Module<'a>, Option), } /// Everything you need to know about a name's location to resolve it. @@ -1467,7 +1472,7 @@ impl<'a> Resolver<'a> { self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| { match scope { - Scope::Module(module) => { + Scope::Module(module, _) => { this.traits_in_module(module, assoc_item, &mut found_traits); } Scope::StdLibPrelude => { @@ -1631,7 +1636,7 @@ impl<'a> Resolver<'a> { /// If the callback returns `Some` result, we stop visiting scopes and return it. fn visit_scopes( &mut self, - scope_set: ScopeSet, + scope_set: ScopeSet<'a>, parent_scope: &ParentScope<'a>, ctxt: SyntaxContext, mut visitor: impl FnMut( @@ -1687,12 +1692,17 @@ impl<'a> Resolver<'a> { ScopeSet::All(ns, _) => (ns, None, false), ScopeSet::AbsolutePath(ns) => (ns, None, true), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false), + ScopeSet::Late(ns, ..) => (ns, None, false), + }; + let module = match scope_set { + // Start with the specified module. + ScopeSet::Late(_, module, _) => module, + // Jump out of trait or enum modules, they do not act as scopes. + _ => parent_scope.module.nearest_item_scope(), }; - // Jump out of trait or enum modules, they do not act as scopes. - let module = parent_scope.module.nearest_item_scope(); let mut scope = match ns { _ if is_absolute_path => Scope::CrateRoot, - TypeNS | ValueNS => Scope::Module(module), + TypeNS | ValueNS => Scope::Module(module, None), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), }; let mut ctxt = ctxt.normalize_to_macros_2_0(); @@ -1757,7 +1767,7 @@ impl<'a> Resolver<'a> { MacroRulesScope::Invocation(invoc_id) => { Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) } - MacroRulesScope::Empty => Scope::Module(module), + MacroRulesScope::Empty => Scope::Module(module, None), }, Scope::CrateRoot => match ns { TypeNS => { @@ -1766,10 +1776,16 @@ impl<'a> Resolver<'a> { } ValueNS | MacroNS => break, }, - Scope::Module(module) => { + Scope::Module(module, prev_lint_id) => { use_prelude = !module.no_implicit_prelude; - match self.hygienic_lexical_parent(module, &mut ctxt) { - Some(parent_module) => Scope::Module(parent_module), + let derive_fallback_lint_id = match scope_set { + ScopeSet::Late(.., lint_id) => lint_id, + _ => None, + }; + match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) { + Some((parent_module, lint_id)) => { + Scope::Module(parent_module, lint_id.or(prev_lint_id)) + } None => { ctxt.adjust(ExpnId::root()); match ns { @@ -1825,6 +1841,7 @@ impl<'a> Resolver<'a> { ribs: &[Rib<'a>], ) -> Option> { assert!(ns == TypeNS || ns == ValueNS); + let orig_ident = ident; if ident.name == kw::Empty { return Some(LexicalScopeBinding::Res(Res::Err)); } @@ -1874,135 +1891,49 @@ impl<'a> Resolver<'a> { _ => continue, }; - let item = self.resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(module), - ident, - ns, - parent_scope, - record_used, - path_span, - ); - if let Ok(binding) = item { - // The ident resolves to an item. - return Some(LexicalScopeBinding::Item(binding)); - } - match module.kind { ModuleKind::Block(..) => {} // We can see through blocks _ => break, } - } - ident = normalized_ident; - let mut poisoned = None; - loop { - let mut span_data = ident.span.data(); - let opt_module = if let Some(node_id) = record_used_id { - self.hygienic_lexical_parent_with_compatibility_fallback( - module, - &mut span_data.ctxt, - node_id, - &mut poisoned, - ) - } else { - self.hygienic_lexical_parent(module, &mut span_data.ctxt) - }; - ident.span = span_data.span(); - module = unwrap_or!(opt_module, break); - let adjusted_parent_scope = &ParentScope { module, ..*parent_scope }; - let result = self.resolve_ident_in_module_unadjusted( + let item = self.resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, - adjusted_parent_scope, + parent_scope, record_used, path_span, ); - - match result { - Ok(binding) => { - if let Some(node_id) = poisoned { - self.lint_buffer.buffer_lint_with_diagnostic( - lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - node_id, - ident.span, - &format!("cannot find {} `{}` in this scope", ns.descr(), ident), - BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(ident.span), - ); - } - return Some(LexicalScopeBinding::Item(binding)); - } - Err(Determined) => continue, - Err(Undetermined) => { - span_bug!(ident.span, "undetermined resolution during main resolution pass") - } - } - } - - if !module.no_implicit_prelude { - ident.span.adjust(ExpnId::root()); - if ns == TypeNS { - if let Some(binding) = self.extern_prelude_get(ident, !record_used) { - return Some(LexicalScopeBinding::Item(binding)); - } - if let Some(ident) = self.registered_tools.get(&ident) { - let binding = - (Res::ToolMod, ty::Visibility::Public, ident.span, ExpnId::root()) - .to_name_binding(self.arenas); - return Some(LexicalScopeBinding::Item(binding)); - } - } - if let Some(prelude) = self.prelude { - if let Ok(binding) = self.resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(prelude), - ident, - ns, - parent_scope, - false, - path_span, - ) { - return Some(LexicalScopeBinding::Item(binding)); - } - } - } - - if ns == TypeNS { - if let Some(prim_ty) = PrimTy::from_name(ident.name) { - let binding = - (Res::PrimTy(prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root()) - .to_name_binding(self.arenas); + if let Ok(binding) = item { + // The ident resolves to an item. return Some(LexicalScopeBinding::Item(binding)); } } - None + self.early_resolve_ident_in_lexical_scope( + orig_ident, + ScopeSet::Late(ns, module, record_used_id), + parent_scope, + record_used, + record_used, + path_span, + ) + .ok() + .map(LexicalScopeBinding::Item) } fn hygienic_lexical_parent( &mut self, module: Module<'a>, ctxt: &mut SyntaxContext, - ) -> Option> { + derive_fallback_lint_id: Option, + ) -> Option<(Module<'a>, Option)> { if !module.expansion.outer_expn_is_descendant_of(*ctxt) { - return Some(self.macro_def_scope(ctxt.remove_mark())); + return Some((self.macro_def_scope(ctxt.remove_mark()), None)); } if let ModuleKind::Block(..) = module.kind { - return Some(module.parent.unwrap().nearest_item_scope()); - } - - None - } - - fn hygienic_lexical_parent_with_compatibility_fallback( - &mut self, - module: Module<'a>, - ctxt: &mut SyntaxContext, - node_id: NodeId, - poisoned: &mut Option, - ) -> Option> { - if let module @ Some(..) = self.hygienic_lexical_parent(module, ctxt) { - return module; + return Some((module.parent.unwrap().nearest_item_scope(), None)); } // We need to support the next case under a deprecation warning @@ -2016,20 +1947,21 @@ impl<'a> Resolver<'a> { // ---- 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 let Some(def_id) = module.expansion.expn_data().macro_def_id { - let ext = self.get_macro_by_def_id(def_id); - if ext.builtin_name.is_none() - && ext.macro_kind() == MacroKind::Derive - && parent.expansion.outer_expn_is_descendant_of(*ctxt) - { - *poisoned = Some(node_id); - return module.parent; + if derive_fallback_lint_id.is_some() { + 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 let Some(def_id) = module.expansion.expn_data().macro_def_id { + let ext = self.get_macro_by_def_id(def_id); + if ext.builtin_name.is_none() + && ext.macro_kind() == MacroKind::Derive + && parent.expansion.outer_expn_is_descendant_of(*ctxt) + { + return Some((parent, derive_fallback_lint_id)); + } } } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 2efce1e1984f3..d238f65c941af 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -24,7 +24,8 @@ use rustc_hir::def_id; use rustc_hir::PrimTy; use rustc_middle::middle::stability; use rustc_middle::ty; -use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNUSED_MACROS}; +use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK}; +use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::feature_err; use rustc_session::Session; @@ -642,7 +643,7 @@ impl<'a> Resolver<'a> { crate fn early_resolve_ident_in_lexical_scope( &mut self, orig_ident: Ident, - scope_set: ScopeSet, + scope_set: ScopeSet<'a>, parent_scope: &ParentScope<'a>, record_used: bool, force: bool, @@ -669,6 +670,7 @@ impl<'a> Resolver<'a> { ScopeSet::All(ns, is_import) => (ns, None, is_import), ScopeSet::AbsolutePath(ns) => (ns, None, false), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false), + ScopeSet::Late(ns, ..) => (ns, None, false), }; // This is *the* result, resolution from the scope closest to the resolved identifier. @@ -777,19 +779,34 @@ impl<'a> Resolver<'a> { Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), } } - Scope::Module(module) => { + Scope::Module(module, derive_fallback_lint_id) => { let adjusted_parent_scope = &ParentScope { module, ..*parent_scope }; let binding = this.resolve_ident_in_module_unadjusted_ext( ModuleOrUniformRoot::Module(module), ident, ns, adjusted_parent_scope, - true, + !matches!(scope_set, ScopeSet::Late(..)), record_used, path_span, ); match binding { Ok(binding) => { + if let Some(lint_id) = derive_fallback_lint_id { + this.lint_buffer.buffer_lint_with_diagnostic( + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + lint_id, + orig_ident.span, + &format!( + "cannot find {} `{}` in this scope", + ns.descr(), + ident + ), + BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback( + orig_ident.span, + ), + ); + } let misc_flags = if ptr::eq(module, this.graph_root) { Flags::MISC_SUGGEST_CRATE } else if module.is_normal() { @@ -873,7 +890,7 @@ impl<'a> Resolver<'a> { Ok((binding, flags)) if sub_namespace_match(binding.macro_kind(), macro_kind) => { - if !record_used { + if !record_used || matches!(scope_set, ScopeSet::Late(..)) { return Some(Ok(binding)); } diff --git a/src/test/ui/proc-macro/generate-mod.stderr b/src/test/ui/proc-macro/generate-mod.stderr index 9b946b5e2449e..5a4ed65ecdc8f 100644 --- a/src/test/ui/proc-macro/generate-mod.stderr +++ b/src/test/ui/proc-macro/generate-mod.stderr @@ -46,7 +46,8 @@ LL | #[derive(generate_mod::CheckDerive)] | = 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 + = note: for more information, see issue #83583 + = note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:16:10 @@ -55,7 +56,8 @@ LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ 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 + = note: for more information, see issue #83583 + = note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: cannot find type `FromOutside` in this scope --> $DIR/generate-mod.rs:23:14 @@ -64,7 +66,8 @@ LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ 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 + = note: for more information, see issue #83583 + = note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) warning: cannot find type `OuterDerive` in this scope --> $DIR/generate-mod.rs:23:14 @@ -73,7 +76,8 @@ LL | #[derive(generate_mod::CheckDerive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ 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 + = note: for more information, see issue #83583 + = note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors; 4 warnings emitted