1
Fork 0

Auto merge of #95655 - kckeiks:create-hir-crate-items-query, r=cjgillot

Refactor HIR item-like traversal (part 1)

Issue  #95004

- Create hir_crate_items query which traverses tcx.hir_crate(()).owners to return a hir::ModuleItems
- use tcx.hir_crate_items in tcx.hir().items() to return an iterator of hir::ItemId
- use tcx.hir_crate_items to introduce a tcx.hir().par_items(impl Fn(hir::ItemId)) to traverse all items in parallel;

Signed-off-by: Miguel Guarniz <mi9uel9@gmail.com>

cc `@cjgillot`
This commit is contained in:
bors 2022-04-17 08:06:53 +00:00
commit edba282770
18 changed files with 435 additions and 422 deletions

View file

@ -7,6 +7,7 @@
use crate::hir;
use crate::{Item, ItemKind, TraitItem, TraitItemKind};
use crate::def::DefKind;
use std::fmt::{self, Display};
#[derive(Copy, Clone, PartialEq, Debug)]
@ -130,6 +131,30 @@ impl Target {
}
}
// FIXME: For now, should only be used with def_kinds from ItemIds
pub fn from_def_kind(def_kind: DefKind) -> Target {
match def_kind {
DefKind::ExternCrate => Target::ExternCrate,
DefKind::Use => Target::Use,
DefKind::Static(..) => Target::Static,
DefKind::Const => Target::Const,
DefKind::Fn => Target::Fn,
DefKind::Macro(..) => Target::MacroDef,
DefKind::Mod => Target::Mod,
DefKind::ForeignMod => Target::ForeignMod,
DefKind::GlobalAsm => Target::GlobalAsm,
DefKind::TyAlias => Target::TyAlias,
DefKind::OpaqueTy => Target::OpaqueTy,
DefKind::Enum => Target::Enum,
DefKind::Struct => Target::Struct,
DefKind::Union => Target::Union,
DefKind::Trait => Target::Trait,
DefKind::TraitAlias => Target::TraitAlias,
DefKind::Impl => Target::Impl,
_ => panic!("impossible case reached"),
}
}
pub fn from_trait_item(trait_item: &TraitItem<'_>) -> Target {
match trait_item.kind {
TraitItemKind::Const(..) => Target::AssocConst,

View file

@ -24,7 +24,6 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::Node as HirNode;
use rustc_hir::{ImplItemKind, ItemKind as HirItem, TraitItemKind};
use rustc_middle::dep_graph::{label_strs, DepNode, DepNodeExt};
@ -147,7 +146,24 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
tcx.dep_graph.with_ignore(|| {
let mut dirty_clean_visitor = DirtyCleanVisitor { tcx, checked_attrs: Default::default() };
tcx.hir().visit_all_item_likes(&mut dirty_clean_visitor);
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
dirty_clean_visitor.check_item(id.def_id);
}
for id in crate_items.trait_items() {
dirty_clean_visitor.check_item(id.def_id);
}
for id in crate_items.impl_items() {
dirty_clean_visitor.check_item(id.def_id);
}
for id in crate_items.foreign_items() {
dirty_clean_visitor.check_item(id.def_id);
}
let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] };
tcx.hir().walk_attributes(&mut all_attrs);
@ -365,7 +381,8 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
}
}
fn check_item(&mut self, item_id: LocalDefId, item_span: Span) {
fn check_item(&mut self, item_id: LocalDefId) {
let item_span = self.tcx.def_span(item_id.to_def_id());
let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id());
for attr in self.tcx.get_attrs(item_id.to_def_id()).iter() {
let Some(assertion) = self.assertion_maybe(item_id, attr) else {
@ -388,24 +405,6 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
}
}
impl<'tcx> ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
self.check_item(item.def_id, item.span);
}
fn visit_trait_item(&mut self, item: &hir::TraitItem<'_>) {
self.check_item(item.def_id, item.span);
}
fn visit_impl_item(&mut self, item: &hir::ImplItem<'_>) {
self.check_item(item.def_id, item.span);
}
fn visit_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
self.check_item(item.def_id, item.span);
}
}
/// Given a `#[rustc_clean]` attribute, scan for a `cfg="foo"` attribute and check whether we have
/// a cfg flag called `foo`.
fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool {

View file

@ -1,35 +1,25 @@
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::sym;
fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
let mut finder = Finder { tcx, decls: None };
tcx.hir().visit_all_item_likes(&mut finder);
finder.decls.map(|id| tcx.hir().local_def_id(id))
for id in tcx.hir().items() {
let attrs = finder.tcx.hir().attrs(id.hir_id());
if finder.tcx.sess.contains_name(attrs, sym::rustc_proc_macro_decls) {
finder.decls = Some(id.def_id);
}
}
finder.decls
}
struct Finder<'tcx> {
tcx: TyCtxt<'tcx>,
decls: Option<hir::HirId>,
}
impl<'v> ItemLikeVisitor<'v> for Finder<'_> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
let attrs = self.tcx.hir().attrs(item.hir_id());
if self.tcx.sess.contains_name(attrs, sym::rustc_proc_macro_decls) {
self.decls = Some(item.hir_id());
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
decls: Option<hir::def_id::LocalDefId>,
}
pub(crate) fn provide(providers: &mut Providers) {

View file

@ -1,29 +1,19 @@
use rustc_hir as hir;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::def::DefKind;
use rustc_middle::ty::TyCtxt;
use rustc_session::cstore::ForeignModule;
crate fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
let mut collector = Collector { modules: Vec::new() };
tcx.hir().visit_all_item_likes(&mut collector);
collector.modules
}
struct Collector {
modules: Vec<ForeignModule>,
}
impl<'tcx> ItemLikeVisitor<'tcx> for Collector {
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
let hir::ItemKind::ForeignMod { items, .. } = it.kind else {
return;
};
let foreign_items = items.iter().map(|it| it.id.def_id.to_def_id()).collect();
self.modules.push(ForeignModule { foreign_items, def_id: it.def_id.to_def_id() });
let mut modules = Vec::new();
for id in tcx.hir().items() {
if !matches!(tcx.hir().def_kind(id.def_id), DefKind::ForeignMod) {
continue;
}
let item = tcx.hir().item(id);
if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
let foreign_items = items.iter().map(|it| it.id.def_id.to_def_id()).collect();
modules.push(ForeignModule { foreign_items, def_id: id.def_id.to_def_id() });
}
}
fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem<'tcx>) {}
fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem<'tcx>) {}
fn visit_foreign_item(&mut self, _it: &'tcx hir::ForeignItem<'tcx>) {}
modules
}

