mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-25 05:14:27 +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.
|
//! HIR walker for walking the contents of nodes.
|
||||||
//!
|
//!
|
||||||
//! **For an overview of the visitor strategy, see the docs on the
|
//! Here are the three available patterns for the visitor strategy,
|
||||||
//! `super::itemlikevisit::ItemLikeVisitor` trait.**
|
//! 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
|
//! If you have decided to use this visitor, here are some general
|
||||||
//! notes on how to do so:
|
//! notes on how to do so:
|
||||||
@ -32,43 +65,12 @@
|
|||||||
//! example generator inference, and possibly also HIR borrowck.
|
//! example generator inference, and possibly also HIR borrowck.
|
||||||
|
|
||||||
use crate::hir::*;
|
use crate::hir::*;
|
||||||
use crate::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor};
|
use crate::itemlikevisit::ParItemLikeVisitor;
|
||||||
use rustc_ast::walk_list;
|
use rustc_ast::walk_list;
|
||||||
use rustc_ast::{Attribute, Label};
|
use rustc_ast::{Attribute, Label};
|
||||||
use rustc_span::symbol::{Ident, Symbol};
|
use rustc_span::symbol::{Ident, Symbol};
|
||||||
use rustc_span::Span;
|
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> {
|
pub trait IntoVisitor<'hir> {
|
||||||
type Visitor: Visitor<'hir>;
|
type Visitor: Visitor<'hir>;
|
||||||
fn into_visitor(&self) -> Self::Visitor;
|
fn into_visitor(&self) -> Self::Visitor;
|
||||||
@ -315,16 +317,6 @@ pub trait Visitor<'v>: Sized {
|
|||||||
walk_body(self, b);
|
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) {
|
fn visit_id(&mut self, _hir_id: HirId) {
|
||||||
|
@ -1,55 +1,5 @@
|
|||||||
use super::{ForeignItem, ImplItem, Item, TraitItem};
|
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`.
|
/// A parallel variant of `ItemLikeVisitor`.
|
||||||
pub trait ParItemLikeVisitor<'hir> {
|
pub trait ParItemLikeVisitor<'hir> {
|
||||||
fn visit_item(&self, item: &'hir Item<'hir>);
|
fn visit_item(&self, item: &'hir Item<'hir>);
|
||||||
|
@ -75,7 +75,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) {
|
|||||||
let mut visitor =
|
let mut visitor =
|
||||||
IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] };
|
IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] };
|
||||||
visitor.process_attrs(hir::CRATE_HIR_ID);
|
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)
|
(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::definitions::DefPathData;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
|
||||||
use rustc_hir::lang_items;
|
use rustc_hir::lang_items;
|
||||||
use rustc_hir::{AnonConst, GenericParamKind};
|
use rustc_hir::{AnonConst, GenericParamKind};
|
||||||
use rustc_index::bit_set::GrowableBitSet;
|
use rustc_index::bit_set::GrowableBitSet;
|
||||||
@ -453,7 +452,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||||||
return;
|
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) {
|
fn encode_def_path_table(&mut self) {
|
||||||
@ -2243,26 +2242,16 @@ pub fn provide(providers: &mut Providers) {
|
|||||||
traits_in_crate: |tcx, cnum| {
|
traits_in_crate: |tcx, cnum| {
|
||||||
assert_eq!(cnum, LOCAL_CRATE);
|
assert_eq!(cnum, LOCAL_CRATE);
|
||||||
|
|
||||||
#[derive(Default)]
|
let mut traits = Vec::new();
|
||||||
struct TraitsVisitor {
|
for id in tcx.hir().items() {
|
||||||
traits: Vec<DefId>,
|
if matches!(tcx.def_kind(id.def_id), DefKind::Trait | DefKind::TraitAlias) {
|
||||||
}
|
traits.push(id.def_id.to_def_id())
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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.
|
// Bring everything into deterministic order.
|
||||||
visitor.traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id));
|
traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id));
|
||||||
tcx.arena.alloc_slice(&visitor.traits)
|
tcx.arena.alloc_slice(&traits)
|
||||||
},
|
},
|
||||||
|
|
||||||
..*providers
|
..*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::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
|
||||||
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
|
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
|
||||||
use rustc_hir::*;
|
use rustc_hir::*;
|
||||||
use rustc_index::vec::Idx;
|
use rustc_index::vec::Idx;
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
@ -161,6 +160,10 @@ impl<'hir> Map<'hir> {
|
|||||||
self.tcx.hir_crate_items(()).items.iter().copied()
|
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) {
|
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));
|
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
|
/// Visits all items in the crate in some deterministic (but
|
||||||
/// unspecified) order. If you just need to process every item,
|
/// unspecified) order. If you need to process every item,
|
||||||
/// but don't care about nesting, this method is the best choice.
|
/// 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
|
/// Please see the notes in `intravisit.rs` for more information.
|
||||||
/// follows lexical scoping rules -- then you want a different
|
pub fn deep_visit_all_item_likes<V>(self, visitor: &mut V)
|
||||||
/// 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)
|
|
||||||
where
|
where
|
||||||
V: itemlikevisit::ItemLikeVisitor<'hir>,
|
V: Visitor<'hir>,
|
||||||
{
|
{
|
||||||
let krate = self.krate();
|
let krate = self.krate();
|
||||||
for owner in krate.owners.iter().filter_map(|i| i.as_owner()) {
|
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
|
where
|
||||||
V: ItemLikeVisitor<'hir>,
|
V: Visitor<'hir>,
|
||||||
{
|
{
|
||||||
let module = self.tcx.hir_module_items(module);
|
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(());
|
let crate_items = self.tcx.hir_crate_items(());
|
||||||
for module in crate_items.submodules.iter() {
|
for module in crate_items.submodules.iter() {
|
||||||
f(*module)
|
f(*module)
|
||||||
|
@ -8,7 +8,7 @@ use rustc_hir::intravisit::nested_filter::NestedFilter;
|
|||||||
/// constant arguments of types, e.g. in `let _: [(); /* HERE */];`.
|
/// constant arguments of types, e.g. in `let _: [(); /* HERE */];`.
|
||||||
///
|
///
|
||||||
/// **This is the most common choice.** A very common pattern is
|
/// **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
|
/// and to have the visitor that visits the contents of each item
|
||||||
/// using this setting.
|
/// using this setting.
|
||||||
pub struct OnlyBodies(());
|
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.
|
/// 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() {
|
if let Some(cnum) = def_id.as_crate_root() {
|
||||||
Some(self.crate_name(cnum))
|
Some(self.crate_name(cnum))
|
||||||
} else {
|
} else {
|
||||||
|
@ -170,7 +170,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
|
|||||||
intravisit::walk_struct_def(self, v)
|
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
|
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) {
|
fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||||
let check_attr_visitor = &mut CheckAttrVisitor { tcx };
|
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() {
|
if module_def_id.is_top_level_module() {
|
||||||
check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
|
check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
|
||||||
check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
|
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) {
|
fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||||
let mut vis = CheckConstVisitor::new(tcx);
|
let mut vis = CheckConstVisitor::new(tcx);
|
||||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
|
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut vis);
|
||||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckConstTraitVisitor::new(tcx));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn provide(providers: &mut Providers) {
|
pub(crate) fn provide(providers: &mut Providers) {
|
||||||
*providers = Providers { check_mod_const_bodies, ..*providers };
|
*providers = Providers { check_mod_const_bodies, ..*providers };
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CheckConstTraitVisitor<'tcx> {
|
fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||||
tcx: TyCtxt<'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> {
|
for trait_item in tcx.associated_items(trait_def_id).in_definition_order()
|
||||||
fn new(tcx: TyCtxt<'tcx>) -> Self {
|
{
|
||||||
CheckConstTraitVisitor { tcx }
|
if let ty::AssocItem {
|
||||||
}
|
kind: ty::AssocKind::Fn,
|
||||||
}
|
defaultness,
|
||||||
|
def_id: trait_item_id,
|
||||||
impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<'tcx> {
|
..
|
||||||
/// check for const trait impls, and errors if the impl uses provided/default functions
|
} = *trait_item
|
||||||
/// of the trait being implemented; as those provided functions can be non-const.
|
{
|
||||||
fn visit_item<'hir>(&mut self, item: &'hir hir::Item<'hir>) {
|
// we can ignore functions that do not have default bodies:
|
||||||
let _: Option<_> = try {
|
// if those are unimplemented it will be caught by typeck.
|
||||||
if let hir::ItemKind::Impl(ref imp) = item.kind && let hir::Constness::Const = imp.constness {
|
if !defaultness.has_value()
|
||||||
let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
|
|| tcx
|
||||||
let ancestors = self
|
.has_attr(trait_item_id, sym::default_method_body_is_const)
|
||||||
.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()
|
|
||||||
{
|
{
|
||||||
if let ty::AssocItem {
|
continue;
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// all nonconst trait functions (not marked with #[default_method_body_is_const])
|
let is_implemented = ancestors
|
||||||
// must be implemented
|
.leaf_def(tcx, trait_item_id)
|
||||||
if !to_implement.is_empty() {
|
.map(|node_item| !node_item.defining_node.is_from_trait())
|
||||||
self.tcx
|
.unwrap_or(false);
|
||||||
.sess
|
|
||||||
.struct_span_err(
|
if !is_implemented {
|
||||||
item.span,
|
to_implement.push(trait_item_id);
|
||||||
"const trait implementations may not use non-const default functions",
|
|
||||||
)
|
|
||||||
.note(&format!("`{}` not implemented", to_implement.join("`, `")))
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_trait_item<'hir>(&mut self, _: &'hir hir::TraitItem<'hir>) {}
|
// all nonconst trait functions (not marked with #[default_method_body_is_const])
|
||||||
|
// must be implemented
|
||||||
fn visit_impl_item<'hir>(&mut self, _: &'hir hir::ImplItem<'hir>) {}
|
if !to_implement.is_empty() {
|
||||||
|
let not_implemented = to_implement
|
||||||
fn visit_foreign_item<'hir>(&mut self, _: &'hir hir::ForeignItem<'hir>) {}
|
.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)]
|
#[derive(Copy, Clone)]
|
||||||
@ -270,6 +252,11 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
|
|||||||
self.tcx.hir()
|
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) {
|
fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
|
||||||
let kind = Some(hir::ConstContext::Const);
|
let kind = Some(hir::ConstContext::Const);
|
||||||
self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
|
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::{CtorOf, DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
|
||||||
use rustc_hir::{Node, PatKind, TyKind};
|
use rustc_hir::{Node, PatKind, TyKind};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
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
|
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:
|
// 1) We want to explicitly consider as live:
|
||||||
// * Item annotated with #[allow(dead_code)]
|
// * Item annotated with #[allow(dead_code)]
|
||||||
// - This is done so that if we want to suppress warnings for a
|
// - 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
|
// or
|
||||||
// 2) We are not sure to be live or not
|
// 2) We are not sure to be live or not
|
||||||
// * Implementations of traits and trait methods
|
// * Implementations of traits and trait methods
|
||||||
struct LifeSeeder<'tcx> {
|
fn check_item<'tcx>(
|
||||||
worklist: Vec<LocalDefId>,
|
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
// see `MarkSymbolVisitor::struct_constructors`
|
worklist: &mut Vec<LocalDefId>,
|
||||||
struct_constructors: FxHashMap<LocalDefId, 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> {
|
match tcx.def_kind(id.def_id) {
|
||||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
DefKind::Enum => {
|
||||||
let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx, item.hir_id());
|
let item = tcx.hir().item(id);
|
||||||
if allow_dead_code {
|
if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
|
||||||
self.worklist.push(item.def_id);
|
let hir = tcx.hir();
|
||||||
}
|
|
||||||
match item.kind {
|
|
||||||
hir::ItemKind::Enum(ref enum_def, _) => {
|
|
||||||
let hir = self.tcx.hir();
|
|
||||||
if allow_dead_code {
|
if allow_dead_code {
|
||||||
self.worklist.extend(
|
worklist.extend(
|
||||||
enum_def.variants.iter().map(|variant| hir.local_def_id(variant.id)),
|
enum_def.variants.iter().map(|variant| hir.local_def_id(variant.id)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for variant in enum_def.variants {
|
for variant in enum_def.variants {
|
||||||
if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
|
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));
|
.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() {
|
DefKind::Impl => {
|
||||||
self.worklist.push(item.def_id);
|
let of_trait = tcx.impl_trait_ref(id.def_id);
|
||||||
}
|
|
||||||
for impl_item_ref in *items {
|
if of_trait.is_some() {
|
||||||
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
|
worklist.push(id.def_id);
|
||||||
if of_trait.is_some()
|
}
|
||||||
|| has_allow_dead_code_or_lang_attr(self.tcx, impl_item.hir_id())
|
|
||||||
{
|
// get DefIds from another query
|
||||||
self.worklist.push(impl_item_ref.id.def_id);
|
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() {
|
if let Some(ctor_hir_id) = variant_data.ctor_hir_id() {
|
||||||
self.struct_constructors
|
struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id);
|
||||||
.insert(self.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<'_>) {
|
fn check_trait_item<'tcx>(tcx: TyCtxt<'tcx>, worklist: &mut Vec<LocalDefId>, id: hir::TraitItemId) {
|
||||||
use hir::TraitItemKind::{Const, Fn};
|
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(_)))
|
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<'_>) {
|
fn check_foreign_item<'tcx>(
|
||||||
// ignore: we are handling this in `visit_item` above
|
tcx: TyCtxt<'tcx>,
|
||||||
}
|
worklist: &mut Vec<LocalDefId>,
|
||||||
|
id: hir::ForeignItemId,
|
||||||
fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
|
) {
|
||||||
use hir::ForeignItemKind::{Fn, Static};
|
if matches!(tcx.def_kind(id.def_id), DefKind::Static(_) | DefKind::Fn)
|
||||||
if matches!(foreign_item.kind, Static(..) | Fn(..))
|
&& has_allow_dead_code_or_lang_attr(tcx, id.hir_id())
|
||||||
&& has_allow_dead_code_or_lang_attr(self.tcx, foreign_item.hir_id())
|
{
|
||||||
{
|
worklist.push(id.def_id);
|
||||||
self.worklist.push(foreign_item.def_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,7 +576,9 @@ fn create_and_seed_worklist<'tcx>(
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
|
) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
|
||||||
let access_levels = &tcx.privacy_access_levels(());
|
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
|
.map
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(
|
.filter_map(
|
||||||
@ -576,11 +590,20 @@ fn create_and_seed_worklist<'tcx>(
|
|||||||
.chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
|
.chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// Seed implemented trait items
|
let crate_items = tcx.hir_crate_items(());
|
||||||
let mut life_seeder = LifeSeeder { worklist, tcx, struct_constructors: Default::default() };
|
for id in crate_items.items() {
|
||||||
tcx.hir().visit_all_item_likes(&mut life_seeder);
|
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>(
|
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_expand::base::resolve_path;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::CrateNum;
|
use rustc_hir::def_id::CrateNum;
|
||||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
use rustc_hir::HirId;
|
||||||
use rustc_hir::{HirId, Target};
|
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::def_id::LOCAL_CRATE;
|
use rustc_span::def_id::LOCAL_CRATE;
|
||||||
@ -14,96 +13,66 @@ use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
struct DebuggerVisualizerCollector<'tcx> {
|
fn check_for_debugger_visualizer<'tcx>(
|
||||||
debugger_visualizers: FxHashSet<DebuggerVisualizerFile>,
|
|
||||||
tcx: TyCtxt<'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> {
|
let meta_item = match list.len() {
|
||||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
1 => match list[0].meta_item() {
|
||||||
let target = Target::from_item(item);
|
Some(meta_item) => meta_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,
|
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
},
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
|
||||||
let meta_item = match list.len() {
|
let file = match (meta_item.name_or_empty(), meta_item.value_str()) {
|
||||||
1 => match list[0].meta_item() {
|
(sym::natvis_file, Some(value)) => {
|
||||||
Some(meta_item) => meta_item,
|
match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) {
|
||||||
_ => continue,
|
Ok(file) => file,
|
||||||
},
|
Err(mut err) => {
|
||||||
_ => continue,
|
err.emit();
|
||||||
};
|
|
||||||
|
|
||||||
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();
|
|
||||||
continue;
|
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);
|
assert_eq!(cnum, LOCAL_CRATE);
|
||||||
|
|
||||||
// Initialize the collector.
|
// Initialize the collector.
|
||||||
let mut collector = DebuggerVisualizerCollector::new(tcx);
|
let mut debugger_visualizers = FxHashSet::default();
|
||||||
|
|
||||||
// Collect debugger visualizers in this crate.
|
// 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.
|
// 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.
|
// Extract out the found debugger_visualizer items.
|
||||||
let DebuggerVisualizerCollector { debugger_visualizers, .. } = collector;
|
|
||||||
|
|
||||||
let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>();
|
let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>();
|
||||||
|
|
||||||
// Sort the visualizers so we always get a deterministic query result.
|
// Sort the visualizers so we always get a deterministic query result.
|
||||||
|
@ -10,49 +10,22 @@
|
|||||||
//! * Compiler internal types like `Ty` and `TyCtxt`
|
//! * Compiler internal types like `Ty` and `TyCtxt`
|
||||||
|
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_hir as hir;
|
|
||||||
use rustc_hir::diagnostic_items::DiagnosticItems;
|
use rustc_hir::diagnostic_items::DiagnosticItems;
|
||||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
|
|
||||||
struct DiagnosticItemCollector<'tcx> {
|
fn observe_item<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
diagnostic_items: DiagnosticItems,
|
diagnostic_items: &mut DiagnosticItems,
|
||||||
}
|
def_id: LocalDefId,
|
||||||
|
) {
|
||||||
impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> {
|
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
let attrs = tcx.hir().attrs(hir_id);
|
||||||
self.observe_item(item.def_id);
|
if let Some(name) = extract(attrs) {
|
||||||
}
|
// insert into our table
|
||||||
|
collect_item(tcx, diagnostic_items, name, def_id.to_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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,12 +68,28 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems
|
|||||||
assert_eq!(cnum, LOCAL_CRATE);
|
assert_eq!(cnum, LOCAL_CRATE);
|
||||||
|
|
||||||
// Initialize the collector.
|
// Initialize the collector.
|
||||||
let mut collector = DiagnosticItemCollector::new(tcx);
|
let mut diagnostic_items = DiagnosticItems::default();
|
||||||
|
|
||||||
// Collect diagnostic items in this crate.
|
// 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.
|
/// Traverse and collect all the diagnostic items in all crates.
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use rustc_ast::entry::EntryPointType;
|
use rustc_ast::entry::EntryPointType;
|
||||||
use rustc_errors::struct_span_err;
|
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::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
|
||||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
|
||||||
use rustc_hir::{ForeignItem, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
|
|
||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::{DefIdTree, TyCtxt};
|
use rustc_middle::ty::{DefIdTree, TyCtxt};
|
||||||
use rustc_session::config::{CrateType, EntryFnType};
|
use rustc_session::config::{CrateType, EntryFnType};
|
||||||
@ -25,25 +25,6 @@ struct EntryContext<'tcx> {
|
|||||||
non_main_fns: Vec<Span>,
|
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)> {
|
fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
|
||||||
let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable);
|
let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable);
|
||||||
if !any_exe {
|
if !any_exe {
|
||||||
@ -59,28 +40,35 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
|
|||||||
let mut ctxt =
|
let mut ctxt =
|
||||||
EntryContext { tcx, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new() };
|
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)
|
configure_main(tcx, &ctxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
|
// Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
|
||||||
// (with `ast::Item`), so make sure to keep them in sync.
|
// (with `ast::Item`), so make sure to keep them in sync.
|
||||||
fn entry_point_type(ctxt: &EntryContext<'_>, item: &Item<'_>, at_root: bool) -> EntryPointType {
|
// A small optimization was added so that hir::Item is fetched only when needed.
|
||||||
let attrs = ctxt.tcx.hir().attrs(item.hir_id());
|
// 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) {
|
if ctxt.tcx.sess.contains_name(attrs, sym::start) {
|
||||||
EntryPointType::Start
|
EntryPointType::Start
|
||||||
} else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
|
} else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
|
||||||
EntryPointType::MainAttr
|
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 {
|
} 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();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) {
|
fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
|
||||||
match entry_point_type(ctxt, item, at_root) {
|
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 => (),
|
EntryPointType::None => (),
|
||||||
_ if !matches!(item.kind, ItemKind::Fn(..)) => {
|
_ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => {
|
||||||
let attrs = ctxt.tcx.hir().attrs(item.hir_id());
|
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
|
||||||
if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::start) {
|
if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::start) {
|
||||||
throw_attr_err(&ctxt.tcx.sess, attr.span, "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::MainNamed => (),
|
||||||
EntryPointType::OtherMain => {
|
EntryPointType::OtherMain => {
|
||||||
ctxt.non_main_fns.push(item.span);
|
ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
|
||||||
}
|
}
|
||||||
EntryPointType::MainAttr => {
|
EntryPointType::MainAttr => {
|
||||||
if ctxt.attr_main_fn.is_none() {
|
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 {
|
} else {
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
ctxt.tcx.sess,
|
ctxt.tcx.sess,
|
||||||
item.span,
|
ctxt.tcx.def_span(id.def_id.to_def_id()),
|
||||||
E0137,
|
E0137,
|
||||||
"multiple functions with a `#[main]` attribute"
|
"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")
|
.span_label(ctxt.attr_main_fn.unwrap().1, "first `#[main]` function")
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EntryPointType::Start => {
|
EntryPointType::Start => {
|
||||||
if ctxt.start_fn.is_none() {
|
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 {
|
} else {
|
||||||
struct_span_err!(ctxt.tcx.sess, item.span, E0138, "multiple `start` functions")
|
struct_span_err!(
|
||||||
.span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
|
ctxt.tcx.sess,
|
||||||
.span_label(item.span, "multiple `start` functions")
|
ctxt.tcx.def_span(id.def_id.to_def_id()),
|
||||||
.emit();
|
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 as hir;
|
||||||
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
||||||
use rustc_hir::intravisit;
|
use rustc_hir::intravisit;
|
||||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
|
||||||
use rustc_hir::{HirId, ItemLocalId};
|
use rustc_hir::{HirId, ItemLocalId};
|
||||||
use rustc_middle::hir::map::Map;
|
use rustc_middle::hir::map::Map;
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
@ -20,8 +19,14 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
|||||||
let hir_map = tcx.hir();
|
let hir_map = tcx.hir();
|
||||||
|
|
||||||
hir_map.par_for_each_module(|module_id| {
|
hir_map.par_for_each_module(|module_id| {
|
||||||
hir_map
|
let mut v = HirIdValidator {
|
||||||
.visit_item_likes_in_module(module_id, &mut OuterVisitor { hir_map, errors: &errors })
|
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();
|
let errors = errors.into_inner();
|
||||||
@ -39,13 +44,8 @@ struct HirIdValidator<'a, 'hir> {
|
|||||||
errors: &'a Lock<Vec<String>>,
|
errors: &'a Lock<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OuterVisitor<'a, 'hir> {
|
impl<'a, 'hir> HirIdValidator<'a, 'hir> {
|
||||||
hir_map: Map<'hir>,
|
fn new_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> {
|
||||||
errors: &'a Lock<Vec<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'hir> OuterVisitor<'a, 'hir> {
|
|
||||||
fn new_inner_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> {
|
|
||||||
HirIdValidator {
|
HirIdValidator {
|
||||||
hir_map,
|
hir_map,
|
||||||
owner: None,
|
owner: None,
|
||||||
@ -53,31 +53,7 @@ impl<'a, 'hir> OuterVisitor<'a, 'hir> {
|
|||||||
errors: self.errors,
|
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]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn error(&self, f: impl FnOnce() -> String) {
|
fn error(&self, f: impl FnOnce() -> String) {
|
||||||
@ -146,6 +122,11 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
|
|||||||
self.hir_map
|
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) {
|
fn visit_id(&mut self, hir_id: HirId) {
|
||||||
let owner = self.owner.expect("no owner");
|
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);
|
self.hir_ids_seen.insert(hir_id.local_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) {
|
fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
|
||||||
// Explicitly do nothing here. ImplItemRefs contain hir::Visibility
|
let mut inner_visitor = self.new_visitor(self.hir_map);
|
||||||
// values that actually belong to an ImplItem instead of the ItemKind::Impl
|
inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
|
||||||
// we are currently in. So for those it's correct that they have a
|
|
||||||
// different owner.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_foreign_item_ref(&mut self, _: &'hir hir::ForeignItemRef) {
|
fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
|
||||||
// Explicitly do nothing here. ForeignItemRefs contain hir::Visibility
|
let mut inner_visitor = self.new_visitor(self.hir_map);
|
||||||
// values that actually belong to an ForeignItem instead of the ItemKind::ForeignMod
|
inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
|
||||||
// we are currently in. So for those it's correct that they have a
|
}
|
||||||
// different owner.
|
|
||||||
|
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;
|
use rustc_target::spec::abi::Abi::RustIntrinsic;
|
||||||
|
|
||||||
fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
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) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use rustc_ast::Attribute;
|
use rustc_ast::Attribute;
|
||||||
use rustc_hir as hir;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
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::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
|
||||||
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
@ -12,97 +10,87 @@ use rustc_target::abi::{HasDataLayout, TargetDataLayout};
|
|||||||
pub fn test_layout(tcx: TyCtxt<'_>) {
|
pub fn test_layout(tcx: TyCtxt<'_>) {
|
||||||
if tcx.features().rustc_attrs {
|
if tcx.features().rustc_attrs {
|
||||||
// if the `rustc_attrs` feature is not enabled, don't bother testing layout
|
// if the `rustc_attrs` feature is not enabled, don't bother testing layout
|
||||||
tcx.hir().visit_all_item_likes(&mut LayoutTest { tcx });
|
for id in tcx.hir().items() {
|
||||||
}
|
if matches!(
|
||||||
}
|
tcx.def_kind(id.def_id),
|
||||||
|
DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
|
||||||
struct LayoutTest<'tcx> {
|
) {
|
||||||
tcx: TyCtxt<'tcx>,
|
for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) {
|
||||||
}
|
dump_layout_of(tcx, id.def_id, attr);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attribute) {
|
||||||
fn dump_layout_of(&self, item_def_id: LocalDefId, item: &hir::Item<'tcx>, attr: &Attribute) {
|
let tcx = tcx;
|
||||||
let tcx = self.tcx;
|
let param_env = tcx.param_env(item_def_id);
|
||||||
let param_env = self.tcx.param_env(item_def_id);
|
let ty = tcx.type_of(item_def_id);
|
||||||
let ty = self.tcx.type_of(item_def_id);
|
match tcx.layout_of(param_env.and(ty)) {
|
||||||
match self.tcx.layout_of(param_env.and(ty)) {
|
Ok(ty_layout) => {
|
||||||
Ok(ty_layout) => {
|
// Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
|
||||||
// Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
|
// The `..` are the names of fields to dump.
|
||||||
// The `..` are the names of fields to dump.
|
let meta_items = attr.meta_item_list().unwrap_or_default();
|
||||||
let meta_items = attr.meta_item_list().unwrap_or_default();
|
for meta_item in meta_items {
|
||||||
for meta_item in meta_items {
|
match meta_item.name_or_empty() {
|
||||||
match meta_item.name_or_empty() {
|
sym::abi => {
|
||||||
sym::abi => {
|
tcx.sess.span_err(
|
||||||
self.tcx.sess.span_err(item.span, &format!("abi: {:?}", ty_layout.abi));
|
tcx.def_span(item_def_id.to_def_id()),
|
||||||
}
|
&format!("abi: {:?}", ty_layout.abi),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
sym::align => {
|
sym::align => {
|
||||||
self.tcx
|
tcx.sess.span_err(
|
||||||
.sess
|
tcx.def_span(item_def_id.to_def_id()),
|
||||||
.span_err(item.span, &format!("align: {:?}", ty_layout.align));
|
&format!("align: {:?}", ty_layout.align),
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
|
||||||
sym::size => {
|
sym::size => {
|
||||||
self.tcx
|
tcx.sess.span_err(
|
||||||
.sess
|
tcx.def_span(item_def_id.to_def_id()),
|
||||||
.span_err(item.span, &format!("size: {:?}", ty_layout.size));
|
&format!("size: {:?}", ty_layout.size),
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
|
||||||
sym::homogeneous_aggregate => {
|
sym::homogeneous_aggregate => {
|
||||||
self.tcx.sess.span_err(
|
tcx.sess.span_err(
|
||||||
item.span,
|
tcx.def_span(item_def_id.to_def_id()),
|
||||||
&format!(
|
&format!(
|
||||||
"homogeneous_aggregate: {:?}",
|
"homogeneous_aggregate: {:?}",
|
||||||
ty_layout
|
ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
|
||||||
.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
sym::debug => {
|
sym::debug => {
|
||||||
let normalized_ty = self.tcx.normalize_erasing_regions(
|
let normalized_ty = tcx.normalize_erasing_regions(
|
||||||
param_env.with_reveal_all_normalized(self.tcx),
|
param_env.with_reveal_all_normalized(tcx),
|
||||||
ty,
|
ty,
|
||||||
);
|
);
|
||||||
self.tcx.sess.span_err(
|
tcx.sess.span_err(
|
||||||
item.span,
|
tcx.def_span(item_def_id.to_def_id()),
|
||||||
&format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
|
&format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
name => {
|
name => {
|
||||||
self.tcx.sess.span_err(
|
tcx.sess.span_err(
|
||||||
meta_item.span(),
|
meta_item.span(),
|
||||||
&format!("unrecognized field name `{}`", name),
|
&format!("unrecognized field name `{}`", name),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Err(layout_error) => {
|
Err(layout_error) => {
|
||||||
self.tcx.sess.span_err(item.span, &format!("layout error: {:?}", 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) {
|
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) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
|
@ -31,9 +31,9 @@ struct CheckLoopVisitor<'a, 'hir> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
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,
|
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;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
fn check_mod_naked_functions(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 CheckNakedFunctions { tcx });
|
||||||
module_def_id,
|
|
||||||
&mut CheckNakedFunctions { tcx }.as_deep_visitor(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn provide(providers: &mut Providers) {
|
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::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
|
||||||
use rustc_hir::Node;
|
use rustc_hir::Node;
|
||||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||||
use rustc_middle::middle::privacy;
|
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
|
fn check_item<'tcx>(
|
||||||
// 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> {
|
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
access_levels: &'a privacy::AccessLevels,
|
id: hir::ItemId,
|
||||||
worklist: &'a mut Vec<LocalDefId>,
|
worklist: &mut Vec<LocalDefId>,
|
||||||
}
|
access_levels: &privacy::AccessLevels,
|
||||||
|
) {
|
||||||
|
if has_custom_linkage(tcx, id.def_id) {
|
||||||
|
worklist.push(id.def_id);
|
||||||
|
}
|
||||||
|
|
||||||
impl CollectPrivateImplItemsVisitor<'_, '_> {
|
if !matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
|
||||||
fn push_to_worklist_if_has_custom_linkage(&mut self, def_id: LocalDefId) {
|
return;
|
||||||
// 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.
|
// We need only trait impls here, not inherent impls, and only non-exported ones
|
||||||
if self.tcx.def_kind(def_id).has_codegen_attrs() {
|
let item = tcx.hir().item(id);
|
||||||
let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
|
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
|
||||||
if codegen_attrs.contains_extern_indicator()
|
item.kind
|
||||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
{
|
||||||
// FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
|
if !access_levels.is_reachable(item.def_id) {
|
||||||
// `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
|
// FIXME(#53488) remove `let`
|
||||||
// `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
|
let tcx = tcx;
|
||||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
|
worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
|
||||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|
|
||||||
{
|
let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
|
||||||
self.worklist.push(def_id);
|
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 has_custom_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
|
||||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
// Anything which has custom linkage gets thrown on the worklist no
|
||||||
self.push_to_worklist_if_has_custom_linkage(item.def_id);
|
// matter where it is in the crate, along with "special std symbols"
|
||||||
|
// which are currently akin to allocator symbols.
|
||||||
// We need only trait impls here, not inherent impls, and only non-exported ones
|
if !tcx.def_kind(def_id).has_codegen_attrs() {
|
||||||
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
|
return false;
|
||||||
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.
|
|
||||||
}
|
}
|
||||||
|
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> {
|
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 {
|
// Some methods from non-exported (completely private) trait impls still have to be
|
||||||
tcx,
|
// reachable if they are called from inlinable code. Generally, it's not known until
|
||||||
access_levels,
|
// monomorphization if a specific trait impl item can be reachable or not. So, we
|
||||||
worklist: &mut reachable_context.worklist,
|
// conservatively mark all of them as reachable.
|
||||||
};
|
// FIXME: One possible strategy for pruning the reachable set is to avoid marking impl
|
||||||
tcx.hir().visit_all_item_likes(&mut collect_private_impl_items);
|
// 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.
|
// 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
|
/// Cross-references the feature names of unstable APIs with enabled
|
||||||
/// features and possibly prints errors.
|
/// features and possibly prints errors.
|
||||||
fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
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) {
|
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 };
|
let mut missing = MissingStabilityAnnotations { tcx, access_levels };
|
||||||
missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
|
missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
|
||||||
tcx.hir().walk_toplevel_module(&mut missing);
|
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;
|
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 as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
|
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
|
||||||
use rustc_hir::intravisit::{self, DeepVisitor, Visitor};
|
use rustc_hir::intravisit::{self, Visitor};
|
||||||
use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
|
use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind};
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
|
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>,
|
tcx: TyCtxt<'tcx>,
|
||||||
old_error_set_ancestry: LocalDefIdSet,
|
old_error_set_ancestry: LocalDefIdSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> PrivateItemsInPublicInterfacesVisitor<'tcx> {
|
impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
|
||||||
fn check(
|
fn check(
|
||||||
&self,
|
&self,
|
||||||
def_id: LocalDefId,
|
def_id: LocalDefId,
|
||||||
@ -1841,110 +1841,110 @@ impl<'tcx> PrivateItemsInPublicInterfacesVisitor<'tcx> {
|
|||||||
check.ty();
|
check.ty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
|
pub fn check_item(&mut self, id: ItemId) {
|
||||||
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>) {
|
|
||||||
let tcx = self.tcx;
|
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 {
|
match def_kind {
|
||||||
// Crates are always public.
|
DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias => {
|
||||||
hir::ItemKind::ExternCrate(..) => {}
|
self.check(id.def_id, item_visibility).generics().predicates().ty();
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
hir::ItemKind::OpaqueTy(..) => {
|
DefKind::OpaqueTy => {
|
||||||
// `ty()` for opaque types is the underlying type,
|
// `ty()` for opaque types is the underlying type,
|
||||||
// it's not a part of interface, so we skip it.
|
// 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) => {
|
DefKind::Trait => {
|
||||||
self.check(item.def_id, item_visibility).generics().predicates();
|
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 {
|
for trait_item_ref in trait_item_refs {
|
||||||
self.check_assoc_item(
|
self.check_assoc_item(
|
||||||
trait_item_ref.id.def_id,
|
trait_item_ref.id.def_id,
|
||||||
trait_item_ref.kind,
|
trait_item_ref.kind,
|
||||||
trait_item_ref.defaultness,
|
trait_item_ref.defaultness,
|
||||||
item_visibility,
|
item_visibility,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let AssocItemKind::Type = trait_item_ref.kind {
|
if let AssocItemKind::Type = trait_item_ref.kind {
|
||||||
self.check(trait_item_ref.id.def_id, item_visibility).bounds();
|
self.check(trait_item_ref.id.def_id, item_visibility).bounds();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::ItemKind::TraitAlias(..) => {
|
DefKind::TraitAlias => {
|
||||||
self.check(item.def_id, item_visibility).generics().predicates();
|
self.check(id.def_id, item_visibility).generics().predicates();
|
||||||
}
|
}
|
||||||
hir::ItemKind::Enum(ref def, _) => {
|
DefKind::Enum => {
|
||||||
self.check(item.def_id, item_visibility).generics().predicates();
|
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 variant in def.variants {
|
||||||
for field in variant.data.fields() {
|
for field in variant.data.fields() {
|
||||||
self.check(self.tcx.hir().local_def_id(field.hir_id), item_visibility).ty();
|
self.check(self.tcx.hir().local_def_id(field.hir_id), item_visibility)
|
||||||
|
.ty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Subitems of foreign modules have their own publicity.
|
// Subitems of foreign modules have their own publicity.
|
||||||
hir::ItemKind::ForeignMod { items, .. } => {
|
DefKind::ForeignMod => {
|
||||||
for foreign_item in items {
|
let item = tcx.hir().item(id);
|
||||||
let vis = tcx.visibility(foreign_item.id.def_id);
|
if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
|
||||||
self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
|
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.
|
// Subitems of structs and unions have their own publicity.
|
||||||
hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
|
DefKind::Struct | DefKind::Union => {
|
||||||
self.check(item.def_id, item_visibility).generics().predicates();
|
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() {
|
for field in struct_def.fields() {
|
||||||
let def_id = tcx.hir().local_def_id(field.hir_id);
|
let def_id = tcx.hir().local_def_id(field.hir_id);
|
||||||
let field_visibility = tcx.visibility(def_id);
|
let field_visibility = tcx.visibility(def_id);
|
||||||
self.check(def_id, min(item_visibility, field_visibility, tcx)).ty();
|
self.check(def_id, min(item_visibility, field_visibility, tcx)).ty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// An inherent impl is public when its type is public
|
// An inherent impl is public when its type is public
|
||||||
// Subitems of inherent impls have their own publicity.
|
// Subitems of inherent impls have their own publicity.
|
||||||
// A trait impl is public when both its type and its trait are public
|
// A trait impl is public when both its type and its trait are public
|
||||||
// Subitems of trait impls have inherited publicity.
|
// Subitems of trait impls have inherited publicity.
|
||||||
hir::ItemKind::Impl(ref impl_) => {
|
DefKind::Impl => {
|
||||||
let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default());
|
let item = tcx.hir().item(id);
|
||||||
// check that private components do not appear in the generics or predicates of inherent impls
|
if let hir::ItemKind::Impl(ref impl_) = item.kind {
|
||||||
// this check is intentionally NOT performed for impls of traits, per #90586
|
let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default());
|
||||||
if impl_.of_trait.is_none() {
|
// check that private components do not appear in the generics or predicates of inherent impls
|
||||||
self.check(item.def_id, impl_vis).generics().predicates();
|
// this check is intentionally NOT performed for impls of traits, per #90586
|
||||||
}
|
if impl_.of_trait.is_none() {
|
||||||
for impl_item_ref in impl_.items {
|
self.check(item.def_id, impl_vis).generics().predicates();
|
||||||
let impl_item_vis = if impl_.of_trait.is_none() {
|
}
|
||||||
min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
|
for impl_item_ref in impl_.items {
|
||||||
} else {
|
let impl_item_vis = if impl_.of_trait.is_none() {
|
||||||
impl_vis
|
min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
|
||||||
};
|
} else {
|
||||||
self.check_assoc_item(
|
impl_vis
|
||||||
impl_item_ref.id.def_id,
|
};
|
||||||
impl_item_ref.kind,
|
self.check_assoc_item(
|
||||||
impl_item_ref.defaultness,
|
impl_item_ref.id.def_id,
|
||||||
impl_item_vis,
|
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.
|
// Check for private types and traits in public interfaces.
|
||||||
let mut visitor = PrivateItemsInPublicInterfacesVisitor {
|
let mut checker = PrivateItemsInPublicInterfacesChecker {
|
||||||
tcx,
|
tcx,
|
||||||
// Only definition IDs are ever searched in `old_error_set_ancestry`,
|
// Only definition IDs are ever searched in `old_error_set_ancestry`,
|
||||||
// so we can filter away all non-definition IDs at this point.
|
// 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))
|
.filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id))
|
||||||
.collect(),
|
.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
|
// Main entry point
|
||||||
|
|
||||||
fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
fn collect_mod_item_types(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 CollectItemTypesVisitor { tcx });
|
||||||
module_def_id,
|
|
||||||
&mut CollectItemTypesVisitor { tcx }.as_deep_visitor(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
|
@ -303,7 +303,7 @@ crate fn run(
|
|||||||
// Run call-finder on all items
|
// Run call-finder on all items
|
||||||
let mut calls = FxHashMap::default();
|
let mut calls = FxHashMap::default();
|
||||||
let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
|
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
|
// Sort call locations within a given file in document order
|
||||||
for fn_calls in calls.values_mut() {
|
for fn_calls in calls.values_mut() {
|
||||||
|
@ -21,7 +21,7 @@ extern crate rustc_session;
|
|||||||
use rustc_borrowck::consumers::BodyWithBorrowckFacts;
|
use rustc_borrowck::consumers::BodyWithBorrowckFacts;
|
||||||
use rustc_driver::Compilation;
|
use rustc_driver::Compilation;
|
||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_interface::interface::Compiler;
|
use rustc_interface::interface::Compiler;
|
||||||
use rustc_interface::{Config, Queries};
|
use rustc_interface::{Config, Queries};
|
||||||
use rustc_middle::ty::query::query_values::mir_borrowck;
|
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| {
|
queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
|
||||||
// Collect definition ids of MIR bodies.
|
// Collect definition ids of MIR bodies.
|
||||||
let hir = tcx.hir();
|
let hir = tcx.hir();
|
||||||
let mut visitor = HirVisitor { bodies: Vec::new() };
|
let mut bodies = Vec::new();
|
||||||
hir.visit_all_item_likes(&mut visitor);
|
|
||||||
|
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.
|
// Trigger borrow checking of all bodies.
|
||||||
for def_id in visitor.bodies {
|
for def_id in bodies {
|
||||||
let _ = tcx.optimized_mir(def_id);
|
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)
|
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.
|
/// Pull MIR bodies stored in the thread-local.
|
||||||
fn get_bodies<'tcx>(tcx: TyCtxt<'tcx>) -> Vec<(String, BodyWithBorrowckFacts<'tcx>)> {
|
fn get_bodies<'tcx>(tcx: TyCtxt<'tcx>) -> Vec<(String, BodyWithBorrowckFacts<'tcx>)> {
|
||||||
MIR_BODIES.with(|state| {
|
MIR_BODIES.with(|state| {
|
||||||
|
@ -2,10 +2,10 @@ error[E0138]: multiple `start` functions
|
|||||||
--> $DIR/E0138.rs:7:1
|
--> $DIR/E0138.rs:7:1
|
||||||
|
|
|
|
||||||
LL | fn foo(argc: isize, argv: *const *const u8) -> isize { 0 }
|
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 }
|
LL | fn f(argc: isize, argv: *const *const u8) -> isize { 0 }
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ multiple `start` functions
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ multiple `start` functions
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ note: here is a function named `main`
|
|||||||
--> $DIR/main-wrong-location.rs:4:5
|
--> $DIR/main-wrong-location.rs:4:5
|
||||||
|
|
|
|
||||||
LL | fn main() { }
|
LL | fn main() { }
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
= note: you have one or more functions named `main` not defined at the crate level
|
= note: you have one or more functions named `main` not defined at the crate level
|
||||||
= help: consider moving the `main` function definitions
|
= 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::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID};
|
||||||
use rustc_hir::hir_id::{HirIdMap, HirIdSet};
|
use rustc_hir::hir_id::{HirIdMap, HirIdSet};
|
||||||
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
|
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
|
||||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
|
||||||
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
|
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl,
|
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,
|
Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
|
||||||
TraitRef, TyKind, UnOp,
|
TraitRef, TyKind, UnOp,
|
||||||
};
|
};
|
||||||
@ -2068,35 +2067,6 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
|
|||||||
false
|
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();
|
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 {
|
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) {
|
match map.entry(module) {
|
||||||
Entry::Occupied(entry) => f(entry.get()),
|
Entry::Occupied(entry) => f(entry.get()),
|
||||||
Entry::Vacant(entry) => {
|
Entry::Vacant(entry) => {
|
||||||
let mut visitor = TestItemNamesVisitor { tcx, names: Vec::new() };
|
let mut names = Vec::new();
|
||||||
tcx.hir().visit_item_likes_in_module(module, &mut visitor);
|
for id in tcx.hir().module_items(module) {
|
||||||
visitor.names.sort_unstable();
|
if matches!(tcx.def_kind(id.def_id), DefKind::Const)
|
||||||
f(&*entry.insert(visitor.names))
|
&& 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