From 9b80a6804e21baa60f7e1663b420dc2ef71ce7d7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 24 Mar 2025 14:39:35 +0000 Subject: [PATCH 1/5] Split trait item resolving into its own method --- compiler/rustc_resolve/src/late.rs | 160 +++++++++++++++-------------- 1 file changed, 82 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3337a4626b040..855c589e4bbe5 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3318,6 +3318,14 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let trait_assoc_items = replace(&mut self.diag_metadata.current_trait_assoc_items, Some(trait_items)); + for item in trait_items { + self.resolve_trait_item(item); + } + + self.diag_metadata.current_trait_assoc_items = trait_assoc_items; + } + + fn resolve_trait_item(&mut self, item: &'ast Item) { let walk_assoc_item = |this: &mut Self, generics: &Generics, kind, item: &'ast AssocItem| { this.with_generic_param_rib( @@ -3330,87 +3338,83 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); }; - for item in trait_items { - self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); - match &item.kind { - AssocItemKind::Const(box ast::ConstItem { - generics, - ty, - rhs_kind, - define_opaque, - .. - }) => { - self.with_generic_param_rib( - &generics.params, - RibKind::AssocItem, - item.id, - LifetimeBinderKind::ConstItem, - generics.span, - |this| { - this.with_lifetime_rib( - LifetimeRibKind::StaticIfNoLifetimeInScope { - lint_id: item.id, - emit_lint: false, - }, - |this| { - this.visit_generics(generics); - if rhs_kind.is_type_const() - && !this.r.tcx.features().generic_const_parameter_types() - { - this.with_rib(TypeNS, RibKind::ConstParamTy, |this| { - this.with_rib(ValueNS, RibKind::ConstParamTy, |this| { - this.with_lifetime_rib( - LifetimeRibKind::ConstParamTy, - |this| this.visit_ty(ty), - ) - }) - }); - } else { - this.visit_ty(ty); - } - - // Only impose the restrictions of `ConstRibKind` for an - // actual constant expression in a provided default. - // - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - this.resolve_const_item_rhs(rhs_kind, None); - }, - ) - }, - ); + self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id)); + match &item.kind { + AssocItemKind::Const(box ast::ConstItem { + generics, + ty, + rhs_kind, + define_opaque, + .. + }) => { + self.with_generic_param_rib( + &generics.params, + RibKind::AssocItem, + item.id, + LifetimeBinderKind::ConstItem, + generics.span, + |this| { + this.with_lifetime_rib( + LifetimeRibKind::StaticIfNoLifetimeInScope { + lint_id: item.id, + emit_lint: false, + }, + |this| { + this.visit_generics(generics); + if rhs_kind.is_type_const() + && !this.r.tcx.features().generic_const_parameter_types() + { + this.with_rib(TypeNS, RibKind::ConstParamTy, |this| { + this.with_rib(ValueNS, RibKind::ConstParamTy, |this| { + this.with_lifetime_rib( + LifetimeRibKind::ConstParamTy, + |this| this.visit_ty(ty), + ) + }) + }); + } else { + this.visit_ty(ty); + } - self.resolve_define_opaques(define_opaque); - } - AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => { - walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); + // Only impose the restrictions of `ConstRibKind` for an + // actual constant expression in a provided default. + // + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + this.resolve_const_item_rhs(rhs_kind, None); + }, + ) + }, + ); - self.resolve_define_opaques(define_opaque); - } - AssocItemKind::Delegation(delegation) => { - self.with_generic_param_rib( - &[], - RibKind::AssocItem, - item.id, - LifetimeBinderKind::Function, - delegation.path.segments.last().unwrap().ident.span, - |this| this.resolve_delegation(delegation, item.id, false), - ); - } - AssocItemKind::Type(box TyAlias { generics, .. }) => self - .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { - walk_assoc_item(this, generics, LifetimeBinderKind::Item, item) - }), - AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => { - panic!("unexpanded macro in resolve!") - } - }; - } + self.resolve_define_opaques(define_opaque); + } + AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => { + walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); - self.diag_metadata.current_trait_assoc_items = trait_assoc_items; + self.resolve_define_opaques(define_opaque); + } + AssocItemKind::Delegation(delegation) => { + self.with_generic_param_rib( + &[], + RibKind::AssocItem, + item.id, + LifetimeBinderKind::Function, + delegation.path.segments.last().unwrap().ident.span, + |this| this.resolve_delegation(delegation, item.id, false), + ); + } + AssocItemKind::Type(box TyAlias { generics, .. }) => self + .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { + walk_assoc_item(this, generics, LifetimeBinderKind::Item, item) + }), + AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => { + panic!("unexpanded macro in resolve!") + } + }; } /// This is called to resolve a trait reference from an `impl` (i.e., `impl Trait for Foo`). From f39d5295ffa0f98f153b4ffb7bd35d4e24a4ef7f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 4 May 2026 17:56:47 +0200 Subject: [PATCH 2/5] Make `UnordItems::flat_map` take `UnordItems` as args, too --- compiler/rustc_data_structures/src/unord.rs | 19 ++++++++++++++++--- .../rustc_resolve/src/late/diagnostics.rs | 7 ++++++- .../clippy_lints/src/len_without_is_empty.rs | 3 ++- .../clippy_lints/src/pass_by_ref_or_value.rs | 3 ++- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 779615f73039f..f585eb9053c2f 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -34,6 +34,11 @@ use crate::stable_hasher::{ pub struct UnordItems>(I); impl> UnordItems { + #[inline] + pub fn wrap(iter: I) -> Self { + Self(iter) + } + #[inline] pub fn map U>(self, f: F) -> UnordItems> { UnordItems(self.0.map(f)) @@ -62,6 +67,14 @@ impl> UnordItems { UnordItems(self.0.filter_map(f)) } + #[inline] + pub fn chain( + self, + other: UnordItems>, + ) -> UnordItems> { + UnordItems(self.0.chain(other.0)) + } + #[inline] pub fn max(self) -> Option where @@ -102,10 +115,10 @@ impl> UnordItems { #[inline] pub fn flat_map(self, f: F) -> UnordItems> where - U: IntoIterator, - F: Fn(T) -> U, + U: Iterator, + F: Fn(T) -> UnordItems, { - UnordItems(self.0.flat_map(f)) + UnordItems(self.0.flat_map(move |x| f(x).0)) } pub fn collect>>(self) -> C { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 6f86759d46c5f..934a6b395e918 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -12,6 +12,7 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust::{path_to_string, where_bound_predicate_to_string}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::unord::UnordItems; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, Diagnostic, ErrorGuaranteed, MultiSpan, SuggestionStyle, pluralize, @@ -2672,7 +2673,11 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .extern_crate_map .items() // FIXME: This doesn't include impls like `impl Default for String`. - .flat_map(|(_, crate_)| self.r.tcx.implementations_of_trait((*crate_, default_trait))) + .flat_map(|(_, crate_)| { + UnordItems::wrap( + self.r.tcx.implementations_of_trait((*crate_, default_trait)).into_iter(), + ) + }) .filter_map(|(_, simplified_self_ty)| *simplified_self_ty) .filter_map(|simplified_self_ty| match simplified_self_ty { SimplifiedType::Adt(did) => Some(did), diff --git a/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs b/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs index 8ae91bbcd2a91..2d604e02cf2cc 100644 --- a/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs +++ b/src/tools/clippy/clippy_lints/src/len_without_is_empty.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::res::MaybeDef; use clippy_utils::{fulfill_or_allowed, get_parent_as_impl, sym}; +use rustc_data_structures::unord::UnordItems; use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::{ @@ -130,7 +131,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, ident: Iden fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx); let is_empty_method_found = current_and_super_traits .items() - .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(sym::is_empty)) + .flat_map(|&i| UnordItems::wrap(cx.tcx.associated_items(i).filter_by_name_unhygienic(sym::is_empty))) .any(|i| i.is_method() && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1); if !is_empty_method_found { diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 6b81b9d117a37..85235e7cca047 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -6,6 +6,7 @@ use clippy_utils::{is_self, is_self_ty}; use core::ops::ControlFlow; use rustc_abi::ExternAbi; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::unord::UnordItems; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::attrs::InlineAttr; @@ -181,7 +182,7 @@ impl PassByRefOrValue { || typeck .adjustments() .items() - .flat_map(|(_, a)| a) + .flat_map(|(_, a)| UnordItems::wrap(a.iter())) .any(|a| matches!(a.kind, Adjust::Pointer(PointerCoercion::UnsafeFnPointer)))) { continue; From 041a571ff6a9b632de525a6c813beca51d98269e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 17 Feb 2026 11:57:28 +0000 Subject: [PATCH 3/5] Split the resolver tables into per-owner tables, starting with `node_id_to_def_id` --- compiler/rustc_ast_lowering/src/item.rs | 2 +- compiler/rustc_ast_lowering/src/lib.rs | 39 ++++-- compiler/rustc_expand/src/base.rs | 7 + compiler/rustc_expand/src/expand.rs | 33 +++-- compiler/rustc_middle/src/ty/mod.rs | 15 ++- compiler/rustc_passes/src/lang_items.rs | 6 +- .../rustc_resolve/src/build_reduced_graph.rs | 14 +- compiler/rustc_resolve/src/check_unused.rs | 16 +-- compiler/rustc_resolve/src/def_collector.rs | 82 ++++++++--- compiler/rustc_resolve/src/diagnostics.rs | 4 +- .../src/effective_visibilities.rs | 8 +- compiler/rustc_resolve/src/late.rs | 127 +++++++++++------- compiler/rustc_resolve/src/lib.rs | 88 ++++++++++-- compiler/rustc_resolve/src/macros.rs | 37 ++++- tests/ui/cfg/both-true-false.stderr | 16 --- tests/ui/cfg/cfg-version/syntax.stderr | 90 ------------- tests/ui/cfg/cmdline-false.stderr | 8 -- tests/ui/cfg/diagnostics-same-crate.stderr | 8 -- ...ed-cfg-attr-conditional-compilation.stderr | 8 -- .../cfg-empty-any-all.stderr | 7 - .../conditional-compilation/test-cfg.stderr | 9 -- tests/ui/macros/macro-inner-attributes.stderr | 7 - tests/ui/rustdoc/cfg-rustdoc.stderr | 8 -- 23 files changed, 342 insertions(+), 297 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 249f8e579eee9..8629a0b88f38f 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -98,7 +98,7 @@ impl<'hir> ItemLowerer<'_, 'hir> { match node { AstOwner::NonOwner => {} AstOwner::Crate(c) => { - assert_eq!(self.resolver.local_def_id(CRATE_NODE_ID), CRATE_DEF_ID); + assert_eq!(self.resolver.owner_id(CRATE_NODE_ID), CRATE_DEF_ID); self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); // FIXME(jdonszelman): is dummy span ever a problem here? diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1ce4478c09e8b..f0f899e4c7522 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -61,7 +61,7 @@ use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; use rustc_middle::hir::{self as mid_hir}; use rustc_middle::span_bug; -use rustc_middle::ty::{DelegationInfo, ResolverAstLowering, TyCtxt}; +use rustc_middle::ty::{DelegationInfo, PerOwnerResolverData, ResolverAstLowering, TyCtxt}; use rustc_session::errors::add_feature_diagnostics; use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::{DUMMY_SP, DesugaringKind, Span}; @@ -126,6 +126,7 @@ struct LoweringContext<'a, 'hir> { is_in_dyn_type: bool, current_hir_id_owner: hir::OwnerId, + owner: &'a PerOwnerResolverData, item_local_id_counter: hir::ItemLocalId, trait_map: ItemLocalMap<&'hir [TraitCandidate<'hir>]>, @@ -168,6 +169,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { tcx, resolver, current_disambiguator: Default::default(), + owner: &resolver.owners[&CRATE_NODE_ID], arena: tcx.hir_arena, // HirId handling. @@ -310,12 +312,8 @@ impl<'tcx> ResolverAstLowering<'tcx> { self.delegation_infos.get(&id) } - fn opt_local_def_id(&self, id: NodeId) -> Option { - self.node_id_to_def_id.get(&id).copied() - } - - fn local_def_id(&self, id: NodeId) -> LocalDefId { - self.opt_local_def_id(id).expect("must have def_id") + fn owner_id(&self, id: NodeId) -> LocalDefId { + self.owners[&id].node_id_to_def_id[&id] } fn lifetime_elision_allowed(&self, id: NodeId) -> bool { @@ -483,20 +481,20 @@ fn index_crate<'a, 'b>( } fn visit_item(&mut self, item: &'a ast::Item) { - let def_id = self.resolver.local_def_id(item.id); + let def_id = self.resolver.owner_id(item.id); *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::Item(item); visit::walk_item(self, item) } fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) { - let def_id = self.resolver.local_def_id(item.id); + let def_id = self.resolver.owner_id(item.id); *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::AssocItem(item, ctxt); visit::walk_assoc_item(self, item, ctxt); } fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) { - let def_id = self.resolver.local_def_id(item.id); + let def_id = self.resolver.owner_id(item.id); *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::ForeignItem(item); visit::walk_item(self, item); @@ -662,12 +660,25 @@ impl<'hir> LoweringContext<'_, 'hir> { fn opt_local_def_id(&self, node: NodeId) -> Option { self.node_id_to_def_id .get(&node) - .or_else(|| self.resolver.node_id_to_def_id.get(&node)) + .or_else(|| self.owner.node_id_to_def_id.get(&node)) .copied() } fn local_def_id(&self, node: NodeId) -> LocalDefId { - self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) + self.opt_local_def_id(node).unwrap_or_else(|| { + self.resolver.owners.items().any(|(id, items)| { + items.node_id_to_def_id.items().any(|(node_id, def_id)| { + if *node_id == node { + panic!( + "{def_id:?} ({node_id}) was found in {:?} ({id})", + items.node_id_to_def_id.get(id), + ) + } + false + }) + }); + panic!("no entry for node id: `{node:?}`"); + }) } fn get_partial_res(&self, id: NodeId) -> Option { @@ -679,7 +690,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Given the id of an owner node in the AST, returns the corresponding `OwnerId`. fn owner_id(&self, node: NodeId) -> hir::OwnerId { - hir::OwnerId { def_id: self.local_def_id(node) } + hir::OwnerId { def_id: self.resolver.owners[&node].node_id_to_def_id[&node] } } /// Freshen the `LoweringContext` and ready it to lower a nested item. @@ -704,6 +715,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .unwrap_or_else(|| PerParentDisambiguatorState::new(def_id)); let disambiguator = std::mem::replace(&mut self.current_disambiguator, new_disambig); + let current_ast_owner = std::mem::replace(&mut self.owner, &self.resolver.owners[&owner]); let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); let current_define_opaque = std::mem::take(&mut self.define_opaque); @@ -739,6 +751,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let info = self.make_owner_info(item); self.current_disambiguator = disambiguator; + self.owner = current_ast_owner; self.attrs = current_attrs; self.bodies = current_bodies; self.define_opaque = current_define_opaque; diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 7f1b58dd1de08..d0bb23206daa2 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1180,6 +1180,13 @@ pub trait ResolverExpand { /// Mark the scope as having a compile error so that error for lookup in this scope /// should be suppressed fn mark_scope_with_compile_error(&mut self, parent_node: NodeId); + + /// Set a new owner and return the old one. Use only in the implementation + /// of `with_owner` and always call [Self::reset_owner] afterwards + fn set_owner(&mut self, id: NodeId) -> NodeId; + + /// Switch back to the original owner. + fn reset_owner(&mut self, id: NodeId); } pub trait LintStoreExpand { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 741c34e0304af..75e0173f19b75 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -8,9 +8,9 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrItemKind, AttrStyle, AttrVec, - DUMMY_NODE_ID, DelegationSuffixes, EarlyParsedAttribute, ExprKind, ForeignItemKind, HasAttrs, - HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind, NodeId, - PatKind, StmtKind, TyKind, token, + CRATE_NODE_ID, DUMMY_NODE_ID, DelegationSuffixes, EarlyParsedAttribute, ExprKind, + ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, + MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, }; use rustc_ast_pretty::pprust; use rustc_attr_parsing::parser::AllowExprMetavar; @@ -2474,11 +2474,22 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { }; } } + + fn with_owner(&mut self, id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T { + if id == DUMMY_NODE_ID { + f(self) + } else { + let old = self.cx.resolver.set_owner(id); + let val = f(self); + self.cx.resolver.reset_owner(old); + val + } + } } impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn flat_map_item(&mut self, node: Box) -> SmallVec<[Box; 1]> { - self.flat_map_node(node) + self.with_owner(node.id, |this| this.flat_map_node(node)) } fn flat_map_assoc_item( @@ -2486,22 +2497,22 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { node: Box, ctxt: AssocCtxt, ) -> SmallVec<[Box; 1]> { - match ctxt { - AssocCtxt::Trait => self.flat_map_node(AstNodeWrapper::new(node, TraitItemTag)), + self.with_owner(node.id, |this| match ctxt { + AssocCtxt::Trait => this.flat_map_node(AstNodeWrapper::new(node, TraitItemTag)), AssocCtxt::Impl { of_trait: false, .. } => { - self.flat_map_node(AstNodeWrapper::new(node, ImplItemTag)) + this.flat_map_node(AstNodeWrapper::new(node, ImplItemTag)) } AssocCtxt::Impl { of_trait: true, .. } => { - self.flat_map_node(AstNodeWrapper::new(node, TraitImplItemTag)) + this.flat_map_node(AstNodeWrapper::new(node, TraitImplItemTag)) } - } + }) } fn flat_map_foreign_item( &mut self, node: Box, ) -> SmallVec<[Box; 1]> { - self.flat_map_node(node) + self.with_owner(node.id, |this| this.flat_map_node(node)) } fn flat_map_variant(&mut self, node: ast::Variant) -> SmallVec<[ast::Variant; 1]> { @@ -2572,7 +2583,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } fn visit_crate(&mut self, node: &mut ast::Crate) { - self.visit_node(node) + self.with_owner(CRATE_NODE_ID, |this| this.visit_node(node)) } fn visit_ty(&mut self, node: &mut ast::Ty) { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f68526724135c..e60b4aa68a79f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -198,6 +198,19 @@ pub struct ResolverGlobalCtxt { pub stripped_cfg_items: Vec, } +#[derive(Debug)] +pub struct PerOwnerResolverData { + pub node_id_to_def_id: NodeMap, + /// The id of the owner + pub id: ast::NodeId, +} + +impl PerOwnerResolverData { + pub fn new(id: ast::NodeId) -> Self { + Self { node_id_to_def_id: Default::default(), id } + } +} + /// Resolutions that should only be used for lowering. /// This struct is meant to be consumed by lowering. #[derive(Debug)] @@ -215,7 +228,7 @@ pub struct ResolverAstLowering<'tcx> { pub next_node_id: ast::NodeId, - pub node_id_to_def_id: NodeMap, + pub owners: NodeMap, pub trait_map: NodeMap<&'tcx [hir::TraitCandidate<'tcx>]>, /// List functions and methods for which lifetime elision was successful. diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 527c618c7a264..d6d21a8bcf104 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -295,7 +295,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { self.check_for_lang( target, - self.resolver.node_id_to_def_id[&i.id], + self.resolver.owners[&i.id].node_id_to_def_id[&i.id], &i.attrs, i.span, i.opt_generics(), @@ -309,7 +309,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { fn visit_variant(&mut self, variant: &'ast ast::Variant) { self.check_for_lang( Target::Variant, - self.resolver.node_id_to_def_id[&variant.id], + self.resolver.owners[&self.parent_item.unwrap().id].node_id_to_def_id[&variant.id], &variant.attrs, variant.span, None, @@ -348,7 +348,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { self.check_for_lang( target, - self.resolver.node_id_to_def_id[&i.id], + self.resolver.owners[&i.id].node_id_to_def_id[&i.id], &i.attrs, i.span, generics, diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 61da931df4d5d..219b45c211143 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -743,12 +743,14 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { } ast::UseTreeKind::Nested { ref items, .. } => { for &(ref tree, id) in items { - let feed = self.create_def(id, None, DefKind::Use, use_tree.span()); - self.build_reduced_graph_for_use_tree( - // This particular use tree - tree, id, &prefix, true, false, // The whole `use` item - item, vis, root_span, feed, - ); + self.with_owner(id, |this| { + let feed = this.create_def(id, None, DefKind::Use, use_tree.span()); + this.build_reduced_graph_for_use_tree( + // This particular use tree + tree, id, &prefix, true, false, // The whole `use` item + item, vis, root_span, feed, + ) + }); } // Empty groups `a::b::{}` are turned into synthetic `self` imports diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 8ab0087ae6158..3c4a7357d115c 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -31,6 +31,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::{DiagArgValue, Diagnostic, MultiSpan}; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::LocalDefId; use rustc_session::lint::builtin::{ MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES, UNUSED_IMPORTS, UNUSED_QUALIFICATIONS, }; @@ -81,9 +82,8 @@ struct ExternCrateToLint { impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { // We have information about whether `use` (import) items are actually // used now. If an import is not used at all, we signal a lint error. - fn check_import(&mut self, id: ast::NodeId) { + fn check_import(&mut self, id: ast::NodeId, def_id: LocalDefId) { let used = self.r.used_imports.contains(&id); - let def_id = self.r.local_def_id(id); if !used { if self.r.maybe_unused_trait_imports.contains(&def_id) { // Check later. @@ -102,7 +102,8 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { } fn check_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId) { - if self.r.effective_visibilities.is_exported(self.r.local_def_id(id)) { + let def_id = self.r.owner_id(id); + if self.r.effective_visibilities.is_exported(def_id) { self.check_import_as_underscore(use_tree, id); return; } @@ -112,7 +113,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { self.unused_import(self.base_id).add(id); } } else { - self.check_import(id); + self.check_import(id, def_id); } } @@ -210,9 +211,8 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { continue; } - let module = self - .r - .get_nearest_non_block_module(self.r.local_def_id(extern_crate.id).to_def_id()); + let module = + self.r.get_nearest_non_block_module(self.r.owner_id(extern_crate.id).to_def_id()); if module.no_implicit_prelude { // If the module has `no_implicit_prelude`, then we don't suggest // replacing the extern crate with a use, as it would not be @@ -494,7 +494,7 @@ impl Resolver<'_, '_> { None } else { let parent_module = visitor.r.get_nearest_non_block_module( - visitor.r.local_def_id(unused.use_tree_id).to_def_id(), + visitor.r.owner_id(unused.use_tree_id).to_def_id(), ); match module_to_string(parent_module) { Some(module) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index b5f46052f03e3..1a9f828ebc07e 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -11,7 +11,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def::Namespace::{TypeNS, ValueNS}; use rustc_hir::def_id::LocalDefId; use rustc_middle::span_bug; -use rustc_middle::ty::TyCtxtFeed; +use rustc_middle::ty::{PerOwnerResolverData, TyCtxtFeed}; use rustc_span::{Span, Symbol, sym}; use tracing::{debug, instrument}; @@ -25,8 +25,13 @@ pub(crate) fn collect_definitions<'ra>( ) -> MacroRulesScopeRef<'ra> { let invocation_parent = resolver.invocation_parents[&parent_scope.expansion]; debug!("new fragment to visit with invocation_parent: {invocation_parent:?}"); + debug_assert_eq!(resolver.current_owner.id, DUMMY_NODE_ID); + resolver.current_owner = resolver.owners.remove(&invocation_parent.owner).unwrap(); let mut visitor = DefCollector { r: resolver, invocation_parent, parent_scope }; fragment.visit_with(&mut visitor); + let tables = + mem::replace(&mut visitor.r.current_owner, PerOwnerResolverData::new(DUMMY_NODE_ID)); + assert!(visitor.r.owners.insert(invocation_parent.owner, tables).is_none()); visitor.parent_scope.macro_rules } @@ -66,6 +71,29 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { self.invocation_parent.parent_def = orig_parent_def; } + pub(super) fn with_owner(&mut self, owner: NodeId, f: F) { + debug_assert_ne!(owner, DUMMY_NODE_ID); + if owner == CRATE_NODE_ID { + // Special case: we always have an invocation parent (set in `collect_definitions`) + // of at least the crate root, even for visiting the crate root, + // which would then remove the crate root from the tables + // list twice and try to insert it twice afterwards. + debug_assert_eq!(self.r.current_owner.id, CRATE_NODE_ID); + return f(self); + } + // We only get here if the owner didn't exist yet. After the owner has been created, + // future invocations of `collect_definitions` will get the owner out of the `owners` + // table. + debug_assert!(!self.r.owners.contains_key(&owner)); + let tables = PerOwnerResolverData::new(owner); + let orig_owner = mem::replace(&mut self.r.current_owner, tables); + let orig_invoc_owner = mem::replace(&mut self.invocation_parent.owner, owner); + f(self); + let tables = mem::replace(&mut self.r.current_owner, orig_owner); + assert!(self.r.owners.insert(owner, tables).is_none()); + assert_eq!(mem::replace(&mut self.invocation_parent.owner, orig_invoc_owner), owner); + } + fn with_impl_trait( &mut self, impl_trait_context: ImplTraitContext, @@ -172,9 +200,10 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, ItemKind::Use(_) => { - let feed = self.create_def(i.id, None, DefKind::Use, i.span); - self.brg_visit_item(i, feed); - return; + return self.with_owner(i.id, |this| { + let feed = this.create_def(i.id, None, DefKind::Use, i.span); + this.brg_visit_item(i, feed); + }); } ItemKind::MacCall(..) => { self.visit_macro_invoc(i.id); @@ -183,14 +212,19 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } ItemKind::DelegationMac(..) => unreachable!(), }; - let feed = self.create_def(i.id, i.kind.ident().map(|ident| ident.name), def_kind, i.span); + self.with_owner(i.id, |this| { + let feed = + this.create_def(i.id, i.kind.ident().map(|ident| ident.name), def_kind, i.span); - if let Some(ext) = opt_syn_ext { - self.r.local_macro_map.insert(feed.def_id(), self.r.arenas.alloc_macro(ext)); - } + if let Some(ext) = opt_syn_ext { + this.r.local_macro_map.insert(feed.def_id(), self.r.arenas.alloc_macro(ext)); + } - self.with_parent(feed.def_id(), |this| { - this.with_impl_trait(ImplTraitContext::Existential, |this| this.brg_visit_item(i, feed)) + this.with_parent(feed.def_id(), |this| { + this.with_impl_trait(ImplTraitContext::Existential, |this| { + this.brg_visit_item(i, feed) + }) + }); }); } @@ -282,12 +316,14 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } }; - let def = self.create_def(fi.id, Some(ident.name), def_kind, fi.span); + self.with_owner(fi.id, |this| { + let def = this.create_def(fi.id, Some(ident.name), def_kind, fi.span); - self.with_parent(def.def_id(), |this| { - this.build_reduced_graph_for_foreign_item(fi, ident, def); - visit::walk_item(this, fi) - }); + this.with_parent(def.def_id(), |this| { + this.build_reduced_graph_for_foreign_item(fi, ident, def); + visit::walk_item(this, fi) + }); + }) } fn visit_variant(&mut self, v: &'a Variant) { @@ -366,8 +402,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } }; - let feed = self.create_def(i.id, Some(ident.name), def_kind, i.span); - self.with_parent(feed.def_id(), |this| this.brg_visit_assoc_item(i, ctxt, ident, ns, feed)); + self.with_owner(i.id, |this| { + let feed = this.create_def(i.id, Some(ident.name), def_kind, i.span); + this.with_parent(feed.def_id(), |this| { + this.brg_visit_assoc_item(i, ctxt, ident, ns, feed) + }); + }) } fn visit_pat(&mut self, pat: &'a Pat) { @@ -564,9 +604,11 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } else { // Visit attributes after items for backward compatibility. // This way they can use `macro_rules` defined later. - visit::walk_list!(self, visit_item, &krate.items); - visit::walk_list!(self, visit_attribute, &krate.attrs); - self.contains_macro_use(&krate.attrs); + self.with_owner(CRATE_NODE_ID, |this| { + visit::walk_list!(this, visit_item, &krate.items); + visit::walk_list!(this, visit_attribute, &krate.attrs); + this.contains_macro_use(&krate.attrs); + }) } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9cdf79ca57d87..7a5888d62b61a 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -3255,7 +3255,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .stripped_cfg_items .iter() .filter_map(|item| { - let parent_scope = self.opt_local_def_id(item.parent_scope)?.to_def_id(); + let parent_scope = self.owners.get(&item.parent_scope)?.node_id_to_def_id + [&item.parent_scope] + .to_def_id(); Some(StrippedCfgItem { parent_scope, ident: item.ident, cfg: item.cfg.clone() }) }) .collect::>(); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 693e49995c1cc..f4ea63fb2c7c4 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -211,7 +211,7 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { impl<'a, 'ra, 'tcx> Visitor<'a> for EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { fn visit_item(&mut self, item: &'a ast::Item) { - let def_id = self.r.local_def_id(item.id); + let def_id = self.r.owner_id(item.id); // Update effective visibilities of nested items. // If it's a mod, also make the visitor walk all of its items match item.kind { @@ -234,16 +234,16 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> ast::ItemKind::Enum(_, _, EnumDef { ref variants }) => { self.set_bindings_effective_visibilities(def_id); for variant in variants { - let variant_def_id = self.r.local_def_id(variant.id); + let variant_def_id = self.r.child_id(item.id, variant.id); for field in variant.data.fields() { - self.update_field(self.r.local_def_id(field.id), variant_def_id); + self.update_field(self.r.child_id(item.id, field.id), variant_def_id); } } } ast::ItemKind::Struct(_, _, ref def) | ast::ItemKind::Union(_, _, ref def) => { for field in def.fields() { - self.update_field(self.r.local_def_id(field.id), def_id); + self.update_field(self.r.child_id(item.id, field.id), def_id); } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 855c589e4bbe5..f5d4dff12a4ef 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -833,7 +833,9 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc let prev = replace(&mut self.diag_metadata.current_item, Some(item)); // Always report errors in items we just entered. let old_ignore = replace(&mut self.in_func_body, false); - self.with_lifetime_rib(LifetimeRibKind::Item, |this| this.resolve_item(item)); + self.with_owner(item.id, |this| { + this.with_lifetime_rib(LifetimeRibKind::Item, |this| this.resolve_item(item)) + }); self.in_func_body = old_ignore; self.diag_metadata.current_item = prev; } @@ -1042,36 +1044,38 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc ); } fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { - self.resolve_doc_links(&foreign_item.attrs, MaybeExported::Ok(foreign_item.id)); - let def_kind = self.r.local_def_kind(foreign_item.id); - match foreign_item.kind { - ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => { - self.with_generic_param_rib( - &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - foreign_item.id, - LifetimeBinderKind::Item, - generics.span, - |this| visit::walk_item(this, foreign_item), - ); - } - ForeignItemKind::Fn(box Fn { ref generics, .. }) => { - self.with_generic_param_rib( - &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), - foreign_item.id, - LifetimeBinderKind::Function, - generics.span, - |this| visit::walk_item(this, foreign_item), - ); - } - ForeignItemKind::Static(..) => { - self.with_static_rib(def_kind, |this| visit::walk_item(this, foreign_item)) - } - ForeignItemKind::MacCall(..) => { - panic!("unexpanded macro in resolve!") + self.with_owner(foreign_item.id, |this| { + this.resolve_doc_links(&foreign_item.attrs, MaybeExported::Ok(foreign_item.id)); + let def_kind = this.r.local_def_kind(foreign_item.id); + match foreign_item.kind { + ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => { + this.with_generic_param_rib( + &generics.params, + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), + foreign_item.id, + LifetimeBinderKind::Item, + generics.span, + |this| visit::walk_item(this, foreign_item), + ); + } + ForeignItemKind::Fn(box Fn { ref generics, .. }) => { + this.with_generic_param_rib( + &generics.params, + RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), + foreign_item.id, + LifetimeBinderKind::Function, + generics.span, + |this| visit::walk_item(this, foreign_item), + ); + } + ForeignItemKind::Static(..) => { + this.with_static_rib(def_kind, |this| visit::walk_item(this, foreign_item)) + } + ForeignItemKind::MacCall(..) => { + panic!("unexpanded macro in resolve!") + } } - } + }) } fn visit_fn(&mut self, fn_kind: FnKind<'ast>, _: &AttrVec, sp: Span, fn_id: NodeId) { let previous_value = self.diag_metadata.current_function; @@ -1710,6 +1714,28 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }) } + #[instrument(level = "debug", skip(self, work))] + fn with_owner(&mut self, owner: NodeId, work: impl FnOnce(&mut Self) -> T) -> T { + let old_owner = std::mem::replace( + &mut self.r.current_owner, + self.r.owners.remove(&owner).unwrap_or_else(|| { + panic!( + "unknown owner {owner}: {:?}", + self.r + .owners + .items() + .filter(|o| o.1.node_id_to_def_id.contains_key(&owner)) + .get_only() + .map(|(_, o)| o.node_id_to_def_id[&owner]) + ) + }), + ); + let ret = work(self); + let prev = std::mem::replace(&mut self.r.current_owner, old_owner); + self.r.owners.insert(prev.id, prev); + ret + } + #[instrument(level = "debug", skip(self, work))] fn with_lifetime_rib( &mut self, @@ -3319,7 +3345,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { replace(&mut self.diag_metadata.current_trait_assoc_items, Some(trait_items)); for item in trait_items { - self.resolve_trait_item(item); + self.with_owner(item.id, |this| this.resolve_trait_item(item)); } self.diag_metadata.current_trait_assoc_items = trait_assoc_items; @@ -3529,7 +3555,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { debug!("resolve_implementation with_self_rib_ns(ValueNS, ...)"); let mut seen_trait_items = Default::default(); for item in impl_items { - this.resolve_impl_item(&**item, &mut seen_trait_items, trait_id, of_trait.is_some()); + this.with_owner(item.id, |this| { + this.resolve_impl_item(&**item, &mut seen_trait_items, trait_id, of_trait.is_some()); + }) } }); }); @@ -5053,7 +5081,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { && let ItemKind::MacroDef(..) = item.kind { num_macro_definition_ribs += 1; - let res = self.r.local_def_id(item.id).to_def_id(); + let res = self.r.owner_id(item.id).to_def_id(); self.ribs[ValueNS].push(Rib::new(RibKind::MacroDefinition(res))); self.label_ribs.push(Rib::new(RibKind::MacroDefinition(res))); } @@ -5548,7 +5576,7 @@ impl ItemInfoCollector<'_, '_, '_> { fn collect_fn_info(&mut self, decl: &FnDecl, id: NodeId) { self.r .delegation_fn_sigs - .insert(self.r.local_def_id(id), DelegationFnSig { has_self: decl.has_self() }); + .insert(self.r.owner_id(id), DelegationFnSig { has_self: decl.has_self() }); } } @@ -5594,7 +5622,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { self.collect_fn_info(&sig.decl, item.id); } - let def_id = self.r.local_def_id(item.id); + let def_id = self.r.owner_id(item.id); let count = generics .params .iter() @@ -5636,7 +5664,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { } if let AssocItemKind::Type(box ast::TyAlias { generics, .. }) = &item.kind { - let def_id = self.r.local_def_id(item.id); + let def_id = self.r.owner_id(item.id); if let Some(suggestion) = required_generic_args_suggestion(generics) { self.r.item_required_generic_args_suggestions.insert(def_id, suggestion); } @@ -5647,18 +5675,21 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) { - visit::walk_crate(&mut ItemInfoCollector { r: self }, krate); - let mut late_resolution_visitor = LateResolutionVisitor::new(self); - late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID)); - visit::walk_crate(&mut late_resolution_visitor, krate); - for (id, span) in late_resolution_visitor.diag_metadata.unused_labels.iter() { - self.lint_buffer.buffer_lint( - lint::builtin::UNUSED_LABELS, - *id, - *span, - errors::UnusedLabel, - ); - } + self.with_owner(CRATE_NODE_ID, |this| { + visit::walk_crate(&mut ItemInfoCollector { r: this }, krate); + let mut late_resolution_visitor = LateResolutionVisitor::new(this); + late_resolution_visitor + .resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID)); + visit::walk_crate(&mut late_resolution_visitor, krate); + for (id, span) in late_resolution_visitor.diag_metadata.unused_labels.iter() { + this.lint_buffer.buffer_lint( + lint::builtin::UNUSED_LABELS, + *id, + *span, + errors::UnusedLabel, + ); + } + }) } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index e5038f2d7f2b9..4f86441771539 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -39,8 +39,8 @@ use macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef}; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; use rustc_ast::{ - self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, Expr, ExprKind, GenericArg, GenericArgs, - Generics, NodeId, Path, attr, + self as ast, AngleBracketedArg, CRATE_NODE_ID, Crate, DUMMY_NODE_ID, Expr, ExprKind, + GenericArg, GenericArgs, Generics, NodeId, Path, attr, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, default}; use rustc_data_structures::intern::Interned; @@ -66,15 +66,15 @@ use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, DelegationInfo, MainDefinition, RegisteredTools, ResolverAstLowering, ResolverGlobalCtxt, - TyCtxt, TyCtxtFeed, Visibility, + self, DelegationInfo, MainDefinition, PerOwnerResolverData, RegisteredTools, + ResolverAstLowering, ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility, }; use rustc_session::config::CrateType; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; -use tracing::debug; +use tracing::{debug, instrument}; type Res = def::Res; @@ -188,6 +188,7 @@ struct InvocationParent { impl_trait_context: ImplTraitContext, in_attr: bool, const_arg_context: ConstArgContext, + owner: NodeId, } impl InvocationParent { @@ -196,6 +197,7 @@ impl InvocationParent { impl_trait_context: ImplTraitContext::Existential, in_attr: false, const_arg_context: ConstArgContext::NonDirect, + owner: CRATE_NODE_ID, }; } @@ -1440,7 +1442,11 @@ pub struct Resolver<'ra, 'tcx> { next_node_id: NodeId = CRATE_NODE_ID, - node_id_to_def_id: NodeMap, + /// Preserves per owner data once the owner is finished resolving. + owners: NodeMap, + + /// An entry of `owners` that gets taken out and reinserted whenever an owner is handled. + current_owner: PerOwnerResolverData, disambiguators: LocalDefIdMap, @@ -1500,6 +1506,22 @@ pub struct Resolver<'ra, 'tcx> { impl_trait_names: FxHashMap = default::fx_hash_map(), } +impl<'ra, 'tcx> std::ops::DerefMut for Resolver<'ra, 'tcx> { + fn deref_mut(&mut self) -> &mut Self::Target { + assert_ne!(self.current_owner.id, DUMMY_NODE_ID); + &mut self.current_owner + } +} + +impl<'ra, 'tcx> std::ops::Deref for Resolver<'ra, 'tcx> { + type Target = PerOwnerResolverData; + + fn deref(&self) -> &Self::Target { + assert_ne!(self.current_owner.id, DUMMY_NODE_ID); + &self.current_owner + } +} + /// This provides memory for the rest of the crate. The `'ra` lifetime that is /// used by many types in this crate is an abbreviation of `ResolverArenas`. #[derive(Default)] @@ -1608,6 +1630,20 @@ impl<'ra, 'tcx> AsRef> for Resolver<'ra, 'tcx> { } impl<'tcx> Resolver<'_, 'tcx> { + /// Only call this in analyses after the resolver has finished. + /// Panics if the node id is currently not in the owner storage, + /// e.g. because it's further up in the current visitor stack. + fn owner_id(&self, node: NodeId) -> LocalDefId { + self.child_id(node, node) + } + + /// Only call this in analyses after the resolver has finished. + /// Panics if the node id is currently not in the owner storage, + /// e.g. because it's further up in the current visitor stack. + fn child_id(&self, owner: NodeId, id: NodeId) -> LocalDefId { + self.owners[&owner].node_id_to_def_id[&id] + } + fn opt_local_def_id(&self, node: NodeId) -> Option { self.node_id_to_def_id.get(&node).copied() } @@ -1705,12 +1741,15 @@ impl<'tcx> Resolver<'_, 'tcx> { } /// This function is very slow, as it iterates over the entire - /// [Resolver::node_id_to_def_id] map just to find the [NodeId] + /// [PerOwnerResolverData::node_id_to_def_id] map for all [Resolver::owners] + /// just to find the [NodeId] /// that corresponds to the given [LocalDefId]. Only use this in - /// diagnostics code paths. + /// diagnostics code paths. Do not use this during macro expansion, + /// as it will not find any node ids within your current expansion's stack. fn def_id_to_node_id(&self, def_id: LocalDefId) -> NodeId { - self.node_id_to_def_id + self.owners .items() + .flat_map(|(_, data)| data.node_id_to_def_id.items()) .filter(|(_, v)| **v == def_id) .map(|(k, _)| *k) .get_only() @@ -1748,11 +1787,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); let empty_module = empty_module.expect_local(); - let mut node_id_to_def_id = NodeMap::default(); + let mut owner_data = PerOwnerResolverData::new(CRATE_NODE_ID); let crate_feed = tcx.create_local_crate_def_id(crate_span); crate_feed.def_kind(DefKind::Mod); - node_id_to_def_id.insert(CRATE_NODE_ID, CRATE_DEF_ID); + owner_data.node_id_to_def_id.insert(CRATE_NODE_ID, crate_feed.key()); + let mut owners = NodeMap::default(); + owners.insert(CRATE_NODE_ID, owner_data); let mut invocation_parents = FxHashMap::default(); invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT); @@ -1815,7 +1856,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { single_segment_macro_resolutions: Default::default(), multi_segment_macro_resolutions: Default::default(), lint_buffer: LintBuffer::default(), - node_id_to_def_id, + owners, + current_owner: PerOwnerResolverData::new(DUMMY_NODE_ID), invocation_parents, trait_impls: Default::default(), confused_type_with_std_module: Default::default(), @@ -1917,7 +1959,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .stripped_cfg_items .into_iter() .filter_map(|item| { - let parent_scope = self.node_id_to_def_id.get(&item.parent_scope)?.to_def_id(); + let parent_scope = self + .owners + .get(&item.parent_scope)? + .node_id_to_def_id + .get(&item.parent_scope)? + .to_def_id(); Some(StrippedCfgItem { parent_scope, ident: item.ident, cfg: item.cfg }) }) .collect(); @@ -1952,7 +1999,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { lifetimes_res_map: self.lifetimes_res_map, extra_lifetime_params_map: self.extra_lifetime_params_map, next_node_id: self.next_node_id, - node_id_to_def_id: self.node_id_to_def_id, + owners: self.owners, trait_map: self.trait_map, lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), @@ -2611,6 +2658,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } self.main_def = Some(MainDefinition { res, is_import, span }); } + + #[instrument(level = "debug", skip(self, work))] + fn with_owner(&mut self, owner: NodeId, work: impl FnOnce(&mut Self) -> T) -> T { + let old_owner = + std::mem::replace(&mut self.current_owner, self.owners.remove(&owner).unwrap()); + let ret = work(self); + assert!( + self.owners + .insert(owner, std::mem::replace(&mut self.current_owner, old_owner)) + .is_none() + ); + ret + } } fn build_extern_prelude<'tcx, 'ra>( diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f4464138ef1fc..a26d4d26e1ea7 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -4,7 +4,7 @@ use std::mem; use std::sync::Arc; -use rustc_ast::{self as ast, Crate, DelegationSuffixes, NodeId}; +use rustc_ast::{self as ast, Crate, DUMMY_NODE_ID, DelegationSuffixes, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr_parsing::AttributeParser; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; @@ -21,7 +21,7 @@ use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_hir::{Attribute, StabilityLevel}; use rustc_middle::middle::stability; -use rustc_middle::ty::{RegisteredTools, TyCtxt}; +use rustc_middle::ty::{PerOwnerResolverData, RegisteredTools, TyCtxt}; use rustc_session::Session; use rustc_session::errors::feature_err; use rustc_session::lint::builtin::{ @@ -165,7 +165,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } fn mark_scope_with_compile_error(&mut self, id: NodeId) { - if let Some(id) = self.opt_local_def_id(id) + if let Some(id) = self.owners.get(&id).map(|i| i.node_id_to_def_id[&id]) && self.tcx.def_kind(id).is_module_like() { self.mods_with_parse_errors.insert(id.to_def_id()); @@ -216,8 +216,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { features: &[Symbol], parent_module_id: Option, ) -> LocalExpnId { - let parent_module = - parent_module_id.map(|module_id| self.local_def_id(module_id).to_def_id()); + let parent_module = parent_module_id.map(|module_id| self.owner_id(module_id).to_def_id()); let expn_id = self.tcx.with_stable_hashing_context(|hcx| { LocalExpnId::fresh( ExpnData::allow_unstable( @@ -491,7 +490,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } fn declare_proc_macro(&mut self, id: NodeId) { - self.proc_macros.push(self.local_def_id(id)) + self.proc_macros.push(self.owner_id(id)) } fn append_stripped_cfg_item( @@ -555,6 +554,32 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { fn insert_impl_trait_name(&mut self, id: NodeId, name: Symbol) { self.impl_trait_names.insert(id, name); } + + fn set_owner(&mut self, id: NodeId) -> NodeId { + assert_ne!(id, DUMMY_NODE_ID); + let old = std::mem::replace(&mut self.current_owner, self.owners.remove(&id).unwrap()); + let old_id = old.id; + if old.id == DUMMY_NODE_ID { + if cfg!(debug_assertions) { + let PerOwnerResolverData { node_id_to_def_id, id: _ } = old; + assert!(node_id_to_def_id.is_empty()); + } + } else { + assert!(self.owners.insert(old.id, old).is_none()); + } + old_id + } + + fn reset_owner(&mut self, id: NodeId) { + let new = if id == DUMMY_NODE_ID { + PerOwnerResolverData::new(DUMMY_NODE_ID) + } else { + self.owners.remove(&id).unwrap() + }; + let old = std::mem::replace(&mut self.current_owner, new); + assert_ne!(old.id, DUMMY_NODE_ID); + assert!(self.owners.insert(old.id, old).is_none()); + } } impl<'ra, 'tcx> Resolver<'ra, 'tcx> { diff --git a/tests/ui/cfg/both-true-false.stderr b/tests/ui/cfg/both-true-false.stderr index 76a5661f0873d..83ed58f90f6b7 100644 --- a/tests/ui/cfg/both-true-false.stderr +++ b/tests/ui/cfg/both-true-false.stderr @@ -3,22 +3,6 @@ error[E0425]: cannot find function `foo` in this scope | LL | foo(); | ^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/both-true-false.rs:7:4 - | -LL | #[cfg(false)] - | ----- the item is gated here -LL | #[cfg(true)] -LL | fn foo() {} - | ^^^ -note: found an item that was configured out - --> $DIR/both-true-false.rs:11:4 - | -LL | #[cfg(false)] - | ----- the item is gated here -LL | fn foo() {} - | ^^^ error: aborting due to 1 previous error diff --git a/tests/ui/cfg/cfg-version/syntax.stderr b/tests/ui/cfg/cfg-version/syntax.stderr index 34ddfff3e8ef6..188f6d7aa5dc1 100644 --- a/tests/ui/cfg/cfg-version/syntax.stderr +++ b/tests/ui/cfg/cfg-version/syntax.stderr @@ -128,150 +128,60 @@ error[E0425]: cannot find function `key_value_form` in this scope | LL | key_value_form(); | ^^^^^^^^^^^^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/syntax.rs:32:4 - | -LL | #[cfg(version = "1.43")] - | ---------------- the item is gated behind the `1.43` feature -LL | -LL | fn key_value_form() {} - | ^^^^^^^^^^^^^^ error[E0425]: cannot find function `not_numbers_or_periods` in this scope --> $DIR/syntax.rs:143:5 | LL | not_numbers_or_periods(); | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/syntax.rs:53:4 - | -LL | #[cfg(version("foo"))] - | ------- the item is gated here -LL | -LL | fn not_numbers_or_periods() {} - | ^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `complex_semver_with_metadata` in this scope --> $DIR/syntax.rs:144:5 | LL | complex_semver_with_metadata(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/syntax.rs:57:4 - | -LL | #[cfg(version("1.20.0-stable"))] - | ----------------- the item is gated here -LL | -LL | fn complex_semver_with_metadata() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `invalid_major_only` in this scope --> $DIR/syntax.rs:145:5 | LL | invalid_major_only(); | ^^^^^^^^^^^^^^^^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/syntax.rs:80:4 - | -LL | #[cfg(version("1"))] - | ----- the item is gated here -LL | -LL | fn invalid_major_only() {} - | ^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `invalid_major_only_zero` in this scope --> $DIR/syntax.rs:146:5 | LL | invalid_major_only_zero(); | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/syntax.rs:84:4 - | -LL | #[cfg(version("0"))] - | ----- the item is gated here -LL | -LL | fn invalid_major_only_zero() {} - | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `invalid_major_only_negative` in this scope --> $DIR/syntax.rs:147:5 | LL | invalid_major_only_negative(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/syntax.rs:97:4 - | -LL | #[cfg(version("-1"))] - | ------ the item is gated here -LL | -LL | fn invalid_major_only_negative() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `exceed_u16_major` in this scope --> $DIR/syntax.rs:148:5 | LL | exceed_u16_major(); | ^^^^^^^^^^^^^^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/syntax.rs:103:4 - | -LL | #[cfg(version("65536"))] - | --------- the item is gated here -LL | -LL | fn exceed_u16_major() {} - | ^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `exceed_u16_minor` in this scope --> $DIR/syntax.rs:149:5 | LL | exceed_u16_minor(); | ^^^^^^^^^^^^^^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/syntax.rs:107:4 - | -LL | #[cfg(version("1.65536.0"))] - | ------------- the item is gated here -LL | -LL | fn exceed_u16_minor() {} - | ^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `exceed_u16_patch` in this scope --> $DIR/syntax.rs:150:5 | LL | exceed_u16_patch(); | ^^^^^^^^^^^^^^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/syntax.rs:111:4 - | -LL | #[cfg(version("1.0.65536"))] - | ------------- the item is gated here -LL | -LL | fn exceed_u16_patch() {} - | ^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `exceed_u16_mixed` in this scope --> $DIR/syntax.rs:151:5 | LL | exceed_u16_mixed(); | ^^^^^^^^^^^^^^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/syntax.rs:115:4 - | -LL | #[cfg(version("65536.0.65536"))] - | ----------------- the item is gated here -LL | -LL | fn exceed_u16_mixed() {} - | ^^^^^^^^^^^^^^^^ error: aborting due to 14 previous errors; 14 warnings emitted diff --git a/tests/ui/cfg/cmdline-false.stderr b/tests/ui/cfg/cmdline-false.stderr index 3d486803821fb..5f57c754c403b 100644 --- a/tests/ui/cfg/cmdline-false.stderr +++ b/tests/ui/cfg/cmdline-false.stderr @@ -3,14 +3,6 @@ error[E0425]: cannot find function `foo` in this scope | LL | foo(); | ^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/cmdline-false.rs:5:4 - | -LL | #[cfg(false)] - | ----- the item is gated here -LL | fn foo() {} - | ^^^ error: aborting due to 1 previous error diff --git a/tests/ui/cfg/diagnostics-same-crate.stderr b/tests/ui/cfg/diagnostics-same-crate.stderr index c20542e19eaf3..2e79895db21a6 100644 --- a/tests/ui/cfg/diagnostics-same-crate.stderr +++ b/tests/ui/cfg/diagnostics-same-crate.stderr @@ -82,14 +82,6 @@ error[E0425]: cannot find function `vanished` in this scope | LL | vanished(); | ^^^^^^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/diagnostics-same-crate.rs:41:8 - | -LL | #[cfg(i_dont_exist_and_you_can_do_nothing_about_it)] - | -------------------------------------------- the item is gated here -LL | pub fn vanished() {} - | ^^^^^^^^ error: aborting due to 7 previous errors diff --git a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr index e93a5433d9791..ddb8ea1e13ae5 100644 --- a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr +++ b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr @@ -3,14 +3,6 @@ error[E0425]: cannot find function `f` in this scope | LL | f() | ^ not found in this scope - | -note: found an item that was configured out - --> $DIR/nested-cfg-attr-conditional-compilation.rs:14:4 - | -LL | #[cfg_attr(true, cfg_attr(true, cfg(false)))] - | ----- the item is gated here -LL | fn f() {} - | ^ error: aborting due to 1 previous error diff --git a/tests/ui/conditional-compilation/cfg-empty-any-all.stderr b/tests/ui/conditional-compilation/cfg-empty-any-all.stderr index 1674f2def23a9..9d489b21af640 100644 --- a/tests/ui/conditional-compilation/cfg-empty-any-all.stderr +++ b/tests/ui/conditional-compilation/cfg-empty-any-all.stderr @@ -4,13 +4,6 @@ error[E0425]: cannot find value `Disabled` in this scope LL | let _ = Disabled; | ^^^^^^^^ not found in this scope | -note: found an item that was configured out - --> $DIR/cfg-empty-any-all.rs:4:8 - | -LL | #[cfg(any())] // Equivalent to cfg(false) - | -- the item is gated here -LL | struct Disabled; - | ^^^^^^^^ help: consider importing this unit variant | LL + use std::backtrace::BacktraceStatus::Disabled; diff --git a/tests/ui/conditional-compilation/test-cfg.stderr b/tests/ui/conditional-compilation/test-cfg.stderr index 379456f74b12f..7897c3be73c62 100644 --- a/tests/ui/conditional-compilation/test-cfg.stderr +++ b/tests/ui/conditional-compilation/test-cfg.stderr @@ -3,15 +3,6 @@ error[E0425]: cannot find function `foo` in this scope | LL | foo(); | ^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/test-cfg.rs:5:4 - | -LL | #[cfg(all(foo, bar))] // foo AND bar - | --- the item is gated here -LL | -LL | fn foo() {} - | ^^^ error: aborting due to 1 previous error diff --git a/tests/ui/macros/macro-inner-attributes.stderr b/tests/ui/macros/macro-inner-attributes.stderr index 5523dda33c323..a65ef60237002 100644 --- a/tests/ui/macros/macro-inner-attributes.stderr +++ b/tests/ui/macros/macro-inner-attributes.stderr @@ -4,13 +4,6 @@ error[E0433]: cannot find module or crate `a` in this scope LL | a::bar(); | ^ use of unresolved module or unlinked crate `a` | -note: found an item that was configured out - --> $DIR/macro-inner-attributes.rs:7:7 - | -LL | test!(a, - | ^ -LL | #[cfg(false)], - | ----- the item is gated here help: there is a crate or module with a similar name | LL - a::bar(); diff --git a/tests/ui/rustdoc/cfg-rustdoc.stderr b/tests/ui/rustdoc/cfg-rustdoc.stderr index 0e8a5dfea61e6..340a8e22482ce 100644 --- a/tests/ui/rustdoc/cfg-rustdoc.stderr +++ b/tests/ui/rustdoc/cfg-rustdoc.stderr @@ -3,14 +3,6 @@ error[E0425]: cannot find value `Foo` in this scope | LL | let f = Foo; | ^^^ not found in this scope - | -note: found an item that was configured out - --> $DIR/cfg-rustdoc.rs:2:12 - | -LL | #[cfg(doc)] - | --- the item is gated here -LL | pub struct Foo; - | ^^^ error: aborting due to 1 previous error From 3a906e05df67f0a951c1120ad4f280a6b12c2532 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 5 May 2026 13:35:24 +0200 Subject: [PATCH 4/5] Iterate over all modules to find cfg-ed out items via their NodeId --- compiler/rustc_resolve/src/diagnostics.rs | 9 +- tests/ui/cfg/both-true-false.stderr | 16 ++++ tests/ui/cfg/cfg-version/syntax.stderr | 90 +++++++++++++++++++ tests/ui/cfg/cmdline-false.stderr | 8 ++ tests/ui/cfg/diagnostics-same-crate.stderr | 8 ++ ...ed-cfg-attr-conditional-compilation.stderr | 8 ++ .../cfg-empty-any-all.stderr | 7 ++ .../conditional-compilation/test-cfg.stderr | 9 ++ tests/ui/macros/macro-inner-attributes.stderr | 7 ++ tests/ui/rustdoc/cfg-rustdoc.stderr | 8 ++ 10 files changed, 167 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7a5888d62b61a..08fee7768dc90 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -3255,9 +3255,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .stripped_cfg_items .iter() .filter_map(|item| { - let parent_scope = self.owners.get(&item.parent_scope)?.node_id_to_def_id - [&item.parent_scope] - .to_def_id(); + let parent_scope = self.local_modules.iter().find_map(|m| match m.kind { + ModuleKind::Def(_, def_id, node_id, _) if node_id == item.parent_scope => { + Some(def_id) + } + _ => None, + })?; Some(StrippedCfgItem { parent_scope, ident: item.ident, cfg: item.cfg.clone() }) }) .collect::>(); diff --git a/tests/ui/cfg/both-true-false.stderr b/tests/ui/cfg/both-true-false.stderr index 83ed58f90f6b7..76a5661f0873d 100644 --- a/tests/ui/cfg/both-true-false.stderr +++ b/tests/ui/cfg/both-true-false.stderr @@ -3,6 +3,22 @@ error[E0425]: cannot find function `foo` in this scope | LL | foo(); | ^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/both-true-false.rs:7:4 + | +LL | #[cfg(false)] + | ----- the item is gated here +LL | #[cfg(true)] +LL | fn foo() {} + | ^^^ +note: found an item that was configured out + --> $DIR/both-true-false.rs:11:4 + | +LL | #[cfg(false)] + | ----- the item is gated here +LL | fn foo() {} + | ^^^ error: aborting due to 1 previous error diff --git a/tests/ui/cfg/cfg-version/syntax.stderr b/tests/ui/cfg/cfg-version/syntax.stderr index 188f6d7aa5dc1..34ddfff3e8ef6 100644 --- a/tests/ui/cfg/cfg-version/syntax.stderr +++ b/tests/ui/cfg/cfg-version/syntax.stderr @@ -128,60 +128,150 @@ error[E0425]: cannot find function `key_value_form` in this scope | LL | key_value_form(); | ^^^^^^^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/syntax.rs:32:4 + | +LL | #[cfg(version = "1.43")] + | ---------------- the item is gated behind the `1.43` feature +LL | +LL | fn key_value_form() {} + | ^^^^^^^^^^^^^^ error[E0425]: cannot find function `not_numbers_or_periods` in this scope --> $DIR/syntax.rs:143:5 | LL | not_numbers_or_periods(); | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/syntax.rs:53:4 + | +LL | #[cfg(version("foo"))] + | ------- the item is gated here +LL | +LL | fn not_numbers_or_periods() {} + | ^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `complex_semver_with_metadata` in this scope --> $DIR/syntax.rs:144:5 | LL | complex_semver_with_metadata(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/syntax.rs:57:4 + | +LL | #[cfg(version("1.20.0-stable"))] + | ----------------- the item is gated here +LL | +LL | fn complex_semver_with_metadata() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `invalid_major_only` in this scope --> $DIR/syntax.rs:145:5 | LL | invalid_major_only(); | ^^^^^^^^^^^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/syntax.rs:80:4 + | +LL | #[cfg(version("1"))] + | ----- the item is gated here +LL | +LL | fn invalid_major_only() {} + | ^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `invalid_major_only_zero` in this scope --> $DIR/syntax.rs:146:5 | LL | invalid_major_only_zero(); | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/syntax.rs:84:4 + | +LL | #[cfg(version("0"))] + | ----- the item is gated here +LL | +LL | fn invalid_major_only_zero() {} + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `invalid_major_only_negative` in this scope --> $DIR/syntax.rs:147:5 | LL | invalid_major_only_negative(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/syntax.rs:97:4 + | +LL | #[cfg(version("-1"))] + | ------ the item is gated here +LL | +LL | fn invalid_major_only_negative() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `exceed_u16_major` in this scope --> $DIR/syntax.rs:148:5 | LL | exceed_u16_major(); | ^^^^^^^^^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/syntax.rs:103:4 + | +LL | #[cfg(version("65536"))] + | --------- the item is gated here +LL | +LL | fn exceed_u16_major() {} + | ^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `exceed_u16_minor` in this scope --> $DIR/syntax.rs:149:5 | LL | exceed_u16_minor(); | ^^^^^^^^^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/syntax.rs:107:4 + | +LL | #[cfg(version("1.65536.0"))] + | ------------- the item is gated here +LL | +LL | fn exceed_u16_minor() {} + | ^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `exceed_u16_patch` in this scope --> $DIR/syntax.rs:150:5 | LL | exceed_u16_patch(); | ^^^^^^^^^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/syntax.rs:111:4 + | +LL | #[cfg(version("1.0.65536"))] + | ------------- the item is gated here +LL | +LL | fn exceed_u16_patch() {} + | ^^^^^^^^^^^^^^^^ error[E0425]: cannot find function `exceed_u16_mixed` in this scope --> $DIR/syntax.rs:151:5 | LL | exceed_u16_mixed(); | ^^^^^^^^^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/syntax.rs:115:4 + | +LL | #[cfg(version("65536.0.65536"))] + | ----------------- the item is gated here +LL | +LL | fn exceed_u16_mixed() {} + | ^^^^^^^^^^^^^^^^ error: aborting due to 14 previous errors; 14 warnings emitted diff --git a/tests/ui/cfg/cmdline-false.stderr b/tests/ui/cfg/cmdline-false.stderr index 5f57c754c403b..3d486803821fb 100644 --- a/tests/ui/cfg/cmdline-false.stderr +++ b/tests/ui/cfg/cmdline-false.stderr @@ -3,6 +3,14 @@ error[E0425]: cannot find function `foo` in this scope | LL | foo(); | ^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/cmdline-false.rs:5:4 + | +LL | #[cfg(false)] + | ----- the item is gated here +LL | fn foo() {} + | ^^^ error: aborting due to 1 previous error diff --git a/tests/ui/cfg/diagnostics-same-crate.stderr b/tests/ui/cfg/diagnostics-same-crate.stderr index 2e79895db21a6..c20542e19eaf3 100644 --- a/tests/ui/cfg/diagnostics-same-crate.stderr +++ b/tests/ui/cfg/diagnostics-same-crate.stderr @@ -82,6 +82,14 @@ error[E0425]: cannot find function `vanished` in this scope | LL | vanished(); | ^^^^^^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/diagnostics-same-crate.rs:41:8 + | +LL | #[cfg(i_dont_exist_and_you_can_do_nothing_about_it)] + | -------------------------------------------- the item is gated here +LL | pub fn vanished() {} + | ^^^^^^^^ error: aborting due to 7 previous errors diff --git a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr index ddb8ea1e13ae5..e93a5433d9791 100644 --- a/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr +++ b/tests/ui/cfg/nested-cfg-attr-conditional-compilation.stderr @@ -3,6 +3,14 @@ error[E0425]: cannot find function `f` in this scope | LL | f() | ^ not found in this scope + | +note: found an item that was configured out + --> $DIR/nested-cfg-attr-conditional-compilation.rs:14:4 + | +LL | #[cfg_attr(true, cfg_attr(true, cfg(false)))] + | ----- the item is gated here +LL | fn f() {} + | ^ error: aborting due to 1 previous error diff --git a/tests/ui/conditional-compilation/cfg-empty-any-all.stderr b/tests/ui/conditional-compilation/cfg-empty-any-all.stderr index 9d489b21af640..1674f2def23a9 100644 --- a/tests/ui/conditional-compilation/cfg-empty-any-all.stderr +++ b/tests/ui/conditional-compilation/cfg-empty-any-all.stderr @@ -4,6 +4,13 @@ error[E0425]: cannot find value `Disabled` in this scope LL | let _ = Disabled; | ^^^^^^^^ not found in this scope | +note: found an item that was configured out + --> $DIR/cfg-empty-any-all.rs:4:8 + | +LL | #[cfg(any())] // Equivalent to cfg(false) + | -- the item is gated here +LL | struct Disabled; + | ^^^^^^^^ help: consider importing this unit variant | LL + use std::backtrace::BacktraceStatus::Disabled; diff --git a/tests/ui/conditional-compilation/test-cfg.stderr b/tests/ui/conditional-compilation/test-cfg.stderr index 7897c3be73c62..379456f74b12f 100644 --- a/tests/ui/conditional-compilation/test-cfg.stderr +++ b/tests/ui/conditional-compilation/test-cfg.stderr @@ -3,6 +3,15 @@ error[E0425]: cannot find function `foo` in this scope | LL | foo(); | ^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/test-cfg.rs:5:4 + | +LL | #[cfg(all(foo, bar))] // foo AND bar + | --- the item is gated here +LL | +LL | fn foo() {} + | ^^^ error: aborting due to 1 previous error diff --git a/tests/ui/macros/macro-inner-attributes.stderr b/tests/ui/macros/macro-inner-attributes.stderr index a65ef60237002..5523dda33c323 100644 --- a/tests/ui/macros/macro-inner-attributes.stderr +++ b/tests/ui/macros/macro-inner-attributes.stderr @@ -4,6 +4,13 @@ error[E0433]: cannot find module or crate `a` in this scope LL | a::bar(); | ^ use of unresolved module or unlinked crate `a` | +note: found an item that was configured out + --> $DIR/macro-inner-attributes.rs:7:7 + | +LL | test!(a, + | ^ +LL | #[cfg(false)], + | ----- the item is gated here help: there is a crate or module with a similar name | LL - a::bar(); diff --git a/tests/ui/rustdoc/cfg-rustdoc.stderr b/tests/ui/rustdoc/cfg-rustdoc.stderr index 340a8e22482ce..0e8a5dfea61e6 100644 --- a/tests/ui/rustdoc/cfg-rustdoc.stderr +++ b/tests/ui/rustdoc/cfg-rustdoc.stderr @@ -3,6 +3,14 @@ error[E0425]: cannot find value `Foo` in this scope | LL | let f = Foo; | ^^^ not found in this scope + | +note: found an item that was configured out + --> $DIR/cfg-rustdoc.rs:2:12 + | +LL | #[cfg(doc)] + | --- the item is gated here +LL | pub struct Foo; + | ^^^ error: aborting due to 1 previous error From 641d6fc16f667eaf1b4bcace852366f419923188 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 May 2026 15:31:23 +0200 Subject: [PATCH 5/5] Stop putting owner's `DefId` into their own `node_id_to_def_id` map Now they unfortunately land in their parent, which is not necessary --- compiler/rustc_ast_lowering/src/delegation.rs | 6 +- .../src/delegation/generics.rs | 4 +- compiler/rustc_ast_lowering/src/item.rs | 6 +- compiler/rustc_ast_lowering/src/lib.rs | 12 +-- compiler/rustc_middle/src/ty/mod.rs | 6 +- compiler/rustc_passes/src/lang_items.rs | 10 +- .../rustc_resolve/src/build_reduced_graph.rs | 3 +- compiler/rustc_resolve/src/def_collector.rs | 95 +++++++++++-------- compiler/rustc_resolve/src/late.rs | 30 +++--- .../rustc_resolve/src/late/diagnostics.rs | 5 +- compiler/rustc_resolve/src/lib.rs | 31 +++--- compiler/rustc_resolve/src/macros.rs | 8 +- 12 files changed, 112 insertions(+), 104 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index adde518af0f41..df5ea7c3168ff 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -122,8 +122,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span); // Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356) - let sig_id = if let Some(delegation_info) = - self.resolver.delegation_info(self.local_def_id(item_id)) + let sig_id = if let Some(delegation_info) = self.resolver.delegation_info(self.owner.def_id) { self.get_sig_id(delegation_info.resolution_node, span) } else { @@ -143,8 +142,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (param_count, c_variadic) = self.param_count(sig_id); - let mut generics = - self.uplift_delegation_generics(delegation, sig_id, item_id, is_method); + let mut generics = self.uplift_delegation_generics(delegation, sig_id, is_method); let body_id = self.lower_delegation_body( delegation, diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index afffc20adf4b3..c2c3bd740e3cf 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -231,11 +231,9 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, delegation: &Delegation, sig_id: DefId, - item_id: NodeId, is_method: bool, ) -> GenericsGenerationResults<'hir> { - let delegation_parent_kind = - self.tcx.def_kind(self.tcx.local_parent(self.local_def_id(item_id))); + let delegation_parent_kind = self.tcx.def_kind(self.tcx.local_parent(self.owner.def_id)); let segments = &delegation.path.segments; let len = segments.len(); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 8629a0b88f38f..5f236c5ce531d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -445,7 +445,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ty, ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { - parent: this.local_def_id(id), + parent: this.owner.def_id, in_assoc_ty: false, }, }, @@ -598,7 +598,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_declaration: _ }) => { let ident = self.lower_ident(*ident); let body = Box::new(self.lower_delim_args(body)); - let def_id = self.local_def_id(id); + let def_id = self.owner.def_id; let def_kind = self.tcx.def_kind(def_id); let DefKind::Macro(macro_kinds) = def_kind else { unreachable!( @@ -1282,7 +1282,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ty, ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias { - parent: this.local_def_id(i.id), + parent: this.owner.def_id, in_assoc_ty: true, }, }, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index f0f899e4c7522..2bd58be73c370 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -313,7 +313,7 @@ impl<'tcx> ResolverAstLowering<'tcx> { } fn owner_id(&self, id: NodeId) -> LocalDefId { - self.owners[&id].node_id_to_def_id[&id] + self.owners[&id].def_id } fn lifetime_elision_allowed(&self, id: NodeId) -> bool { @@ -690,7 +690,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Given the id of an owner node in the AST, returns the corresponding `OwnerId`. fn owner_id(&self, node: NodeId) -> hir::OwnerId { - hir::OwnerId { def_id: self.resolver.owners[&node].node_id_to_def_id[&node] } + hir::OwnerId { def_id: self.resolver.owners[&node].def_id } } /// Freshen the `LoweringContext` and ready it to lower a nested item. @@ -1800,7 +1800,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let output = match coro { Some(coro) => { - let fn_def_id = self.local_def_id(fn_node_id); + let fn_def_id = self.owner.def_id; self.lower_coroutine_fn_ret_ty(&decl.output, fn_def_id, coro, kind) } None => match &decl.output { @@ -1808,19 +1808,19 @@ impl<'hir> LoweringContext<'_, 'hir> { let itctx = match kind { FnDeclKind::Fn | FnDeclKind::Inherent => ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn { - parent: self.local_def_id(fn_node_id), + parent: self.owner.def_id, in_trait_or_impl: None, }, }, FnDeclKind::Trait => ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn { - parent: self.local_def_id(fn_node_id), + parent: self.owner.def_id, in_trait_or_impl: Some(hir::RpitContext::Trait), }, }, FnDeclKind::Impl => ImplTraitContext::OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn { - parent: self.local_def_id(fn_node_id), + parent: self.owner.def_id, in_trait_or_impl: Some(hir::RpitContext::TraitImpl), }, }, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e60b4aa68a79f..ecdca5ca58246 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -203,11 +203,13 @@ pub struct PerOwnerResolverData { pub node_id_to_def_id: NodeMap, /// The id of the owner pub id: ast::NodeId, + /// The `DefId` of the owner, can't be found in `node_id_to_def_id`. + pub def_id: LocalDefId, } impl PerOwnerResolverData { - pub fn new(id: ast::NodeId) -> Self { - Self { node_id_to_def_id: Default::default(), id } + pub fn new(id: ast::NodeId, def_id: LocalDefId) -> Self { + Self { node_id_to_def_id: Default::default(), id, def_id } } } diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index d6d21a8bcf104..c274ca48df622 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -295,7 +295,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { self.check_for_lang( target, - self.resolver.owners[&i.id].node_id_to_def_id[&i.id], + self.resolver.owners[&i.id].def_id, &i.attrs, i.span, i.opt_generics(), @@ -346,13 +346,7 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { } }; - self.check_for_lang( - target, - self.resolver.owners[&i.id].node_id_to_def_id[&i.id], - &i.attrs, - i.span, - generics, - ); + self.check_for_lang(target, self.resolver.owners[&i.id].def_id, &i.attrs, i.span, generics); visit::walk_assoc_item(self, i, ctxt); } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 219b45c211143..54a50c2203361 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -743,8 +743,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { } ast::UseTreeKind::Nested { ref items, .. } => { for &(ref tree, id) in items { - self.with_owner(id, |this| { - let feed = this.create_def(id, None, DefKind::Use, use_tree.span()); + self.with_owner(id, None, DefKind::Use, use_tree.span(), |this, feed| { this.build_reduced_graph_for_use_tree( // This particular use tree tree, id, &prefix, true, false, // The whole `use` item diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 1a9f828ebc07e..6e86dc61a3791 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -9,7 +9,7 @@ use rustc_hir as hir; use rustc_hir::Target; use rustc_hir::def::DefKind; use rustc_hir::def::Namespace::{TypeNS, ValueNS}; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; use rustc_middle::span_bug; use rustc_middle::ty::{PerOwnerResolverData, TyCtxtFeed}; use rustc_span::{Span, Symbol, sym}; @@ -29,8 +29,10 @@ pub(crate) fn collect_definitions<'ra>( resolver.current_owner = resolver.owners.remove(&invocation_parent.owner).unwrap(); let mut visitor = DefCollector { r: resolver, invocation_parent, parent_scope }; fragment.visit_with(&mut visitor); - let tables = - mem::replace(&mut visitor.r.current_owner, PerOwnerResolverData::new(DUMMY_NODE_ID)); + let tables = mem::replace( + &mut visitor.r.current_owner, + PerOwnerResolverData::new(DUMMY_NODE_ID, CRATE_DEF_ID), + ); assert!(visitor.r.owners.insert(invocation_parent.owner, tables).is_none()); visitor.parent_scope.macro_rules } @@ -62,6 +64,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { def_kind, self.parent_scope.expansion.to_expn_id(), span.with_parent(None), + false, ) } @@ -71,24 +74,34 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { self.invocation_parent.parent_def = orig_parent_def; } - pub(super) fn with_owner(&mut self, owner: NodeId, f: F) { + pub(super) fn with_owner)>( + &mut self, + owner: NodeId, + name: Option, + def_kind: DefKind, + span: Span, + f: F, + ) { debug_assert_ne!(owner, DUMMY_NODE_ID); - if owner == CRATE_NODE_ID { - // Special case: we always have an invocation parent (set in `collect_definitions`) - // of at least the crate root, even for visiting the crate root, - // which would then remove the crate root from the tables - // list twice and try to insert it twice afterwards. - debug_assert_eq!(self.r.current_owner.id, CRATE_NODE_ID); - return f(self); - } + debug_assert_ne!(owner, CRATE_NODE_ID); // We only get here if the owner didn't exist yet. After the owner has been created, // future invocations of `collect_definitions` will get the owner out of the `owners` // table. debug_assert!(!self.r.owners.contains_key(&owner)); - let tables = PerOwnerResolverData::new(owner); + let parent_def = self.invocation_parent.parent_def; + let feed = self.r.create_def( + parent_def, + owner, + name, + def_kind, + self.parent_scope.expansion.to_expn_id(), + span.with_parent(None), + true, + ); + let tables = PerOwnerResolverData::new(owner, feed.key()); let orig_owner = mem::replace(&mut self.r.current_owner, tables); let orig_invoc_owner = mem::replace(&mut self.invocation_parent.owner, owner); - f(self); + f(self, feed); let tables = mem::replace(&mut self.r.current_owner, orig_owner); assert!(self.r.owners.insert(owner, tables).is_none()); assert_eq!(mem::replace(&mut self.invocation_parent.owner, orig_invoc_owner), owner); @@ -200,8 +213,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, ItemKind::Use(_) => { - return self.with_owner(i.id, |this| { - let feed = this.create_def(i.id, None, DefKind::Use, i.span); + return self.with_owner(i.id, None, DefKind::Use, i.span, |this, feed| { this.brg_visit_item(i, feed); }); } @@ -212,20 +224,23 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } ItemKind::DelegationMac(..) => unreachable!(), }; - self.with_owner(i.id, |this| { - let feed = - this.create_def(i.id, i.kind.ident().map(|ident| ident.name), def_kind, i.span); - - if let Some(ext) = opt_syn_ext { - this.r.local_macro_map.insert(feed.def_id(), self.r.arenas.alloc_macro(ext)); - } + self.with_owner( + i.id, + i.kind.ident().map(|ident| ident.name), + def_kind, + i.span, + |this, feed| { + if let Some(ext) = opt_syn_ext { + this.r.local_macro_map.insert(feed.def_id(), self.r.arenas.alloc_macro(ext)); + } - this.with_parent(feed.def_id(), |this| { - this.with_impl_trait(ImplTraitContext::Existential, |this| { - this.brg_visit_item(i, feed) - }) - }); - }); + this.with_parent(feed.def_id(), |this| { + this.with_impl_trait(ImplTraitContext::Existential, |this| { + this.brg_visit_item(i, feed) + }) + }); + }, + ); } fn visit_block(&mut self, block: &'a Block) { @@ -316,9 +331,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } }; - self.with_owner(fi.id, |this| { - let def = this.create_def(fi.id, Some(ident.name), def_kind, fi.span); - + self.with_owner(fi.id, Some(ident.name), def_kind, fi.span, |this, def| { this.with_parent(def.def_id(), |this| { this.build_reduced_graph_for_foreign_item(fi, ident, def); visit::walk_item(this, fi) @@ -402,8 +415,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } }; - self.with_owner(i.id, |this| { - let feed = this.create_def(i.id, Some(ident.name), def_kind, i.span); + self.with_owner(i.id, Some(ident.name), def_kind, i.span, |this, feed| { this.with_parent(feed.def_id(), |this| { this.brg_visit_assoc_item(i, ctxt, ident, ns, feed) }); @@ -604,11 +616,16 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } else { // Visit attributes after items for backward compatibility. // This way they can use `macro_rules` defined later. - self.with_owner(CRATE_NODE_ID, |this| { - visit::walk_list!(this, visit_item, &krate.items); - visit::walk_list!(this, visit_attribute, &krate.attrs); - this.contains_macro_use(&krate.attrs); - }) + + // We always have an invocation parent (set in `collect_definitions`) + // of at least the crate root, even for visiting the crate root, + // which would then remove the crate root from the tables + // list twice and try to insert it twice afterwards. + debug_assert_eq!(self.r.current_owner.id, CRATE_NODE_ID); + + visit::walk_list!(self, visit_item, &krate.items); + visit::walk_list!(self, visit_attribute, &krate.attrs); + self.contains_macro_use(&krate.attrs); } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f5d4dff12a4ef..1cabf0056f262 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -692,7 +692,11 @@ enum MaybeExported<'a> { impl MaybeExported<'_> { fn eval(self, r: &Resolver<'_, '_>) -> bool { let def_id = match self { - MaybeExported::Ok(node_id) => Some(r.local_def_id(node_id)), + MaybeExported::Ok(node_id) => Some(if r.current_owner.id == node_id { + r.current_owner.def_id + } else { + r.current_owner.node_id_to_def_id[&node_id] + }), MaybeExported::Impl(Some(trait_def_id)) | MaybeExported::ImplItem(Ok(trait_def_id)) => { trait_def_id.as_local() } @@ -1046,7 +1050,7 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) { self.with_owner(foreign_item.id, |this| { this.resolve_doc_links(&foreign_item.attrs, MaybeExported::Ok(foreign_item.id)); - let def_kind = this.r.local_def_kind(foreign_item.id); + let def_kind = this.r.tcx.def_kind(this.r.def_id); match foreign_item.kind { ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => { this.with_generic_param_rib( @@ -2763,7 +2767,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) { debug!("resolve_adt"); - let kind = self.r.local_def_kind(item.id); + let kind = self.r.tcx.def_kind(self.r.def_id); self.with_current_self_item(item, |this| { this.with_generic_param_rib( &generics.params, @@ -2772,7 +2776,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { LifetimeBinderKind::Item, generics.span, |this| { - let item_def_id = this.r.local_def_id(item.id).to_def_id(); + let item_def_id = this.r.def_id.to_def_id(); this.with_self_rib( Res::SelfTyAlias { alias_to: item_def_id, is_trait_impl: false }, |this| { @@ -2833,7 +2837,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { debug!("(resolving item) resolving {:?} ({:?})", item.kind.ident(), item.kind); - let def_kind = self.r.local_def_kind(item.id); + let def_kind = self.r.tcx.def_kind(self.r.current_owner.def_id); match &item.kind { ItemKind::TyAlias(box TyAlias { generics, .. }) => { self.with_generic_param_rib( @@ -2889,7 +2893,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { LifetimeBinderKind::Item, generics.span, |this| { - let local_def_id = this.r.local_def_id(item.id).to_def_id(); + let local_def_id = this.r.def_id.to_def_id(); this.with_self_rib(Res::SelfTyParam { trait_: local_def_id }, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits); @@ -2908,7 +2912,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { LifetimeBinderKind::Item, generics.span, |this| { - let local_def_id = this.r.local_def_id(item.id).to_def_id(); + let local_def_id = this.r.def_id.to_def_id(); this.with_self_rib(Res::SelfTyParam { trait_: local_def_id }, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds, BoundKind::Bound); @@ -2918,7 +2922,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } ItemKind::Mod(..) => { - let module = self.r.expect_module(self.r.local_def_id(item.id).to_def_id()); + let module = self.r.expect_module(self.r.def_id.to_def_id()); let orig_module = replace(&mut self.parent_scope.module, module); self.with_rib(ValueNS, RibKind::Module(module.expect_local()), |this| { this.with_rib(TypeNS, RibKind::Module(module.expect_local()), |this| { @@ -3049,7 +3053,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // Maintain macro_rules scopes in the same way as during early resolution // for diagnostics and doc links. if macro_def.macro_rules { - let def_id = self.r.local_def_id(item.id); + let def_id = self.r.def_id; self.parent_scope.macro_rules = self.r.macro_rules_scopes[&def_id]; } @@ -3503,7 +3507,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // If applicable, create a rib for the type parameters. self.with_generic_param_rib( &generics.params, - RibKind::Item(HasGenericParams::Yes(generics.span), self.r.local_def_kind(item_id)), + RibKind::Item(HasGenericParams::Yes(generics.span), self.r.tcx.def_kind(self.r.def_id)), item_id, LifetimeBinderKind::ImplBlock, generics.span, @@ -3523,7 +3527,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { |this, trait_id| { this.resolve_doc_links(attrs, MaybeExported::Impl(trait_id)); - let item_def_id = this.r.local_def_id(item_id); + let item_def_id = this.r.def_id; // Register the trait definitions from here. if let Some(trait_id) = trait_id { @@ -3801,7 +3805,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // HACK: because we don't want to track the `TyCtxtFeed` through the resolver to here // in a hash-map, we instead conjure a `TyCtxtFeed` for any `DefId` here, but prevent // it from being used generally. - this.r.tcx.feed_visibility_for_trait_impl_item(this.r.local_def_id(id), vis); + this.r.tcx.feed_visibility_for_trait_impl_item(this.r.def_id, vis); }; let Some(decl) = decl else { @@ -3916,7 +3920,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.visit_path(&delegation.path); self.r.delegation_infos.insert( - self.r.local_def_id(item_id), + self.r.def_id, DelegationInfo { resolution_node: if is_in_trait_impl { item_id } else { delegation.id }, }, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 934a6b395e918..a71ee45687f4c 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2780,8 +2780,9 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { ast::AssocItemKind::Delegation(..) if self .r - .delegation_fn_sigs - .get(&self.r.local_def_id(assoc_item.id)) + .owners + .get(&assoc_item.id) + .and_then(|o| self.r.delegation_fn_sigs.get(&o.def_id)) .is_some_and(|sig| sig.has_self) => { AssocSuggestion::MethodWithSelf { called } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 4f86441771539..fc448adea6aa2 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -46,7 +46,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, de use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard}; -use rustc_data_structures::unord::{UnordMap, UnordSet}; +use rustc_data_structures::unord::{UnordItems, UnordMap, UnordSet}; use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed, LintBuffer}; use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; @@ -1633,8 +1633,8 @@ impl<'tcx> Resolver<'_, 'tcx> { /// Only call this in analyses after the resolver has finished. /// Panics if the node id is currently not in the owner storage, /// e.g. because it's further up in the current visitor stack. - fn owner_id(&self, node: NodeId) -> LocalDefId { - self.child_id(node, node) + fn owner_id(&self, owner: NodeId) -> LocalDefId { + self.owners[&owner].def_id } /// Only call this in analyses after the resolver has finished. @@ -1652,10 +1652,6 @@ impl<'tcx> Resolver<'_, 'tcx> { self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`")) } - fn local_def_kind(&self, node: NodeId) -> DefKind { - self.tcx.def_kind(self.local_def_id(node)) - } - /// Adds a definition with a parent definition. fn create_def( &mut self, @@ -1665,6 +1661,7 @@ impl<'tcx> Resolver<'_, 'tcx> { def_kind: DefKind, expn_id: ExpnId, span: Span, + is_owner: bool, ) -> TyCtxtFeed<'tcx, LocalDefId> { assert!( !self.node_id_to_def_id.contains_key(&node_id), @@ -1694,7 +1691,7 @@ impl<'tcx> Resolver<'_, 'tcx> { // Some things for which we allocate `LocalDefId`s don't correspond to // anything in the AST, so they don't have a `NodeId`. For these cases // we don't need a mapping from `NodeId` to `LocalDefId`. - if node_id != ast::DUMMY_NODE_ID { + if node_id != ast::DUMMY_NODE_ID && !is_owner { debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id); self.node_id_to_def_id.insert(node_id, def_id); } @@ -1749,7 +1746,11 @@ impl<'tcx> Resolver<'_, 'tcx> { fn def_id_to_node_id(&self, def_id: LocalDefId) -> NodeId { self.owners .items() - .flat_map(|(_, data)| data.node_id_to_def_id.items()) + .flat_map(|(_, data)| { + data.node_id_to_def_id + .items() + .chain(UnordItems::wrap([(&data.id, &data.def_id)].into_iter())) + }) .filter(|(_, v)| **v == def_id) .map(|(k, _)| *k) .get_only() @@ -1787,11 +1788,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); let empty_module = empty_module.expect_local(); - let mut owner_data = PerOwnerResolverData::new(CRATE_NODE_ID); + let owner_data = PerOwnerResolverData::new(CRATE_NODE_ID, CRATE_DEF_ID); let crate_feed = tcx.create_local_crate_def_id(crate_span); crate_feed.def_kind(DefKind::Mod); - owner_data.node_id_to_def_id.insert(CRATE_NODE_ID, crate_feed.key()); let mut owners = NodeMap::default(); owners.insert(CRATE_NODE_ID, owner_data); @@ -1857,7 +1857,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { multi_segment_macro_resolutions: Default::default(), lint_buffer: LintBuffer::default(), owners, - current_owner: PerOwnerResolverData::new(DUMMY_NODE_ID), + current_owner: PerOwnerResolverData::new(DUMMY_NODE_ID, CRATE_DEF_ID), invocation_parents, trait_impls: Default::default(), confused_type_with_std_module: Default::default(), @@ -1959,12 +1959,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .stripped_cfg_items .into_iter() .filter_map(|item| { - let parent_scope = self - .owners - .get(&item.parent_scope)? - .node_id_to_def_id - .get(&item.parent_scope)? - .to_def_id(); + let parent_scope = self.owners.get(&item.parent_scope)?.def_id.to_def_id(); Some(StrippedCfgItem { parent_scope, ident: item.ident, cfg: item.cfg }) }) .collect(); diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index a26d4d26e1ea7..4d7bccd8f4f1c 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -18,7 +18,7 @@ use rustc_expand::expand::{ }; use rustc_hir::attrs::{AttributeKind, CfgEntry, StrippedCfgItem}; use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind}; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; +use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LocalDefId}; use rustc_hir::{Attribute, StabilityLevel}; use rustc_middle::middle::stability; use rustc_middle::ty::{PerOwnerResolverData, RegisteredTools, TyCtxt}; @@ -165,7 +165,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } fn mark_scope_with_compile_error(&mut self, id: NodeId) { - if let Some(id) = self.owners.get(&id).map(|i| i.node_id_to_def_id[&id]) + if let Some(id) = self.owners.get(&id).map(|i| i.def_id) && self.tcx.def_kind(id).is_module_like() { self.mods_with_parse_errors.insert(id.to_def_id()); @@ -561,7 +561,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { let old_id = old.id; if old.id == DUMMY_NODE_ID { if cfg!(debug_assertions) { - let PerOwnerResolverData { node_id_to_def_id, id: _ } = old; + let PerOwnerResolverData { node_id_to_def_id, id: _, def_id: _ } = old; assert!(node_id_to_def_id.is_empty()); } } else { @@ -572,7 +572,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { fn reset_owner(&mut self, id: NodeId) { let new = if id == DUMMY_NODE_ID { - PerOwnerResolverData::new(DUMMY_NODE_ID) + PerOwnerResolverData::new(DUMMY_NODE_ID, CRATE_DEF_ID) } else { self.owners.remove(&id).unwrap() };