View file

@ -3,7 +3,7 @@ use rustc_attr as attr;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::def::DefKind;
use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib};
use rustc_session::parse::feature_err;
@ -15,7 +15,9 @@ use rustc_target::spec::abi::Abi;
crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
let mut collector = Collector { tcx, libs: Vec::new() };
tcx.hir().visit_all_item_likes(&mut collector);
for id in tcx.hir().items() {
collector.process_item(id);
}
collector.process_command_line();
collector.libs
}
@ -32,8 +34,13 @@ struct Collector<'tcx> {
libs: Vec<NativeLib>,
}
impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
impl<'tcx> Collector<'tcx> {
fn process_item(&mut self, id: rustc_hir::ItemId) {
if !matches!(self.tcx.hir().def_kind(id.def_id), DefKind::ForeignMod) {
return;
}
let it = self.tcx.hir().item(id);
let hir::ItemKind::ForeignMod { abi, items: foreign_mod_items } = it.kind else {
return;
};
@ -252,12 +259,6 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
}
}
fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem<'tcx>) {}
fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem<'tcx>) {}
fn visit_foreign_item(&mut self, _it: &'tcx hir::ForeignItem<'tcx>) {}
}
impl Collector<'_> {
fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
if lib.name.as_ref().map_or(false, |&s| s == kw::Empty) {
match span {

View file

@ -1787,10 +1787,27 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
debug!("EncodeContext::encode_traits_and_impls()");
empty_proc_macro!(self);
let tcx = self.tcx;
let mut visitor = ImplsVisitor { tcx, impls: FxHashMap::default() };
tcx.hir().visit_all_item_likes(&mut visitor);
let mut fx_hash_map: FxHashMap<DefId, Vec<(DefIndex, Option<SimplifiedType>)>> =
FxHashMap::default();
let mut all_impls: Vec<_> = visitor.impls.into_iter().collect();
for id in tcx.hir().items() {
if matches!(tcx.hir().def_kind(id.def_id), DefKind::Impl) {
if let Some(trait_ref) = tcx.impl_trait_ref(id.def_id.to_def_id()) {
let simplified_self_ty = fast_reject::simplify_type(
self.tcx,
trait_ref.self_ty(),
TreatParams::AsPlaceholders,
);
fx_hash_map
.entry(trait_ref.def_id)
.or_default()
.push((id.def_id.local_def_index, simplified_self_ty));
}
}
}
let mut all_impls: Vec<_> = fx_hash_map.into_iter().collect();
// Bring everything into deterministic order for hashing
all_impls.sort_by_cached_key(|&(trait_def_id, _)| tcx.def_path_hash(trait_def_id));
@ -2053,41 +2070,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
}
struct ImplsVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
impls: FxHashMap<DefId, Vec<(DefIndex, Option<SimplifiedType>)>>,
}
impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplsVisitor<'tcx> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
match item.kind {
hir::ItemKind::Impl(..) => {
if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id.to_def_id()) {
let simplified_self_ty = fast_reject::simplify_type(
self.tcx,
trait_ref.self_ty(),
TreatParams::AsPlaceholders,
);
self.impls
.entry(trait_ref.def_id)
.or_default()
.push((item.def_id.local_def_index, simplified_self_ty));
}
}
_ => {}
}
}
fn visit_trait_item(&mut self, _trait_item: &'v hir::TraitItem<'v>) {}
fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem<'v>) {
// handled in `visit_item` above
}
fn visit_foreign_item(&mut self, _foreign_item: &'v hir::ForeignItem<'v>) {}
}
/// Used to prefetch queries which will be needed later by metadata encoding.
/// Only a subset of the queries are actually prefetched to keep this code smaller.
fn prefetch_mir(tcx: TyCtxt<'_>) {

View file

@ -18,7 +18,6 @@ use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
use std::collections::VecDeque;
fn fn_decl<'hir>(node: Node<'hir>) -> Option<&'hir FnDecl<'hir>> {
match node {
@ -159,12 +158,12 @@ impl<'hir> Map<'hir> {
}
}
pub fn items(self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir {
let krate = self.krate();
krate.owners.iter().filter_map(|owner| match owner.as_owner()?.node() {
OwnerNode::Item(item) => Some(item),
_ => None,
})
pub fn items(self) -> impl Iterator<Item = ItemId> + 'hir {
self.tcx.hir_crate_items(()).items.iter().copied()
}
pub fn par_for_each_item(self, f: impl Fn(ItemId) + Sync + Send) {
par_for_each_in(&self.tcx.hir_crate_items(()).items[..], |id| f(*id));
}
pub fn def_key(self, def_id: LocalDefId) -> DefKey {
@ -675,13 +674,9 @@ impl<'hir> Map<'hir> {
}
pub fn for_each_module(self, f: impl Fn(LocalDefId)) {
let mut queue = VecDeque::new();
queue.push_back(CRATE_DEF_ID);
while let Some(id) = queue.pop_front() {
f(id);
let items = self.tcx.hir_module_items(id);
queue.extend(items.submodules.iter().copied())
let crate_items = self.tcx.hir_crate_items(());
for module in crate_items.submodules.iter() {
f(*module)
}
}
@ -1308,3 +1303,69 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalDefId) -> Module
}
}
}
pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
let mut collector = CrateCollector {
tcx,
submodules: Vec::default(),
items: Vec::default(),
trait_items: Vec::default(),
impl_items: Vec::default(),
foreign_items: Vec::default(),
};
tcx.hir().walk_toplevel_module(&mut collector);
let CrateCollector { submodules, items, trait_items, impl_items, foreign_items, .. } =
collector;
return ModuleItems {
submodules: submodules.into_boxed_slice(),
items: items.into_boxed_slice(),
trait_items: trait_items.into_boxed_slice(),
impl_items: impl_items.into_boxed_slice(),
foreign_items: foreign_items.into_boxed_slice(),
};
struct CrateCollector<'tcx> {
tcx: TyCtxt<'tcx>,
submodules: Vec<LocalDefId>,
items: Vec<ItemId>,
trait_items: Vec<TraitItemId>,
impl_items: Vec<ImplItemId>,
foreign_items: Vec<ForeignItemId>,
}
impl<'hir> Visitor<'hir> for CrateCollector<'hir> {
type NestedFilter = nested_filter::All;
fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir()
}
fn visit_item(&mut self, item: &'hir Item<'hir>) {
self.items.push(item.item_id());
intravisit::walk_item(self, item)
}
fn visit_mod(&mut self, m: &'hir Mod<'hir>, _s: Span, n: HirId) {
self.submodules.push(n.owner);
intravisit::walk_mod(self, m, n);
}
fn visit_foreign_item(&mut self, item: &'hir ForeignItem<'hir>) {
self.foreign_items.push(item.foreign_item_id());
intravisit::walk_foreign_item(self, item)
}
fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) {
self.trait_items.push(item.trait_item_id());
intravisit::walk_trait_item(self, item)
}
fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) {
self.impl_items.push(item.impl_item_id());
intravisit::walk_impl_item(self, item)
}
}
}

