diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 45ea2dcd121ff..ec4487e3ad34d 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -29,7 +29,6 @@ use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHashe use rustc_data_structures::tagged_ptr::Tag; use rustc_macros::{Decodable, Encodable, StableHash, Walkable}; pub use rustc_span::AttrId; -use rustc_span::def_id::LocalDefId; use rustc_span::{ ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, LocalExpnId, Span, Spanned, Symbol, kw, respan, sym, @@ -4410,9 +4409,6 @@ pub type ForeignItem = Item; pub enum AstOwner { /// This definition does not correspond to a HIR owner. NonOwner, - /// This definition corresponds to a nested `use` tree. - /// The `LocalDefId` points to its HIR owner. - NestedUseTree(LocalDefId), Crate(Box), Item(Box), TraitItem(Box), diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index be0a1d490da6a..7f647deabc1c3 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -152,6 +152,13 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { self.visit_body(body); } + fn visit_use(&mut self, tree: &'hir UseTree<'hir>, hir_id: HirId) { + if !hir_id.is_owner() { + self.insert(tree.prefix.span, hir_id, Node::NestedUseTree(tree)); + } + intravisit::walk_use(self, tree, hir_id); + } + fn visit_param(&mut self, param: &'hir Param<'hir>) { let node = Node::Param(param); self.insert(param.pat.span, param.hir_id, node); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index fcbe3122c2d3d..404abad423784 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -3,12 +3,11 @@ use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::attrs::{AttributeKind, EiiImplResolution}; -use rustc_hir::def::{DefKind, PerNS, Res}; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ self as hir, CRATE_OWNER_ID, HirId, ImplItemImplKind, LifetimeSource, PredicateOrigin, Target, find_attr, }; -use rustc_middle::span_bug; use rustc_middle::ty::data_structures::IndexMap; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::def_id::{DefId, LocalDefId}; @@ -244,11 +243,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ItemKind::ExternCrate(*orig_name, ident) } ItemKind::Use(use_tree) => { - // Start with an empty prefix. - let prefix = - Path { segments: ThinVec::new(), span: use_tree.prefix.span.shrink_to_lo() }; - - self.lower_use_tree(use_tree, &prefix, id, vis_span, attrs) + hir::ItemKind::Use(self.lower_use_tree(use_tree, id, vis_span, attrs)) } ItemKind::Static(ast::StaticItem { ident, @@ -591,13 +586,12 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_use_tree( &mut self, tree: &UseTree, - prefix: &Path, id: NodeId, vis_span: Span, attrs: &'hir [hir::Attribute], - ) -> hir::ItemKind<'hir> { + ) -> hir::UseTree<'hir> { let path = &tree.prefix; - let segments = prefix.segments.iter().chain(path.segments.iter()).cloned().collect(); + let segments = path.segments.iter().cloned().collect(); match tree.kind { UseTreeKind::Simple(rename) => { @@ -619,104 +613,35 @@ impl<'hir> LoweringContext<'_, 'hir> { let res = self.lower_import_res(id, path.span); let path = self.lower_use_path(res, &path, ParamMode::Explicit); let ident = self.lower_ident(ident); - hir::ItemKind::Use(path, hir::UseKind::Single(ident)) + hir::UseTree { prefix: path, kind: hir::UseKind::Single(ident) } } UseTreeKind::Glob(_) => { let res = self.expect_full_res(id); let res = self.lower_res(res); // Put the result in the appropriate namespace. - let res = match res { - Res::Def(DefKind::Mod | DefKind::Trait, _) => { - PerNS { type_ns: Some(res), value_ns: None, macro_ns: None } - } - Res::Def(DefKind::Enum, _) => { - PerNS { type_ns: None, value_ns: Some(res), macro_ns: None } - } - Res::Err => { - // Propagate the error to all namespaces, just to be sure. - let err = Some(Res::Err); - PerNS { type_ns: err, value_ns: err, macro_ns: err } - } - _ => span_bug!(path.span, "bad glob res {:?}", res), - }; + let res = res.in_namespace(); let path = Path { segments, span: path.span }; let path = self.lower_use_path(res, &path, ParamMode::Explicit); - hir::ItemKind::Use(path, hir::UseKind::Glob) + hir::UseTree { prefix: path, kind: hir::UseKind::Glob } } UseTreeKind::Nested { items: ref trees, .. } => { - // Nested imports are desugared into simple imports. - // So, if we start with - // - // ``` - // pub(x) use foo::{a, b}; - // ``` - // - // we will create three items: - // - // ``` - // pub(x) use foo::a; - // pub(x) use foo::b; - // pub(x) use foo::{}; // <-- this is called the `ListStem` - // ``` - // - // The first two are produced by recursively invoking - // `lower_use_tree` (and indeed there may be things - // like `use foo::{a::{b, c}}` and so forth). They - // wind up being directly added to - // `self.items`. However, the structure of this - // function also requires us to return one item, and - // for that we return the `{}` import (called the - // `ListStem`). - - let span = prefix.span.to(path.span); - let prefix = Path { segments, span }; + let res = self.expect_full_res(id); + let res = self.lower_res(res); + // Put the result in the appropriate namespace. + let res = res.in_namespace(); + let prefix = self.lower_use_path(res, &path, ParamMode::Explicit); // Add all the nested `PathListItem`s to the HIR. - for &(ref use_tree, id) in trees { - let owner_id = self.owner_id(id); - - // Each `use` import is an item and thus are owners of the - // names in the path. Up to this point the nested import is - // the current owner, since we want each desugared import to - // own its own names, we have to adjust the owner before - // lowering the rest of the import. - self.with_hir_id_owner(id, |this| { - // `prefix` is lowered multiple times, but in different HIR owners. - // So each segment gets renewed `HirId` with the same - // `ItemLocalId` and the new owner. (See `lower_node_id`) - let kind = this.lower_use_tree(use_tree, &prefix, id, vis_span, attrs); - if !attrs.is_empty() { - this.attrs.insert(hir::ItemLocalId::ZERO, attrs); - } - - let item = hir::Item { - owner_id, - kind, - vis_span, - span: this.lower_span(use_tree.span()), - eii: find_attr!(attrs, EiiImpl(..) | EiiDeclaration(..)), - }; - hir::OwnerNode::Item(this.arena.alloc(item)) - }); - } + let items = self.arena.alloc_from_iter(trees.iter().map(|&(ref use_tree, id)| { + let hir_id = self.lower_node_id(id); + let def_id = self.owner.node_id_to_def_id[&id]; + if !attrs.is_empty() { + self.attrs.insert(hir_id.local_id, attrs); + } + (self.lower_use_tree(use_tree, id, vis_span, attrs), hir_id, def_id) + })); - // Condition should match `build_reduced_graph_for_use_tree`. - let path = if trees.is_empty() - && !(prefix.segments.is_empty() - || prefix.segments.len() == 1 - && prefix.segments[0].ident.name == kw::PathRoot) - { - // For empty lists we need to lower the prefix so it is checked for things - // like stability later. - let res = self.lower_import_res(id, span); - self.lower_use_path(res, &prefix, ParamMode::Explicit) - } else { - // For non-empty lists we can just drop all the data, the prefix is already - // present in HIR as a part of nested imports. - let span = self.lower_span(span); - self.arena.alloc(hir::UsePath { res: PerNS::default(), segments: &[], span }) - }; - hir::ItemKind::Use(path, hir::UseKind::ListStem) + hir::UseTree { prefix, kind: hir::UseKind::Nested { items } } } } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1265bae778601..7f590cc1356d0 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -51,7 +51,6 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hash::{StableHash, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::tagged_ptr::TaggedRef; -use rustc_data_structures::unord::ExtendUnord; use rustc_errors::codes::*; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, ErrorGuaranteed}; use rustc_hir::attrs::lang_items::LangItem; @@ -507,7 +506,7 @@ fn index_ast<'tcx>( let (resolver, krate) = tcx.resolver_for_lowering(); let mut resolver = resolver.steal(); - let mut krate = krate.steal(); + let mut krate: Crate = krate.steal(); let mut indexer = Indexer { owners: &resolver.owners, @@ -575,27 +574,6 @@ fn index_ast<'tcx>( let item = mem::replace(item, *dummy); self.insert(item.id, node(Box::new(item))); } - - #[tracing::instrument(level = "trace", skip(self))] - fn visit_item_id_use_tree( - &mut self, - tree: &UseTree, - parent: LocalDefId, - items: &mut SmallVec<[Box; 1]>, - ) { - match tree.kind { - UseTreeKind::Glob(_) | UseTreeKind::Simple(_) => {} - UseTreeKind::Nested { items: ref nested_vec, span } => { - for &(ref nested, id) in nested_vec { - self.insert(id, AstOwner::NestedUseTree(parent)); - items.push(self.make_dummy(id, span, ItemKind::MacCall)); - - let def_id = self.owners[&id].def_id; - self.visit_item_id_use_tree(nested, def_id, items); - } - } - } - } } impl MutVisitor for Indexer<'_, '_> { @@ -605,37 +583,13 @@ fn index_ast<'tcx>( } fn flat_map_item(&mut self, mut item: Box) -> SmallVec<[Box; 1]> { - let def_id = self.owners[&item.id].def_id; mut_visit::walk_item(self, &mut *item); let dummy = self.make_dummy(item.id, item.span, ItemKind::MacCall); - let mut items = smallvec![dummy]; - if let ItemKind::Use(ref use_tree) = item.kind { - self.visit_item_id_use_tree(use_tree, def_id, &mut items); - } + let items = smallvec![dummy]; self.insert(item.id, AstOwner::Item(item)); items } - fn flat_map_stmt(&mut self, stmt: Stmt) -> SmallVec<[Stmt; 1]> { - let Stmt { id, span, kind } = stmt; - let mut id = Some(id); - mut_visit::walk_flat_map_stmt_kind(self, kind) - .into_iter() - .map(|kind| { - // Expanding the current statement is a nested `use` item, - // it is expanded into several flat `use` items. - // Create new NodeIds for the corresponding statements - // as two statements cannot have the same. - let id = id.take().unwrap_or_else(|| { - let next = self.next_node_id; - self.next_node_id.increment_by(1); - next - }); - Stmt { id, kind, span } - }) - .collect() - } - fn visit_assoc_item(&mut self, item: &mut AssocItem, ctxt: visit::AssocCtxt) { mut_visit::walk_assoc_item(self, item, ctxt); match ctxt { @@ -660,12 +614,12 @@ fn lower_to_hir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::MaybeOwner<'_> { let ast_index = tcx.index_ast(()); let resolver_and_node = ast_index.get(def_id).map(Steal::steal); - let fallback_to_ancestor = |parent_id| { + let fallback_to_ancestor = || { // The item did not exist in the AST, it was created while lowering another item. - // `parent_id` may be different from the direct parent of `def_id`, - // for instance use-trees are lowered by the first sibling. + + let parent_id = tcx.local_parent(def_id); let mut parent_info = tcx.lower_to_hir(parent_id); - if let hir::MaybeOwner::NonOwner(hir_id) = parent_info { + while let hir::MaybeOwner::NonOwner(hir_id) = parent_info { // `parent_id` could also not be a owner either. // For instance if `def_id` is an enum variant field, // the direct parent is the enum variant. @@ -676,7 +630,8 @@ fn lower_to_hir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::MaybeOwner<'_> { let parent_info = parent_info.unwrap(); *parent_info.children.get(&def_id).unwrap_or_else(|| { - panic!( + span_bug!( + tcx.source_span(def_id), "{:?} does not appear in children of {:?}", def_id, parent_info.nodes.node().def_id() @@ -688,7 +643,7 @@ fn lower_to_hir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::MaybeOwner<'_> { // `ast_index` does not contain all definitions, only up-to the highest // `LocalDefId` which has a non-trivial `AstOwner`. Gracefully handle // other definitions, in particular those nested inside this highest definition. - return fallback_to_ancestor(tcx.local_parent(def_id)); + return fallback_to_ancestor(); }; let mut item_lowerer = item::ItemLowerer { tcx, resolver: &*resolver }; @@ -700,10 +655,9 @@ fn lower_to_hir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::MaybeOwner<'_> { AstOwner::TraitItem(item) => item_lowerer.lower_trait_item(&item), AstOwner::ImplItem(item) => item_lowerer.lower_impl_item(&item), AstOwner::ForeignItem(item) => item_lowerer.lower_foreign_item(&item), - AstOwner::NestedUseTree(owner_id) => fallback_to_ancestor(*owner_id), // The item existed in the AST, but is not a HIR owner. // Fetch the correct information from its parent. - AstOwner::NonOwner => fallback_to_ancestor(tcx.local_parent(def_id)), + AstOwner::NonOwner => fallback_to_ancestor(), }; tcx.sess.time("drop_ast", || mem::drop(node)); @@ -812,84 +766,6 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::OwnerId { def_id: self.resolver.owners[&node].def_id } } - /// Freshen the `LoweringContext` and ready it to lower a nested item. - /// The lowered item is registered into `self.children`. - /// - /// This function sets up `HirId` lowering infrastructure, - /// and stashes the shared mutable state to avoid pollution by the closure. - #[instrument(level = "debug", skip(self, f))] - fn with_hir_id_owner( - &mut self, - owner: NodeId, - f: impl FnOnce(&mut Self) -> hir::OwnerNode<'hir>, - ) { - let owner_id = self.owner_id(owner); - let def_id = owner_id.def_id; - - let new_disambig = self - .resolver - .disambiguators - .get(&def_id) - .map(|s| s.steal()) - .unwrap_or_else(|| PerParentDisambiguatorState::new(def_id)); - - let disambiguator = mem::replace(&mut self.current_disambiguator, new_disambig); - let current_ast_owner = mem::replace(&mut self.owner, &self.resolver.owners[&owner]); - let current_attrs = mem::take(&mut self.attrs); - let current_bodies = mem::take(&mut self.bodies); - let current_define_opaque = mem::take(&mut self.define_opaque); - let current_ident_and_label_to_local_id = mem::take(&mut self.ident_and_label_to_local_id); - - #[cfg(debug_assertions)] - let current_relowering_checker = mem::take(&mut self.relowering_checker); - let current_trait_map = mem::take(&mut self.trait_map); - let current_owner = mem::replace(&mut self.current_hir_id_owner, owner_id); - let current_local_counter = - mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1)); - let current_impl_trait_defs = mem::take(&mut self.impl_trait_defs); - let current_impl_trait_bounds = mem::take(&mut self.impl_trait_bounds); - let current_delayed_lints = mem::take(&mut self.delayed_lints); - let current_children = mem::take(&mut self.children); - - // Do not reset `next_node_id` and `node_id_to_def_id`: - // we want `f` to be able to refer to the `LocalDefId`s that the caller created. - // and the caller to refer to some of the subdefinitions' nodes' `LocalDefId`s. - - // Always allocate the first `HirId` for the owner itself. - #[cfg(debug_assertions)] - self.relowering_checker.assert_node_is_not_relowered(owner, hir::ItemLocalId::ZERO); - - let item = f(self); - assert_eq!(owner_id, item.def_id()); - // `f` should have consumed all the elements in these vectors when constructing `item`. - assert!(self.impl_trait_defs.is_empty()); - assert!(self.impl_trait_bounds.is_empty()); - 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; - self.ident_and_label_to_local_id = current_ident_and_label_to_local_id; - - #[cfg(debug_assertions)] - { - self.relowering_checker = current_relowering_checker; - } - self.trait_map = current_trait_map; - self.current_hir_id_owner = current_owner; - self.item_local_id_counter = current_local_counter; - self.impl_trait_defs = current_impl_trait_defs; - self.impl_trait_bounds = current_impl_trait_bounds; - self.delayed_lints = current_delayed_lints; - self.children = current_children; - self.children.extend_unord(info.children.items().map(|(&def_id, &info)| (def_id, info))); - - debug_assert!(!self.children.contains_key(&owner_id.def_id)); - self.children.insert(owner_id.def_id, hir::MaybeOwner::Owner(info)); - } - fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> { let attrs = mem::take(&mut self.attrs); let mut bodies = mem::take(&mut self.bodies); @@ -1003,8 +879,20 @@ impl<'hir> LoweringContext<'_, 'hir> { } fn lower_import_res(&mut self, id: NodeId, span: Span) -> PerNS> { - debug_assert_eq!(id, self.owner.id); - let per_ns = self.owner.import_res.map(|res| res.map(|res| self.lower_res(res))); + let per_ns = self + .owner + .import_res + .get(&id) + .unwrap_or_else(|| { + let sp = self.tcx.source_span(self.owner.def_id); + self.tcx.dcx().span_delayed_bug( + sp, + "no import_res entry for import, \ + this should only happen if it already errored in resolve", + ); + &PerNS { value_ns: None, type_ns: None, macro_ns: None } + }) + .map(|res| res.map(|res| self.lower_res(res))); if per_ns.is_empty() { // Propagate the error to all namespaces, just to be sure. self.dcx().span_delayed_bug(span, "no resolution for an import"); diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 59e4f084ab81b..73e6a959fe550 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -574,6 +574,25 @@ pub enum Res { Err, } +impl Res { + pub fn in_namespace(self) -> PerNS> { + match self { + Res::Def(DefKind::Mod | DefKind::Trait, _) => { + PerNS { type_ns: Some(self), value_ns: None, macro_ns: None } + } + Res::Def(DefKind::Enum, _) => { + PerNS { type_ns: None, value_ns: Some(self), macro_ns: None } + } + Res::Err => { + // Propagate the error to all namespaces, just to be sure. + let err = Some(Res::Err); + PerNS { type_ns: err, value_ns: err, macro_ns: err } + } + _ => panic!("bad path segment res {self:?}"), + } + } +} + impl IntoDiagArg for Res { fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Borrowed(self.descr())) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 37b2ca7718498..7aec551f500d8 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4078,8 +4078,32 @@ pub struct Variant<'hir> { pub span: Span, } -#[derive(Copy, Clone, PartialEq, Debug, StableHash)] -pub enum UseKind { +#[derive(Copy, Clone, Debug, StableHash)] +pub struct UseTree<'hir> { + pub prefix: &'hir UsePath<'hir>, + pub kind: UseKind<'hir>, +} + +impl UseTree<'_> { + pub fn resolutions(&self) -> impl Iterator>> { + Box::new(std::iter::iter!(|| { + match self.kind { + UseKind::Glob => yield self.prefix.res, + UseKind::Single(_) => yield self.prefix.res, + UseKind::Nested { items } => { + for (item, _, _) in items { + for res in item.resolutions() { + yield res; + } + } + } + } + })()) + } +} + +#[derive(Copy, Clone, Debug, StableHash)] +pub enum UseKind<'hir> { /// One import, e.g., `use foo::bar` or `use foo::bar as baz`. /// Also produced for each element of a list `use`, e.g. /// `use foo::{a, b}` lowers to `use foo::a; use foo::b;`. @@ -4091,10 +4115,8 @@ pub enum UseKind { /// Glob import, e.g., `use foo::*`. Glob, - /// Degenerate list import, e.g., `use foo::{a, b}` produces - /// an additional `use foo::{}` for performing checks such as - /// unstable feature gating. May be removed in the future. - ListStem, + /// `use prefix::{...}` + Nested { items: &'hir [(UseTree<'hir>, HirId, LocalDefId)] }, } /// References to traits in impls. @@ -4273,7 +4295,7 @@ impl<'hir> Item<'hir> { expect_extern_crate, (Option, Ident), ItemKind::ExternCrate(s, ident), (*s, *ident); - expect_use, (&'hir UsePath<'hir>, UseKind), ItemKind::Use(p, uk), (p, *uk); + expect_use, UseTree<'hir>, ItemKind::Use(ut), *ut; expect_static, (Mutability, Ident, &'hir Ty<'hir>, BodyId), ItemKind::Static(mutbl, ident, ty, body), (*mutbl, *ident, ty, *body); @@ -4478,7 +4500,7 @@ pub enum ItemKind<'hir> { /// or just /// /// `use foo::bar::baz;` (with `as baz` implicitly on the right). - Use(&'hir UsePath<'hir>, UseKind), + Use(UseTree<'hir>), /// A `static` item. Static(Mutability, Ident, &'hir Ty<'hir>, BodyId), @@ -4565,7 +4587,7 @@ impl ItemKind<'_> { pub fn ident(&self) -> Option { match *self { ItemKind::ExternCrate(_, ident) - | ItemKind::Use(_, UseKind::Single(ident)) + | ItemKind::Use(UseTree { kind: UseKind::Single(ident), .. }) | ItemKind::Static(_, ident, ..) | ItemKind::Const(ident, ..) | ItemKind::Fn { ident, .. } @@ -4578,7 +4600,7 @@ impl ItemKind<'_> { | ItemKind::Trait { ident, .. } | ItemKind::TraitAlias(_, ident, ..) => Some(ident), - ItemKind::Use(_, UseKind::Glob | UseKind::ListStem) + ItemKind::Use(UseTree { kind: UseKind::Glob | UseKind::Nested { .. }, .. }) | ItemKind::ForeignMod { .. } | ItemKind::GlobalAsm { .. } | ItemKind::Impl(_) => None, @@ -4833,6 +4855,7 @@ impl<'hir> From> for Node<'hir> { pub enum Node<'hir> { Param(&'hir Param<'hir>), Item(&'hir Item<'hir>), + NestedUseTree(&'hir UseTree<'hir>), ForeignItem(&'hir ForeignItem<'hir>), TraitItem(&'hir TraitItem<'hir>), ImplItem(&'hir ImplItem<'hir>), @@ -4895,6 +4918,7 @@ impl<'hir> Node<'hir> { Node::TraitItem(TraitItem { ident, .. }) | Node::ImplItem(ImplItem { ident, .. }) | Node::ForeignItem(ForeignItem { ident, .. }) + | Node::NestedUseTree(UseTree { kind: UseKind::Single(ident), .. }) | Node::Field(FieldDef { ident, .. }) | Node::Variant(Variant { ident, .. }) | Node::PathSegment(PathSegment { ident, .. }) => Some(*ident), @@ -4922,6 +4946,7 @@ impl<'hir> Node<'hir> { | Node::Ty(..) | Node::TraitRef(..) | Node::OpaqueTy(..) + | Node::NestedUseTree(_) | Node::Infer(..) | Node::WherePredicate(..) | Node::Synthetic diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3b721392519a7..99c446ad95f92 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -421,8 +421,8 @@ pub trait Visitor<'v>: Sized { ) -> Self::Result { walk_fn(self, fk, fd, b, id) } - fn visit_use(&mut self, path: &'v UsePath<'v>, hir_id: HirId) -> Self::Result { - walk_use(self, path, hir_id) + fn visit_use(&mut self, tree: &'v UseTree<'v>, hir_id: HirId) -> Self::Result { + walk_use(self, tree, hir_id) } fn visit_trait_item(&mut self, ti: &'v TraitItem<'v>) -> Self::Result { walk_trait_item(self, ti) @@ -533,12 +533,8 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: visit_opt!(visitor, visit_name, orig_name); try_visit!(visitor.visit_ident(ident)); } - ItemKind::Use(ref path, kind) => { - try_visit!(visitor.visit_use(path, item.hir_id())); - match kind { - UseKind::Single(ident) => try_visit!(visitor.visit_ident(ident)), - UseKind::Glob | UseKind::ListStem => {} - } + ItemKind::Use(ref tree) => { + try_visit!(visitor.visit_use(tree, item.hir_id())); } ItemKind::Static(_, ident, ref typ, body) => { try_visit!(visitor.visit_ident(ident)); @@ -1245,13 +1241,25 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<' pub fn walk_use<'v, V: Visitor<'v>>( visitor: &mut V, - path: &'v UsePath<'v>, + tree: &'v UseTree<'v>, hir_id: HirId, ) -> V::Result { - let UsePath { segments, ref res, span } = *path; + visitor.visit_id(hir_id); + let UseTree { prefix, kind } = *tree; + let UsePath { segments, ref res, span } = *prefix; for res in res.present_items() { try_visit!(visitor.visit_path(&Path { segments, res, span }, hir_id)); } + + match kind { + UseKind::Single(ident) => try_visit!(visitor.visit_ident(ident)), + UseKind::Glob => {} + UseKind::Nested { items } => { + for (tree, id, _) in items { + try_visit!(visitor.visit_use(tree, *id)); + } + } + } V::Result::output() } diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 8fa3b0e83aafe..6dcc1175ad99d 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -10,7 +10,9 @@ #![feature(default_field_values)] #![feature(derive_const)] #![feature(exhaustive_patterns)] +#![feature(iter_macro)] #![feature(never_type)] +#![feature(yield_expr)] #![recursion_limit = "256"] // tidy-alphabetical-end diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index 7302913cc1ae7..3b82200596e38 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -44,16 +44,15 @@ pub(super) fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) { if used_trait_imports.contains(&id) { continue; } - let item = tcx.hir_expect_item(id); - if item.span.is_dummy() { + let span = tcx.def_span(id); + if span.is_dummy() { continue; } - let (path, _) = item.expect_use(); tcx.emit_node_span_lint( lint::builtin::UNUSED_IMPORTS, - item.hir_id(), - path.span, - UnusedImport { tcx, span: path.span }, + tcx.local_def_id_to_hir_id(id), + span, + UnusedImport { tcx, span }, ); } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 25ba0c810489e..c955d131fa09a 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -262,7 +262,7 @@ impl<'tcx> ItemCtxt<'tcx> { ItemCtxt::new_internal(tcx, item_def_id, true) } - pub(crate) fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { + pub(crate) fn lower_ty(&self, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { self.lowerer().lower_ty(hir_ty) } @@ -451,7 +451,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { &self, span: Span, item_def_id: DefId, - item_segment: &rustc_hir::PathSegment<'tcx>, + item_segment: &rustc_hir::PathSegment<'_>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> { if let Some(trait_ref) = poly_trait_ref.no_bound_vars() { @@ -549,7 +549,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { fn lower_fn_sig( &self, - decl: &hir::FnDecl<'tcx>, + decl: &hir::FnDecl<'_>, _generics: Option<&hir::Generics<'_>>, hir_id: rustc_hir::HirId, _hir_ty: Option<&hir::Ty<'_>>, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 613202ef35345..a2a1672298c79 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -107,7 +107,7 @@ fn collect_bounds<'a, 'tcx>( fn collect_sizedness_bounds<'tcx>( tcx: TyCtxt<'tcx>, - hir_bounds: &'tcx [hir::GenericBound<'tcx>], + hir_bounds: &[hir::GenericBound<'_>], context: ImpliedBoundsContext<'tcx>, span: Span, ) -> CollectedSizednessBounds { @@ -150,7 +150,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, - hir_bounds: &'tcx [hir::GenericBound<'tcx>], + hir_bounds: &[hir::GenericBound<'_>], context: ImpliedBoundsContext<'tcx>, span: Span, ) { @@ -212,7 +212,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, - hir_bounds: &[hir::GenericBound<'tcx>], + hir_bounds: &[hir::GenericBound<'_>], context: ImpliedBoundsContext<'tcx>, span: Span, ) { @@ -229,7 +229,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_: LangItem, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, - hir_bounds: &[hir::GenericBound<'tcx>], + hir_bounds: &[hir::GenericBound<'_>], context: ImpliedBoundsContext<'tcx>, span: Span, ) { @@ -251,10 +251,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } /// Returns `true` if default trait bound should be added. - fn should_add_default_traits<'a>( + fn should_add_default_traits( &self, trait_def_id: DefId, - hir_bounds: &'a [hir::GenericBound<'tcx>], + hir_bounds: &[hir::GenericBound<'_>], context: ImpliedBoundsContext<'tcx>, ) -> bool { let collected = collect_bounds(hir_bounds, context, trait_def_id); @@ -308,7 +308,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// There is an implied binder around `param_ty` and `hir_bounds`. /// See `lower_poly_trait_ref` for more details. #[instrument(level = "debug", skip(self, hir_bounds, bounds))] - pub(crate) fn lower_bounds<'hir, I: IntoIterator>>( + pub(crate) fn lower_bounds<'a, I: IntoIterator>>( &self, param_ty: Ty<'tcx>, hir_bounds: I, @@ -316,9 +316,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bound_vars: &'tcx ty::List>, predicate_filter: PredicateFilter, overlapping_assoc_constraints: OverlappingAsssocItemConstraints, - ) where - 'tcx: 'hir, - { + ) { for hir_bound in hir_bounds { // In order to avoid cycles, when we're lowering `SelfTraitThatDefines`, // we skip over any traits that don't define the given associated type. @@ -379,7 +377,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, hir_ref_id: hir::HirId, trait_ref: ty::PolyTraitRef<'tcx>, - constraint: &hir::AssocItemConstraint<'tcx>, + constraint: &hir::AssocItemConstraint<'_>, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, duplicates: Option<&mut FxIndexMap>, path_span: Span, @@ -616,7 +614,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a type, possibly specially handling the type if it's a return type notation /// which we otherwise deny in other positions. - pub fn lower_ty_maybe_return_type_notation(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { + pub fn lower_ty_maybe_return_type_notation(&self, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { let hir::TyKind::Path(qpath) = hir_ty.kind else { return self.lower_ty(hir_ty); }; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 3d8c23ebdf8d3..4ac34edb4ef8a 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -37,7 +37,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, span: Span, hir_id: hir::HirId, - hir_bounds: &[hir::PolyTraitRef<'tcx>], + hir_bounds: &[hir::PolyTraitRef<'_>], lifetime: &hir::Lifetime, syntax: TraitObjectSyntax, ) -> Ty<'tcx> { @@ -569,7 +569,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, span: Span, hir_id: hir::HirId, - hir_bounds: &[hir::PolyTraitRef<'tcx>], + hir_bounds: &[hir::PolyTraitRef<'_>], ) -> Option { struct TraitObjectWithoutDyn<'a, 'tcx> { span: Span, @@ -871,7 +871,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, span: Span, hir_id: hir::HirId, - hir_bounds: &[hir::PolyTraitRef<'tcx>], + hir_bounds: &[hir::PolyTraitRef<'_>], diag: &mut Diag<'_>, ) -> bool { let tcx = self.tcx(); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index e5dbae16d07d4..0f4e632522f11 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -120,7 +120,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_tag: ty::AssocTag, assoc_ident: Ident, span: Span, - constraint: Option<&hir::AssocItemConstraint<'tcx>>, + constraint: Option<&hir::AssocItemConstraint<'_>>, ) -> ErrorGuaranteed where I: Iterator>, @@ -349,7 +349,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_tag: ty::AssocTag, ident: Ident, span: Span, - constraint: Option<&hir::AssocItemConstraint<'tcx>>, + constraint: Option<&hir::AssocItemConstraint<'_>>, ) -> ErrorGuaranteed { let tcx = self.tcx(); @@ -415,7 +415,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_tag: ty::AssocTag, assoc_ident: Ident, span: Span, - constraint: Option<&hir::AssocItemConstraint<'tcx>>, + constraint: Option<&hir::AssocItemConstraint<'_>>, ) -> ErrorGuaranteed { let tcx = self.tcx(); @@ -544,7 +544,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, trait_def_id: DefId, span: Span, - item_segment: &hir::PathSegment<'tcx>, + item_segment: &hir::PathSegment<'_>, assoc_tag: ty::AssocTag, ) -> ErrorGuaranteed { let tcx = self.tcx(); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index c65e9bdbd211e..c49e01ac5840c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -199,13 +199,13 @@ pub trait HirTyLowerer<'tcx> { &self, span: Span, item_def_id: DefId, - item_segment: &hir::PathSegment<'tcx>, + item_segment: &hir::PathSegment<'_>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>; fn lower_fn_sig( &self, - decl: &hir::FnDecl<'tcx>, + decl: &hir::FnDecl<'_>, generics: Option<&hir::Generics<'_>>, hir_id: HirId, hir_ty: Option<&hir::Ty<'_>>, @@ -366,13 +366,13 @@ pub struct GenericArgCountResult { /// Its only consumer is [`generics::lower_generic_args`]. /// Read its documentation to learn more. pub trait GenericArgsLowerer<'a, 'tcx> { - fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool); + fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'a>>, bool); fn provided_kind( &mut self, preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, - arg: &GenericArg<'tcx>, + arg: &GenericArg<'_>, ) -> ty::GenericArg<'tcx>; fn inferred_kind( @@ -625,7 +625,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, span: Span, def_id: DefId, - item_segment: &hir::PathSegment<'tcx>, + item_segment: &hir::PathSegment<'_>, ) -> GenericArgsRef<'tcx> { let (args, _) = self.lower_generic_args_of_path(span, def_id, &[], item_segment, None); if let Some(c) = item_segment.args().constraints.first() { @@ -674,7 +674,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, def_id: DefId, parent_args: &[ty::GenericArg<'tcx>], - segment: &hir::PathSegment<'tcx>, + segment: &hir::PathSegment<'_>, self_ty: Option>, ) -> (GenericArgsRef<'tcx>, GenericArgCountResult) { // If the type is parameterized by this region, then replace this @@ -718,7 +718,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { struct GenericArgsCtxt<'a, 'tcx> { lowerer: &'a dyn HirTyLowerer<'tcx>, def_id: DefId, - generic_args: &'a GenericArgs<'tcx>, + generic_args: &'a GenericArgs<'a>, span: Span, infer_args: bool, create_synth_args: bool, @@ -726,7 +726,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for GenericArgsCtxt<'a, 'tcx> { - fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool) { + fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'a>>, bool) { if did == self.def_id { (Some(self.generic_args), self.infer_args) } else { @@ -739,7 +739,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &mut self, preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, - arg: &GenericArg<'tcx>, + arg: &GenericArg<'_>, ) -> ty::GenericArg<'tcx> { let tcx = self.lowerer.tcx(); @@ -749,7 +749,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - let handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| { + let handle_ty_args = |has_default, ty: &hir::Ty<'_>| { if has_default { tcx.check_optional_stability( param.def_id, @@ -896,7 +896,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, span: Span, item_def_id: DefId, - item_segment: &hir::PathSegment<'tcx>, + item_segment: &hir::PathSegment<'_>, parent_args: GenericArgsRef<'tcx>, ) -> GenericArgsRef<'tcx> { let (args, _) = @@ -959,7 +959,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { modifiers: hir::TraitBoundModifiers { constness, polarity }, trait_ref, span, - }: &hir::PolyTraitRef<'tcx>, + }: &hir::PolyTraitRef<'_>, self_ty: Ty<'tcx>, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, predicate_filter: PredicateFilter, @@ -1182,7 +1182,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, trait_def_id: DefId, self_ty: Ty<'tcx>, - trait_segment: &hir::PathSegment<'tcx>, + trait_segment: &hir::PathSegment<'_>, is_impl: bool, ) -> ty::TraitRef<'tcx> { self.report_internal_fn_trait(span, trait_def_id, trait_segment, is_impl); @@ -1211,7 +1211,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, span: Span, def_id: DefId, - item_segment: &hir::PathSegment<'tcx>, + item_segment: &hir::PathSegment<'_>, ) -> Ty<'tcx> { let tcx = self.tcx(); let args = self.lower_generic_args_of_path_segment(span, def_id, item_segment); @@ -1348,7 +1348,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_tag: ty::AssocTag, assoc_ident: Ident, span: Span, - constraint: Option<&hir::AssocItemConstraint<'tcx>>, + constraint: Option<&hir::AssocItemConstraint<'_>>, ) -> Result, ErrorGuaranteed> where I: Iterator>, @@ -1419,8 +1419,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn lower_type_relative_ty_path( &self, self_ty: Ty<'tcx>, - hir_self_ty: &'tcx hir::Ty<'tcx>, - segment: &'tcx hir::PathSegment<'tcx>, + hir_self_ty: &hir::Ty<'_>, + segment: &hir::PathSegment<'_>, qpath_hir_id: HirId, span: Span, permit_variants: PermitVariants, @@ -1461,8 +1461,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn lower_type_relative_const_path( &self, self_ty: Ty<'tcx>, - hir_self_ty: &'tcx hir::Ty<'tcx>, - segment: &'tcx hir::PathSegment<'tcx>, + hir_self_ty: &hir::Ty<'_>, + segment: &hir::PathSegment<'_>, qpath_hir_id: HirId, span: Span, ) -> Result, ErrorGuaranteed> { @@ -1507,8 +1507,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn lower_type_relative_path( &self, self_ty: Ty<'tcx>, - hir_self_ty: &'tcx hir::Ty<'tcx>, - segment: &'tcx hir::PathSegment<'tcx>, + hir_self_ty: &hir::Ty<'_>, + segment: &hir::PathSegment<'_>, qpath_hir_id: HirId, span: Span, mode: LowerTypeRelativePathMode, @@ -1612,9 +1612,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn resolve_type_relative_path( &self, self_ty: Ty<'tcx>, - hir_self_ty: &'tcx hir::Ty<'tcx>, + hir_self_ty: &hir::Ty<'_>, assoc_tag: ty::AssocTag, - segment: &'tcx hir::PathSegment<'tcx>, + segment: &hir::PathSegment<'_>, qpath_hir_id: HirId, span: Span, variant_def_id: Option, @@ -1679,7 +1679,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Search for inherent associated items for use at the type level. fn probe_inherent_assoc_item( &self, - segment: &hir::PathSegment<'tcx>, + segment: &hir::PathSegment<'_>, adt_did: DefId, self_ty: Ty<'tcx>, block: HirId, @@ -1904,8 +1904,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, opt_self_ty: Option>, item_def_id: DefId, - trait_segment: Option<&hir::PathSegment<'tcx>>, - item_segment: &hir::PathSegment<'tcx>, + trait_segment: Option<&hir::PathSegment<'_>>, + item_segment: &hir::PathSegment<'_>, ) -> Ty<'tcx> { match self.lower_resolved_assoc_item_path( span, @@ -1929,8 +1929,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, opt_self_ty: Option>, item_def_id: DefId, - trait_segment: Option<&hir::PathSegment<'tcx>>, - item_segment: &hir::PathSegment<'tcx>, + trait_segment: Option<&hir::PathSegment<'_>>, + item_segment: &hir::PathSegment<'_>, ) -> Result, ErrorGuaranteed> { let tcx = self.tcx(); let (item_def_id, item_args) = self.lower_resolved_assoc_item_path( @@ -1957,8 +1957,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, opt_self_ty: Option>, item_def_id: DefId, - trait_segment: Option<&hir::PathSegment<'tcx>>, - item_segment: &hir::PathSegment<'tcx>, + trait_segment: Option<&hir::PathSegment<'_>>, + item_segment: &hir::PathSegment<'_>, assoc_tag: ty::AssocTag, ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> { let tcx = self.tcx(); @@ -2183,7 +2183,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn lower_resolved_ty_path( &self, opt_self_ty: Option>, - path: &hir::Path<'tcx>, + path: &hir::Path<'_>, hir_id: HirId, permit_variants: PermitVariants, ) -> Ty<'tcx> { @@ -2381,7 +2381,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a [`hir::ConstArg`] to a (type-level) [`ty::Const`]. #[instrument(skip(self), level = "debug")] - pub fn lower_const_arg(&self, const_arg: &hir::ConstArg<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + pub fn lower_const_arg(&self, const_arg: &hir::ConstArg<'_>, ty: Ty<'tcx>) -> Const<'tcx> { let tcx = self.tcx(); if let hir::ConstArgKind::Anon(anon) = &const_arg.kind { @@ -2475,7 +2475,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn lower_const_arg_array( &self, - array_expr: &'tcx hir::ConstArgArrayExpr<'tcx>, + array_expr: &hir::ConstArgArrayExpr<'_>, ty: Ty<'tcx>, ) -> Const<'tcx> { let tcx = self.tcx(); @@ -2524,8 +2524,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn lower_const_arg_tuple_call( &self, hir_id: HirId, - qpath: hir::QPath<'tcx>, - args: &'tcx [&'tcx hir::ConstArg<'tcx>], + qpath: hir::QPath<'_>, + args: &[&hir::ConstArg<'_>], span: Span, ) -> Const<'tcx> { let tcx = self.tcx(); @@ -2625,7 +2625,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn lower_const_arg_tup( &self, - exprs: &'tcx [&'tcx hir::ConstArg<'tcx>], + exprs: &[&hir::ConstArg<'_>], ty: Ty<'tcx>, span: Span, ) -> Const<'tcx> { @@ -2667,8 +2667,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn lower_const_arg_struct( &self, hir_id: HirId, - qpath: hir::QPath<'tcx>, - inits: &'tcx [&'tcx hir::ConstArgExprField<'tcx>], + qpath: hir::QPath<'_>, + inits: &[&hir::ConstArgExprField<'_>], span: Span, ) -> Const<'tcx> { // FIXME(mgca): try to deduplicate this function with @@ -2809,7 +2809,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn lower_path_for_struct_expr( &self, - qpath: hir::QPath<'tcx>, + qpath: hir::QPath<'_>, path_span: Span, hir_id: HirId, ) -> ResolvedStructPath<'tcx> { @@ -2846,7 +2846,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn lower_resolved_const_path( &self, opt_self_ty: Option>, - path: &hir::Path<'tcx>, + path: &hir::Path<'_>, hir_id: HirId, ) -> Const<'tcx> { let tcx = self.tcx(); @@ -3152,7 +3152,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - fn lower_delegation_ty(&self, infer: hir::InferDelegation<'tcx>) -> Ty<'tcx> { + fn lower_delegation_ty(&self, infer: hir::InferDelegation<'_>) -> Ty<'tcx> { match infer { hir::InferDelegation::DefId(def_id) => { self.tcx().type_of(def_id).instantiate_identity().skip_norm_wip() @@ -3170,7 +3170,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a type from the HIR to our internal notion of a type. #[instrument(level = "debug", skip(self), ret)] - pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { + pub fn lower_ty(&self, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { let tcx = self.tcx(); let result_ty = match &hir_ty.kind { @@ -3428,7 +3428,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, ty: Ty<'tcx>, ty_span: Span, - pat: &hir::TyPat<'tcx>, + pat: &hir::TyPat<'_>, ) -> Result, ErrorGuaranteed> { let tcx = self.tcx(); match pat.kind { @@ -3669,7 +3669,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_id: HirId, safety: hir::Safety, abi: rustc_abi::ExternAbi, - decl: &hir::FnDecl<'tcx>, + decl: &hir::FnDecl<'_>, generics: Option<&hir::Generics<'_>>, hir_ty: Option<&hir::Ty<'_>>, ) -> ty::PolyFnSig<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 572200dbd7634..dc0b895ea1aa9 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -226,7 +226,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { /// It's used in rustdoc and Clippy. /// /// -pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { +pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { // In case there are any projections, etc., find the "environment" // def-ID that will be used to determine the traits/predicates in // scope. This is derived from the enclosing item-like thing. @@ -240,7 +240,7 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { // FIXME(const_generics): having special methods for rustdoc in `rustc_hir_analysis` is cursed pub fn lower_const_arg_for_rustdoc<'tcx>( tcx: TyCtxt<'tcx>, - hir_ct: &hir::ConstArg<'tcx>, + hir_ct: &hir::ConstArg<'_>, ty: Ty<'tcx>, ) -> Const<'tcx> { let env_def_id = tcx.hir_get_parent_item(hir_ct.hir_id); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index f2f485a30300a..f046235274c14 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -216,6 +216,7 @@ impl<'a> State<'a> { Node::LetStmt(a) => self.print_local_decl(a), Node::Crate(..) => panic!("cannot print Crate"), Node::WherePredicate(pred) => self.print_where_predicate(pred), + Node::NestedUseTree(tree) => self.print_use_tree(tree), Node::Synthetic => unreachable!(), Node::Err(_) => self.word("/*ERROR*/"), } @@ -604,22 +605,10 @@ impl<'a> State<'a> { self.end(ib); self.end(cb); } - hir::ItemKind::Use(path, kind) => { + hir::ItemKind::Use(ref tree) => { let (cb, ib) = self.head("use"); - self.print_path(path, false); - match kind { - hir::UseKind::Single(ident) => { - if path.segments.last().unwrap().ident != ident { - self.space(); - self.word_space("as"); - self.print_ident(ident); - } - self.word(";"); - } - hir::UseKind::Glob => self.word("::*;"), - hir::UseKind::ListStem => self.word("::{};"), - } + self.print_use_tree(tree); self.end(ib); self.end(cb); } @@ -811,6 +800,29 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Item(item)) } + fn print_use_tree(&mut self, tree: &hir::UseTree<'_>) { + let hir::UseTree { prefix, kind } = *tree; + self.print_path(prefix, false); + match kind { + hir::UseKind::Single(ident) => { + if tree.prefix.segments.last().unwrap().ident != ident { + self.space(); + self.word_space("as"); + self.print_ident(ident); + } + self.word(";"); + } + hir::UseKind::Glob => self.word("::*;"), + hir::UseKind::Nested { items } => { + self.word("::{"); + for (item, _, _) in items { + self.print_use_tree(item) + } + self.word("};"); + } + } + } + fn print_trait_ref(&mut self, t: &hir::TraitRef<'_>) { self.print_path(t.path, false); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 8ff4c3bf28c34..49559304d6ba3 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -569,7 +569,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(crate) fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> LoweredTy<'tcx> { + pub(crate) fn lower_ty(&self, hir_ty: &hir::Ty<'_>) -> LoweredTy<'tcx> { let ty = self.lowerer().lower_ty(hir_ty); self.register_wf_obligation(ty.into(), hir_ty.span, ObligationCauseCode::WellFormed(None)); LoweredTy::from_raw(self, hir_ty.span, ty) @@ -629,7 +629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn lower_const_arg( &self, - const_arg: &'tcx hir::ConstArg<'tcx>, + const_arg: &hir::ConstArg<'_>, ty: Ty<'tcx>, ) -> ty::Const<'tcx> { let ct = self.lowerer().lower_const_arg(const_arg, ty); @@ -1346,7 +1346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &mut self, preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, - arg: &GenericArg<'tcx>, + arg: &GenericArg<'_>, ) -> ty::GenericArg<'tcx> { match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 20fa6d5f7a344..e488f8c9a7887 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -387,7 +387,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { &self, span: Span, item_def_id: DefId, - item_segment: &rustc_hir::PathSegment<'tcx>, + item_segment: &rustc_hir::PathSegment<'_>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> { let trait_ref = self.instantiate_binder_with_fresh_vars( @@ -452,7 +452,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { fn lower_fn_sig( &self, - decl: &rustc_hir::FnDecl<'tcx>, + decl: &rustc_hir::FnDecl<'_>, _generics: Option<&rustc_hir::Generics<'_>>, _hir_id: rustc_hir::HirId, _hir_ty: Option<&hir::Ty<'_>>, diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index e31692492c263..fd1e37b842893 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -451,7 +451,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { &mut self, preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, - arg: &GenericArg<'tcx>, + arg: &GenericArg<'_>, ) -> ty::GenericArg<'tcx> { match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs index 87a64e4227b1d..ccf09e294f48d 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -442,23 +442,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Find an identifier with which this trait was imported (note that `_` doesn't count). for item in import_items.iter() { - let (_, kind) = item.expect_use(); - match kind { + match item.expect_use().kind { hir::UseKind::Single(ident) => { if ident.name != kw::Underscore { return Some(format!("{}", ident.name)); } } hir::UseKind::Glob => return None, // Glob import, so just use its name. - hir::UseKind::ListStem => unreachable!(), + hir::UseKind::Nested { .. } => unreachable!(), } } // All that is left is `_`! We need to use the full path. It doesn't matter which one we // pick, so just take the first one. match import_items[0].kind { - ItemKind::Use(path, _) => { - Some(join_path_idents(path.segments.iter().map(|seg| seg.ident))) + ItemKind::Use(tree) => { + Some(join_path_idents(tree.prefix.segments.iter().map(|seg| seg.ident))) } _ => { span_bug!(span, "unexpected item kind, expected a use: {:?}", import_items[0].kind); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 627fb962d5dbf..ae80dafe38d3c 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1152,49 +1152,48 @@ impl UnreachablePub { exportable: bool, ) { let mut applicability = Applicability::MachineApplicable; - if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id) + if !cx.tcx.visibility(def_id).is_public() { + return; + } + if cx.effective_visibilities.is_reachable(def_id) { + return; + } + + // prefer suggesting `pub(super)` instead of `pub(crate)` when possible, + // except when `pub(super) == pub(crate)` + let new_vis = if let Some(ty::Visibility::Restricted(restricted_did)) = + cx.effective_visibilities.effective_vis(def_id).map(|effective_vis| { + effective_vis.at_level(rustc_middle::middle::privacy::Level::Reachable) + }) + && let parent_parent = + cx.tcx.parent_module_from_def_id(cx.tcx.parent_module_from_def_id(def_id).into()) + && *restricted_did == parent_parent + && !restricted_did.to_def_id().is_crate_root() { - // prefer suggesting `pub(super)` instead of `pub(crate)` when possible, - // except when `pub(super) == pub(crate)` - let new_vis = if let Some(ty::Visibility::Restricted(restricted_did)) = - cx.effective_visibilities.effective_vis(def_id).map(|effective_vis| { - effective_vis.at_level(rustc_middle::middle::privacy::Level::Reachable) - }) - && let parent_parent = cx - .tcx - .parent_module_from_def_id(cx.tcx.parent_module_from_def_id(def_id).into()) - && *restricted_did == parent_parent - && !restricted_did.to_def_id().is_crate_root() - { - "pub(super)" - } else { - "pub(crate)" - }; + "pub(super)" + } else { + "pub(crate)" + }; - if vis_span.from_expansion() { - applicability = Applicability::MaybeIncorrect; - } - let def_span = cx.tcx.def_span(def_id); - cx.emit_span_lint( - UNREACHABLE_PUB, - def_span, - BuiltinUnreachablePub { - what, - new_vis, - suggestion: (vis_span, applicability), - help: exportable, - }, - ); + if vis_span.from_expansion() { + applicability = Applicability::MaybeIncorrect; } + let def_span = cx.tcx.def_span(def_id); + cx.emit_span_lint( + UNREACHABLE_PUB, + def_span, + BuiltinUnreachablePub { + what, + new_vis, + suggestion: (vis_span, applicability), + help: exportable, + }, + ); } } impl<'tcx> LateLintPass<'tcx> for UnreachablePub { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - // Do not warn for fake `use` statements. - if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind { - return; - } self.perform_lint(cx, "item", item.owner_id.def_id, item.vis_span, true); } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 454e99f2d29e0..b0b17223ab96b 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -407,7 +407,9 @@ impl<'tcx> LateLintPass<'tcx> for TypeIr { } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - let rustc_hir::ItemKind::Use(path, kind) = item.kind else { return }; + let rustc_hir::ItemKind::Use(hir::UseTree { prefix: path, kind }) = item.kind else { + return; + }; let is_mod_inherent = |res: Res| { res.opt_def_id() diff --git a/compiler/rustc_lint/src/unqualified_local_imports.rs b/compiler/rustc_lint/src/unqualified_local_imports.rs index 40bafff12d8d4..bcd31c871787a 100644 --- a/compiler/rustc_lint/src/unqualified_local_imports.rs +++ b/compiler/rustc_lint/src/unqualified_local_imports.rs @@ -45,7 +45,7 @@ declare_lint_pass!(UnqualifiedLocalImports => [UNQUALIFIED_LOCAL_IMPORTS]); impl<'tcx> LateLintPass<'tcx> for UnqualifiedLocalImports { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { - let hir::ItemKind::Use(path, _kind) = item.kind else { return }; + let hir::ItemKind::Use(hir::UseTree { prefix: path, .. }) = item.kind else { return }; // Check the type and value namespace resolutions for a local crate. let is_local_import = matches!( path.res.type_ns, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f4d3380594c9f..c739736e53272 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1449,7 +1449,6 @@ impl CrateMetadata { // Structure and variant constructors don't have any attributes encoded for them, // but we assume that someone passing a constructor ID actually wants to look at // the attributes on the corresponding struct or variant. - assert_eq!(def_key.disambiguated_data.data, DefPathData::Ctor); let parent_id = def_key.parent.expect("no parent for a constructor"); self.root .tables diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 8ec27921a5787..9be22bb27eb52 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -794,6 +794,7 @@ impl<'tcx> TyCtxt<'tcx> { } Node::Crate(..) => String::from("(root_crate)"), Node::WherePredicate(_) => node_str("where predicate"), + Node::NestedUseTree(_) => node_str("use"), Node::Synthetic => unreachable!(), Node::Err(_) => node_str("error"), Node::PreciseCapturingNonLifetimeArg(_param) => node_str("parameter"), @@ -998,10 +999,10 @@ impl<'tcx> TyCtxt<'tcx> { } // Other cases. Node::Item(item) => match &item.kind { - ItemKind::Use(path, _) => { + ItemKind::Use(use_tree) => { // Ensure that the returned span has the item's SyntaxContext, and not the // SyntaxContext of the path. - path.span.find_ancestor_in_same_ctxt(item.span).unwrap_or(item.span) + use_tree.prefix.span.find_ancestor_in_same_ctxt(item.span).unwrap_or(item.span) } _ => { if let Some(ident) = item.kind.ident() { @@ -1070,6 +1071,7 @@ impl<'tcx> TyCtxt<'tcx> { Node::Crate(item) => item.spans.inner_span, Node::WherePredicate(pred) => pred.span, Node::PreciseCapturingNonLifetimeArg(param) => param.ident.span, + Node::NestedUseTree(tree) => tree.prefix.span, Node::Synthetic => unreachable!(), Node::Err(span) => span, } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 5099859218187..847cc580e6355 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -343,6 +343,7 @@ impl<'tcx> TyCtxt<'tcx> { | Node::Synthetic | Node::Err(_) | Node::Ctor(_) + | Node::NestedUseTree(_) | Node::Lifetime(_) | Node::GenericParam(_) | Node::Crate(_) diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 5bf4bbe79a9a0..816ce8933350a 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -8,7 +8,7 @@ use std::hash::Hash; use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher}; use rustc_hir::def::DefKind; -use rustc_hir::{ItemKind, Node, UseKind}; +use rustc_hir::{ItemKind, Node, UseKind, UseTree}; use rustc_macros::StableHash; use rustc_span::def_id::{CRATE_DEF_ID, LocalDefId}; @@ -188,7 +188,7 @@ impl EffectiveVisibilities { let nominal_vis = tcx.visibility(def_id); if ev.reachable.greater_than(nominal_vis, tcx) { if let Node::Item(item) = tcx.hir_node_by_def_id(def_id) - && let ItemKind::Use(_, UseKind::Glob) = item.kind + && let ItemKind::Use(UseTree { kind: UseKind::Glob, .. }) = item.kind { // Glob import visibilities can be increased by other // more public glob imports in cases of ambiguity. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index cd9e5f6903478..8755230dcf7bd 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -217,8 +217,8 @@ pub struct PerOwnerResolverData<'tcx> { pub trait_map: NodeMap<&'tcx [hir::TraitCandidate<'tcx>]> = Default::default(), - /// Resolution for import nodes, which have multiple resolutions in different namespaces. - pub import_res: hir::def::PerNS>> = Default::default(), + /// Resolutions for import nodes, which have multiple resolutions in different namespaces. + pub import_res: NodeMap>>> = Default::default(), /// Lifetime parameters that lowering will have to introduce. pub extra_lifetime_params_map: NodeMap> = Default::default(), diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 62a0cbc24fd73..7fb22d9a6a4f3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1070,7 +1070,7 @@ fn find_fallback_pattern_typo<'tcx>( if let DefKind::Use = cx.tcx.def_kind(item.owner_id) { // Look for consts being re-exported. let item = cx.tcx.hir_expect_item(item.owner_id.def_id); - let hir::ItemKind::Use(path, _) = item.kind else { + let hir::ItemKind::Use(hir::UseTree { prefix: path, .. }) = item.kind else { continue; }; if let Some(value_ns) = path.res.value_ns diff --git a/compiler/rustc_passes/src/check_export.rs b/compiler/rustc_passes/src/check_export.rs index 411aad0717959..2c34394ea57da 100644 --- a/compiler/rustc_passes/src/check_export.rs +++ b/compiler/rustc_passes/src/check_export.rs @@ -132,13 +132,15 @@ impl<'tcx> Visitor<'tcx> for ExportableItemCollector<'tcx> { | hir::ItemKind::TyAlias(..) => { self.add_exportable(def_id); } - hir::ItemKind::Use(path, _) => { - for res in path.res.present_items() { - // Only local items are exportable. - if let Some(res_id) = res.opt_def_id() - && let Some(res_id) = res_id.as_local() - { - self.add_exportable(res_id); + hir::ItemKind::Use(tree) => { + for res in tree.resolutions() { + for res in res.present_items() { + // Only local items are exportable. + if let Some(res_id) = res.opt_def_id() + && let Some(res_id) = res_id.as_local() + { + self.add_exportable(res_id); + } } } } diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 87193b73a1a95..119a36d43e38d 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -448,16 +448,24 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_fn(self, fk, fd, b, id) } - fn visit_use(&mut self, p: &'v hir::UsePath<'v>, _hir_id: HirId) { + fn visit_use(&mut self, tree: &'v hir::UseTree<'v>, _hir_id: HirId) { // This is `visit_use`, but the type is `Path` so record it that way. - self.record("Path", None, p); + self.record("Path", None, tree); // Don't call `hir_visit::walk_use(self, p, hir_id)`: it calls // `visit_path` up to three times, once for each namespace result in // `p.res`, by building temporary `Path`s that are not part of the real // HIR, which causes `p` to be double- or triple-counted. Instead just // walk the path internals (i.e. the segments) directly. - let hir::Path { span: _, res: _, segments } = *p; + let hir::Path { span: _, res: _, segments } = *tree.prefix; ast_visit::walk_list!(self, visit_path_segment, segments); + match tree.kind { + rustc_hir::UseKind::Single(_) | rustc_hir::UseKind::Glob => {} + rustc_hir::UseKind::Nested { items } => { + for (tree, id, _) in items { + self.visit_use(tree, *id); + } + } + } } fn visit_trait_item(&mut self, ti: &'v hir::TraitItem<'v>) { diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 05f12aaedcfce..7f1b882e1a2ba 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -300,6 +300,7 @@ impl<'tcx> ReachableContext<'tcx> { | Node::Field(_) | Node::Ty(_) | Node::Crate(_) + | Node::NestedUseTree(_) | Node::Synthetic | Node::OpaqueTy(..) => {} _ => { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 5d388bd44ecac..fe2e175f4ffef 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -742,36 +742,72 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { intravisit::walk_poly_trait_ref(self, t); } - fn visit_use(&mut self, path: &'tcx UsePath<'tcx>, hir_id: HirId) { - let res = path.res; - - // A use item can import something from two namespaces at the same time. - // For deprecation/stability we don't want to warn twice. - // This specifically happens with constructors for unit/tuple structs. - if let Some(ty_ns_res) = res.type_ns - && let Some(value_ns_res) = res.value_ns - && let Some(type_ns_did) = ty_ns_res.opt_def_id() - && let Some(value_ns_did) = value_ns_res.opt_def_id() - && let DefKind::Ctor(.., _) = self.tcx.def_kind(value_ns_did) - && self.tcx.parent(value_ns_did) == type_ns_did - { - // Only visit the value namespace path when we've detected a duplicate, - // not the type namespace path. - let UsePath { segments, res: _, span } = *path; - self.visit_path(&Path { segments, res: value_ns_res, span }, hir_id); - - // Though, visit the macro namespace if it exists, - // regardless of the checks above relating to constructors. - if let Some(res) = res.macro_ns { - self.visit_path(&Path { segments, res, span }, hir_id); + fn visit_use(&mut self, tree: &'tcx hir::UseTree<'tcx>, hir_id: HirId) { + let mut v = vec![]; + + #[instrument(skip(visitor))] + fn recurse<'tcx>( + visitor: &mut Checker<'tcx>, + tree: &'tcx hir::UseTree<'tcx>, + hir_id: HirId, + stack: &mut Vec<&'tcx [hir::PathSegment<'tcx>]>, + ) { + let UsePath { segments, res, span } = *tree.prefix; + + match tree.kind { + hir::UseKind::Single(_) | hir::UseKind::Glob => { + // A use item can import something from two namespaces at the same time. + // For deprecation/stability we don't want to warn twice. + // This specifically happens with constructors for unit/tuple structs. + if let Some(res) = res.value_ns.or(res.type_ns) { + visitor.check_path(&Path { segments, res, span }, hir_id, stack); + } + + // Though, visit the macro namespace if it exists, + // regardless of the checks above relating to constructors. + if let Some(res) = res.macro_ns { + visitor.check_path(&Path { segments, res, span }, hir_id, stack); + } + } + hir::UseKind::Nested { items } => { + stack.push(tree.prefix.segments); + if items.is_empty() { + // need to handle `use foo::bar::{};` + visitor.check_path( + &Path { + segments, + res: segments.last().map_or(Res::Err, |seg| seg.res), + span, + }, + hir_id, + stack, + ); + } else { + for (tree, id, _) in items { + recurse(visitor, tree, *id, stack); + } + } + stack.pop(); + } } - } else { - // if there's no duplicate, just walk as normal - intravisit::walk_use(self, path, hir_id) } + recurse(self, tree, hir_id, &mut v); } fn visit_path(&mut self, path: &hir::Path<'tcx>, id: hir::HirId) { + self.check_path(path, id, &[]); + + intravisit::walk_path(self, path) + } +} + +impl<'tcx> Checker<'tcx> { + fn check_path( + &mut self, + path: &hir::Path<'tcx>, + id: hir::HirId, + prefix: &[&[hir::PathSegment<'tcx>]], + ) { if let Some(def_id) = path.res.opt_def_id() { let method_span = path.segments.last().map(|s| s.ident.span); let item_is_allowed = self.tcx.check_stability_allow_unstable( @@ -787,7 +823,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { ); if item_is_allowed { - // The item itself is allowed; check whether the path there is also allowed. let is_allowed_through_unstable_modules: Option = self.tcx.lookup_stability(def_id).and_then(|stab| match stab.level { StabilityLevel::Stable { allowed_through_unstable_modules, .. } => { @@ -795,86 +830,103 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } _ => None, }); + for segment in prefix + .into_iter() + .flat_map(|i| i.into_iter()) + .chain(path.segments.iter().rev().skip(1)) + { + self.check_path_segments( + path.span, + segment, + id, + method_span, + is_allowed_through_unstable_modules, + ); + } + } + } + } + /// Check parent modules stability as well if the item the path refers to is itself + /// stable. We only emit errors for unstable path segments if the item is stable + /// or allowed because stability is often inherited, so the most common case is that + /// both the segments and the item are unstable behind the same feature flag. + /// + /// We check here rather than in `visit_path_segment` to prevent visiting the last + /// path segment twice + /// + /// We include special cases via #[rustc_allowed_through_unstable_modules] for items + /// that were accidentally stabilized through unstable paths before this check was + /// added, such as `core::intrinsics::transmute` + fn check_path_segments( + &mut self, + span: Span, + path_segment: &hir::PathSegment<'_>, + id: HirId, + method_span: Option, + is_allowed_through_unstable_modules: Option, + ) { + // The item itself is allowed; check whether the path there is also allowed. - // Check parent modules stability as well if the item the path refers to is itself - // stable. We only emit errors for unstable path segments if the item is stable - // or allowed because stability is often inherited, so the most common case is that - // both the segments and the item are unstable behind the same feature flag. - // - // We check here rather than in `visit_path_segment` to prevent visiting the last - // path segment twice - // - // We include special cases via #[rustc_allowed_through_unstable_modules] for items - // that were accidentally stabilized through unstable paths before this check was - // added, such as `core::intrinsics::transmute` - let parents = path.segments.iter().rev().skip(1); - for path_segment in parents { - if let Some(def_id) = path_segment.res.opt_def_id() { - match is_allowed_through_unstable_modules { - None => { - // Emit a hard stability error if this path is not stable. - - // use `None` for id to prevent deprecation check - self.tcx.check_stability_allow_unstable( - def_id, - None, - path_segment.ident.span, - None, - if is_unstable_reexport(self.tcx, id) { - AllowUnstable::Yes - } else { - AllowUnstable::No - }, - ); - } - Some(deprecation) => { - // Call the stability check directly so that we can control which - // diagnostic is emitted. - let eval_result = self.tcx.eval_stability_allow_unstable( - def_id, - None, - path.span, - None, - if is_unstable_reexport(self.tcx, id) { - AllowUnstable::Yes - } else { - AllowUnstable::No - }, - ); - let is_allowed = matches!(eval_result, EvalResult::Allow); - if !is_allowed { - // Calculating message for lint involves calling `self.def_path_str`, - // which will by default invoke the expensive `visible_parent_map` query. - // Skip all that work if the lint is allowed anyway. - if self.tcx.lint_level_spec_at_node(DEPRECATED, id).is_allow() { - return; - } - // Show a deprecation message. - let def_path = - with_no_trimmed_paths!(self.tcx.def_path_str(def_id)); - let def_kind = self.tcx.def_descr(def_id); - let diag = Deprecated { - sub: None, - kind: def_kind.to_owned(), - path: def_path, - note: Some(deprecation), - since_kind: lint::DeprecatedSinceKind::InEffect, - }; - self.tcx.emit_node_span_lint( - DEPRECATED, - id, - method_span.unwrap_or(path.span), - diag, - ); - } - } + if let Some(def_id) = path_segment.res.opt_def_id() { + match is_allowed_through_unstable_modules { + None => { + // Emit a hard stability error if this path is not stable. + + // use `None` for id to prevent deprecation check + self.tcx.check_stability_allow_unstable( + def_id, + None, + path_segment.ident.span, + None, + if is_unstable_reexport(self.tcx, id) { + AllowUnstable::Yes + } else { + AllowUnstable::No + }, + ); + } + Some(deprecation) => { + // Call the stability check directly so that we can control which + // diagnostic is emitted. + let eval_result = self.tcx.eval_stability_allow_unstable( + def_id, + None, + span, + None, + if is_unstable_reexport(self.tcx, id) { + AllowUnstable::Yes + } else { + AllowUnstable::No + }, + ); + let is_allowed = matches!(eval_result, EvalResult::Allow); + if !is_allowed { + // Calculating message for lint involves calling `self.def_path_str`, + // which will by default invoke the expensive `visible_parent_map` query. + // Skip all that work if the lint is allowed anyway. + if self.tcx.lint_level_spec_at_node(DEPRECATED, id).is_allow() { + return; } + // Show a deprecation message. + let def_path = with_no_trimmed_paths!(self.tcx.def_path_str(def_id)); + let def_kind = self.tcx.def_descr(def_id); + let diag = Deprecated { + sub: None, + kind: def_kind.to_owned(), + path: def_path, + note: Some(deprecation), + since_kind: lint::DeprecatedSinceKind::InEffect, + }; + self.tcx.emit_node_span_lint( + DEPRECATED, + id, + method_span.unwrap_or(span), + diag, + ); } } } } - - intravisit::walk_path(self, path) } } @@ -883,10 +935,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { /// See issue #94972 for details on why this is a special case fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { // Get the LocalDefId so we can lookup the item to check the kind. - let Some(owner) = id.as_owner() else { - return false; - }; - let def_id = owner.def_id; + let def_id = id.owner.def_id; let Some(stab) = tcx.lookup_stability(def_id) else { return false; @@ -898,7 +947,10 @@ fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { } // If this is a path that isn't a use, we don't need to do anything special - if !matches!(tcx.hir_expect_item(def_id).kind, ItemKind::Use(..)) { + if !matches!( + tcx.hir_node(id), + hir::Node::Item(hir::Item { kind: ItemKind::Use(..), .. }) | hir::Node::NestedUseTree(_) + ) { return false; } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 8ce95f80633b0..ee53e46dccae4 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -752,13 +752,12 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { } ast::UseTreeKind::Nested { ref items, .. } => { for &(ref tree, id) in items { - 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 - item, vis, root_span, feed, - ) - }); + 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, + ); } // 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 52e46bb21a9f3..260032c88e07b 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -38,13 +38,14 @@ use rustc_session::lint::builtin::{ use rustc_span::{DUMMY_SP, Ident, Span, kw}; use crate::imports::{Import, ImportKind}; -use crate::{DeclKind, IdentKey, LateDecl, Resolver, diagnostics, module_to_string}; +use crate::{DeclKind, IdentKey, LateDecl, Resolver, diagnostics, module_to_string, with_owner}; struct UnusedImport { use_tree: ast::UseTree, use_tree_id: ast::NodeId, item_span: Span, unused: UnordSet, + use_tree_def_id: LocalDefId, } impl UnusedImport { @@ -59,7 +60,6 @@ struct UnusedImportCheckVisitor<'a, 'ra, 'tcx> { unused_imports: FxIndexMap, extern_crate_items: Vec, base_use_tree: Option<&'a ast::UseTree>, - base_id: ast::NodeId, item_span: Span, } @@ -89,20 +89,19 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { // Check later. return; } - self.unused_import(self.base_id).add(id); + self.unused_import().add(id); } else { // This trait import is definitely used, in a way other than // method resolution. // FIXME(#120456) - is `swap_remove` correct? self.r.maybe_unused_trait_imports.swap_remove(&def_id); - if let Some(i) = self.unused_imports.get_mut(&self.base_id) { + if let Some(i) = self.unused_imports.get_mut(&self.r.current_owner.id) { i.unused.remove(&id); } } } - fn check_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId) { - let def_id = self.r.owner_def_id(id); + fn check_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId, def_id: LocalDefId) { if self.r.effective_visibilities.is_exported(def_id) { self.check_import_as_underscore(use_tree, id); self.r.maybe_unused_trait_imports.swap_remove(&def_id); @@ -111,23 +110,24 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind { if items.is_empty() { - self.unused_import(self.base_id).add(id); + self.unused_import().add(id); } } else { self.check_import(id, def_id); } } - fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport { - let use_tree_id = self.base_id; + fn unused_import(&mut self) -> &mut UnusedImport { + let use_tree_id = self.r.current_owner.id; let use_tree = self.base_use_tree.unwrap().clone(); let item_span = self.item_span; - self.unused_imports.entry(id).or_insert_with(|| UnusedImport { + self.unused_imports.entry(use_tree_id).or_insert_with(|| UnusedImport { use_tree, use_tree_id, item_span, unused: Default::default(), + use_tree_def_id: self.r.current_owner.def_id, }) } @@ -136,11 +136,11 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { ast::UseTreeKind::Simple(Some(ident)) => { if ident.name == kw::Underscore && !matches!( - self.r.owners[&id].import_res.type_ns, + self.r.current_owner.import_res[&id].type_ns, Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) ) { - self.unused_import(self.base_id).add(id); + self.unused_import().add(id); } } ast::UseTreeKind::Nested { ref items, .. } => self.check_imports_as_underscore(items), @@ -243,6 +243,12 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { } } +impl<'a, 'ra, 'tcx> AsMut> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> { + fn as_mut(&mut self) -> &mut Resolver<'ra, 'tcx> { + self.r + } +} + impl<'a, 'ra, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> { fn visit_item(&mut self, item: &'a ast::Item) { self.item_span = item.span_with_attributes(); @@ -255,9 +261,8 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> { // Use the base UseTree's NodeId as the item id // This allows the grouping of all the lints in the same item ast::ItemKind::Use(use_tree) => { - self.base_id = item.id; self.base_use_tree = Some(use_tree); - self.check_use_tree(use_tree, item.id); + self.check_use_tree(use_tree, item.id, self.r.current_owner.def_id); } &ast::ItemKind::ExternCrate(orig_name, ident) => { self.extern_crate_items.push(ExternCrateToLint { @@ -277,7 +282,7 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> { } fn visit_nested_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId) { - self.check_use_tree(use_tree, id); + self.check_use_tree(use_tree, id, self.r.local_def_id(id)); visit::walk_use_tree(self, use_tree); } } @@ -462,12 +467,11 @@ impl Resolver<'_, '_> { unused_imports: Default::default(), extern_crate_items: Default::default(), base_use_tree: None, - base_id: ast::DUMMY_NODE_ID, item_span: DUMMY_SP, }; // `use_items` is in crate DFS order, so diagnostics and side effects are unchanged. for item in use_items { - visitor.visit_item(item); + with_owner(&mut visitor, item.id, |visitor| visitor.visit_item(item)) } visitor.report_unused_extern_crate_items(maybe_unused_extern_crates); @@ -502,9 +506,8 @@ impl Resolver<'_, '_> { let test_module_span = if tcx.sess.is_test_crate() { None } else { - let parent_module = visitor.r.get_nearest_non_block_module( - visitor.r.owner_def_id(unused.use_tree_id).to_def_id(), - ); + let parent_module = + visitor.r.get_nearest_non_block_module(unused.use_tree_def_id.to_def_id()); match module_to_string(parent_module) { Some(module) if module == "test" diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index a04f2b5421e37..98fca517ec10d 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -204,7 +204,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, ItemKind::Use(_) => { return self.with_owner(i.id, None, DefKind::Use, i.span, |this, feed| { - this.brg_visit_item(i, feed); + this.with_parent(feed.def_id(), |this| { + this.brg_visit_item(i, feed); + }) }); } ItemKind::MacCall(..) => { diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 7fabc15d00bda..f03a8389f51e5 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -109,7 +109,12 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { for (decl, eff_vis) in visitor.import_effective_visibilities.iter() { let DeclKind::Import { import, .. } = decl.kind else { unreachable!() }; if let Some(def_id) = import.def_id() { - r.effective_visibilities.update_eff_vis(def_id, eff_vis, r.tcx) + r.effective_visibilities.update_eff_vis(def_id, eff_vis, r.tcx); + let root = r.owners[&import.root_id].def_id; + // The `unreachable_pub` lint also needs to know whether any of the nested entries are + // exported by this use statement. + // FIXME: We could compute this lazily in `unreachable_pub` directly, but this is less invasive. + r.effective_visibilities.update_eff_vis(root, eff_vis, r.tcx); } if decl.ambiguity.get().is_some() && eff_vis.is_public_at_level(Level::Reexported) { exported_ambiguities.insert(*decl); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 749e414d2ba9e..92bb6100a8f89 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1641,7 +1641,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // purposes it's good enough to just favor one over the other. self.per_ns_mut(|this, ns| { if let Some(binding) = bindings[ns].get().decl().map(|b| b.import_source()) { - this.owners.get_mut(&import_id).unwrap().import_res[ns] = Some(binding.res()); + this.owners + .get_mut(&import.root_id) + .unwrap() + .import_res + .entry(import_id) + .or_default()[ns] = Some(binding.res()); } }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6493631bcc145..276ac8eac8a85 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -835,6 +835,9 @@ struct LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// `use` injections are delayed for better placement and deduplication. use_injections: Vec>, + + /// All `use` and `extern crate` items, in the order in which they are visited. + use_items: Vec<&'ast Item>, } impl<'ra, 'tcx> AsRef> for LateResolutionVisitor<'_, '_, 'ra, 'tcx> { @@ -1515,6 +1518,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { in_func_body: false, lifetime_uses: Default::default(), use_injections: Vec::new(), + use_items: Vec::new(), } } @@ -3004,6 +3008,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ), ItemKind::Use(use_tree) => { + self.use_items.push(item); let maybe_exported = match use_tree.kind { UseTreeKind::Simple(_) | UseTreeKind::Glob(_) => MaybeExported::Ok(item.id), UseTreeKind::Nested { .. } => MaybeExported::NestedUse(&item.vis), @@ -3049,7 +3054,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); } - ItemKind::ExternCrate(..) => {} + ItemKind::ExternCrate(..) => self.use_items.push(item), ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => { panic!("unexpanded macro in resolve!") @@ -5539,13 +5544,11 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// Walks the whole crate in DFS order, visiting each item, counting the declared number of /// lifetime generic parameters and function parameters. Also collects all `use` and /// `extern crate` items so that `check_unused` doesn't need to walk the crate again. -struct ItemInfoCollector<'a, 'ast, 'ra, 'tcx> { +struct ItemInfoCollector<'a, 'ra, 'tcx> { r: &'a mut Resolver<'ra, 'tcx>, - /// All `use` and `extern crate` items, in the order in which they are visited. - use_items: Vec<&'ast Item>, } -impl ItemInfoCollector<'_, '_, '_, '_> { +impl ItemInfoCollector<'_, '_, '_> { fn collect_fn_info(&mut self, decl: &FnDecl, id: NodeId) { self.r .delegation_fn_sigs @@ -5579,8 +5582,8 @@ fn required_generic_args_suggestion(generics: &ast::Generics) -> Option if required.is_empty() { None } else { Some(format!("<{}>", required.join(", "))) } } -impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, 'ast, '_, '_> { - fn visit_item(&mut self, item: &'ast Item) { +impl Visitor<'_> for ItemInfoCollector<'_, '_, '_> { + fn visit_item(&mut self, item: &Item) { match &item.kind { ItemKind::TyAlias(TyAlias { generics, .. }) | ItemKind::Const(ConstItem { generics, .. }) @@ -5612,16 +5615,14 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, 'ast, '_, '_> { } } - ItemKind::Use(..) | ItemKind::ExternCrate(..) => { - self.use_items.push(item); - } - ItemKind::Mod(..) | ItemKind::Static(..) | ItemKind::ConstBlock(..) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) | ItemKind::MacCall(..) + | ItemKind::Use(..) + | ItemKind::ExternCrate(..) | ItemKind::DelegationMac(..) => {} ItemKind::Delegation(..) => { // Delegated functions have lifetimes, their count is not necessarily zero. @@ -5633,7 +5634,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, 'ast, '_, '_> { visit::walk_item(self, item) } - fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) { + fn visit_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) { if let AssocItemKind::Fn(Fn { sig, .. }) = &item.kind { self.collect_fn_info(&sig.decl, item.id); } @@ -5655,14 +5656,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { krate: &'ast Crate, ) -> (Vec<&'ast Item>, Vec>) { with_owner(self, CRATE_NODE_ID, |this| { - let mut info_collector = ItemInfoCollector { r: this, use_items: Vec::new() }; + let mut info_collector = ItemInfoCollector { r: this }; visit::walk_crate(&mut info_collector, krate); - let use_items = info_collector.use_items; 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); - let LateResolutionVisitor { use_injections, diag_metadata, .. } = + let LateResolutionVisitor { use_injections, diag_metadata, use_items, .. } = late_resolution_visitor; for (id, span) in diag_metadata.unused_labels.iter() { this.lint_buffer.buffer_lint( diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2b02fe136f2ad..cc1a94c23a07f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1650,7 +1650,12 @@ impl<'tcx> Resolver<'_, 'tcx> { /// Get the `DefId` of a child of the current owner 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(|| { + panic!( + "no entry for node id `{node:?}` in owner {:?}, available: {:#?}", + self.current_owner.def_id, self.current_owner.node_id_to_def_id + ) + }) } /// Adds a definition with a parent definition. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9f972376c11ac..5c181252eaa41 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -41,7 +41,7 @@ use rustc_errors::{FatalError, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::attrs::{AttributeKind, DocAttribute, DocInline}; -use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res}; +use rustc_hir::def::{CtorKind, DefKind, MacroKinds, PerNS, Res}; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId}; use rustc_hir::{PredicateOrigin, find_attr}; use rustc_hir_analysis::{lower_const_arg_for_rustdoc, lower_ty}; @@ -66,6 +66,14 @@ use crate::core::DocContext; use crate::formats::item_type::ItemType; use crate::visit_ast; +#[derive(Copy, Clone, Debug)] +enum ImportLowerMode { + Everything, + GlobsOnly, + NoGlobs, +} + +#[instrument(level = "trace", skip(cx))] pub(crate) fn clean_doc_module<'tcx>( doc: &visit_ast::Module<'tcx>, cx: &mut DocContext<'tcx>, @@ -103,9 +111,6 @@ pub(crate) fn clean_doc_module<'tcx>( items.extend(doc.items.values().flat_map( |visit_ast::ItemEntry { item, renamed, import_ids }| { // First, lower everything other than glob imports. - if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { - return Vec::new(); - } let v = clean_maybe_renamed_item(cx, item, *renamed, import_ids); for item in &v { if let Some(name) = item.name @@ -123,16 +128,22 @@ pub(crate) fn clean_doc_module<'tcx>( let name = renamed.unwrap_or_else(|| cx.tcx.item_name(def_id)); let import = cx.tcx.hir_expect_item(*import_id); match import.kind { - hir::ItemKind::Use(path, kind) => { - let hir::UsePath { segments, span, .. } = *path; - let path = hir::Path { segments, res: *res, span }; - clean_use_statement_inner( + hir::ItemKind::Use(tree) => { + let hir::UsePath { segments, span, .. } = *tree.prefix; + let path = hir::UsePath { + segments, + res: PerNS { value_ns: Some(*res), type_ns: None, macro_ns: None }, + span, + }; + clean_use_statement( + import.owner_id.def_id, import, Some(name), &path, - kind, + tree.kind, cx, &mut Default::default(), + ImportLowerMode::Everything, ) } _ => unreachable!(), @@ -142,8 +153,17 @@ pub(crate) fn clean_doc_module<'tcx>( items.extend(doc.items.values().flat_map( |visit_ast::ItemEntry { item, renamed, import_ids: _ }| { // Now we actually lower the imports, skipping everything else. - if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind { - clean_use_statement(item, *renamed, path, hir::UseKind::Glob, cx, &mut inserted) + if let hir::ItemKind::Use(tree) = item.kind { + clean_use_statement( + item.owner_id.def_id, + item, + *renamed, + tree.prefix, + tree.kind, + cx, + &mut inserted, + ImportLowerMode::GlobsOnly, + ) } else { // skip everything else Vec::new() @@ -180,10 +200,10 @@ pub(crate) fn clean_doc_module<'tcx>( } fn is_glob_import(tcx: TyCtxt<'_>, import_id: LocalDefId) -> bool { - if let hir::Node::Item(item) = tcx.hir_node_by_def_id(import_id) - && let hir::ItemKind::Use(_, use_kind) = item.kind + if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Use(tree), .. }) + | hir::Node::NestedUseTree(tree) = tcx.hir_node_by_def_id(import_id) { - use_kind == hir::UseKind::Glob + matches!(tree.kind, hir::UseKind::Glob) } else { false } @@ -265,7 +285,7 @@ fn generate_item_with_correct_attrs( } fn clean_generic_bound<'tcx>( - bound: &hir::GenericBound<'tcx>, + bound: &hir::GenericBound<'_>, cx: &mut DocContext<'tcx>, ) -> Option { Some(match bound { @@ -509,7 +529,7 @@ fn clean_middle_term<'tcx>( fn clean_hir_term<'tcx>( assoc_item: Option, - term: &hir::Term<'tcx>, + term: &hir::Term<'_>, cx: &mut DocContext<'tcx>, ) -> Term { match term { @@ -657,8 +677,8 @@ enum ParamDefaults { fn clean_generic_param<'tcx>( cx: &mut DocContext<'tcx>, - generics: Option<&hir::Generics<'tcx>>, - param: &hir::GenericParam<'tcx>, + generics: Option<&hir::Generics<'_>>, + param: &hir::GenericParam<'_>, ) -> GenericParamDef { let (name, kind) = match param.kind { hir::GenericParamKind::Lifetime { .. } => { @@ -1161,7 +1181,7 @@ fn clean_function<'tcx>( fn clean_params<'tcx>( cx: &mut DocContext<'tcx>, - decl: &hir::FnDecl<'tcx>, + decl: &hir::FnDecl<'_>, idents: &[Option], postprocess: impl Fn(Option) -> Option, ) -> Vec { @@ -1197,7 +1217,7 @@ fn clean_params_via_body<'tcx>( fn clean_fn_decl_with_params<'tcx>( cx: &mut DocContext<'tcx>, - decl: &hir::FnDecl<'tcx>, + decl: &hir::FnDecl<'_>, header: Option<&hir::FnHeader>, params: Vec, ) -> FnDecl { @@ -1253,14 +1273,14 @@ fn clean_poly_fn_sig<'tcx>( FnDecl { inputs: params, output, c_variadic: sig.skip_binder().c_variadic() } } -fn clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'tcx>, cx: &mut DocContext<'tcx>) -> Path { +fn clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'_>, cx: &mut DocContext<'tcx>) -> Path { let path = clean_path(trait_ref.path, cx); register_res(cx, path.res); path } fn clean_poly_trait_ref<'tcx>( - poly_trait_ref: &hir::PolyTraitRef<'tcx>, + poly_trait_ref: &hir::PolyTraitRef<'_>, cx: &mut DocContext<'tcx>, ) -> PolyTrait { PolyTrait { @@ -1610,8 +1630,8 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo fn first_non_private_clean_path<'tcx>( cx: &mut DocContext<'tcx>, - path: &hir::Path<'tcx>, - new_path_segments: &'tcx [hir::PathSegment<'tcx>], + path: &hir::Path<'_>, + new_path_segments: &[hir::PathSegment<'_>], new_path_span: rustc_span::Span, ) -> Path { let new_hir_path = @@ -1639,7 +1659,7 @@ fn first_non_private_clean_path<'tcx>( fn first_non_private<'tcx>( cx: &mut DocContext<'tcx>, hir_id: hir::HirId, - path: &hir::Path<'tcx>, + path: &hir::Path<'_>, ) -> Option { let target_def_id = path.res.opt_def_id()?; let (parent_def_id, ident) = match &path.segments { @@ -1681,10 +1701,32 @@ fn first_non_private<'tcx>( 'reexps: for reexp in child.reexport_chain.iter() { if let Some(use_def_id) = reexp.id() && let Some(local_use_def_id) = use_def_id.as_local() - && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_use_def_id) - && let hir::ItemKind::Use(path, hir::UseKind::Single(_)) = item.kind + && let hir::Node::Item(hir::Item { kind: hir::ItemKind::Use(tree), .. }) + | hir::Node::NestedUseTree(tree) = + cx.tcx.hir_node_by_def_id(local_use_def_id) + && let hir::UseKind::Single(_) = tree.kind { - for res in path.res.present_items() { + let mut segments = tree.prefix.segments.to_vec(); + let mut span = tree.prefix.span; + let mut parent = cx.tcx.local_parent(local_use_def_id); + loop { + match cx.tcx.hir_node_by_def_id(parent) { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Use(tree), .. + }) => { + span = tree.prefix.span.to(span); + segments.splice(0..0, tree.prefix.segments.iter().copied()); + break; + } + hir::Node::NestedUseTree(tree) => { + span = tree.prefix.span.to(span); + segments.splice(0..0, tree.prefix.segments.iter().copied()); + parent = cx.tcx.local_parent(local_use_def_id); + } + _ => break, + } + } + for res in tree.prefix.res.present_items() { if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res { continue; } @@ -1697,7 +1739,7 @@ fn first_non_private<'tcx>( { break 'reexps; } - last_path_res = Some((path, res)); + last_path_res = Some((segments, span, res)); continue 'reexps; } } @@ -1708,13 +1750,8 @@ fn first_non_private<'tcx>( // // 1. We found a public reexport. // 2. We didn't find a public reexport so it's the "end type" path. - if let Some((new_path, _)) = last_path_res { - return Some(first_non_private_clean_path( - cx, - path, - new_path.segments, - new_path.span, - )); + if let Some((segments, span, _)) = last_path_res { + return Some(first_non_private_clean_path(cx, path, &segments, span)); } // If `last_path_res` is `None`, it can mean two things: // @@ -1727,7 +1764,7 @@ fn first_non_private<'tcx>( None } -fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { +fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'tcx>) -> Type { let hir::Ty { hir_id, span, ref kind } = *hir_ty; let hir::TyKind::Path(qpath) = kind else { unreachable!() }; @@ -1815,7 +1852,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type fn maybe_expand_private_type_alias<'tcx>( cx: &mut DocContext<'tcx>, - path: &hir::Path<'tcx>, + path: &hir::Path<'_>, ) -> Option { let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None }; // Substitute private type aliases @@ -1885,7 +1922,7 @@ fn maybe_expand_private_type_alias<'tcx>( })) } -pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { +pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'_>, cx: &mut DocContext<'tcx>) -> Type { use rustc_hir::*; match ty.kind { @@ -2637,7 +2674,7 @@ fn clean_variant_data<'tcx>( Variant { discriminant, kind } } -fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path { +fn clean_path<'tcx>(path: &hir::Path<'_>, cx: &mut DocContext<'tcx>) -> Path { Path { res: path.res, segments: path.segments.iter().map(|x| clean_path_segment(x, cx)).collect(), @@ -2646,7 +2683,7 @@ fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path { fn clean_generic_args<'tcx>( trait_did: Option, - generic_args: &hir::GenericArgs<'tcx>, + generic_args: &hir::GenericArgs<'_>, cx: &mut DocContext<'tcx>, ) -> GenericArgs { match generic_args.parenthesized { @@ -2694,10 +2731,7 @@ fn clean_generic_args<'tcx>( } } -fn clean_path_segment<'tcx>( - path: &hir::PathSegment<'tcx>, - cx: &mut DocContext<'tcx>, -) -> PathSegment { +fn clean_path_segment<'tcx>(path: &hir::PathSegment<'_>, cx: &mut DocContext<'tcx>) -> PathSegment { let trait_did = match path.res { hir::def::Res::Def(DefKind::Trait | DefKind::TraitAlias, did) => Some(did), _ => None, @@ -2706,7 +2740,7 @@ fn clean_path_segment<'tcx>( } fn clean_bare_fn_ty<'tcx>( - bare_fn: &hir::FnPtrTy<'tcx>, + bare_fn: &hir::FnPtrTy<'_>, cx: &mut DocContext<'tcx>, ) -> BareFunctionDecl { let (generic_params, decl) = enter_impl_trait(cx, |cx| { @@ -2735,7 +2769,7 @@ fn clean_bare_fn_ty<'tcx>( } fn clean_unsafe_binder_ty<'tcx>( - unsafe_binder_ty: &hir::UnsafeBinderTy<'tcx>, + unsafe_binder_ty: &hir::UnsafeBinderTy<'_>, cx: &mut DocContext<'tcx>, ) -> UnsafeBinderTy { let generic_params = unsafe_binder_ty @@ -2870,6 +2904,7 @@ fn add_without_unwanted_attributes<'hir>( } } +#[instrument(level = "trace", skip(cx))] fn clean_maybe_renamed_item<'tcx>( cx: &mut DocContext<'tcx>, item: &hir::Item<'tcx>, @@ -2892,14 +2927,16 @@ fn clean_maybe_renamed_item<'tcx>( // generate an impl placeholder and not a "real" impl item. return clean_impl(impl_, item.owner_id.def_id, cx, renamed.is_some()); } - ItemKind::Use(path, kind) => { + ItemKind::Use(tree) => { return clean_use_statement( + item.owner_id.def_id, item, get_name(cx.tcx, item, renamed), - path, - kind, + tree.prefix, + tree.kind, cx, &mut FxHashSet::default(), + ImportLowerMode::NoGlobs, ); } _ => {} @@ -3146,28 +3183,66 @@ fn clean_extern_crate<'tcx>( )] } +#[instrument(level = "trace", skip(cx, import))] fn clean_use_statement<'tcx>( + import_def_id: LocalDefId, import: &hir::Item<'tcx>, name: Option, - path: &hir::UsePath<'tcx>, - kind: hir::UseKind, + path: &hir::UsePath<'_>, + kind: hir::UseKind<'tcx>, cx: &mut DocContext<'tcx>, inlined_names: &mut FxHashSet<(ItemType, Symbol)>, + mode: ImportLowerMode, ) -> Vec { - let mut items = Vec::new(); - let hir::UsePath { segments, ref res, span } = *path; - for res in res.present_items() { - let path = hir::Path { segments, res, span }; - items.append(&mut clean_use_statement_inner(import, name, &path, kind, cx, inlined_names)); - } - items + let name = match (kind, mode) { + (rustc_hir::UseKind::Single(n), ImportLowerMode::Everything | ImportLowerMode::NoGlobs) => { + name.or(Some(n.name)) + } + (rustc_hir::UseKind::Glob, ImportLowerMode::NoGlobs) + | (rustc_hir::UseKind::Single(_), ImportLowerMode::GlobsOnly) => return vec![], + (rustc_hir::UseKind::Glob, ImportLowerMode::Everything | ImportLowerMode::GlobsOnly) => { + name + } + (rustc_hir::UseKind::Nested { items }, _) => { + let mut all = vec![]; + for (tree, _, def_id) in items { + let mut segments = path.segments.to_vec(); + segments.extend(tree.prefix.segments.iter()); + let path = hir::UsePath { + segments: &segments, + res: tree.prefix.res, + span: path.span.to(tree.prefix.span), + }; + all.append(&mut clean_use_statement( + *def_id, + import, + None, + &path, + tree.kind, + cx, + inlined_names, + mode, + )); + } + return all; + } + }; + path.res + .present_items() + .flat_map(|res| { + let path = hir::Path { span: path.span, res, segments: path.segments }; + clean_use_statement_leaf(import_def_id, import, name, &path, kind, cx, inlined_names) + }) + .collect() } -fn clean_use_statement_inner<'tcx>( +#[instrument(level = "trace", skip(cx, import))] +fn clean_use_statement_leaf<'tcx>( + import_def_id: LocalDefId, import: &hir::Item<'tcx>, name: Option, - path: &hir::Path<'tcx>, - kind: hir::UseKind, + path: &hir::Path<'_>, + kind: hir::UseKind<'tcx>, cx: &mut DocContext<'tcx>, inlined_names: &mut FxHashSet<(ItemType, Symbol)>, ) -> Vec { @@ -3181,7 +3256,7 @@ fn clean_use_statement_inner<'tcx>( return Vec::new(); } - let visibility = cx.tcx.visibility(import.owner_id); + let visibility = cx.tcx.visibility(import_def_id); let attrs = cx.tcx.hir_attrs(import.hir_id()); let inline_attr = find_attr!( attrs, @@ -3189,8 +3264,7 @@ fn clean_use_statement_inner<'tcx>( ) .and_then(|d| d.inline.first()); let pub_underscore = visibility.is_public() && name == Some(kw::Underscore); - let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id); - let import_def_id = import.owner_id.def_id; + let current_mod = cx.tcx.parent_module_from_def_id(import_def_id); // The parent of the module in which this import resides. This // is the same as `current_mod` if that's already the top @@ -3232,7 +3306,7 @@ fn clean_use_statement_inner<'tcx>( // Also check whether imports were asked to be inlined, in case we're trying to re-export a // crate in Rust 2018+ let path = clean_path(path, cx); - let inner = if kind == hir::UseKind::Glob { + let inner = if matches!(kind, hir::UseKind::Glob) { if !denied { let mut visited = DefIdSet::default(); if let Some(items) = inline::try_inline_glob( @@ -3322,7 +3396,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( fn clean_assoc_item_constraint<'tcx>( trait_did: DefId, - constraint: &hir::AssocItemConstraint<'tcx>, + constraint: &hir::AssocItemConstraint<'_>, cx: &mut DocContext<'tcx>, ) -> AssocItemConstraint { AssocItemConstraint { diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs index 6700ca649d7be..3ba4a1bef51e4 100644 --- a/src/librustdoc/passes/propagate_stability.rs +++ b/src/librustdoc/passes/propagate_stability.rs @@ -44,9 +44,9 @@ impl DocFolder for StabilityPropagator<'_, '_> { matches!( self.cx.tcx.hir_node(hir_id), rustc_hir::Node::Item(rustc_hir::Item { - kind: rustc_hir::ItemKind::Use(_, rustc_hir::UseKind::Glob), + kind: rustc_hir::ItemKind::Use(tree), .. - }) + }) | rustc_hir::Node::NestedUseTree(tree) if matches!(tree.kind, rustc_hir::UseKind::Glob) ) }); let own_stability = if let Some(item_stab) = item_stability diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index d0b02c20644fe..0f21d63ae984b 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -212,7 +212,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // the second loop): for &i in m.item_ids { let item = self.cx.tcx.hir_item(i); - if !matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { + if !matches!( + item.kind, + hir::ItemKind::Use(hir::UseTree { kind: hir::UseKind::Glob, .. }) + ) { self.visit_item(item); } } @@ -221,7 +224,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // To match the way import precedence works, visit glob imports last. // Later passes in rustdoc will de-duplicate by name and kind, so if glob- // imported items appear last, then they'll be the ones that get discarded. - if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { + if matches!( + item.kind, + hir::ItemKind::Use(hir::UseTree { kind: hir::UseKind::Glob, .. }) + ) { self.visit_item(item); } } @@ -486,9 +492,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // If we're inlining, skip private items. _ if self.inlining && !is_pub => {} hir::ItemKind::GlobalAsm { .. } => {} - hir::ItemKind::Use(_, hir::UseKind::ListStem) => {} - hir::ItemKind::Use(path, kind) => { - for res in path.res.present_items() { + hir::ItemKind::Use(tree) => { + for res in tree.prefix.res.present_items() { // Struct and variant constructors and proc macro stubs always show up alongside // their definitions, we've already processed them so just discard these. if should_ignore_res(res) { @@ -515,10 +520,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { if d.inline.first().is_some_and(|(inline, _)| *inline == DocInline::Inline) ) }; - let ident = match kind { + let ident = match tree.kind { hir::UseKind::Single(ident) => Some(ident.name), hir::UseKind::Glob => None, - hir::UseKind::ListStem => unreachable!(), + hir::UseKind::Nested { .. } => None, }; if self.maybe_inline_local( item.owner_id.def_id, @@ -645,7 +650,7 @@ impl<'tcx> Visitor<'tcx> for RustdocVisitor<'_, 'tcx> { // Handled in `visit_item_inner` } - fn visit_use(&mut self, _: &hir::UsePath<'tcx>, _: hir::HirId) { + fn visit_use(&mut self, _: &hir::UseTree<'tcx>, _: hir::HirId) { // Handled in `visit_item_inner` } diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs index 2c520d053f439..975bf948e7ff9 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs @@ -5,7 +5,7 @@ use clippy_utils::paths::PathNS; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefIdMap; -use rustc_hir::{AmbigArg, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind}; +use rustc_hir::{AmbigArg, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind, UseTree}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; @@ -108,8 +108,11 @@ pub fn def_kind_predicate(def_kind: DefKind) -> bool { impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind - && let Some(res) = path.res.type_ns + if let ItemKind::Use(UseTree { + prefix, + kind: UseKind::Single(_), + }) = &item.kind + && let Some(res) = prefix.res.type_ns { self.check_res_emit(cx, &res, item.span); } diff --git a/src/tools/clippy/clippy_lints/src/ifs/branches_sharing_code.rs b/src/tools/clippy/clippy_lints/src/ifs/branches_sharing_code.rs index ff4683349ad88..de361e0d88d3c 100644 --- a/src/tools/clippy/clippy_lints/src/ifs/branches_sharing_code.rs +++ b/src/tools/clippy/clippy_lints/src/ifs/branches_sharing_code.rs @@ -11,7 +11,7 @@ use core::iter; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::{ - Arm, Block, Expr, ExprKind, HirId, HirIdSet, ItemKind, LetStmt, Node, Stmt, StmtKind, UseKind, intravisit, + Arm, Block, Expr, ExprKind, HirId, HirIdSet, ItemKind, LetStmt, Node, Stmt, StmtKind, UseKind, UseTree, intravisit, }; use rustc_lint::LateContext; use rustc_span::hygiene::walk_chain; @@ -259,7 +259,10 @@ fn eq_binding_names(cx: &LateContext<'_>, s: &Stmt<'_>, names: &[(HirId, Symbol) | ItemKind::Const(ident, ..) | ItemKind::Fn { ident, .. } | ItemKind::TyAlias(ident, ..) - | ItemKind::Use(_, UseKind::Single(ident)) + | ItemKind::Use(UseTree { + kind: UseKind::Single(ident), + .. + }) | ItemKind::Mod(ident, _) = item.kind => { *name == ident.name diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs index 9569b50a32070..3b63d28cfc1c6 100644 --- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs +++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir}; use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case}; use clippy_utils::{is_bool, is_from_proc_macro}; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{Body, EnumDef, FieldDef, Item, ItemKind, QPath, TyKind, UseKind, Variant, VariantData}; +use rustc_hir::{Body, EnumDef, FieldDef, Item, ItemKind, QPath, TyKind, UseKind, UseTree, Variant, VariantData}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::symbol::Symbol; @@ -532,7 +532,10 @@ impl LateLintPass<'_> for ItemNameRepetitions { | ItemKind::TraitAlias(_, ident, ..) | ItemKind::TyAlias(ident, ..) | ItemKind::Union(ident, ..) - | ItemKind::Use(_, UseKind::Single(ident)) => ident, + | ItemKind::Use(UseTree { + kind: UseKind::Single(ident), + .. + }) => ident, ItemKind::ForeignMod { .. } | ItemKind::GlobalAsm { .. } | ItemKind::Impl(_) | ItemKind::Use(..) => return, }; diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs index 0b7aaa707eecc..363a15bc1b26f 100644 --- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs +++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs @@ -5,8 +5,7 @@ use clippy_utils::source::SpanExt as _; use clippy_utils::{is_from_proc_macro, sym}; use hir::def_id::DefId; use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_hir::{ExprKind, Item, ItemKind, QPath, UseKind}; +use rustc_hir::{self as hir, ExprKind, Item, ItemKind, QPath, UseKind, UseTree}; use rustc_lint::{LateContext, LateLintPass, LintContext as _}; use rustc_session::impl_lint_pass; use rustc_span::Symbol; @@ -45,18 +44,26 @@ impl LegacyNumericConstants { pub fn new(conf: &'static Conf) -> Self { Self { msrv: conf.msrv.into() } } -} -impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + fn check_use_tree(&mut self, cx: &LateContext<'_>, tree: &UseTree<'_>) { + match tree.kind { + UseKind::Single(_) | UseKind::Glob => {}, + UseKind::Nested { items } => { + for (tree, ..) in items { + self.check_use_tree(cx, tree); + } + return; + }, + } + + let prefix = tree.prefix; // Integer modules are "TBD" deprecated, and the contents are too, // so lint on the `use` statement directly. - if let ItemKind::Use(path, kind @ (UseKind::Single(_) | UseKind::Glob)) = item.kind - && !item.span.in_external_macro(cx.sess().source_map()) - // use `present_items` because it could be in either type_ns or value_ns - && let Some(res) = path.res.present_items().next() - && let Some(def_id) = res.opt_def_id() - && self.msrv.meets(cx, msrvs::NUMERIC_ASSOCIATED_CONSTANTS) + if !tree.prefix.span.in_external_macro(cx.sess().source_map()) + // use `present_items` because it could be in either type_ns or value_ns + && let Some(res) = prefix.res.present_items().next() + && let Some(def_id) = res.opt_def_id() + && self.msrv.meets(cx, msrvs::NUMERIC_ASSOCIATED_CONSTANTS) { let module = if is_integer_module(cx, def_id) { true @@ -69,14 +76,14 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { span_lint_and_then( cx, LEGACY_NUMERIC_CONSTANTS, - path.span, + prefix.span, if module { "importing legacy numeric constants" } else { "importing a legacy numeric constant" }, |diag| { - if let UseKind::Single(ident) = kind + if let UseKind::Single(ident) = tree.kind && ident.name == kw::Underscore { diag.help("remove this import"); @@ -86,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { let def_path = cx.get_def_path(def_id); if module && let [.., module_name] = &*def_path { - if kind == UseKind::Glob { + if matches!(tree.kind, UseKind::Glob) { diag.help(format!("remove this import and use associated constants `{module_name}::` from the primitive type instead")); } else { diag.help("remove this import").note(format!( @@ -95,13 +102,21 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { } } else if let [.., module_name, name] = &*def_path { diag.help( - format!("remove this import and use the associated constant `{module_name}::{name}` from the primitive type instead") - ); + format!("remove this import and use the associated constant `{module_name}::{name}` from the primitive type instead") + ); } }, ); } } +} + +impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if let ItemKind::Use(tree) = &item.kind { + self.check_use_tree(cx, tree); + } + } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { // `std::::` check diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index e746ea9cbfc7b..a0edae14e0525 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -3,7 +3,7 @@ use clippy_utils::source::snippet; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{self as hir, AmbigArg, find_attr}; +use rustc_hir::{self as hir, AmbigArg, UseTree, find_attr}; use rustc_lint::{LateContext, LateLintPass, LintContext as _}; use rustc_session::impl_lint_pass; use rustc_span::Span; @@ -96,11 +96,11 @@ impl MacroUseImports { impl LateLintPass<'_> for MacroUseImports { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { if cx.sess().opts.edition >= Edition::Edition2018 - && let hir::ItemKind::Use(path, _kind) = &item.kind + && let hir::ItemKind::Use(UseTree { prefix, .. }) = &item.kind && let hir_id = item.hir_id() && let attrs = cx.tcx.hir_attrs(hir_id) && let Some(mac_attr_span) = find_attr!(attrs, MacroUse {span, ..} => *span) - && let Some(Res::Def(DefKind::Mod, id)) = path.res.type_ns + && let Some(Res::Def(DefKind::Mod, id)) = prefix.res.type_ns && !id.is_local() { for kid in cx.tcx.module_children(id) { diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs index b127eb14413fe..511ef2b1b7f5f 100644 --- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs +++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs @@ -7,7 +7,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::pluralize; use rustc_hir::{ FieldDef, HirId, ImplItem, ImplItemImplKind, ImplItemKind, Item, ItemKind, Node, Pat, PatKind, TraitFn, TraitItem, - TraitItemKind, UseKind, Variant, + TraitItemKind, UseKind, UseTree, Variant, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -113,6 +113,24 @@ impl MinIdentChars { }); } } + + fn check_tree(&self, cx: &LateContext<'_>, tree: &UseTree<'_>) { + match tree.kind { + UseKind::Single(ident) => { + if tree.prefix.segments.last().is_some_and(|p| p.ident.span != ident.span) + && let Some(missing) = self.check_sym(ident.name) + { + self.emit(cx, ident, missing); + } + }, + UseKind::Glob => {}, + UseKind::Nested { items } => { + for (tree, _, _) in items { + self.check_tree(cx, tree); + } + }, + } + } } impl LateLintPass<'_> for MinIdentChars { @@ -133,17 +151,15 @@ impl LateLintPass<'_> for MinIdentChars { | ItemKind::TraitAlias(_, ident, ..) | ItemKind::TyAlias(ident, ..) | ItemKind::Union(ident, ..) => ident, - ItemKind::Use(path, UseKind::Single(ident)) - if path.segments.last().is_some_and(|p| p.ident.span != ident.span) => - { - ident + ItemKind::Use(ref tree) => { + self.check_tree(cx, tree); + return; }, ItemKind::ExternCrate(..) | ItemKind::ForeignMod { .. } | ItemKind::GlobalAsm { .. } - | ItemKind::Impl(_) - | ItemKind::Use(..) => return, + | ItemKind::Impl(_) => return, }; if let Some(missing) = self.check_sym(ident.name) && !(matches!(i.kind, ItemKind::Fn { .. }) diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs index c8e3226ea22e9..e5f84ddb96715 100644 --- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs +++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs @@ -5,7 +5,7 @@ use clippy_utils::source::SpanExt as _; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefIdMap; -use rustc_hir::{Item, ItemKind, UseKind}; +use rustc_hir::{Item, ItemKind, UseKind, UseTree}; use rustc_lint::{LateContext, LateLintPass, LintContext as _}; use rustc_middle::ty::TyCtxt; use rustc_session::impl_lint_pass; @@ -67,41 +67,55 @@ impl ImportRename { .collect(), } } + + fn check_use_tree(&mut self, cx: &LateContext<'_>, tree: &UseTree<'_>) { + let hi = match tree.kind { + UseKind::Single(ident) => ident.span.hi(), + UseKind::Glob => return, + UseKind::Nested { items } => { + for (tree, ..) in items { + self.check_use_tree(cx, tree); + } + return; + }, + }; + // use `present_items` because it could be in any of type_ns, value_ns, macro_ns + for res in tree.prefix.res.present_items() { + if let Res::Def(_, id) = res + && let Some(name) = self.renames.get(&id) + // Remove semicolon since it is not present for nested imports + && let span_without_semi = cx.sess().source_map().span_until_char(tree.prefix.span.with_hi(hi), ';') + && let Some(snip) = span_without_semi.get_text(cx) + && let Some(import) = match snip.split_once(" as ") { + None => Some(snip.as_str()), + Some((import, rename)) => { + let trimmed_rename = rename.trim(); + if trimmed_rename == "_" || trimmed_rename == name.as_str() { + None + } else { + Some(import.trim()) + } + }, + } + { + span_lint_and_sugg( + cx, + MISSING_ENFORCED_IMPORT_RENAMES, + span_without_semi, + "this import should be renamed", + "try", + format!("{import} as {name}"), + Applicability::MachineApplicable, + ); + } + } + } } impl LateLintPass<'_> for ImportRename { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { - if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind { - // use `present_items` because it could be in any of type_ns, value_ns, macro_ns - for res in path.res.present_items() { - if let Res::Def(_, id) = res - && let Some(name) = self.renames.get(&id) - // Remove semicolon since it is not present for nested imports - && let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';') - && let Some(snip) = span_without_semi.get_text(cx) - && let Some(import) = match snip.split_once(" as ") { - None => Some(snip.as_str()), - Some((import, rename)) => { - let trimmed_rename = rename.trim(); - if trimmed_rename == "_" || trimmed_rename == name.as_str() { - None - } else { - Some(import.trim()) - } - }, - } - { - span_lint_and_sugg( - cx, - MISSING_ENFORCED_IMPORT_RENAMES, - span_without_semi, - "this import should be renamed", - "try", - format!("{import} as {name}"), - Applicability::MachineApplicable, - ); - } - } + if let ItemKind::Use(tree) = &item.kind { + self.check_use_tree(cx, tree) } } } diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs index 8abb5159f90e6..f065eb6960b3e 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Item, ItemKind, UseKind}; +use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; @@ -84,10 +84,12 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { } } -// We ignore macro exports. And `ListStem` uses, which aren't interesting. +// We ignore macro exports. fn is_ignorable_export<'tcx>(item: &'tcx Item<'tcx>) -> bool { - if let ItemKind::Use(path, kind) = item.kind { - let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(_), _))) || kind == UseKind::ListStem; + if let ItemKind::Use(tree) = item.kind { + let ignore = tree + .resolutions() + .any(|res| matches!(res.macro_ns, Some(Res::Def(DefKind::Macro(_), _)))); if ignore { return true; } diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index 3f4ba4724e942..d9ec7302e5705 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -5,11 +5,11 @@ use clippy_utils::msrvs::Msrv; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{Block, Body, HirId, Path, PathSegment, StabilityLevel, StableSince}; +use rustc_hir::{Block, Body, HirId, Item, ItemKind, Path, PathSegment, StabilityLevel, StableSince}; use rustc_lint::{LateContext, LateLintPass, Lint, LintContext as _}; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; -use rustc_span::{Span, sym}; +use rustc_span::{Ident, Span, sym}; declare_clippy_lint! { /// ### What it does @@ -95,6 +95,7 @@ impl_lint_pass!(StdReexports => [ pub struct StdReexports { lint_points: Option<(Span, Vec)>, msrv: Msrv, + tree_start: Option<(Res, Ident)>, } impl StdReexports { @@ -102,6 +103,7 @@ impl StdReexports { Self { lint_points: Option::default(), msrv: conf.msrv.into(), + tree_start: None, } } @@ -122,36 +124,46 @@ enum LintPoint { } impl<'tcx> LateLintPass<'tcx> for StdReexports { + fn check_item(&mut self, _: &LateContext<'_>, item: &Item<'_>) { + if let ItemKind::Use(tree) = item.kind { + self.tree_start = get_first_segment(tree.prefix.segments); + } + } + + fn check_item_post(&mut self, _: &LateContext<'_>, _: &Item<'_>) { + self.tree_start = None; + } + fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { if let Res::Def(def_kind, def_id) = path.res && !matches!(def_kind, DefKind::Macro(_)) - && let Some(first_segment) = get_first_segment(path) - && let Res::Def(DefKind::Mod, crate_def_id) = first_segment.res + && let Some((res, ident)) = self.tree_start.or(get_first_segment(path.segments)) + && let Res::Def(DefKind::Mod, crate_def_id) = res && crate_def_id.is_crate_root() && is_stable(cx, def_id, self.msrv) && !path.span.in_external_macro(cx.sess().source_map()) - && !is_from_proc_macro(cx, &first_segment.ident) + && !is_from_proc_macro(cx, &ident) && let Some(last_segment) = path.segments.last() { - let (lint, used_mod, replace_with) = match first_segment.ident.name { + let (lint, used_mod, replace_with) = match ident.name { sym::std => match cx.tcx.crate_name(def_id.krate) { sym::core => (STD_INSTEAD_OF_CORE, "std", "core"), sym::alloc => (STD_INSTEAD_OF_ALLOC, "std", "alloc"), _ => { - self.lint_if_finish(cx, first_segment.ident.span, LintPoint::Conflict); + self.lint_if_finish(cx, ident.span, LintPoint::Conflict); return; }, }, sym::alloc if cx.tcx.crate_name(def_id.krate) == sym::core => (ALLOC_INSTEAD_OF_CORE, "alloc", "core"), _ => { - self.lint_if_finish(cx, first_segment.ident.span, LintPoint::Conflict); + self.lint_if_finish(cx, ident.span, LintPoint::Conflict); return; }, }; self.lint_if_finish( cx, - first_segment.ident.span, + ident.span, LintPoint::Available(last_segment.ident.span, lint, used_mod, replace_with), ); } @@ -223,11 +235,11 @@ fn emit_lints(cx: &LateContext<'_>, lint_points: Option<(Span, Vec)>) /// /// If this is a global path (such as `::std::fmt::Debug`), then the segment after [`kw::PathRoot`] /// is returned. -fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { - match path.segments { +fn get_first_segment<'tcx>(segments: &'tcx [PathSegment<'tcx>]) -> Option<(Res, Ident)> { + match segments { // A global path will have PathRoot as the first segment. In this case, return the segment after. - [x, y, ..] if x.ident.name == kw::PathRoot => Some(y), - [x, ..] => Some(x), + [x, y, ..] if x.ident.name == kw::PathRoot => Some((y.res, y.ident)), + [x, ..] => Some((x.res, x.ident)), _ => None, } } diff --git a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs index 8f6bacdd70ec3..7d4a177c8b08b 100644 --- a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs +++ b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs @@ -5,7 +5,8 @@ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_opt; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Item, ItemKind, UseKind}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{Item, ItemKind, UseKind, UseTree}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Visibility; use rustc_session::impl_lint_pass; @@ -55,21 +56,29 @@ impl UnusedTraitNames { pub fn new(conf: &'static Conf) -> Self { Self { msrv: conf.msrv.into() } } -} -impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames { - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if !item.span.from_expansion() - && let ItemKind::Use(path, UseKind::Single(ident)) = item.kind - // Ignore imports that already use Underscore - && ident.name != kw::Underscore + fn check_use_tree(&mut self, cx: &LateContext<'_>, tree: &UseTree<'_>, def_id: LocalDefId) { + let ident = match tree.kind { + UseKind::Single(ident) => ident, + UseKind::Glob => return, + UseKind::Nested { items } => { + for (tree, _, def_id) in items { + self.check_use_tree(cx, tree, *def_id); + } + return; + }, + }; + let prefix = tree.prefix; + if + // Ignore imports that already use Underscore + ident.name != kw::Underscore // Only check traits - && let Some(Res::Def(DefKind::Trait, _)) = path.res.type_ns - && cx.tcx.resolutions(()).maybe_unused_trait_imports.contains(&item.owner_id.def_id) + && let Some(Res::Def(DefKind::Trait, _)) = prefix.res.type_ns + && cx.tcx.resolutions(()).maybe_unused_trait_imports.contains(&def_id) // Only check this import if it is visible to its module only (no pub, pub(crate), ...) - && let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id) - && cx.tcx.local_visibility(item.owner_id.def_id) == Visibility::Restricted(module) - && let Some(last_segment) = path.segments.last() + && let module = cx.tcx.parent_module_from_def_id(def_id) + && cx.tcx.local_visibility(def_id) == Visibility::Restricted(module) + && let Some(last_segment) = prefix.segments.last() && let Some(snip) = snippet_opt(cx, last_segment.ident.span) && self.msrv.meets(cx, msrvs::UNDERSCORE_IMPORTS) && !is_from_proc_macro(cx, &last_segment.ident) @@ -87,3 +96,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames { } } } + +impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if !item.span.from_expansion() + && let ItemKind::Use(tree) = &item.kind + { + self.check_use_tree(cx, tree, item.owner_id.def_id); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 57a2c1e667cb7..1de7730e302f3 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -5,12 +5,13 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Item, ItemKind, PathSegment, UseKind}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::{HirId, Item, ItemKind, PathSegment, UseKind, UseTree}; use rustc_lint::{LateContext, LateLintPass, LintContext as _}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::BytePos; use rustc_span::symbol::kw; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -126,9 +127,27 @@ impl LateLintPass<'_> for WildcardImports { if cx.tcx.local_visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module) && !self.warn_on_all { return; } - if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind - && (self.warn_on_all || !self.check_exceptions(cx, item, use_path.segments)) - && let Some(used_imports) = cx.tcx.resolutions(()).glob_map.get(&item.owner_id.def_id) + if let ItemKind::Use(tree) = &item.kind { + self.check_use_tree(cx, tree, item.hir_id(), item.owner_id.def_id); + } + } +} + +impl WildcardImports { + fn check_use_tree(&mut self, cx: &LateContext<'_>, tree: &UseTree<'_>, hir_id: HirId, def_id: LocalDefId) { + match tree.kind { + UseKind::Single(_) => return, + UseKind::Glob => {}, + UseKind::Nested { items } => { + for (tree, id, def_id) in items { + self.check_use_tree(cx, tree, *id, *def_id); + } + return; + }, + } + let use_path = tree.prefix; + if (self.warn_on_all || !self.check_exceptions(cx, use_path.span, hir_id, use_path.segments)) + && let Some(used_imports) = cx.tcx.resolutions(()).glob_map.get(&def_id) && !used_imports.is_empty() // Already handled by `unused_imports` && !used_imports.contains(&kw::Underscore) { @@ -145,10 +164,14 @@ impl LateLintPass<'_> for WildcardImports { // formatting like `use _ :: *;`, we extend it up to, but not including the // `;`. In nested imports, like `use _::{inner::*, _}` there is no `;` and we // can just use the end of the item span - let mut span = use_path.span.with_hi(item.span.hi()); + let mut span = use_path.span; if snippet(cx, span, "").ends_with(';') { - span = use_path.span.with_hi(item.span.hi() - BytePos(1)); + span = use_path.span.with_hi(span.hi() - BytePos(1)); } + while !snippet(cx, span, "").ends_with('*') { + span = use_path.span.with_hi(span.hi() + BytePos(1)); + } + (span, false) }; @@ -180,11 +203,11 @@ impl LateLintPass<'_> for WildcardImports { } impl WildcardImports { - fn check_exceptions(&self, cx: &LateContext<'_>, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool { - item.span.from_expansion() + fn check_exceptions(&self, cx: &LateContext<'_>, span: Span, hir_id: HirId, segments: &[PathSegment<'_>]) -> bool { + span.from_expansion() || is_prelude_import(segments) || is_allowed_via_config(segments, self.allowed_segments) - || (is_super_only_import(segments) && is_in_test(cx.tcx, item.hir_id())) + || (is_super_only_import(segments) && is_in_test(cx.tcx, hir_id)) } } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 19388e6cd35dd..69a7d5c48738d 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -15,7 +15,7 @@ use rustc_hir::{ GenericParam, GenericParamKind, GenericParamSource, Generics, HirId, HirIdMap, InlineAsmOperand, ItemId, ItemKind, LetExpr, Lifetime, LifetimeKind, LifetimeParamKind, Node, ParamName, Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PreciseCapturingArgKind, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty, - TyFieldPath, TyKind, TyPat, TyPatKind, UseKind, WherePredicate, WherePredicateKind, + TyFieldPath, TyKind, TyPat, TyPatKind, UseKind, UseTree, WherePredicate, WherePredicateKind, }; use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; use rustc_lint::LateContext; @@ -245,14 +245,7 @@ impl HirEqInterExpr<'_, '_, '_> { (ItemKind::TyAlias(l_ident, l_generics, l_ty), ItemKind::TyAlias(r_ident, r_generics, r_ty)) => { l_ident.name == r_ident.name && self.eq_generics(l_generics, r_generics) && self.eq_ty(l_ty, r_ty) }, - (ItemKind::Use(l_path, l_kind), ItemKind::Use(r_path, r_kind)) => { - self.eq_path_segments(l_path.segments, r_path.segments) - && match (l_kind, r_kind) { - (UseKind::Single(l_ident), UseKind::Single(r_ident)) => l_ident.name == r_ident.name, - (UseKind::Glob, UseKind::Glob) | (UseKind::ListStem, UseKind::ListStem) => true, - _ => false, - } - }, + (ItemKind::Use(ref l_tree), ItemKind::Use(ref r_tree)) => self.eq_use_tree(l_tree, r_tree), (ItemKind::Mod(l_ident, l_mod), ItemKind::Mod(r_ident, r_mod)) => { l_ident.name == r_ident.name && over(l_mod.item_ids, r_mod.item_ids, |l, r| self.eq_item(*l, *r)) }, @@ -264,6 +257,22 @@ impl HirEqInterExpr<'_, '_, '_> { eq } + fn eq_use_tree(&mut self, l_tree: &UseTree<'_>, r_tree: &UseTree<'_>) -> bool { + self.eq_path_segments(l_tree.prefix.segments, r_tree.prefix.segments) + && match (l_tree.kind, r_tree.kind) { + (UseKind::Single(l_ident), UseKind::Single(r_ident)) => l_ident.name == r_ident.name, + (UseKind::Glob, UseKind::Glob) => true, + (UseKind::Nested { items: l_items }, UseKind::Nested { items: r_items }) => { + l_items.len() == r_items.len() + && l_items + .iter() + .zip(r_items) + .all(|((l, _, _), (r, _, _))| self.eq_use_tree(l, r)) + }, + _ => false, + } + } + fn eq_fn_sig(&mut self, left: &FnSig<'_>, right: &FnSig<'_>) -> bool { left.header.safety == right.header.safety && left.header.constness == right.header.constness diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 9e69df1640e5e..0f18f18674505 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -2788,6 +2788,7 @@ pub fn expr_use_sites<'tcx>( | Node::TraitRef(_) | Node::Ty(_) | Node::TyPat(_) + | Node::NestedUseTree(_) | Node::WherePredicate(_) => { // This shouldn't be possible to hit; the inner iterator should have // been moved to the end before we hit any of these nodes. diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index f27c92f0d4921..f660c2ee534f4 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::Namespace::{MacroNS, TypeNS, ValueNS}; use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; -use rustc_hir::{ItemKind, Node, UseKind}; +use rustc_hir::{ItemKind, Node, UseKind, UseTree}; use rustc_lint::LateContext; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::layout::HasTyCtxt; @@ -310,13 +310,17 @@ fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, n match item_kind { ItemKind::Mod(_, r#mod) => r#mod.item_ids.iter().find_map(|&item_id| { let item = tcx.hir_item(item_id); - if let ItemKind::Use(path, UseKind::Single(ident)) = item.kind { + if let ItemKind::Use(UseTree { + prefix, + kind: UseKind::Single(ident), + }) = item.kind + { if ident.name == name { let opt_def_id = |ns: Option| ns.and_then(|res| res.opt_def_id()); match ns { - PathNS::Type => opt_def_id(path.res.type_ns), - PathNS::Value => opt_def_id(path.res.value_ns), - PathNS::Macro => opt_def_id(path.res.macro_ns), + PathNS::Type => opt_def_id(prefix.res.type_ns), + PathNS::Value => opt_def_id(prefix.res.value_ns), + PathNS::Macro => opt_def_id(prefix.res.macro_ns), PathNS::Field => None, PathNS::Arbitrary => unreachable!(), } diff --git a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr index 139331d176198..ff6b1b8822a7b 100644 --- a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr +++ b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr @@ -8,10 +8,10 @@ LL | use std::process::{Child as Kid, exit as wrong_exit}; = help: to override `-D warnings` add `#[allow(clippy::missing_enforced_import_renames)]` error: this import should be renamed - --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:7:1 + --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:7:5 | LL | use std::thread::sleep; - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `use std::thread::sleep as thread_sleep` + | ^^^^^^^^^^^^^^^^^^ help: try: `std::thread::sleep as thread_sleep` error: this import should be renamed --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:11:11 @@ -32,10 +32,10 @@ LL | sync :: Mutex, | ^^^^^^^^^^^^^ help: try: `sync :: Mutex as StdMutie` error: this import should be renamed - --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:21:5 + --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:21:9 | LL | use std::collections::BTreeMap as OopsWrongRename; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `use std::collections::BTreeMap as Map` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::collections::BTreeMap as Map` error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.stderr b/src/tools/clippy/tests/ui/redundant_pub_crate.stderr index b6542e1db0902..37edb6a51ac98 100644 --- a/src/tools/clippy/tests/ui/redundant_pub_crate.stderr +++ b/src/tools/clippy/tests/ui/redundant_pub_crate.stderr @@ -138,10 +138,10 @@ LL | pub(crate) use m5_1::*; | help: consider using: `pub` error: pub(crate) import inside private module - --> tests/ui/redundant_pub_crate.rs:138:27 + --> tests/ui/redundant_pub_crate.rs:138:5 | LL | pub(crate) use m5_1::{*}; - | ---------- ^ + | ----------^^^^^^^^^^^^^^^ | | | help: consider using: `pub` diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed index 27d01e6573b85..a2854d3f1b0fe 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed @@ -200,7 +200,7 @@ fn test_reexported() { #[rustfmt::skip] fn test_weird_formatting() { - use crate:: in_fn_test::exported; + use crate:: in_fn_test::exported ; //~^ wildcard_imports use crate:: fn_mod::foo; diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr index 26434656a509e..1ec063fa14f5b 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr @@ -89,7 +89,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports.rs:203:9 | LL | use crate:: in_fn_test:: * ; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import --> tests/ui/wildcard_imports.rs:205:9 diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed index 46abaa91a1c2f..e4a1a32ca2271 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -194,7 +194,7 @@ fn test_reexported() { #[rustfmt::skip] fn test_weird_formatting() { - use crate:: in_fn_test::exported; + use crate:: in_fn_test::exported ; //~^ wildcard_imports use crate:: fn_mod::foo; diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr index 873ce41b04f49..84f26820c63f6 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -89,7 +89,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:197:9 | LL | use crate:: in_fn_test:: * ; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:199:9 diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed index 46abaa91a1c2f..e4a1a32ca2271 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -194,7 +194,7 @@ fn test_reexported() { #[rustfmt::skip] fn test_weird_formatting() { - use crate:: in_fn_test::exported; + use crate:: in_fn_test::exported ; //~^ wildcard_imports use crate:: fn_mod::foo; diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr index 873ce41b04f49..84f26820c63f6 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -89,7 +89,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:197:9 | LL | use crate:: in_fn_test:: * ; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:199:9 diff --git a/tests/rustdoc-ui/intra-doc/broken-link-in-unused-doc-string.stderr b/tests/rustdoc-ui/intra-doc/broken-link-in-unused-doc-string.stderr index b25849f25b455..676962d9169c3 100644 --- a/tests/rustdoc-ui/intra-doc/broken-link-in-unused-doc-string.stderr +++ b/tests/rustdoc-ui/intra-doc/broken-link-in-unused-doc-string.stderr @@ -1,12 +1,3 @@ -warning: unresolved link to `3` - --> $DIR/broken-link-in-unused-doc-string.rs:14:6 - | -LL | /// [3] - | ^ no item named `3` in scope - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` - = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default - warning: unresolved link to `1` --> $DIR/broken-link-in-unused-doc-string.rs:6:6 | @@ -14,6 +5,7 @@ LL | /// [1] | ^ no item named `1` in scope | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default warning: unresolved link to `1` --> $DIR/broken-link-in-unused-doc-string.rs:6:6 @@ -24,5 +16,13 @@ LL | /// [1] = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +warning: unresolved link to `3` + --> $DIR/broken-link-in-unused-doc-string.rs:14:6 + | +LL | /// [3] + | ^ no item named `3` in scope + | + = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + warning: 3 warnings emitted diff --git a/tests/ui/lint/unreachable_pub.stderr b/tests/ui/lint/unreachable_pub.stderr index 5173ff1f0264d..30a77f589b38e 100644 --- a/tests/ui/lint/unreachable_pub.stderr +++ b/tests/ui/lint/unreachable_pub.stderr @@ -14,10 +14,10 @@ LL | #![warn(unreachable_pub)] | ^^^^^^^^^^^^^^^ warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:11:24 + --> $DIR/unreachable_pub.rs:11:13 | LL | pub use std::env::{Args}; // braced-use has different item spans than unbraced - | --- ^^^^ + | --- ^^^^^^^^ | | | help: consider restricting its visibility: `pub(crate)` | diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 78403e1704dca..536a188538206 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -404,9 +404,7 @@ mod items { } /// ItemKind::Use mod item_use { - use ::{}; - use crate::expressions; - use crate::items::item_use; + use crate::{expressions;items::item_use;}; use core::*; } /// ItemKind::Static