mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 14:31:55 +00:00
Auto merge of #96825 - kckeiks:remove-item-like-visitor-trait, r=cjgillot
Retire `ItemLikeVisitor` trait Issue #95004 cc `@cjgillot`
This commit is contained in:
commit
7355d971a9
@ -1,7 +1,40 @@
|
||||
//! HIR walker for walking the contents of nodes.
|
||||
//!
|
||||
//! **For an overview of the visitor strategy, see the docs on the
|
||||
//! `super::itemlikevisit::ItemLikeVisitor` trait.**
|
||||
//! Here are the three available patterns for the visitor strategy,
|
||||
//! in roughly the order of desirability:
|
||||
//!
|
||||
//! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
|
||||
//! - Example: find all items with a `#[foo]` attribute on them.
|
||||
//! - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids
|
||||
//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir().item*(id)` to filter and
|
||||
//! access actual item-like thing, respectively.
|
||||
//! - Pro: Efficient; just walks the lists of item ids and gives users control whether to access
|
||||
//! the hir_owners themselves or not.
|
||||
//! - Con: Don't get information about nesting
|
||||
//! - Con: Don't have methods for specific bits of HIR, like "on
|
||||
//! every expr, do this".
|
||||
//! 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within
|
||||
//! an item, but don't care about how item-like things are nested
|
||||
//! within one another.
|
||||
//! - Example: Examine each expression to look for its type and do some check or other.
|
||||
//! - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
|
||||
//! `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use
|
||||
//! `tcx.hir().deep_visit_all_item_likes(&mut visitor)`. Within your
|
||||
//! `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
|
||||
//! `intravisit::walk_expr()` to keep walking the subparts).
|
||||
//! - Pro: Visitor methods for any kind of HIR node, not just item-like things.
|
||||
//! - Pro: Integrates well into dependency tracking.
|
||||
//! - Con: Don't get information about nesting between items
|
||||
//! 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between
|
||||
//! item-like things.
|
||||
//! - Example: Lifetime resolution, which wants to bring lifetimes declared on the
|
||||
//! impl into scope while visiting the impl-items, and then back out again.
|
||||
//! - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
|
||||
//! `nested_filter::All` (and implement `nested_visit_map`). Walk your crate with
|
||||
//! `tcx.hir().walk_toplevel_module(visitor)` invoked on `tcx.hir().krate()`.
|
||||
//! - Pro: Visitor methods for any kind of HIR node, not just item-like things.
|
||||
//! - Pro: Preserves nesting information
|
||||
//! - Con: Does not integrate well into dependency tracking.
|
||||
//!
|
||||
//! If you have decided to use this visitor, here are some general
|
||||
//! notes on how to do so:
|
||||
@ -32,43 +65,12 @@
|
||||
//! example generator inference, and possibly also HIR borrowck.
|
||||
|
||||
use crate::hir::*;
|
||||
use crate::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor};
|
||||
use crate::itemlikevisit::ParItemLikeVisitor;
|
||||
use rustc_ast::walk_list;
|
||||
use rustc_ast::{Attribute, Label};
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
pub struct DeepVisitor<'v, V> {
|
||||
visitor: &'v mut V,
|
||||
}
|
||||
|
||||
impl<'v, V> DeepVisitor<'v, V> {
|
||||
pub fn new(base: &'v mut V) -> Self {
|
||||
DeepVisitor { visitor: base }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V>
|
||||
where
|
||||
V: Visitor<'hir>,
|
||||
{
|
||||
fn visit_item(&mut self, item: &'hir Item<'hir>) {
|
||||
self.visitor.visit_item(item);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>) {
|
||||
self.visitor.visit_trait_item(trait_item);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>) {
|
||||
self.visitor.visit_impl_item(impl_item);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>) {
|
||||
self.visitor.visit_foreign_item(foreign_item);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoVisitor<'hir> {
|
||||
type Visitor: Visitor<'hir>;
|
||||
fn into_visitor(&self) -> Self::Visitor;
|
||||
@ -315,16 +317,6 @@ pub trait Visitor<'v>: Sized {
|
||||
walk_body(self, b);
|
||||
}
|
||||
|
||||
/// When invoking `visit_all_item_likes()`, you need to supply an
|
||||
/// item-like visitor. This method converts an "intra-visit"
|
||||
/// visitor into an item-like visitor that walks the entire tree.
|
||||
/// If you use this, you probably don't want to process the
|
||||
/// contents of nested item-like things, since the outer loop will
|
||||
/// visit them as well.
|
||||
fn as_deep_visitor(&mut self) -> DeepVisitor<'_, Self> {
|
||||
DeepVisitor::new(self)
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
fn visit_id(&mut self, _hir_id: HirId) {
|
||||
|
@ -1,55 +1,5 @@
|
||||
use super::{ForeignItem, ImplItem, Item, TraitItem};
|
||||
|
||||
/// The "item-like visitor" defines only the top-level methods
|
||||
/// that can be invoked by `Crate::visit_all_item_likes()`. Whether
|
||||
/// this trait is the right one to implement will depend on the
|
||||
/// overall pattern you need. Here are the three available patterns,
|
||||
/// in roughly the order of desirability:
|
||||
///
|
||||
/// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
|
||||
/// - Example: find all items with a `#[foo]` attribute on them.
|
||||
/// - How: Implement `ItemLikeVisitor` and call `tcx.hir().visit_all_item_likes()`.
|
||||
/// - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves.
|
||||
/// - Con: Don't get information about nesting
|
||||
/// - Con: Don't have methods for specific bits of HIR, like "on
|
||||
/// every expr, do this".
|
||||
/// 2. **Deep visit**: Want to scan for specific kinds of HIR nodes within
|
||||
/// an item, but don't care about how item-like things are nested
|
||||
/// within one another.
|
||||
/// - Example: Examine each expression to look for its type and do some check or other.
|
||||
/// - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
|
||||
/// `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use
|
||||
/// `tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within your
|
||||
/// `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
|
||||
/// `intravisit::walk_expr()` to keep walking the subparts).
|
||||
/// - Pro: Visitor methods for any kind of HIR node, not just item-like things.
|
||||
/// - Pro: Integrates well into dependency tracking.
|
||||
/// - Con: Don't get information about nesting between items
|
||||
/// 3. **Nested visit**: Want to visit the whole HIR and you care about the nesting between
|
||||
/// item-like things.
|
||||
/// - Example: Lifetime resolution, which wants to bring lifetimes declared on the
|
||||
/// impl into scope while visiting the impl-items, and then back out again.
|
||||
/// - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
|
||||
/// `nested_filter::All` (and implement `nested_visit_map`). Walk your crate with
|
||||
/// `tcx.hir().walk_toplevel_module(visitor)` invoked on `tcx.hir().krate()`.
|
||||
/// - Pro: Visitor methods for any kind of HIR node, not just item-like things.
|
||||
/// - Pro: Preserves nesting information
|
||||
/// - Con: Does not integrate well into dependency tracking.
|
||||
///
|
||||
/// Note: the methods of `ItemLikeVisitor` intentionally have no
|
||||
/// defaults, so that as we expand the list of item-like things, we
|
||||
/// revisit the various visitors to see if they need to change. This
|
||||
/// is harder to do with `intravisit::Visitor`, so when you add a new
|
||||
/// `visit_nested_foo()` method, it is recommended that you search for
|
||||
/// existing `fn visit_nested` methods to see where changes are
|
||||
/// needed.
|
||||
pub trait ItemLikeVisitor<'hir> {
|
||||
fn visit_item(&mut self, item: &'hir Item<'hir>);
|
||||
fn visit_trait_item(&mut self, trait_item: &'hir TraitItem<'hir>);
|
||||
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem<'hir>);
|
||||
fn visit_foreign_item(&mut self, foreign_item: &'hir ForeignItem<'hir>);
|
||||
}
|
||||
|
||||
/// A parallel variant of `ItemLikeVisitor`.
|
||||
pub trait ParItemLikeVisitor<'hir> {
|
||||
fn visit_item(&self, item: &'hir Item<'hir>);
|
||||
|
@ -75,7 +75,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) {
|
||||
let mut visitor =
|
||||
IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] };
|
||||
visitor.process_attrs(hir::CRATE_HIR_ID);
|
||||
tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor());
|
||||
tcx.hir().deep_visit_all_item_likes(&mut visitor);
|
||||
(visitor.if_this_changed, visitor.then_this_would_need)
|
||||
};
|
||||
|
||||
|
@ -14,7 +14,6 @@ use rustc_hir::def_id::{
|
||||
};
|
||||
use rustc_hir::definitions::DefPathData;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::lang_items;
|
||||
use rustc_hir::{AnonConst, GenericParamKind};
|
||||
use rustc_index::bit_set::GrowableBitSet;
|
||||
@ -453,7 +452,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
self.tcx.hir().visit_all_item_likes(&mut self.as_deep_visitor());
|
||||
self.tcx.hir().deep_visit_all_item_likes(self);
|
||||
}
|
||||
|
||||
fn encode_def_path_table(&mut self) {
|
||||
@ -2243,26 +2242,16 @@ pub fn provide(providers: &mut Providers) {
|
||||
traits_in_crate: |tcx, cnum| {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
|
||||
#[derive(Default)]
|
||||
struct TraitsVisitor {
|
||||
traits: Vec<DefId>,
|
||||
}
|
||||
impl ItemLikeVisitor<'_> for TraitsVisitor {
|
||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
||||
if let hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) = item.kind {
|
||||
self.traits.push(item.def_id.to_def_id());
|
||||
}
|
||||
let mut traits = Vec::new();
|
||||
for id in tcx.hir().items() {
|
||||
if matches!(tcx.def_kind(id.def_id), DefKind::Trait | DefKind::TraitAlias) {
|
||||
traits.push(id.def_id.to_def_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<'_>) {}
|
||||
}
|
||||
|
||||
let mut visitor = TraitsVisitor::default();
|
||||
tcx.hir().visit_all_item_likes(&mut visitor);
|
||||
// Bring everything into deterministic order.
|
||||
visitor.traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id));
|
||||
tcx.arena.alloc_slice(&visitor.traits)
|
||||
traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id));
|
||||
tcx.arena.alloc_slice(&traits)
|
||||
},
|
||||
|
||||
..*providers
|
||||
|
@ -9,7 +9,6 @@ use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
|
||||
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::*;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
@ -161,6 +160,10 @@ impl<'hir> Map<'hir> {
|
||||
self.tcx.hir_crate_items(()).items.iter().copied()
|
||||
}
|
||||
|
||||
pub fn module_items(self, module: LocalDefId) -> impl Iterator<Item = ItemId> + 'hir {
|
||||
self.tcx.hir_module_items(module).items()
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
@ -603,16 +606,16 @@ impl<'hir> Map<'hir> {
|
||||
}
|
||||
|
||||
/// Visits all items in the crate in some deterministic (but
|
||||
/// unspecified) order. If you just need to process every item,
|
||||
/// but don't care about nesting, this method is the best choice.
|
||||
/// unspecified) order. If you need to process every item,
|
||||
/// and care about nesting -- usually because your algorithm
|
||||
/// follows lexical scoping rules -- then this method is the best choice.
|
||||
/// If you don't care about nesting, you should use the `tcx.hir_crate_items()` query
|
||||
/// or `items()` instead.
|
||||
///
|
||||
/// If you do care about nesting -- usually because your algorithm
|
||||
/// follows lexical scoping rules -- then you want a different
|
||||
/// approach. You should override `visit_nested_item` in your
|
||||
/// visitor and then call `intravisit::walk_crate` instead.
|
||||
pub fn visit_all_item_likes<V>(self, visitor: &mut V)
|
||||
/// Please see the notes in `intravisit.rs` for more information.
|
||||
pub fn deep_visit_all_item_likes<V>(self, visitor: &mut V)
|
||||
where
|
||||
V: itemlikevisit::ItemLikeVisitor<'hir>,
|
||||
V: Visitor<'hir>,
|
||||
{
|
||||
let krate = self.krate();
|
||||
for owner in krate.owners.iter().filter_map(|i| i.as_owner()) {
|
||||
@ -643,9 +646,12 @@ impl<'hir> Map<'hir> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
|
||||
/// If you don't care about nesting, you should use the
|
||||
/// `tcx.hir_module_items()` query or `module_items()` instead.
|
||||
/// Please see notes in `deep_visit_all_item_likes`.
|
||||
pub fn deep_visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
|
||||
where
|
||||
V: ItemLikeVisitor<'hir>,
|
||||
V: Visitor<'hir>,
|
||||
{
|
||||
let module = self.tcx.hir_module_items(module);
|
||||
|
||||
@ -666,7 +672,7 @@ impl<'hir> Map<'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn for_each_module(self, f: impl Fn(LocalDefId)) {
|
||||
pub fn for_each_module(self, mut f: impl FnMut(LocalDefId)) {
|
||||
let crate_items = self.tcx.hir_crate_items(());
|
||||
for module in crate_items.submodules.iter() {
|
||||
f(*module)
|
||||
|
@ -8,7 +8,7 @@ use rustc_hir::intravisit::nested_filter::NestedFilter;
|
||||
/// constant arguments of types, e.g. in `let _: [(); /* HERE */];`.
|
||||
///
|
||||
/// **This is the most common choice.** A very common pattern is
|
||||
/// to use `visit_all_item_likes()` as an outer loop,
|
||||
/// to use `deep_visit_all_item_likes()` as an outer loop,
|
||||
/// and to have the visitor that visits the contents of each item
|
||||
/// using this setting.
|
||||
pub struct OnlyBodies(());
|
||||
|
@ -1995,7 +1995,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
||||
}
|
||||
|
||||
/// Look up the name of a definition across crates. This does not look at HIR.
|
||||
fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
|
||||
pub fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
|
||||
if let Some(cnum) = def_id.as_crate_root() {
|
||||
Some(self.crate_name(cnum))
|
||||
} else {
|
||||
|
@ -170,7 +170,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
|
||||
intravisit::walk_struct_def(self, v)
|
||||
}
|
||||
}
|
||||
tcx.hir().visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor());
|
||||
tcx.hir().deep_visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set });
|
||||
|
||||
set
|
||||
}
|
||||
|
@ -2390,7 +2390,7 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
|
||||
|
||||
fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
let check_attr_visitor = &mut CheckAttrVisitor { tcx };
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor());
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_def_id, check_attr_visitor);
|
||||
if module_def_id.is_top_level_module() {
|
||||
check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
|
||||
check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
|
||||
|
@ -57,89 +57,71 @@ impl NonConstExpr {
|
||||
|
||||
fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
let mut vis = CheckConstVisitor::new(tcx);
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckConstTraitVisitor::new(tcx));
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut vis);
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { check_mod_const_bodies, ..*providers };
|
||||
}
|
||||
|
||||
struct CheckConstTraitVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
let _: Option<_> = try {
|
||||
if let hir::ItemKind::Impl(ref imp) = item.kind && let hir::Constness::Const = imp.constness {
|
||||
let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
|
||||
let ancestors = tcx
|
||||
.trait_def(trait_def_id)
|
||||
.ancestors(tcx, item.def_id.to_def_id())
|
||||
.ok()?;
|
||||
let mut to_implement = Vec::new();
|
||||
|
||||
impl<'tcx> CheckConstTraitVisitor<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||
CheckConstTraitVisitor { tcx }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<'tcx> {
|
||||
/// check for const trait impls, and errors if the impl uses provided/default functions
|
||||
/// of the trait being implemented; as those provided functions can be non-const.
|
||||
fn visit_item<'hir>(&mut self, item: &'hir hir::Item<'hir>) {
|
||||
let _: Option<_> = try {
|
||||
if let hir::ItemKind::Impl(ref imp) = item.kind && let hir::Constness::Const = imp.constness {
|
||||
let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
|
||||
let ancestors = self
|
||||
.tcx
|
||||
.trait_def(trait_def_id)
|
||||
.ancestors(self.tcx, item.def_id.to_def_id())
|
||||
.ok()?;
|
||||
let mut to_implement = Vec::new();
|
||||
|
||||
for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
|
||||
for trait_item in tcx.associated_items(trait_def_id).in_definition_order()
|
||||
{
|
||||
if let ty::AssocItem {
|
||||
kind: ty::AssocKind::Fn,
|
||||
defaultness,
|
||||
def_id: trait_item_id,
|
||||
..
|
||||
} = *trait_item
|
||||
{
|
||||
// we can ignore functions that do not have default bodies:
|
||||
// if those are unimplemented it will be caught by typeck.
|
||||
if !defaultness.has_value()
|
||||
|| tcx
|
||||
.has_attr(trait_item_id, sym::default_method_body_is_const)
|
||||
{
|
||||
if let ty::AssocItem {
|
||||
kind: ty::AssocKind::Fn,
|
||||
defaultness,
|
||||
def_id: trait_item_id,
|
||||
..
|
||||
} = *trait_item
|
||||
{
|
||||
// we can ignore functions that do not have default bodies:
|
||||
// if those are unimplemented it will be caught by typeck.
|
||||
if !defaultness.has_value()
|
||||
|| self
|
||||
.tcx
|
||||
.has_attr(trait_item_id, sym::default_method_body_is_const)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_implemented = ancestors
|
||||
.leaf_def(self.tcx, trait_item_id)
|
||||
.map(|node_item| !node_item.defining_node.is_from_trait())
|
||||
.unwrap_or(false);
|
||||
|
||||
if !is_implemented {
|
||||
to_implement.push(self.tcx.item_name(trait_item_id).to_string());
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// all nonconst trait functions (not marked with #[default_method_body_is_const])
|
||||
// must be implemented
|
||||
if !to_implement.is_empty() {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
item.span,
|
||||
"const trait implementations may not use non-const default functions",
|
||||
)
|
||||
.note(&format!("`{}` not implemented", to_implement.join("`, `")))
|
||||
.emit();
|
||||
let is_implemented = ancestors
|
||||
.leaf_def(tcx, trait_item_id)
|
||||
.map(|node_item| !node_item.defining_node.is_from_trait())
|
||||
.unwrap_or(false);
|
||||
|
||||
if !is_implemented {
|
||||
to_implement.push(trait_item_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn visit_trait_item<'hir>(&mut self, _: &'hir hir::TraitItem<'hir>) {}
|
||||
|
||||
fn visit_impl_item<'hir>(&mut self, _: &'hir hir::ImplItem<'hir>) {}
|
||||
|
||||
fn visit_foreign_item<'hir>(&mut self, _: &'hir hir::ForeignItem<'hir>) {}
|
||||
// all nonconst trait functions (not marked with #[default_method_body_is_const])
|
||||
// must be implemented
|
||||
if !to_implement.is_empty() {
|
||||
let not_implemented = to_implement
|
||||
.into_iter()
|
||||
.map(|did| tcx.item_name(did).to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("`, `");
|
||||
tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
item.span,
|
||||
"const trait implementations may not use non-const default functions",
|
||||
)
|
||||
.note(&format!("`{}` not implemented", not_implemented))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@ -270,6 +252,11 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
|
||||
self.tcx.hir()
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
intravisit::walk_item(self, item);
|
||||
check_item(self.tcx, item);
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
|
||||
let kind = Some(hir::ConstContext::Const);
|
||||
self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
|
||||
|
@ -8,7 +8,6 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::{Node, PatKind, TyKind};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
@ -468,7 +467,7 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
||||
tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
|
||||
}
|
||||
|
||||
// This visitor seeds items that
|
||||
// These check_* functions seeds items that
|
||||
// 1) We want to explicitly consider as live:
|
||||
// * Item annotated with #[allow(dead_code)]
|
||||
// - This is done so that if we want to suppress warnings for a
|
||||
@ -481,82 +480,95 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
||||
// or
|
||||
// 2) We are not sure to be live or not
|
||||
// * Implementations of traits and trait methods
|
||||
struct LifeSeeder<'tcx> {
|
||||
worklist: Vec<LocalDefId>,
|
||||
fn check_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
// see `MarkSymbolVisitor::struct_constructors`
|
||||
struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
|
||||
}
|
||||
worklist: &mut Vec<LocalDefId>,
|
||||
struct_constructors: &mut FxHashMap<LocalDefId, LocalDefId>,
|
||||
id: hir::ItemId,
|
||||
) {
|
||||
let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.hir_id());
|
||||
if allow_dead_code {
|
||||
worklist.push(id.def_id);
|
||||
}
|
||||
|
||||
impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
||||
let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx, item.hir_id());
|
||||
if allow_dead_code {
|
||||
self.worklist.push(item.def_id);
|
||||
}
|
||||
match item.kind {
|
||||
hir::ItemKind::Enum(ref enum_def, _) => {
|
||||
let hir = self.tcx.hir();
|
||||
match tcx.def_kind(id.def_id) {
|
||||
DefKind::Enum => {
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
|
||||
let hir = tcx.hir();
|
||||
if allow_dead_code {
|
||||
self.worklist.extend(
|
||||
worklist.extend(
|
||||
enum_def.variants.iter().map(|variant| hir.local_def_id(variant.id)),
|
||||
);
|
||||
}
|
||||
|
||||
for variant in enum_def.variants {
|
||||
if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
|
||||
self.struct_constructors
|
||||
struct_constructors
|
||||
.insert(hir.local_def_id(ctor_hir_id), hir.local_def_id(variant.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Impl(hir::Impl { ref of_trait, items, .. }) => {
|
||||
if of_trait.is_some() {
|
||||
self.worklist.push(item.def_id);
|
||||
}
|
||||
for impl_item_ref in *items {
|
||||
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
|
||||
if of_trait.is_some()
|
||||
|| has_allow_dead_code_or_lang_attr(self.tcx, impl_item.hir_id())
|
||||
{
|
||||
self.worklist.push(impl_item_ref.id.def_id);
|
||||
}
|
||||
}
|
||||
DefKind::Impl => {
|
||||
let of_trait = tcx.impl_trait_ref(id.def_id);
|
||||
|
||||
if of_trait.is_some() {
|
||||
worklist.push(id.def_id);
|
||||
}
|
||||
|
||||
// get DefIds from another query
|
||||
let local_def_ids = tcx
|
||||
.associated_item_def_ids(id.def_id)
|
||||
.iter()
|
||||
.filter_map(|def_id| def_id.as_local());
|
||||
|
||||
// And we access the Map here to get HirId from LocalDefId
|
||||
for id in local_def_ids {
|
||||
if of_trait.is_some()
|
||||
|| has_allow_dead_code_or_lang_attr(tcx, tcx.hir().local_def_id_to_hir_id(id))
|
||||
{
|
||||
worklist.push(id);
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Struct(ref variant_data, _) => {
|
||||
}
|
||||
DefKind::Struct => {
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::Struct(ref variant_data, _) = item.kind {
|
||||
if let Some(ctor_hir_id) = variant_data.ctor_hir_id() {
|
||||
self.struct_constructors
|
||||
.insert(self.tcx.hir().local_def_id(ctor_hir_id), item.def_id);
|
||||
struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id);
|
||||
}
|
||||
}
|
||||
hir::ItemKind::GlobalAsm(_) => {
|
||||
// global_asm! is always live.
|
||||
self.worklist.push(item.def_id);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
DefKind::GlobalAsm => {
|
||||
// global_asm! is always live.
|
||||
worklist.push(id.def_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
|
||||
use hir::TraitItemKind::{Const, Fn};
|
||||
fn check_trait_item<'tcx>(tcx: TyCtxt<'tcx>, worklist: &mut Vec<LocalDefId>, id: hir::TraitItemId) {
|
||||
use hir::TraitItemKind::{Const, Fn};
|
||||
if matches!(tcx.def_kind(id.def_id), DefKind::AssocConst | DefKind::AssocFn) {
|
||||
let trait_item = tcx.hir().trait_item(id);
|
||||
if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
|
||||
&& has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id())
|
||||
&& has_allow_dead_code_or_lang_attr(tcx, trait_item.hir_id())
|
||||
{
|
||||
self.worklist.push(trait_item.def_id);
|
||||
worklist.push(trait_item.def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, _item: &hir::ImplItem<'_>) {
|
||||
// ignore: we are handling this in `visit_item` above
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
|
||||
use hir::ForeignItemKind::{Fn, Static};
|
||||
if matches!(foreign_item.kind, Static(..) | Fn(..))
|
||||
&& has_allow_dead_code_or_lang_attr(self.tcx, foreign_item.hir_id())
|
||||
{
|
||||
self.worklist.push(foreign_item.def_id);
|
||||
}
|
||||
fn check_foreign_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
worklist: &mut Vec<LocalDefId>,
|
||||
id: hir::ForeignItemId,
|
||||
) {
|
||||
if matches!(tcx.def_kind(id.def_id), DefKind::Static(_) | DefKind::Fn)
|
||||
&& has_allow_dead_code_or_lang_attr(tcx, id.hir_id())
|
||||
{
|
||||
worklist.push(id.def_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -564,7 +576,9 @@ fn create_and_seed_worklist<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
|
||||
let access_levels = &tcx.privacy_access_levels(());
|
||||
let worklist = access_levels
|
||||
// see `MarkSymbolVisitor::struct_constructors`
|
||||
let mut struct_constructors = Default::default();
|
||||
let mut worklist = access_levels
|
||||
.map
|
||||
.iter()
|
||||
.filter_map(
|
||||
@ -576,11 +590,20 @@ fn create_and_seed_worklist<'tcx>(
|
||||
.chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Seed implemented trait items
|
||||
let mut life_seeder = LifeSeeder { worklist, tcx, struct_constructors: Default::default() };
|
||||
tcx.hir().visit_all_item_likes(&mut life_seeder);
|
||||
let crate_items = tcx.hir_crate_items(());
|
||||
for id in crate_items.items() {
|
||||
check_item(tcx, &mut worklist, &mut struct_constructors, id);
|
||||
}
|
||||
|
||||
(life_seeder.worklist, life_seeder.struct_constructors)
|
||||
for id in crate_items.trait_items() {
|
||||
check_trait_item(tcx, &mut worklist, id);
|
||||
}
|
||||
|
||||
for id in crate_items.foreign_items() {
|
||||
check_foreign_item(tcx, &mut worklist, id);
|
||||
}
|
||||
|
||||
(worklist, struct_constructors)
|
||||
}
|
||||
|
||||
fn live_symbols_and_ignored_derived_traits<'tcx>(
|
||||
|
@ -5,8 +5,7 @@ use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_expand::base::resolve_path;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::{HirId, Target};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
@ -14,96 +13,66 @@ use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
struct DebuggerVisualizerCollector<'tcx> {
|
||||
debugger_visualizers: FxHashSet<DebuggerVisualizerFile>,
|
||||
fn check_for_debugger_visualizer<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
hir_id: HirId,
|
||||
debugger_visualizers: &mut FxHashSet<DebuggerVisualizerFile>,
|
||||
) {
|
||||
let attrs = tcx.hir().attrs(hir_id);
|
||||
for attr in attrs {
|
||||
if attr.has_name(sym::debugger_visualizer) {
|
||||
let list = match attr.meta_item_list() {
|
||||
Some(list) => list,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
impl<'v, 'tcx> ItemLikeVisitor<'v> for DebuggerVisualizerCollector<'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
||||
let target = Target::from_item(item);
|
||||
match target {
|
||||
Target::Mod => {
|
||||
self.check_for_debugger_visualizer(item.hir_id());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _: &hir::TraitItem<'_>) {}
|
||||
|
||||
fn visit_impl_item(&mut self, _: &hir::ImplItem<'_>) {}
|
||||
|
||||
fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {}
|
||||
}
|
||||
|
||||
impl<'tcx> DebuggerVisualizerCollector<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> DebuggerVisualizerCollector<'tcx> {
|
||||
DebuggerVisualizerCollector { tcx, debugger_visualizers: FxHashSet::default() }
|
||||
}
|
||||
|
||||
fn check_for_debugger_visualizer(&mut self, hir_id: HirId) {
|
||||
let attrs = self.tcx.hir().attrs(hir_id);
|
||||
for attr in attrs {
|
||||
if attr.has_name(sym::debugger_visualizer) {
|
||||
let list = match attr.meta_item_list() {
|
||||
Some(list) => list,
|
||||
let meta_item = match list.len() {
|
||||
1 => match list[0].meta_item() {
|
||||
Some(meta_item) => meta_item,
|
||||
_ => continue,
|
||||
};
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let meta_item = match list.len() {
|
||||
1 => match list[0].meta_item() {
|
||||
Some(meta_item) => meta_item,
|
||||
_ => continue,
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let file = match (meta_item.name_or_empty(), meta_item.value_str()) {
|
||||
(sym::natvis_file, Some(value)) => {
|
||||
match resolve_path(&self.tcx.sess.parse_sess, value.as_str(), attr.span) {
|
||||
Ok(file) => file,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
(_, _) => continue,
|
||||
};
|
||||
|
||||
if file.is_file() {
|
||||
let contents = match std::fs::read(&file) {
|
||||
Ok(contents) => contents,
|
||||
Err(err) => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
&format!(
|
||||
"Unable to read contents of file `{}`. {}",
|
||||
file.display(),
|
||||
err
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
let file = match (meta_item.name_or_empty(), meta_item.value_str()) {
|
||||
(sym::natvis_file, Some(value)) => {
|
||||
match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) {
|
||||
Ok(file) => file,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
self.debugger_visualizers.insert(DebuggerVisualizerFile::new(
|
||||
Arc::from(contents),
|
||||
DebuggerVisualizerType::Natvis,
|
||||
));
|
||||
} else {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
&format!("{} is not a valid file", file.display()),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
(_, _) => continue,
|
||||
};
|
||||
|
||||
if file.is_file() {
|
||||
let contents = match std::fs::read(&file) {
|
||||
Ok(contents) => contents,
|
||||
Err(err) => {
|
||||
tcx.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
&format!(
|
||||
"Unable to read contents of file `{}`. {}",
|
||||
file.display(),
|
||||
err
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
debugger_visualizers.insert(DebuggerVisualizerFile::new(
|
||||
Arc::from(contents),
|
||||
DebuggerVisualizerType::Natvis,
|
||||
));
|
||||
} else {
|
||||
tcx.sess
|
||||
.struct_span_err(attr.span, &format!("{} is not a valid file", file.display()))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,17 +83,21 @@ fn debugger_visualizers<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> Vec<Debugger
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
|
||||
// Initialize the collector.
|
||||
let mut collector = DebuggerVisualizerCollector::new(tcx);
|
||||
let mut debugger_visualizers = FxHashSet::default();
|
||||
|
||||
// Collect debugger visualizers in this crate.
|
||||
tcx.hir().visit_all_item_likes(&mut collector);
|
||||
tcx.hir().for_each_module(|id| {
|
||||
check_for_debugger_visualizer(
|
||||
tcx,
|
||||
tcx.hir().local_def_id_to_hir_id(id),
|
||||
&mut debugger_visualizers,
|
||||
)
|
||||
});
|
||||
|
||||
// Collect debugger visualizers on the crate attributes.
|
||||
collector.check_for_debugger_visualizer(CRATE_HIR_ID);
|
||||
check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers);
|
||||
|
||||
// Extract out the found debugger_visualizer items.
|
||||
let DebuggerVisualizerCollector { debugger_visualizers, .. } = collector;
|
||||
|
||||
let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>();
|
||||
|
||||
// Sort the visualizers so we always get a deterministic query result.
|
||||
|
@ -10,49 +10,22 @@
|
||||
//! * Compiler internal types like `Ty` and `TyCtxt`
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::diagnostic_items::DiagnosticItems;
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
struct DiagnosticItemCollector<'tcx> {
|
||||
fn observe_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
diagnostic_items: DiagnosticItems,
|
||||
}
|
||||
|
||||
impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
||||
self.observe_item(item.def_id);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
|
||||
self.observe_item(trait_item.def_id);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
|
||||
self.observe_item(impl_item.def_id);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
|
||||
self.observe_item(foreign_item.def_id);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> DiagnosticItemCollector<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> {
|
||||
DiagnosticItemCollector { tcx, diagnostic_items: DiagnosticItems::default() }
|
||||
}
|
||||
|
||||
fn observe_item(&mut self, def_id: LocalDefId) {
|
||||
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let attrs = self.tcx.hir().attrs(hir_id);
|
||||
if let Some(name) = extract(attrs) {
|
||||
// insert into our table
|
||||
collect_item(self.tcx, &mut self.diagnostic_items, name, def_id.to_def_id());
|
||||
}
|
||||
diagnostic_items: &mut DiagnosticItems,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let attrs = tcx.hir().attrs(hir_id);
|
||||
if let Some(name) = extract(attrs) {
|
||||
// insert into our table
|
||||
collect_item(tcx, diagnostic_items, name, def_id.to_def_id());
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,12 +68,28 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
|
||||
// Initialize the collector.
|
||||
let mut collector = DiagnosticItemCollector::new(tcx);
|
||||
let mut diagnostic_items = DiagnosticItems::default();
|
||||
|
||||
// Collect diagnostic items in this crate.
|
||||
tcx.hir().visit_all_item_likes(&mut collector);
|
||||
let crate_items = tcx.hir_crate_items(());
|
||||
|
||||
collector.diagnostic_items
|
||||
for id in crate_items.items() {
|
||||
observe_item(tcx, &mut diagnostic_items, id.def_id);
|
||||
}
|
||||
|
||||
for id in crate_items.trait_items() {
|
||||
observe_item(tcx, &mut diagnostic_items, id.def_id);
|
||||
}
|
||||
|
||||
for id in crate_items.impl_items() {
|
||||
observe_item(tcx, &mut diagnostic_items, id.def_id);
|
||||
}
|
||||
|
||||
for id in crate_items.foreign_items() {
|
||||
observe_item(tcx, &mut diagnostic_items, id.def_id);
|
||||
}
|
||||
|
||||
diagnostic_items
|
||||
}
|
||||
|
||||
/// Traverse and collect all the diagnostic items in all crates.
|
||||
|
@ -1,8 +1,8 @@
|
||||
use rustc_ast::entry::EntryPointType;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::{ForeignItem, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
|
||||
use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{DefIdTree, TyCtxt};
|
||||
use rustc_session::config::{CrateType, EntryFnType};
|
||||
@ -25,25 +25,6 @@ struct EntryContext<'tcx> {
|
||||
non_main_fns: Vec<Span>,
|
||||
}
|
||||
|
||||
impl<'tcx> ItemLikeVisitor<'tcx> for EntryContext<'tcx> {
|
||||
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
|
||||
let at_root = self.tcx.opt_local_parent(item.def_id) == Some(CRATE_DEF_ID);
|
||||
find_item(item, self, at_root);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _trait_item: &'tcx TraitItem<'tcx>) {
|
||||
// Entry fn is never a trait item.
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem<'tcx>) {
|
||||
// Entry fn is never a trait item.
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, _: &'tcx ForeignItem<'tcx>) {
|
||||
// Entry fn is never a foreign item.
|
||||
}
|
||||
}
|
||||
|
||||
fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
|
||||
let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable);
|
||||
if !any_exe {
|
||||
@ -59,28 +40,35 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
|
||||
let mut ctxt =
|
||||
EntryContext { tcx, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new() };
|
||||
|
||||
tcx.hir().visit_all_item_likes(&mut ctxt);
|
||||
for id in tcx.hir().items() {
|
||||
find_item(id, &mut ctxt);
|
||||
}
|
||||
|
||||
configure_main(tcx, &ctxt)
|
||||
}
|
||||
|
||||
// Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
|
||||
// (with `ast::Item`), so make sure to keep them in sync.
|
||||
fn entry_point_type(ctxt: &EntryContext<'_>, item: &Item<'_>, at_root: bool) -> EntryPointType {
|
||||
let attrs = ctxt.tcx.hir().attrs(item.hir_id());
|
||||
// A small optimization was added so that hir::Item is fetched only when needed.
|
||||
// An equivalent optimization was not applied to the duplicated code in test_harness.rs.
|
||||
fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> EntryPointType {
|
||||
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
|
||||
if ctxt.tcx.sess.contains_name(attrs, sym::start) {
|
||||
EntryPointType::Start
|
||||
} else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
|
||||
EntryPointType::MainAttr
|
||||
} else if item.ident.name == sym::main {
|
||||
if at_root {
|
||||
// This is a top-level function so can be `main`.
|
||||
EntryPointType::MainNamed
|
||||
} else {
|
||||
EntryPointType::OtherMain
|
||||
}
|
||||
} else {
|
||||
EntryPointType::None
|
||||
if let Some(name) = ctxt.tcx.opt_item_name(id.def_id.to_def_id())
|
||||
&& name == sym::main {
|
||||
if at_root {
|
||||
// This is a top-level function so can be `main`.
|
||||
EntryPointType::MainNamed
|
||||
} else {
|
||||
EntryPointType::OtherMain
|
||||
}
|
||||
} else {
|
||||
EntryPointType::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,11 +77,13 @@ fn throw_attr_err(sess: &Session, span: Span, attr: &str) {
|
||||
.emit();
|
||||
}
|
||||
|
||||
fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) {
|
||||
match entry_point_type(ctxt, item, at_root) {
|
||||
fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
|
||||
let at_root = ctxt.tcx.opt_local_parent(id.def_id) == Some(CRATE_DEF_ID);
|
||||
|
||||
match entry_point_type(ctxt, id, at_root) {
|
||||
EntryPointType::None => (),
|
||||
_ if !matches!(item.kind, ItemKind::Fn(..)) => {
|
||||
let attrs = ctxt.tcx.hir().attrs(item.hir_id());
|
||||
_ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => {
|
||||
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
|
||||
if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::start) {
|
||||
throw_attr_err(&ctxt.tcx.sess, attr.span, "start");
|
||||
}
|
||||
@ -103,31 +93,39 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) {
|
||||
}
|
||||
EntryPointType::MainNamed => (),
|
||||
EntryPointType::OtherMain => {
|
||||
ctxt.non_main_fns.push(item.span);
|
||||
ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
|
||||
}
|
||||
EntryPointType::MainAttr => {
|
||||
if ctxt.attr_main_fn.is_none() {
|
||||
ctxt.attr_main_fn = Some((item.def_id, item.span));
|
||||
ctxt.attr_main_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
|
||||
} else {
|
||||
struct_span_err!(
|
||||
ctxt.tcx.sess,
|
||||
item.span,
|
||||
ctxt.tcx.def_span(id.def_id.to_def_id()),
|
||||
E0137,
|
||||
"multiple functions with a `#[main]` attribute"
|
||||
)
|
||||
.span_label(item.span, "additional `#[main]` function")
|
||||
.span_label(
|
||||
ctxt.tcx.def_span(id.def_id.to_def_id()),
|
||||
"additional `#[main]` function",
|
||||
)
|
||||
.span_label(ctxt.attr_main_fn.unwrap().1, "first `#[main]` function")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
EntryPointType::Start => {
|
||||
if ctxt.start_fn.is_none() {
|
||||
ctxt.start_fn = Some((item.def_id, item.span));
|
||||
ctxt.start_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
|
||||
} else {
|
||||
struct_span_err!(ctxt.tcx.sess, item.span, E0138, "multiple `start` functions")
|
||||
.span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
|
||||
.span_label(item.span, "multiple `start` functions")
|
||||
.emit();
|
||||
struct_span_err!(
|
||||
ctxt.tcx.sess,
|
||||
ctxt.tcx.def_span(id.def_id.to_def_id()),
|
||||
E0138,
|
||||
"multiple `start` functions"
|
||||
)
|
||||
.span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
|
||||
.span_label(ctxt.tcx.def_span(id.def_id.to_def_id()), "multiple `start` functions")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ use rustc_data_structures::sync::Lock;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::{HirId, ItemLocalId};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
@ -20,8 +19,14 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
||||
let hir_map = tcx.hir();
|
||||
|
||||
hir_map.par_for_each_module(|module_id| {
|
||||
hir_map
|
||||
.visit_item_likes_in_module(module_id, &mut OuterVisitor { hir_map, errors: &errors })
|
||||
let mut v = HirIdValidator {
|
||||
hir_map,
|
||||
owner: None,
|
||||
hir_ids_seen: Default::default(),
|
||||
errors: &errors,
|
||||
};
|
||||
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_id, &mut v);
|
||||
});
|
||||
|
||||
let errors = errors.into_inner();
|
||||
@ -39,13 +44,8 @@ struct HirIdValidator<'a, 'hir> {
|
||||
errors: &'a Lock<Vec<String>>,
|
||||
}
|
||||
|
||||
struct OuterVisitor<'a, 'hir> {
|
||||
hir_map: Map<'hir>,
|
||||
errors: &'a Lock<Vec<String>>,
|
||||
}
|
||||
|
||||
impl<'a, 'hir> OuterVisitor<'a, 'hir> {
|
||||
fn new_inner_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> {
|
||||
impl<'a, 'hir> HirIdValidator<'a, 'hir> {
|
||||
fn new_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> {
|
||||
HirIdValidator {
|
||||
hir_map,
|
||||
owner: None,
|
||||
@ -53,31 +53,7 @@ impl<'a, 'hir> OuterVisitor<'a, 'hir> {
|
||||
errors: self.errors,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'hir> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> {
|
||||
fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
|
||||
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i));
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
|
||||
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
|
||||
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i));
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
|
||||
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'hir> HirIdValidator<'a, 'hir> {
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn error(&self, f: impl FnOnce() -> String) {
|
||||
@ -146,6 +122,11 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
|
||||
self.hir_map
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
|
||||
let mut inner_visitor = self.new_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i));
|
||||
}
|
||||
|
||||
fn visit_id(&mut self, hir_id: HirId) {
|
||||
let owner = self.owner.expect("no owner");
|
||||
|
||||
@ -163,17 +144,18 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
|
||||
self.hir_ids_seen.insert(hir_id.local_id);
|
||||
}
|
||||
|
||||
fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) {
|
||||
// Explicitly do nothing here. ImplItemRefs contain hir::Visibility
|
||||
// values that actually belong to an ImplItem instead of the ItemKind::Impl
|
||||
// we are currently in. So for those it's correct that they have a
|
||||
// different owner.
|
||||
fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
|
||||
let mut inner_visitor = self.new_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
|
||||
}
|
||||
|
||||
fn visit_foreign_item_ref(&mut self, _: &'hir hir::ForeignItemRef) {
|
||||
// Explicitly do nothing here. ForeignItemRefs contain hir::Visibility
|
||||
// values that actually belong to an ForeignItem instead of the ItemKind::ForeignMod
|
||||
// we are currently in. So for those it's correct that they have a
|
||||
// different owner.
|
||||
fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
|
||||
let mut inner_visitor = self.new_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
|
||||
let mut inner_visitor = self.new_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i));
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ use rustc_target::asm::{InlineAsmRegOrRegClass, InlineAsmType};
|
||||
use rustc_target::spec::abi::Abi::RustIntrinsic;
|
||||
|
||||
fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx }.as_deep_visitor());
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx });
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
|
@ -1,8 +1,6 @@
|
||||
use rustc_ast::Attribute;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::ItemKind;
|
||||
use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
|
||||
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
@ -12,97 +10,87 @@ use rustc_target::abi::{HasDataLayout, TargetDataLayout};
|
||||
pub fn test_layout(tcx: TyCtxt<'_>) {
|
||||
if tcx.features().rustc_attrs {
|
||||
// if the `rustc_attrs` feature is not enabled, don't bother testing layout
|
||||
tcx.hir().visit_all_item_likes(&mut LayoutTest { tcx });
|
||||
}
|
||||
}
|
||||
|
||||
struct LayoutTest<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ItemLikeVisitor<'tcx> for LayoutTest<'tcx> {
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
match item.kind {
|
||||
ItemKind::TyAlias(..)
|
||||
| ItemKind::Enum(..)
|
||||
| ItemKind::Struct(..)
|
||||
| ItemKind::Union(..) => {
|
||||
for attr in self.tcx.get_attrs(item.def_id.to_def_id(), sym::rustc_layout) {
|
||||
self.dump_layout_of(item.def_id, item, attr);
|
||||
for id in tcx.hir().items() {
|
||||
if matches!(
|
||||
tcx.def_kind(id.def_id),
|
||||
DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
|
||||
) {
|
||||
for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) {
|
||||
dump_layout_of(tcx, id.def_id, attr);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
|
||||
fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
|
||||
fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {}
|
||||
}
|
||||
|
||||
impl<'tcx> LayoutTest<'tcx> {
|
||||
fn dump_layout_of(&self, item_def_id: LocalDefId, item: &hir::Item<'tcx>, attr: &Attribute) {
|
||||
let tcx = self.tcx;
|
||||
let param_env = self.tcx.param_env(item_def_id);
|
||||
let ty = self.tcx.type_of(item_def_id);
|
||||
match self.tcx.layout_of(param_env.and(ty)) {
|
||||
Ok(ty_layout) => {
|
||||
// Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
|
||||
// The `..` are the names of fields to dump.
|
||||
let meta_items = attr.meta_item_list().unwrap_or_default();
|
||||
for meta_item in meta_items {
|
||||
match meta_item.name_or_empty() {
|
||||
sym::abi => {
|
||||
self.tcx.sess.span_err(item.span, &format!("abi: {:?}", ty_layout.abi));
|
||||
}
|
||||
fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attribute) {
|
||||
let tcx = tcx;
|
||||
let param_env = tcx.param_env(item_def_id);
|
||||
let ty = tcx.type_of(item_def_id);
|
||||
match tcx.layout_of(param_env.and(ty)) {
|
||||
Ok(ty_layout) => {
|
||||
// Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
|
||||
// The `..` are the names of fields to dump.
|
||||
let meta_items = attr.meta_item_list().unwrap_or_default();
|
||||
for meta_item in meta_items {
|
||||
match meta_item.name_or_empty() {
|
||||
sym::abi => {
|
||||
tcx.sess.span_err(
|
||||
tcx.def_span(item_def_id.to_def_id()),
|
||||
&format!("abi: {:?}", ty_layout.abi),
|
||||
);
|
||||
}
|
||||
|
||||
sym::align => {
|
||||
self.tcx
|
||||
.sess
|
||||
.span_err(item.span, &format!("align: {:?}", ty_layout.align));
|
||||
}
|
||||
sym::align => {
|
||||
tcx.sess.span_err(
|
||||
tcx.def_span(item_def_id.to_def_id()),
|
||||
&format!("align: {:?}", ty_layout.align),
|
||||
);
|
||||
}
|
||||
|
||||
sym::size => {
|
||||
self.tcx
|
||||
.sess
|
||||
.span_err(item.span, &format!("size: {:?}", ty_layout.size));
|
||||
}
|
||||
sym::size => {
|
||||
tcx.sess.span_err(
|
||||
tcx.def_span(item_def_id.to_def_id()),
|
||||
&format!("size: {:?}", ty_layout.size),
|
||||
);
|
||||
}
|
||||
|
||||
sym::homogeneous_aggregate => {
|
||||
self.tcx.sess.span_err(
|
||||
item.span,
|
||||
&format!(
|
||||
"homogeneous_aggregate: {:?}",
|
||||
ty_layout
|
||||
.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
|
||||
),
|
||||
);
|
||||
}
|
||||
sym::homogeneous_aggregate => {
|
||||
tcx.sess.span_err(
|
||||
tcx.def_span(item_def_id.to_def_id()),
|
||||
&format!(
|
||||
"homogeneous_aggregate: {:?}",
|
||||
ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
sym::debug => {
|
||||
let normalized_ty = self.tcx.normalize_erasing_regions(
|
||||
param_env.with_reveal_all_normalized(self.tcx),
|
||||
ty,
|
||||
);
|
||||
self.tcx.sess.span_err(
|
||||
item.span,
|
||||
&format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
|
||||
);
|
||||
}
|
||||
sym::debug => {
|
||||
let normalized_ty = tcx.normalize_erasing_regions(
|
||||
param_env.with_reveal_all_normalized(tcx),
|
||||
ty,
|
||||
);
|
||||
tcx.sess.span_err(
|
||||
tcx.def_span(item_def_id.to_def_id()),
|
||||
&format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
|
||||
);
|
||||
}
|
||||
|
||||
name => {
|
||||
self.tcx.sess.span_err(
|
||||
meta_item.span(),
|
||||
&format!("unrecognized field name `{}`", name),
|
||||
);
|
||||
}
|
||||
name => {
|
||||
tcx.sess.span_err(
|
||||
meta_item.span(),
|
||||
&format!("unrecognized field name `{}`", name),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(layout_error) => {
|
||||
self.tcx.sess.span_err(item.span, &format!("layout error: {:?}", layout_error));
|
||||
}
|
||||
Err(layout_error) => {
|
||||
tcx.sess.span_err(
|
||||
tcx.def_span(item_def_id.to_def_id()),
|
||||
&format!("layout error: {:?}", layout_error),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
|
||||
}
|
||||
|
||||
fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx).as_deep_visitor());
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx));
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
|
@ -31,9 +31,9 @@ struct CheckLoopVisitor<'a, 'hir> {
|
||||
}
|
||||
|
||||
fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
tcx.hir().visit_item_likes_in_module(
|
||||
tcx.hir().deep_visit_item_likes_in_module(
|
||||
module_def_id,
|
||||
&mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal }.as_deep_visitor(),
|
||||
&mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal },
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -14,10 +14,7 @@ use rustc_span::Span;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
tcx.hir().visit_item_likes_in_module(
|
||||
module_def_id,
|
||||
&mut CheckNakedFunctions { tcx }.as_deep_visitor(),
|
||||
);
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx });
|
||||
}
|
||||
|
||||
crate fn provide(providers: &mut Providers) {
|
||||
|
@ -10,7 +10,6 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::Node;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
use rustc_middle::middle::privacy;
|
||||
@ -314,79 +313,60 @@ impl<'tcx> ReachableContext<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// Some methods from non-exported (completely private) trait impls still have to be
|
||||
// reachable if they are called from inlinable code. Generally, it's not known until
|
||||
// monomorphization if a specific trait impl item can be reachable or not. So, we
|
||||
// conservatively mark all of them as reachable.
|
||||
// FIXME: One possible strategy for pruning the reachable set is to avoid marking impl
|
||||
// items of non-exported traits (or maybe all local traits?) unless their respective
|
||||
// trait items are used from inlinable code through method call syntax or UFCS, or their
|
||||
// trait is a lang item.
|
||||
struct CollectPrivateImplItemsVisitor<'a, 'tcx> {
|
||||
fn check_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
access_levels: &'a privacy::AccessLevels,
|
||||
worklist: &'a mut Vec<LocalDefId>,
|
||||
}
|
||||
id: hir::ItemId,
|
||||
worklist: &mut Vec<LocalDefId>,
|
||||
access_levels: &privacy::AccessLevels,
|
||||
) {
|
||||
if has_custom_linkage(tcx, id.def_id) {
|
||||
worklist.push(id.def_id);
|
||||
}
|
||||
|
||||
impl CollectPrivateImplItemsVisitor<'_, '_> {
|
||||
fn push_to_worklist_if_has_custom_linkage(&mut self, def_id: LocalDefId) {
|
||||
// Anything which has custom linkage gets thrown on the worklist no
|
||||
// matter where it is in the crate, along with "special std symbols"
|
||||
// which are currently akin to allocator symbols.
|
||||
if self.tcx.def_kind(def_id).has_codegen_attrs() {
|
||||
let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
|
||||
if codegen_attrs.contains_extern_indicator()
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
||||
// FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
|
||||
// `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
|
||||
// `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|
||||
{
|
||||
self.worklist.push(def_id);
|
||||
if !matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need only trait impls here, not inherent impls, and only non-exported ones
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
|
||||
item.kind
|
||||
{
|
||||
if !access_levels.is_reachable(item.def_id) {
|
||||
// FIXME(#53488) remove `let`
|
||||
let tcx = tcx;
|
||||
worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
|
||||
|
||||
let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
if !trait_def_id.is_local() {
|
||||
return;
|
||||
}
|
||||
|
||||
worklist.extend(
|
||||
tcx.provided_trait_methods(trait_def_id).map(|assoc| assoc.def_id.expect_local()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
||||
self.push_to_worklist_if_has_custom_linkage(item.def_id);
|
||||
|
||||
// We need only trait impls here, not inherent impls, and only non-exported ones
|
||||
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
|
||||
item.kind
|
||||
{
|
||||
if !self.access_levels.is_reachable(item.def_id) {
|
||||
// FIXME(#53488) remove `let`
|
||||
let tcx = self.tcx;
|
||||
self.worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
|
||||
|
||||
let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
if !trait_def_id.is_local() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.worklist.extend(
|
||||
tcx.provided_trait_methods(trait_def_id)
|
||||
.map(|assoc| assoc.def_id.expect_local()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
|
||||
|
||||
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
|
||||
self.push_to_worklist_if_has_custom_linkage(impl_item.def_id);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {
|
||||
// We never export foreign functions as they have no body to export.
|
||||
fn has_custom_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
|
||||
// Anything which has custom linkage gets thrown on the worklist no
|
||||
// matter where it is in the crate, along with "special std symbols"
|
||||
// which are currently akin to allocator symbols.
|
||||
if !tcx.def_kind(def_id).has_codegen_attrs() {
|
||||
return false;
|
||||
}
|
||||
let codegen_attrs = tcx.codegen_fn_attrs(def_id);
|
||||
codegen_attrs.contains_extern_indicator()
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
||||
// FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
|
||||
// `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
|
||||
// `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|
||||
}
|
||||
|
||||
fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
|
||||
@ -418,12 +398,25 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
|
||||
}
|
||||
}
|
||||
{
|
||||
let mut collect_private_impl_items = CollectPrivateImplItemsVisitor {
|
||||
tcx,
|
||||
access_levels,
|
||||
worklist: &mut reachable_context.worklist,
|
||||
};
|
||||
tcx.hir().visit_all_item_likes(&mut collect_private_impl_items);
|
||||
// Some methods from non-exported (completely private) trait impls still have to be
|
||||
// reachable if they are called from inlinable code. Generally, it's not known until
|
||||
// monomorphization if a specific trait impl item can be reachable or not. So, we
|
||||
// conservatively mark all of them as reachable.
|
||||
// FIXME: One possible strategy for pruning the reachable set is to avoid marking impl
|
||||
// items of non-exported traits (or maybe all local traits?) unless their respective
|
||||
// trait items are used from inlinable code through method call syntax or UFCS, or their
|
||||
// trait is a lang item.
|
||||
let crate_items = tcx.hir_crate_items(());
|
||||
|
||||
for id in crate_items.items() {
|
||||
check_item(tcx, id, &mut reachable_context.worklist, access_levels);
|
||||
}
|
||||
|
||||
for id in crate_items.impl_items() {
|
||||
if has_custom_linkage(tcx, id.def_id) {
|
||||
reachable_context.worklist.push(id.def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Mark all symbols that the symbols on the worklist touch.
|
||||
|
@ -661,7 +661,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
|
||||
/// Cross-references the feature names of unstable APIs with enabled
|
||||
/// features and possibly prints errors.
|
||||
fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }.as_deep_visitor());
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
@ -837,7 +837,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
|
||||
let mut missing = MissingStabilityAnnotations { tcx, access_levels };
|
||||
missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
|
||||
tcx.hir().walk_toplevel_module(&mut missing);
|
||||
tcx.hir().visit_all_item_likes(&mut missing.as_deep_visitor());
|
||||
tcx.hir().deep_visit_all_item_likes(&mut missing);
|
||||
}
|
||||
|
||||
let declared_lang_features = &tcx.features().declared_lang_features;
|
||||
|
@ -14,8 +14,8 @@ use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
|
||||
use rustc_hir::intravisit::{self, DeepVisitor, Visitor};
|
||||
use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
|
||||
@ -1802,12 +1802,12 @@ impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
struct PrivateItemsInPublicInterfacesVisitor<'tcx> {
|
||||
struct PrivateItemsInPublicInterfacesChecker<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
old_error_set_ancestry: LocalDefIdSet,
|
||||
}
|
||||
|
||||
impl<'tcx> PrivateItemsInPublicInterfacesVisitor<'tcx> {
|
||||
impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
|
||||
fn check(
|
||||
&self,
|
||||
def_id: LocalDefId,
|
||||
@ -1841,110 +1841,110 @@ impl<'tcx> PrivateItemsInPublicInterfacesVisitor<'tcx> {
|
||||
check.ty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
|
||||
type NestedFilter = nested_filter::OnlyBodies;
|
||||
|
||||
fn nested_visit_map(&mut self) -> Self::Map {
|
||||
self.tcx.hir()
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
pub fn check_item(&mut self, id: ItemId) {
|
||||
let tcx = self.tcx;
|
||||
let item_visibility = tcx.visibility(item.def_id);
|
||||
let item_visibility = tcx.visibility(id.def_id);
|
||||
let def_kind = tcx.def_kind(id.def_id);
|
||||
|
||||
match item.kind {
|
||||
// Crates are always public.
|
||||
hir::ItemKind::ExternCrate(..) => {}
|
||||
// All nested items are checked by `visit_item`.
|
||||
hir::ItemKind::Mod(..) => {}
|
||||
// Checked in resolve.
|
||||
hir::ItemKind::Use(..) => {}
|
||||
// No subitems.
|
||||
hir::ItemKind::Macro(..) | hir::ItemKind::GlobalAsm(..) => {}
|
||||
// Subitems of these items have inherited publicity.
|
||||
hir::ItemKind::Const(..)
|
||||
| hir::ItemKind::Static(..)
|
||||
| hir::ItemKind::Fn(..)
|
||||
| hir::ItemKind::TyAlias(..) => {
|
||||
self.check(item.def_id, item_visibility).generics().predicates().ty();
|
||||
match def_kind {
|
||||
DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias => {
|
||||
self.check(id.def_id, item_visibility).generics().predicates().ty();
|
||||
}
|
||||
hir::ItemKind::OpaqueTy(..) => {
|
||||
DefKind::OpaqueTy => {
|
||||
// `ty()` for opaque types is the underlying type,
|
||||
// it's not a part of interface, so we skip it.
|
||||
self.check(item.def_id, item_visibility).generics().bounds();
|
||||
self.check(id.def_id, item_visibility).generics().bounds();
|
||||
}
|
||||
hir::ItemKind::Trait(.., trait_item_refs) => {
|
||||
self.check(item.def_id, item_visibility).generics().predicates();
|
||||
DefKind::Trait => {
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind {
|
||||
self.check(item.def_id, item_visibility).generics().predicates();
|
||||
|
||||
for trait_item_ref in trait_item_refs {
|
||||
self.check_assoc_item(
|
||||
trait_item_ref.id.def_id,
|
||||
trait_item_ref.kind,
|
||||
trait_item_ref.defaultness,
|
||||
item_visibility,
|
||||
);
|
||||
for trait_item_ref in trait_item_refs {
|
||||
self.check_assoc_item(
|
||||
trait_item_ref.id.def_id,
|
||||
trait_item_ref.kind,
|
||||
trait_item_ref.defaultness,
|
||||
item_visibility,
|
||||
);
|
||||
|
||||
if let AssocItemKind::Type = trait_item_ref.kind {
|
||||
self.check(trait_item_ref.id.def_id, item_visibility).bounds();
|
||||
if let AssocItemKind::Type = trait_item_ref.kind {
|
||||
self.check(trait_item_ref.id.def_id, item_visibility).bounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ItemKind::TraitAlias(..) => {
|
||||
self.check(item.def_id, item_visibility).generics().predicates();
|
||||
DefKind::TraitAlias => {
|
||||
self.check(id.def_id, item_visibility).generics().predicates();
|
||||
}
|
||||
hir::ItemKind::Enum(ref def, _) => {
|
||||
self.check(item.def_id, item_visibility).generics().predicates();
|
||||
DefKind::Enum => {
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::Enum(ref def, _) = item.kind {
|
||||
self.check(item.def_id, item_visibility).generics().predicates();
|
||||
|
||||
for variant in def.variants {
|
||||
for field in variant.data.fields() {
|
||||
self.check(self.tcx.hir().local_def_id(field.hir_id), item_visibility).ty();
|
||||
for variant in def.variants {
|
||||
for field in variant.data.fields() {
|
||||
self.check(self.tcx.hir().local_def_id(field.hir_id), item_visibility)
|
||||
.ty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Subitems of foreign modules have their own publicity.
|
||||
hir::ItemKind::ForeignMod { items, .. } => {
|
||||
for foreign_item in items {
|
||||
let vis = tcx.visibility(foreign_item.id.def_id);
|
||||
self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
|
||||
DefKind::ForeignMod => {
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
|
||||
for foreign_item in items {
|
||||
let vis = tcx.visibility(foreign_item.id.def_id);
|
||||
self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Subitems of structs and unions have their own publicity.
|
||||
hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
|
||||
self.check(item.def_id, item_visibility).generics().predicates();
|
||||
DefKind::Struct | DefKind::Union => {
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::Struct(ref struct_def, _)
|
||||
| hir::ItemKind::Union(ref struct_def, _) = item.kind
|
||||
{
|
||||
self.check(item.def_id, item_visibility).generics().predicates();
|
||||
|
||||
for field in struct_def.fields() {
|
||||
let def_id = tcx.hir().local_def_id(field.hir_id);
|
||||
let field_visibility = tcx.visibility(def_id);
|
||||
self.check(def_id, min(item_visibility, field_visibility, tcx)).ty();
|
||||
for field in struct_def.fields() {
|
||||
let def_id = tcx.hir().local_def_id(field.hir_id);
|
||||
let field_visibility = tcx.visibility(def_id);
|
||||
self.check(def_id, min(item_visibility, field_visibility, tcx)).ty();
|
||||
}
|
||||
}
|
||||
}
|
||||
// An inherent impl is public when its type is public
|
||||
// Subitems of inherent impls have their own publicity.
|
||||
// A trait impl is public when both its type and its trait are public
|
||||
// Subitems of trait impls have inherited publicity.
|
||||
hir::ItemKind::Impl(ref impl_) => {
|
||||
let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default());
|
||||
// check that private components do not appear in the generics or predicates of inherent impls
|
||||
// this check is intentionally NOT performed for impls of traits, per #90586
|
||||
if impl_.of_trait.is_none() {
|
||||
self.check(item.def_id, impl_vis).generics().predicates();
|
||||
}
|
||||
for impl_item_ref in impl_.items {
|
||||
let impl_item_vis = if impl_.of_trait.is_none() {
|
||||
min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
|
||||
} else {
|
||||
impl_vis
|
||||
};
|
||||
self.check_assoc_item(
|
||||
impl_item_ref.id.def_id,
|
||||
impl_item_ref.kind,
|
||||
impl_item_ref.defaultness,
|
||||
impl_item_vis,
|
||||
);
|
||||
DefKind::Impl => {
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::Impl(ref impl_) = item.kind {
|
||||
let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default());
|
||||
// check that private components do not appear in the generics or predicates of inherent impls
|
||||
// this check is intentionally NOT performed for impls of traits, per #90586
|
||||
if impl_.of_trait.is_none() {
|
||||
self.check(item.def_id, impl_vis).generics().predicates();
|
||||
}
|
||||
for impl_item_ref in impl_.items {
|
||||
let impl_item_vis = if impl_.of_trait.is_none() {
|
||||
min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
|
||||
} else {
|
||||
impl_vis
|
||||
};
|
||||
self.check_assoc_item(
|
||||
impl_item_ref.id.def_id,
|
||||
impl_item_ref.kind,
|
||||
impl_item_ref.defaultness,
|
||||
impl_item_vis,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2069,7 +2069,7 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
|
||||
}
|
||||
|
||||
// Check for private types and traits in public interfaces.
|
||||
let mut visitor = PrivateItemsInPublicInterfacesVisitor {
|
||||
let mut checker = PrivateItemsInPublicInterfacesChecker {
|
||||
tcx,
|
||||
// Only definition IDs are ever searched in `old_error_set_ancestry`,
|
||||
// so we can filter away all non-definition IDs at this point.
|
||||
@ -2078,5 +2078,8 @@ fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
|
||||
.filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id))
|
||||
.collect(),
|
||||
};
|
||||
tcx.hir().visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
|
||||
|
||||
for id in tcx.hir().items() {
|
||||
checker.check_item(id);
|
||||
}
|
||||
}
|
||||
|
@ -59,10 +59,7 @@ struct OnlySelfBounds(bool);
|
||||
// Main entry point
|
||||
|
||||
fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
tcx.hir().visit_item_likes_in_module(
|
||||
module_def_id,
|
||||
&mut CollectItemTypesVisitor { tcx }.as_deep_visitor(),
|
||||
);
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx });
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
|
@ -303,7 +303,7 @@ crate fn run(
|
||||
// Run call-finder on all items
|
||||
let mut calls = FxHashMap::default();
|
||||
let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
|
||||
tcx.hir().visit_all_item_likes(&mut finder.as_deep_visitor());
|
||||
tcx.hir().deep_visit_all_item_likes(&mut finder);
|
||||
|
||||
// Sort call locations within a given file in document order
|
||||
for fn_calls in calls.values_mut() {
|
||||
|
@ -21,7 +21,7 @@ extern crate rustc_session;
|
||||
use rustc_borrowck::consumers::BodyWithBorrowckFacts;
|
||||
use rustc_driver::Compilation;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_interface::interface::Compiler;
|
||||
use rustc_interface::{Config, Queries};
|
||||
use rustc_middle::ty::query::query_values::mir_borrowck;
|
||||
@ -65,11 +65,34 @@ impl rustc_driver::Callbacks for CompilerCalls {
|
||||
queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
|
||||
// Collect definition ids of MIR bodies.
|
||||
let hir = tcx.hir();
|
||||
let mut visitor = HirVisitor { bodies: Vec::new() };
|
||||
hir.visit_all_item_likes(&mut visitor);
|
||||
let mut bodies = Vec::new();
|
||||
|
||||
let crate_items = tcx.hir_crate_items(());
|
||||
for id in crate_items.items() {
|
||||
if matches!(tcx.def_kind(id.def_id), DefKind::Fn) {
|
||||
bodies.push(id.def_id);
|
||||
}
|
||||
}
|
||||
|
||||
for id in crate_items.trait_items() {
|
||||
if matches!(tcx.def_kind(id.def_id), DefKind::AssocFn) {
|
||||
let trait_item = hir.trait_item(id);
|
||||
if let rustc_hir::TraitItemKind::Fn(_, trait_fn) = &trait_item.kind {
|
||||
if let rustc_hir::TraitFn::Provided(_) = trait_fn {
|
||||
bodies.push(trait_item.def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for id in crate_items.impl_items() {
|
||||
if matches!(tcx.def_kind(id.def_id), DefKind::AssocFn) {
|
||||
bodies.push(id.def_id);
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger borrow checking of all bodies.
|
||||
for def_id in visitor.bodies {
|
||||
for def_id in bodies {
|
||||
let _ = tcx.optimized_mir(def_id);
|
||||
}
|
||||
|
||||
@ -121,35 +144,6 @@ fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> mir_borrowck<'tc
|
||||
original_mir_borrowck(tcx, def_id)
|
||||
}
|
||||
|
||||
/// Visitor that collects all body definition ids mentioned in the program.
|
||||
struct HirVisitor {
|
||||
bodies: Vec<LocalDefId>,
|
||||
}
|
||||
|
||||
impl<'tcx> ItemLikeVisitor<'tcx> for HirVisitor {
|
||||
fn visit_item(&mut self, item: &rustc_hir::Item) {
|
||||
if let rustc_hir::ItemKind::Fn(..) = item.kind {
|
||||
self.bodies.push(item.def_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, trait_item: &rustc_hir::TraitItem) {
|
||||
if let rustc_hir::TraitItemKind::Fn(_, trait_fn) = &trait_item.kind {
|
||||
if let rustc_hir::TraitFn::Provided(_) = trait_fn {
|
||||
self.bodies.push(trait_item.def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, impl_item: &rustc_hir::ImplItem) {
|
||||
if let rustc_hir::ImplItemKind::Fn(..) = impl_item.kind {
|
||||
self.bodies.push(impl_item.def_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, _foreign_item: &rustc_hir::ForeignItem) {}
|
||||
}
|
||||
|
||||
/// Pull MIR bodies stored in the thread-local.
|
||||
fn get_bodies<'tcx>(tcx: TyCtxt<'tcx>) -> Vec<(String, BodyWithBorrowckFacts<'tcx>)> {
|
||||
MIR_BODIES.with(|state| {
|
||||
|
@ -2,10 +2,10 @@ error[E0138]: multiple `start` functions
|
||||
--> $DIR/E0138.rs:7:1
|
||||
|
|
||||
LL | fn foo(argc: isize, argv: *const *const u8) -> isize { 0 }
|
||||
| ---------------------------------------------------------- previous `#[start]` function here
|
||||
| ---------------------------------------------------- previous `#[start]` function here
|
||||
...
|
||||
LL | fn f(argc: isize, argv: *const *const u8) -> isize { 0 }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ multiple `start` functions
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ multiple `start` functions
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -8,7 +8,7 @@ note: here is a function named `main`
|
||||
--> $DIR/main-wrong-location.rs:4:5
|
||||
|
|
||||
LL | fn main() { }
|
||||
| ^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^
|
||||
= note: you have one or more functions named `main` not defined at the crate level
|
||||
= help: consider moving the `main` function definitions
|
||||
|
||||
|
@ -74,11 +74,10 @@ use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_hir::hir_id::{HirIdMap, HirIdSet};
|
||||
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
|
||||
use rustc_hir::{
|
||||
def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl,
|
||||
ForeignItem, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource,
|
||||
HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource,
|
||||
Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
|
||||
TraitRef, TyKind, UnOp,
|
||||
};
|
||||
@ -2068,35 +2067,6 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
struct TestItemNamesVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
names: Vec<Symbol>,
|
||||
}
|
||||
|
||||
impl<'hir> ItemLikeVisitor<'hir> for TestItemNamesVisitor<'hir> {
|
||||
fn visit_item(&mut self, item: &Item<'_>) {
|
||||
if let ItemKind::Const(ty, _body) = item.kind {
|
||||
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
|
||||
// We could also check for the type name `test::TestDescAndFn`
|
||||
if let Res::Def(DefKind::Struct, _) = path.res {
|
||||
let has_test_marker = self
|
||||
.tcx
|
||||
.hir()
|
||||
.attrs(item.hir_id())
|
||||
.iter()
|
||||
.any(|a| a.has_name(sym::rustc_test_marker));
|
||||
if has_test_marker {
|
||||
self.names.push(item.ident.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn visit_trait_item(&mut self, _: &TraitItem<'_>) {}
|
||||
fn visit_impl_item(&mut self, _: &ImplItem<'_>) {}
|
||||
fn visit_foreign_item(&mut self, _: &ForeignItem<'_>) {}
|
||||
}
|
||||
|
||||
static TEST_ITEM_NAMES_CACHE: SyncOnceCell<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = SyncOnceCell::new();
|
||||
|
||||
fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
|
||||
@ -2105,10 +2075,28 @@ fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(
|
||||
match map.entry(module) {
|
||||
Entry::Occupied(entry) => f(entry.get()),
|
||||
Entry::Vacant(entry) => {
|
||||
let mut visitor = TestItemNamesVisitor { tcx, names: Vec::new() };
|
||||
tcx.hir().visit_item_likes_in_module(module, &mut visitor);
|
||||
visitor.names.sort_unstable();
|
||||
f(&*entry.insert(visitor.names))
|
||||
let mut names = Vec::new();
|
||||
for id in tcx.hir().module_items(module) {
|
||||
if matches!(tcx.def_kind(id.def_id), DefKind::Const)
|
||||
&& let item = tcx.hir().item(id)
|
||||
&& let ItemKind::Const(ty, _body) = item.kind {
|
||||
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
|
||||
// We could also check for the type name `test::TestDescAndFn`
|
||||
if let Res::Def(DefKind::Struct, _) = path.res {
|
||||
let has_test_marker = tcx
|
||||
.hir()
|
||||
.attrs(item.hir_id())
|
||||
.iter()
|
||||
.any(|a| a.has_name(sym::rustc_test_marker));
|
||||
if has_test_marker {
|
||||
names.push(item.ident.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
names.sort_unstable();
|
||||
f(&*entry.insert(names))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user