View file

@ -45,6 +45,24 @@ pub struct ModuleItems {
foreign_items: Box<[ForeignItemId]>,
}
impl ModuleItems {
pub fn items(&self) -> impl Iterator<Item = ItemId> + '_ {
self.items.iter().copied()
}
pub fn trait_items(&self) -> impl Iterator<Item = TraitItemId> + '_ {
self.trait_items.iter().copied()
}
pub fn impl_items(&self) -> impl Iterator<Item = ImplItemId> + '_ {
self.impl_items.iter().copied()
}
pub fn foreign_items(&self) -> impl Iterator<Item = ForeignItemId> + '_ {
self.foreign_items.iter().copied()
}
}
impl<'tcx> TyCtxt<'tcx> {
#[inline(always)]
pub fn hir(self) -> map::Map<'tcx> {
@ -68,6 +86,7 @@ pub fn provide(providers: &mut Providers) {
hir.get_module_parent_node(hir.local_def_id_to_hir_id(id))
};
providers.hir_crate = |tcx, ()| tcx.untracked_crate;
providers.hir_crate_items = map::hir_crate_items;
providers.crate_hash = map::crate_hash;
providers.hir_module_items = map::hir_module_items;
providers.hir_owner = |tcx, id| {

View file

@ -45,6 +45,13 @@ rustc_queries! {
desc { "get the crate HIR" }
}
/// All items in the crate.
query hir_crate_items(_: ()) -> rustc_middle::hir::ModuleItems {
storage(ArenaCacheSelector<'tcx>)
eval_always
desc { "get HIR crate items" }
}
/// The items in a module.
///
/// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.

View file

@ -8,7 +8,6 @@ use rustc_hir as hir;
use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
use rustc_hir::def_id::{DefId, DefIdSet, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
use rustc_hir::ItemKind;
use rustc_session::config::TrimmedDefPaths;
use rustc_session::cstore::{ExternCrate, ExternCrateSource};
use rustc_span::symbol::{kw, Ident, Symbol};
@ -2678,8 +2677,13 @@ define_print_and_forward_display! {
fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) {
// Iterate all local crate items no matter where they are defined.
let hir = tcx.hir();
for item in hir.items() {
if item.ident.name.as_str().is_empty() || matches!(item.kind, ItemKind::Use(_, _)) {
for id in hir.items() {
if matches!(hir.def_kind(id.def_id), DefKind::Use) {
continue;
}
let item = hir.item(id);
if item.ident.name == kw::Empty {
continue;
}

View file

@ -181,8 +181,8 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::GrowableBitSet;
use rustc_middle::mir::interpret::{AllocId, ConstValue};
@ -327,11 +327,19 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<
debug!("collect_roots: entry_fn = {:?}", entry_fn);
let mut visitor = RootCollector { tcx, mode, entry_fn, output: &mut roots };
let mut collector = RootCollector { tcx, mode, entry_fn, output: &mut roots };
tcx.hir().visit_all_item_likes(&mut visitor);
let crate_items = tcx.hir_crate_items(());
visitor.push_extra_entry_roots();
for id in crate_items.items() {
collector.process_item(id);
}
for id in crate_items.impl_items() {
collector.process_impl_item(id);
}
collector.push_extra_entry_roots();
}
// We can only codegen items that are instantiable - items all of
@ -1159,87 +1167,74 @@ struct RootCollector<'a, 'tcx> {
entry_fn: Option<(DefId, EntryFnType)>,
}
impl<'v> ItemLikeVisitor<'v> for RootCollector<'_, 'v> {
fn visit_item(&mut self, item: &'v hir::Item<'v>) {
match item.kind {
hir::ItemKind::ExternCrate(..)
| hir::ItemKind::Use(..)
| hir::ItemKind::Macro(..)
| hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::TyAlias(..)
| hir::ItemKind::Trait(..)
| hir::ItemKind::TraitAlias(..)
| hir::ItemKind::OpaqueTy(..)
| hir::ItemKind::Mod(..) => {
// Nothing to do, just keep recursing.
}
impl<'v> RootCollector<'_, 'v> {
fn process_item(&mut self, id: hir::ItemId) {
match self.tcx.hir().def_kind(id.def_id) {
DefKind::Enum | DefKind::Struct | DefKind::Union => {
let item = self.tcx.hir().item(id);
match item.kind {
hir::ItemKind::Enum(_, ref generics)
| hir::ItemKind::Struct(_, ref generics)
| hir::ItemKind::Union(_, ref generics) => {
if generics.params.is_empty() {
if self.mode == MonoItemCollectionMode::Eager {
debug!(
"RootCollector: ADT drop-glue for {}",
self.tcx.def_path_str(item.def_id.to_def_id())
);
hir::ItemKind::Impl { .. } => {
if self.mode == MonoItemCollectionMode::Eager {
create_mono_items_for_default_impls(self.tcx, item, self.output);
}
}
hir::ItemKind::Enum(_, ref generics)
| hir::ItemKind::Struct(_, ref generics)
| hir::ItemKind::Union(_, ref generics) => {
if generics.params.is_empty() {
if self.mode == MonoItemCollectionMode::Eager {
debug!(
"RootCollector: ADT drop-glue for {}",
self.tcx.def_path_str(item.def_id.to_def_id())
);
let ty = Instance::new(item.def_id.to_def_id(), InternalSubsts::empty())
.ty(self.tcx, ty::ParamEnv::reveal_all());
visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
let ty =
Instance::new(item.def_id.to_def_id(), InternalSubsts::empty())
.ty(self.tcx, ty::ParamEnv::reveal_all());
visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
}
}
}
_ => bug!(),
}
}
hir::ItemKind::GlobalAsm(..) => {
DefKind::GlobalAsm => {
debug!(
"RootCollector: ItemKind::GlobalAsm({})",
self.tcx.def_path_str(item.def_id.to_def_id())
self.tcx.def_path_str(id.def_id.to_def_id())
);
self.output.push(dummy_spanned(MonoItem::GlobalAsm(item.item_id())));
self.output.push(dummy_spanned(MonoItem::GlobalAsm(id)));
}
hir::ItemKind::Static(..) => {
DefKind::Static(..) => {
debug!(
"RootCollector: ItemKind::Static({})",
self.tcx.def_path_str(item.def_id.to_def_id())
self.tcx.def_path_str(id.def_id.to_def_id())
);
self.output.push(dummy_spanned(MonoItem::Static(item.def_id.to_def_id())));
self.output.push(dummy_spanned(MonoItem::Static(id.def_id.to_def_id())));
}
hir::ItemKind::Const(..) => {
DefKind::Const => {
// const items only generate mono items if they are
// actually used somewhere. Just declaring them is insufficient.
// but even just declaring them must collect the items they refer to
if let Ok(val) = self.tcx.const_eval_poly(item.def_id.to_def_id()) {
if let Ok(val) = self.tcx.const_eval_poly(id.def_id.to_def_id()) {
collect_const_value(self.tcx, val, &mut self.output);
}
}
hir::ItemKind::Fn(..) => {
self.push_if_root(item.def_id);
DefKind::Impl => {
if self.mode == MonoItemCollectionMode::Eager {
let item = self.tcx.hir().item(id);
create_mono_items_for_default_impls(self.tcx, item, self.output);
}
}
DefKind::Fn => {
self.push_if_root(id.def_id);
}
_ => {}
}
}
fn visit_trait_item(&mut self, _: &'v hir::TraitItem<'v>) {
// Even if there's a default body with no explicit generics,
// it's still generic over some `Self: Trait`, so not a root.
}
fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) {
if let hir::ImplItemKind::Fn(hir::FnSig { .. }, _) = ii.kind {
self.push_if_root(ii.def_id);
fn process_impl_item(&mut self, id: hir::ImplItemId) {
if matches!(self.tcx.hir().def_kind(id.def_id), DefKind::AssocFn) {
self.push_if_root(id.def_id);
}
}
fn visit_foreign_item(&mut self, _foreign_item: &'v hir::ForeignItem<'v>) {}
}
impl<'v> RootCollector<'_, 'v> {
fn is_root(&self, def_id: LocalDefId) -> bool {
!item_requires_monomorphization(self.tcx, def_id)
&& match self.mode {

View file

@ -12,8 +12,8 @@ use crate::weak_lang_items;
use rustc_errors::{pluralize, struct_span_err};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS};
use rustc_hir::{HirId, LangItem, LanguageItems, Target};
use rustc_middle::ty::TyCtxt;
@ -27,28 +27,6 @@ struct LanguageItemCollector<'tcx> {
tcx: TyCtxt<'tcx>,
}
impl<'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
self.check_for_lang(Target::from_item(item), item.hir_id());
if let hir::ItemKind::Enum(def, ..) = &item.kind {
for variant in def.variants {
self.check_for_lang(Target::Variant, variant.id);
}
}
}
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
self.check_for_lang(Target::from_trait_item(trait_item), trait_item.hir_id())
}
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
self.check_for_lang(target_from_impl_item(self.tcx, impl_item), impl_item.hir_id())
}
fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {}
}
impl<'tcx> LanguageItemCollector<'tcx> {
fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
LanguageItemCollector { tcx, items: LanguageItems::new() }
@ -259,7 +237,32 @@ fn get_lang_items(tcx: TyCtxt<'_>, (): ()) -> LanguageItems {
}
// Collect lang items in this crate.
tcx.hir().visit_all_item_likes(&mut collector);
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
collector.check_for_lang(Target::from_def_kind(tcx.hir().def_kind(id.def_id)), id.hir_id());
if matches!(tcx.hir().def_kind(id.def_id), DefKind::Enum) {
let item = tcx.hir().item(id);
if let hir::ItemKind::Enum(def, ..) = &item.kind {
for variant in def.variants {
collector.check_for_lang(Target::Variant, variant.id);
}
}
}
}
// FIXME: avoid calling trait_item() when possible
for id in crate_items.trait_items() {
let item = tcx.hir().trait_item(id);
collector.check_for_lang(Target::from_trait_item(item), item.hir_id())
}
// FIXME: avoid calling impl_item() when possible
for id in crate_items.impl_items() {
let item = tcx.hir().impl_item(id);
collector.check_for_lang(target_from_impl_item(tcx, item), item.hir_id())
}
// Extract out the found lang items.
let LanguageItemCollector { mut items, .. } = collector;

View file

@ -2,20 +2,11 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::lang_items::{self, LangItem};
use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
use rustc_middle::middle::lang_items::required;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::CrateType;
use rustc_span::symbol::Symbol;
use rustc_span::Span;
struct Context<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
items: &'a mut lang_items::LanguageItems,
}
/// Checks the crate for usage of weak lang items, returning a vector of all the
/// language items required by this crate, but not defined yet.
@ -30,10 +21,28 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem
items.missing.push(LangItem::EhCatchTypeinfo);
}
{
let mut cx = Context { tcx, items };
tcx.hir().visit_all_item_likes(&mut cx.as_deep_visitor());
let crate_items = tcx.hir_crate_items(());
for id in crate_items.foreign_items() {
let attrs = tcx.hir().attrs(id.hir_id());
if let Some((lang_item, _)) = lang_items::extract(attrs) {
if let Some(&item) = WEAK_ITEMS_REFS.get(&lang_item) {
if items.require(item).is_err() {
items.missing.push(item);
}
} else {
let span = tcx.def_span(id.def_id);
struct_span_err!(
tcx.sess,
span,
E0264,
"unknown external lang item: `{}`",
lang_item
)
.emit();
}
}
}
verify(tcx, items);
}
@ -80,26 +89,3 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) {
}
}
}
impl<'a, 'tcx> Context<'a, 'tcx> {
fn register(&mut self, name: Symbol, span: Span) {
if let Some(&item) = WEAK_ITEMS_REFS.get(&name) {
if self.items.require(item).is_err() {
self.items.missing.push(item);
}
} else {
struct_span_err!(self.tcx.sess, span, E0264, "unknown external lang item: `{}`", name)
.emit();
}
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) {
let attrs = self.tcx.hir().attrs(i.hir_id());
if let Some((lang_item, _)) = lang_items::extract(attrs) {
self.register(lang_item, i.span);
}
intravisit::walk_foreign_item(self, i)
}
}

View file

@ -4,7 +4,6 @@
//! def-path. This is used for unit testing the code that generates
//! paths etc in all kinds of annoying scenarios.
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{subst::InternalSubsts, Instance, TyCtxt};
@ -22,8 +21,24 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) {
}
tcx.dep_graph.with_ignore(|| {
let mut visitor = SymbolNamesTest { tcx };
tcx.hir().visit_all_item_likes(&mut visitor);
let mut symbol_names = SymbolNamesTest { tcx };
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
symbol_names.process_attrs(id.def_id);
}
for id in crate_items.trait_items() {
symbol_names.process_attrs(id.def_id);
}
for id in crate_items.impl_items() {
symbol_names.process_attrs(id.def_id);
}
for id in crate_items.foreign_items() {
symbol_names.process_attrs(id.def_id);
}
})
}
@ -58,21 +73,3 @@ impl SymbolNamesTest<'_> {
}
}
}
impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for SymbolNamesTest<'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
self.process_attrs(item.def_id);
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
self.process_attrs(trait_item.def_id);
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
self.process_attrs(impl_item.def_id);
}
fn visit_foreign_item(&mut self, foreign_item: &'tcx hir::ForeignItem<'tcx>) {
self.process_attrs(foreign_item.def_id);
}
}

View file

@ -1,72 +1,58 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint;
use rustc_span::{Span, Symbol};
pub fn check_crate(tcx: TyCtxt<'_>) {
let mut used_trait_imports = FxHashSet::default();
let mut used_trait_imports: FxHashSet<LocalDefId> = FxHashSet::default();
for item_def_id in tcx.hir().body_owners() {
let imports = tcx.used_trait_imports(item_def_id);
debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
used_trait_imports.extend(imports.iter());
}
let mut visitor = CheckVisitor { tcx, used_trait_imports };
tcx.hir().visit_all_item_likes(&mut visitor);
for id in tcx.hir().items() {
if matches!(tcx.hir().def_kind(id.def_id), DefKind::Use) {
let item = tcx.hir().item(id);
if item.vis.node.is_pub() || item.span.is_dummy() {
continue;
}
if let hir::ItemKind::Use(path, _) = item.kind {
check_import(tcx, &mut used_trait_imports, item.item_id(), path.span);
}
}
}
unused_crates_lint(tcx);
}
impl<'tcx> ItemLikeVisitor<'_> for CheckVisitor<'tcx> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
if item.vis.node.is_pub() || item.span.is_dummy() {
return;
}
if let hir::ItemKind::Use(path, _) = item.kind {
self.check_import(item.item_id(), path.span);
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
}
struct CheckVisitor<'tcx> {
fn check_import<'tcx>(
tcx: TyCtxt<'tcx>,
used_trait_imports: FxHashSet<LocalDefId>,
}
impl<'tcx> CheckVisitor<'tcx> {
fn check_import(&self, item_id: hir::ItemId, span: Span) {
if !self.tcx.maybe_unused_trait_import(item_id.def_id) {
return;
}
if self.used_trait_imports.contains(&item_id.def_id) {
return;
}
self.tcx.struct_span_lint_hir(
lint::builtin::UNUSED_IMPORTS,
item_id.hir_id(),
span,
|lint| {
let msg = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
format!("unused import: `{}`", snippet)
} else {
"unused import".to_owned()
};
lint.build(&msg).emit();
},
);
used_trait_imports: &mut FxHashSet<LocalDefId>,
item_id: hir::ItemId,
span: Span,
) {
if !tcx.maybe_unused_trait_import(item_id.def_id) {
return;
}
if used_trait_imports.contains(&item_id.def_id) {
return;
}
tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item_id.hir_id(), span, |lint| {
let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
format!("unused import: `{}`", snippet)
} else {
"unused import".to_owned()
};
lint.build(&msg).emit();
});
}
fn unused_crates_lint(tcx: TyCtxt<'_>) {
@ -110,9 +96,20 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
// Collect all the extern crates (in a reliable order).
let mut crates_to_lint = vec![];
tcx.hir().visit_all_item_likes(&mut CollectExternCrateVisitor {
crates_to_lint: &mut crates_to_lint,
});
for id in tcx.hir().items() {
if matches!(tcx.hir().def_kind(id.def_id), DefKind::ExternCrate) {
let item = tcx.hir().item(id);
if let hir::ItemKind::ExternCrate(orig_name) = item.kind {
crates_to_lint.push(ExternCrateToLint {
def_id: item.def_id.to_def_id(),
span: item.span,
orig_name,
warn_if_unused: !item.ident.as_str().starts_with('_'),
});
}
}
}
let extern_prelude = &tcx.resolutions(()).extern_prelude;
@ -193,10 +190,6 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
}
}
struct CollectExternCrateVisitor<'a> {
crates_to_lint: &'a mut Vec<ExternCrateToLint>,
}
struct ExternCrateToLint {
/// `DefId` of the extern crate
def_id: DefId,
@ -213,22 +206,3 @@ struct ExternCrateToLint {
/// about it going unused (but we should still emit idiom lints).
warn_if_unused: bool,
}
impl<'a, 'v> ItemLikeVisitor<'v> for CollectExternCrateVisitor<'a> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
if let hir::ItemKind::ExternCrate(orig_name) = item.kind {
self.crates_to_lint.push(ExternCrateToLint {
def_id: item.def_id.to_def_id(),
span: item.span,
orig_name,
warn_if_unused: !item.ident.as_str().starts_with('_'),
});
}
}
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
}

View file

@ -1,7 +1,6 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
@ -29,81 +28,57 @@ pub fn infer_predicates<'tcx>(
while predicates_added {
predicates_added = false;
let mut visitor = InferVisitor {
tcx,
global_inferred_outlives: &mut global_inferred_outlives,
predicates_added: &mut predicates_added,
explicit_map,
};
// Visit all the crates and infer predicates
tcx.hir().visit_all_item_likes(&mut visitor);
}
for id in tcx.hir().items() {
let item_did = id.def_id;
global_inferred_outlives
}
debug!("InferVisitor::visit_item(item={:?})", item_did);
pub struct InferVisitor<'cx, 'tcx> {
tcx: TyCtxt<'tcx>,
global_inferred_outlives: &'cx mut FxHashMap<DefId, RequiredPredicates<'tcx>>,
predicates_added: &'cx mut bool,
explicit_map: &'cx mut ExplicitPredicatesMap<'tcx>,
}
let mut item_required_predicates = RequiredPredicates::default();
match tcx.hir().def_kind(item_did) {
DefKind::Union | DefKind::Enum | DefKind::Struct => {
let adt_def = tcx.adt_def(item_did.to_def_id());
impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
let item_did = item.def_id;
debug!("InferVisitor::visit_item(item={:?})", item_did);
let mut item_required_predicates = RequiredPredicates::default();
match item.kind {
hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) => {
let adt_def = self.tcx.adt_def(item_did.to_def_id());
// Iterate over all fields in item_did
for field_def in adt_def.all_fields() {
// Calculating the predicate requirements necessary
// for item_did.
//
// For field of type &'a T (reference) or Adt
// (struct/enum/union) there will be outlive
// requirements for adt_def.
let field_ty = self.tcx.type_of(field_def.did);
let field_span = self.tcx.def_span(field_def.did);
insert_required_predicates_to_be_wf(
self.tcx,
field_ty,
field_span,
self.global_inferred_outlives,
&mut item_required_predicates,
&mut self.explicit_map,
);
// Iterate over all fields in item_did
for field_def in adt_def.all_fields() {
// Calculating the predicate requirements necessary
// for item_did.
//
// For field of type &'a T (reference) or Adt
// (struct/enum/union) there will be outlive
// requirements for adt_def.
let field_ty = tcx.type_of(field_def.did);
let field_span = tcx.def_span(field_def.did);
insert_required_predicates_to_be_wf(
tcx,
field_ty,
field_span,
&mut global_inferred_outlives,
&mut item_required_predicates,
explicit_map,
);
}
}
_ => {}
};
// If new predicates were added (`local_predicate_map` has more
// predicates than the `global_inferred_outlives`), the new predicates
// might result in implied predicates for their parent types.
// Therefore mark `predicates_added` as true and which will ensure
// we walk the crates again and re-calculate predicates for all
// items.
let item_predicates_len: usize =
global_inferred_outlives.get(&item_did.to_def_id()).map_or(0, |p| p.len());
if item_required_predicates.len() > item_predicates_len {
predicates_added = true;
global_inferred_outlives.insert(item_did.to_def_id(), item_required_predicates);
}
_ => {}
};
// If new predicates were added (`local_predicate_map` has more
// predicates than the `global_inferred_outlives`), the new predicates
// might result in implied predicates for their parent types.
// Therefore mark `predicates_added` as true and which will ensure
// we walk the crates again and re-calculate predicates for all
// items.
let item_predicates_len: usize =
self.global_inferred_outlives.get(&item_did.to_def_id()).map_or(0, |p| p.len());
if item_required_predicates.len() > item_predicates_len {
*self.predicates_added = true;
self.global_inferred_outlives.insert(item_did.to_def_id(), item_required_predicates);
}
}
fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem<'tcx>) {}
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem<'tcx>) {}
fn visit_foreign_item(&mut self, _foreign_item: &'tcx hir::ForeignItem<'tcx>) {}
global_inferred_outlives
}
fn insert_required_predicates_to_be_wf<'tcx>(

View file

@ -50,7 +50,12 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
let mut map = FxHashMap::<Res, ExistingName>::default();
for item in cx.tcx.hir().items() {
for id in cx.tcx.hir().items() {
if !matches!(cx.tcx.hir().def_kind(id.def_id), DefKind::Impl) {
continue;
}
let item = cx.tcx.hir().item(id);
if let ItemKind::Impl(Impl {
items,
of_trait,

View file

@ -11,6 +11,19 @@ note: existing `foo` defined here
LL | fn foo() {}
| ^^^^^^^^^^^
error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:34:13
|
LL | fn clone() {}
| ^^^^^^^^^^^^^
|
note: existing `clone` defined here
--> $DIR/same_name_method.rs:30:18
|
LL | #[derive(Clone)]
| ^^^^^
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:44:13
|
@ -47,18 +60,5 @@ note: existing `foo` defined here
LL | impl T1 for S {}
| ^^^^^^^^^^^^^^^^
error: method's name is the same as an existing method in a trait
--> $DIR/same_name_method.rs:34:13
|
LL | fn clone() {}
| ^^^^^^^^^^^^^
|
note: existing `clone` defined here
--> $DIR/same_name_method.rs:30:18
|
LL | #[derive(Clone)]
| ^^^^^
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 5 previous errors