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
29 changed files with 640 additions and 791 deletions
|
@ -2390,7 +2390,7 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
|
|||
|
||||
fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
let check_attr_visitor = &mut CheckAttrVisitor { tcx };
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor());
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_def_id, check_attr_visitor);
|
||||
if module_def_id.is_top_level_module() {
|
||||
check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
|
||||
check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
|
||||
|
|
|
@ -57,89 +57,71 @@ impl NonConstExpr {
|
|||
|
||||
fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
let mut vis = CheckConstVisitor::new(tcx);
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor());
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckConstTraitVisitor::new(tcx));
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut vis);
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { check_mod_const_bodies, ..*providers };
|
||||
}
|
||||
|
||||
struct CheckConstTraitVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
|
||||
let _: Option<_> = try {
|
||||
if let hir::ItemKind::Impl(ref imp) = item.kind && let hir::Constness::Const = imp.constness {
|
||||
let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
|
||||
let ancestors = tcx
|
||||
.trait_def(trait_def_id)
|
||||
.ancestors(tcx, item.def_id.to_def_id())
|
||||
.ok()?;
|
||||
let mut to_implement = Vec::new();
|
||||
|
||||
impl<'tcx> CheckConstTraitVisitor<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||
CheckConstTraitVisitor { tcx }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor<'tcx> {
|
||||
/// check for const trait impls, and errors if the impl uses provided/default functions
|
||||
/// of the trait being implemented; as those provided functions can be non-const.
|
||||
fn visit_item<'hir>(&mut self, item: &'hir hir::Item<'hir>) {
|
||||
let _: Option<_> = try {
|
||||
if let hir::ItemKind::Impl(ref imp) = item.kind && let hir::Constness::Const = imp.constness {
|
||||
let trait_def_id = imp.of_trait.as_ref()?.trait_def_id()?;
|
||||
let ancestors = self
|
||||
.tcx
|
||||
.trait_def(trait_def_id)
|
||||
.ancestors(self.tcx, item.def_id.to_def_id())
|
||||
.ok()?;
|
||||
let mut to_implement = Vec::new();
|
||||
|
||||
for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
|
||||
for trait_item in tcx.associated_items(trait_def_id).in_definition_order()
|
||||
{
|
||||
if let ty::AssocItem {
|
||||
kind: ty::AssocKind::Fn,
|
||||
defaultness,
|
||||
def_id: trait_item_id,
|
||||
..
|
||||
} = *trait_item
|
||||
{
|
||||
// we can ignore functions that do not have default bodies:
|
||||
// if those are unimplemented it will be caught by typeck.
|
||||
if !defaultness.has_value()
|
||||
|| tcx
|
||||
.has_attr(trait_item_id, sym::default_method_body_is_const)
|
||||
{
|
||||
if let ty::AssocItem {
|
||||
kind: ty::AssocKind::Fn,
|
||||
defaultness,
|
||||
def_id: trait_item_id,
|
||||
..
|
||||
} = *trait_item
|
||||
{
|
||||
// we can ignore functions that do not have default bodies:
|
||||
// if those are unimplemented it will be caught by typeck.
|
||||
if !defaultness.has_value()
|
||||
|| self
|
||||
.tcx
|
||||
.has_attr(trait_item_id, sym::default_method_body_is_const)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_implemented = ancestors
|
||||
.leaf_def(self.tcx, trait_item_id)
|
||||
.map(|node_item| !node_item.defining_node.is_from_trait())
|
||||
.unwrap_or(false);
|
||||
|
||||
if !is_implemented {
|
||||
to_implement.push(self.tcx.item_name(trait_item_id).to_string());
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// all nonconst trait functions (not marked with #[default_method_body_is_const])
|
||||
// must be implemented
|
||||
if !to_implement.is_empty() {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
item.span,
|
||||
"const trait implementations may not use non-const default functions",
|
||||
)
|
||||
.note(&format!("`{}` not implemented", to_implement.join("`, `")))
|
||||
.emit();
|
||||
let is_implemented = ancestors
|
||||
.leaf_def(tcx, trait_item_id)
|
||||
.map(|node_item| !node_item.defining_node.is_from_trait())
|
||||
.unwrap_or(false);
|
||||
|
||||
if !is_implemented {
|
||||
to_implement.push(trait_item_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn visit_trait_item<'hir>(&mut self, _: &'hir hir::TraitItem<'hir>) {}
|
||||
|
||||
fn visit_impl_item<'hir>(&mut self, _: &'hir hir::ImplItem<'hir>) {}
|
||||
|
||||
fn visit_foreign_item<'hir>(&mut self, _: &'hir hir::ForeignItem<'hir>) {}
|
||||
// all nonconst trait functions (not marked with #[default_method_body_is_const])
|
||||
// must be implemented
|
||||
if !to_implement.is_empty() {
|
||||
let not_implemented = to_implement
|
||||
.into_iter()
|
||||
.map(|did| tcx.item_name(did).to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("`, `");
|
||||
tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
item.span,
|
||||
"const trait implementations may not use non-const default functions",
|
||||
)
|
||||
.note(&format!("`{}` not implemented", not_implemented))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -270,6 +252,11 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
|
|||
self.tcx.hir()
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
intravisit::walk_item(self, item);
|
||||
check_item(self.tcx, item);
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
|
||||
let kind = Some(hir::ConstContext::Const);
|
||||
self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
|
||||
|
|
|
@ -8,7 +8,6 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::{Node, PatKind, TyKind};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
|
@ -468,7 +467,7 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
|||
tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
|
||||
}
|
||||
|
||||
// This visitor seeds items that
|
||||
// These check_* functions seeds items that
|
||||
// 1) We want to explicitly consider as live:
|
||||
// * Item annotated with #[allow(dead_code)]
|
||||
// - This is done so that if we want to suppress warnings for a
|
||||
|
@ -481,82 +480,95 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
|
|||
// or
|
||||
// 2) We are not sure to be live or not
|
||||
// * Implementations of traits and trait methods
|
||||
struct LifeSeeder<'tcx> {
|
||||
worklist: Vec<LocalDefId>,
|
||||
fn check_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
// see `MarkSymbolVisitor::struct_constructors`
|
||||
struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
|
||||
}
|
||||
worklist: &mut Vec<LocalDefId>,
|
||||
struct_constructors: &mut FxHashMap<LocalDefId, LocalDefId>,
|
||||
id: hir::ItemId,
|
||||
) {
|
||||
let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.hir_id());
|
||||
if allow_dead_code {
|
||||
worklist.push(id.def_id);
|
||||
}
|
||||
|
||||
impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
||||
let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx, item.hir_id());
|
||||
if allow_dead_code {
|
||||
self.worklist.push(item.def_id);
|
||||
}
|
||||
match item.kind {
|
||||
hir::ItemKind::Enum(ref enum_def, _) => {
|
||||
let hir = self.tcx.hir();
|
||||
match tcx.def_kind(id.def_id) {
|
||||
DefKind::Enum => {
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
|
||||
let hir = tcx.hir();
|
||||
if allow_dead_code {
|
||||
self.worklist.extend(
|
||||
worklist.extend(
|
||||
enum_def.variants.iter().map(|variant| hir.local_def_id(variant.id)),
|
||||
);
|
||||
}
|
||||
|
||||
for variant in enum_def.variants {
|
||||
if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
|
||||
self.struct_constructors
|
||||
struct_constructors
|
||||
.insert(hir.local_def_id(ctor_hir_id), hir.local_def_id(variant.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Impl(hir::Impl { ref of_trait, items, .. }) => {
|
||||
if of_trait.is_some() {
|
||||
self.worklist.push(item.def_id);
|
||||
}
|
||||
for impl_item_ref in *items {
|
||||
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
|
||||
if of_trait.is_some()
|
||||
|| has_allow_dead_code_or_lang_attr(self.tcx, impl_item.hir_id())
|
||||
{
|
||||
self.worklist.push(impl_item_ref.id.def_id);
|
||||
}
|
||||
}
|
||||
DefKind::Impl => {
|
||||
let of_trait = tcx.impl_trait_ref(id.def_id);
|
||||
|
||||
if of_trait.is_some() {
|
||||
worklist.push(id.def_id);
|
||||
}
|
||||
|
||||
// get DefIds from another query
|
||||
let local_def_ids = tcx
|
||||
.associated_item_def_ids(id.def_id)
|
||||
.iter()
|
||||
.filter_map(|def_id| def_id.as_local());
|
||||
|
||||
// And we access the Map here to get HirId from LocalDefId
|
||||
for id in local_def_ids {
|
||||
if of_trait.is_some()
|
||||
|| has_allow_dead_code_or_lang_attr(tcx, tcx.hir().local_def_id_to_hir_id(id))
|
||||
{
|
||||
worklist.push(id);
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Struct(ref variant_data, _) => {
|
||||
}
|
||||
DefKind::Struct => {
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::Struct(ref variant_data, _) = item.kind {
|
||||
if let Some(ctor_hir_id) = variant_data.ctor_hir_id() {
|
||||
self.struct_constructors
|
||||
.insert(self.tcx.hir().local_def_id(ctor_hir_id), item.def_id);
|
||||
struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id);
|
||||
}
|
||||
}
|
||||
hir::ItemKind::GlobalAsm(_) => {
|
||||
// global_asm! is always live.
|
||||
self.worklist.push(item.def_id);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
DefKind::GlobalAsm => {
|
||||
// global_asm! is always live.
|
||||
worklist.push(id.def_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
|
||||
use hir::TraitItemKind::{Const, Fn};
|
||||
fn check_trait_item<'tcx>(tcx: TyCtxt<'tcx>, worklist: &mut Vec<LocalDefId>, id: hir::TraitItemId) {
|
||||
use hir::TraitItemKind::{Const, Fn};
|
||||
if matches!(tcx.def_kind(id.def_id), DefKind::AssocConst | DefKind::AssocFn) {
|
||||
let trait_item = tcx.hir().trait_item(id);
|
||||
if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
|
||||
&& has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id())
|
||||
&& has_allow_dead_code_or_lang_attr(tcx, trait_item.hir_id())
|
||||
{
|
||||
self.worklist.push(trait_item.def_id);
|
||||
worklist.push(trait_item.def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, _item: &hir::ImplItem<'_>) {
|
||||
// ignore: we are handling this in `visit_item` above
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
|
||||
use hir::ForeignItemKind::{Fn, Static};
|
||||
if matches!(foreign_item.kind, Static(..) | Fn(..))
|
||||
&& has_allow_dead_code_or_lang_attr(self.tcx, foreign_item.hir_id())
|
||||
{
|
||||
self.worklist.push(foreign_item.def_id);
|
||||
}
|
||||
fn check_foreign_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
worklist: &mut Vec<LocalDefId>,
|
||||
id: hir::ForeignItemId,
|
||||
) {
|
||||
if matches!(tcx.def_kind(id.def_id), DefKind::Static(_) | DefKind::Fn)
|
||||
&& has_allow_dead_code_or_lang_attr(tcx, id.hir_id())
|
||||
{
|
||||
worklist.push(id.def_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -564,7 +576,9 @@ fn create_and_seed_worklist<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
|
||||
let access_levels = &tcx.privacy_access_levels(());
|
||||
let worklist = access_levels
|
||||
// see `MarkSymbolVisitor::struct_constructors`
|
||||
let mut struct_constructors = Default::default();
|
||||
let mut worklist = access_levels
|
||||
.map
|
||||
.iter()
|
||||
.filter_map(
|
||||
|
@ -576,11 +590,20 @@ fn create_and_seed_worklist<'tcx>(
|
|||
.chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Seed implemented trait items
|
||||
let mut life_seeder = LifeSeeder { worklist, tcx, struct_constructors: Default::default() };
|
||||
tcx.hir().visit_all_item_likes(&mut life_seeder);
|
||||
let crate_items = tcx.hir_crate_items(());
|
||||
for id in crate_items.items() {
|
||||
check_item(tcx, &mut worklist, &mut struct_constructors, id);
|
||||
}
|
||||
|
||||
(life_seeder.worklist, life_seeder.struct_constructors)
|
||||
for id in crate_items.trait_items() {
|
||||
check_trait_item(tcx, &mut worklist, id);
|
||||
}
|
||||
|
||||
for id in crate_items.foreign_items() {
|
||||
check_foreign_item(tcx, &mut worklist, id);
|
||||
}
|
||||
|
||||
(worklist, struct_constructors)
|
||||
}
|
||||
|
||||
fn live_symbols_and_ignored_derived_traits<'tcx>(
|
||||
|
|
|
@ -5,8 +5,7 @@ use rustc_data_structures::fx::FxHashSet;
|
|||
use rustc_expand::base::resolve_path;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::{HirId, Target};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
|
@ -14,96 +13,66 @@ use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
|
|||
|
||||
use std::sync::Arc;
|
||||
|
||||
struct DebuggerVisualizerCollector<'tcx> {
|
||||
debugger_visualizers: FxHashSet<DebuggerVisualizerFile>,
|
||||
fn check_for_debugger_visualizer<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
hir_id: HirId,
|
||||
debugger_visualizers: &mut FxHashSet<DebuggerVisualizerFile>,
|
||||
) {
|
||||
let attrs = tcx.hir().attrs(hir_id);
|
||||
for attr in attrs {
|
||||
if attr.has_name(sym::debugger_visualizer) {
|
||||
let list = match attr.meta_item_list() {
|
||||
Some(list) => list,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
impl<'v, 'tcx> ItemLikeVisitor<'v> for DebuggerVisualizerCollector<'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
||||
let target = Target::from_item(item);
|
||||
match target {
|
||||
Target::Mod => {
|
||||
self.check_for_debugger_visualizer(item.hir_id());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _: &hir::TraitItem<'_>) {}
|
||||
|
||||
fn visit_impl_item(&mut self, _: &hir::ImplItem<'_>) {}
|
||||
|
||||
fn visit_foreign_item(&mut self, _: &hir::ForeignItem<'_>) {}
|
||||
}
|
||||
|
||||
impl<'tcx> DebuggerVisualizerCollector<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> DebuggerVisualizerCollector<'tcx> {
|
||||
DebuggerVisualizerCollector { tcx, debugger_visualizers: FxHashSet::default() }
|
||||
}
|
||||
|
||||
fn check_for_debugger_visualizer(&mut self, hir_id: HirId) {
|
||||
let attrs = self.tcx.hir().attrs(hir_id);
|
||||
for attr in attrs {
|
||||
if attr.has_name(sym::debugger_visualizer) {
|
||||
let list = match attr.meta_item_list() {
|
||||
Some(list) => list,
|
||||
let meta_item = match list.len() {
|
||||
1 => match list[0].meta_item() {
|
||||
Some(meta_item) => meta_item,
|
||||
_ => continue,
|
||||
};
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let meta_item = match list.len() {
|
||||
1 => match list[0].meta_item() {
|
||||
Some(meta_item) => meta_item,
|
||||
_ => continue,
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let file = match (meta_item.name_or_empty(), meta_item.value_str()) {
|
||||
(sym::natvis_file, Some(value)) => {
|
||||
match resolve_path(&self.tcx.sess.parse_sess, value.as_str(), attr.span) {
|
||||
Ok(file) => file,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
(_, _) => continue,
|
||||
};
|
||||
|
||||
if file.is_file() {
|
||||
let contents = match std::fs::read(&file) {
|
||||
Ok(contents) => contents,
|
||||
Err(err) => {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
&format!(
|
||||
"Unable to read contents of file `{}`. {}",
|
||||
file.display(),
|
||||
err
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
let file = match (meta_item.name_or_empty(), meta_item.value_str()) {
|
||||
(sym::natvis_file, Some(value)) => {
|
||||
match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) {
|
||||
Ok(file) => file,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
self.debugger_visualizers.insert(DebuggerVisualizerFile::new(
|
||||
Arc::from(contents),
|
||||
DebuggerVisualizerType::Natvis,
|
||||
));
|
||||
} else {
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
&format!("{} is not a valid file", file.display()),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
(_, _) => continue,
|
||||
};
|
||||
|
||||
if file.is_file() {
|
||||
let contents = match std::fs::read(&file) {
|
||||
Ok(contents) => contents,
|
||||
Err(err) => {
|
||||
tcx.sess
|
||||
.struct_span_err(
|
||||
attr.span,
|
||||
&format!(
|
||||
"Unable to read contents of file `{}`. {}",
|
||||
file.display(),
|
||||
err
|
||||
),
|
||||
)
|
||||
.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
debugger_visualizers.insert(DebuggerVisualizerFile::new(
|
||||
Arc::from(contents),
|
||||
DebuggerVisualizerType::Natvis,
|
||||
));
|
||||
} else {
|
||||
tcx.sess
|
||||
.struct_span_err(attr.span, &format!("{} is not a valid file", file.display()))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,17 +83,21 @@ fn debugger_visualizers<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> Vec<Debugger
|
|||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
|
||||
// Initialize the collector.
|
||||
let mut collector = DebuggerVisualizerCollector::new(tcx);
|
||||
let mut debugger_visualizers = FxHashSet::default();
|
||||
|
||||
// Collect debugger visualizers in this crate.
|
||||
tcx.hir().visit_all_item_likes(&mut collector);
|
||||
tcx.hir().for_each_module(|id| {
|
||||
check_for_debugger_visualizer(
|
||||
tcx,
|
||||
tcx.hir().local_def_id_to_hir_id(id),
|
||||
&mut debugger_visualizers,
|
||||
)
|
||||
});
|
||||
|
||||
// Collect debugger visualizers on the crate attributes.
|
||||
collector.check_for_debugger_visualizer(CRATE_HIR_ID);
|
||||
check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers);
|
||||
|
||||
// Extract out the found debugger_visualizer items.
|
||||
let DebuggerVisualizerCollector { debugger_visualizers, .. } = collector;
|
||||
|
||||
let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>();
|
||||
|
||||
// Sort the visualizers so we always get a deterministic query result.
|
||||
|
|
|
@ -10,49 +10,22 @@
|
|||
//! * Compiler internal types like `Ty` and `TyCtxt`
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::diagnostic_items::DiagnosticItems;
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
struct DiagnosticItemCollector<'tcx> {
|
||||
fn observe_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
diagnostic_items: DiagnosticItems,
|
||||
}
|
||||
|
||||
impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
||||
self.observe_item(item.def_id);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
|
||||
self.observe_item(trait_item.def_id);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
|
||||
self.observe_item(impl_item.def_id);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
|
||||
self.observe_item(foreign_item.def_id);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> DiagnosticItemCollector<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> {
|
||||
DiagnosticItemCollector { tcx, diagnostic_items: DiagnosticItems::default() }
|
||||
}
|
||||
|
||||
fn observe_item(&mut self, def_id: LocalDefId) {
|
||||
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let attrs = self.tcx.hir().attrs(hir_id);
|
||||
if let Some(name) = extract(attrs) {
|
||||
// insert into our table
|
||||
collect_item(self.tcx, &mut self.diagnostic_items, name, def_id.to_def_id());
|
||||
}
|
||||
diagnostic_items: &mut DiagnosticItems,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
let attrs = tcx.hir().attrs(hir_id);
|
||||
if let Some(name) = extract(attrs) {
|
||||
// insert into our table
|
||||
collect_item(tcx, diagnostic_items, name, def_id.to_def_id());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,12 +68,28 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems
|
|||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
|
||||
// Initialize the collector.
|
||||
let mut collector = DiagnosticItemCollector::new(tcx);
|
||||
let mut diagnostic_items = DiagnosticItems::default();
|
||||
|
||||
// Collect diagnostic items in this crate.
|
||||
tcx.hir().visit_all_item_likes(&mut collector);
|
||||
let crate_items = tcx.hir_crate_items(());
|
||||
|
||||
collector.diagnostic_items
|
||||
for id in crate_items.items() {
|
||||
observe_item(tcx, &mut diagnostic_items, id.def_id);
|
||||
}
|
||||
|
||||
for id in crate_items.trait_items() {
|
||||
observe_item(tcx, &mut diagnostic_items, id.def_id);
|
||||
}
|
||||
|
||||
for id in crate_items.impl_items() {
|
||||
observe_item(tcx, &mut diagnostic_items, id.def_id);
|
||||
}
|
||||
|
||||
for id in crate_items.foreign_items() {
|
||||
observe_item(tcx, &mut diagnostic_items, id.def_id);
|
||||
}
|
||||
|
||||
diagnostic_items
|
||||
}
|
||||
|
||||
/// Traverse and collect all the diagnostic items in all crates.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use rustc_ast::entry::EntryPointType;
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::{ForeignItem, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
|
||||
use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{DefIdTree, TyCtxt};
|
||||
use rustc_session::config::{CrateType, EntryFnType};
|
||||
|
@ -25,25 +25,6 @@ struct EntryContext<'tcx> {
|
|||
non_main_fns: Vec<Span>,
|
||||
}
|
||||
|
||||
impl<'tcx> ItemLikeVisitor<'tcx> for EntryContext<'tcx> {
|
||||
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
|
||||
let at_root = self.tcx.opt_local_parent(item.def_id) == Some(CRATE_DEF_ID);
|
||||
find_item(item, self, at_root);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _trait_item: &'tcx TraitItem<'tcx>) {
|
||||
// Entry fn is never a trait item.
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem<'tcx>) {
|
||||
// Entry fn is never a trait item.
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, _: &'tcx ForeignItem<'tcx>) {
|
||||
// Entry fn is never a foreign item.
|
||||
}
|
||||
}
|
||||
|
||||
fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
|
||||
let any_exe = tcx.sess.crate_types().iter().any(|ty| *ty == CrateType::Executable);
|
||||
if !any_exe {
|
||||
|
@ -59,28 +40,35 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
|
|||
let mut ctxt =
|
||||
EntryContext { tcx, attr_main_fn: None, start_fn: None, non_main_fns: Vec::new() };
|
||||
|
||||
tcx.hir().visit_all_item_likes(&mut ctxt);
|
||||
for id in tcx.hir().items() {
|
||||
find_item(id, &mut ctxt);
|
||||
}
|
||||
|
||||
configure_main(tcx, &ctxt)
|
||||
}
|
||||
|
||||
// Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
|
||||
// (with `ast::Item`), so make sure to keep them in sync.
|
||||
fn entry_point_type(ctxt: &EntryContext<'_>, item: &Item<'_>, at_root: bool) -> EntryPointType {
|
||||
let attrs = ctxt.tcx.hir().attrs(item.hir_id());
|
||||
// A small optimization was added so that hir::Item is fetched only when needed.
|
||||
// An equivalent optimization was not applied to the duplicated code in test_harness.rs.
|
||||
fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> EntryPointType {
|
||||
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
|
||||
if ctxt.tcx.sess.contains_name(attrs, sym::start) {
|
||||
EntryPointType::Start
|
||||
} else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
|
||||
EntryPointType::MainAttr
|
||||
} else if item.ident.name == sym::main {
|
||||
if at_root {
|
||||
// This is a top-level function so can be `main`.
|
||||
EntryPointType::MainNamed
|
||||
} else {
|
||||
EntryPointType::OtherMain
|
||||
}
|
||||
} else {
|
||||
EntryPointType::None
|
||||
if let Some(name) = ctxt.tcx.opt_item_name(id.def_id.to_def_id())
|
||||
&& name == sym::main {
|
||||
if at_root {
|
||||
// This is a top-level function so can be `main`.
|
||||
EntryPointType::MainNamed
|
||||
} else {
|
||||
EntryPointType::OtherMain
|
||||
}
|
||||
} else {
|
||||
EntryPointType::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,11 +77,13 @@ fn throw_attr_err(sess: &Session, span: Span, attr: &str) {
|
|||
.emit();
|
||||
}
|
||||
|
||||
fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) {
|
||||
match entry_point_type(ctxt, item, at_root) {
|
||||
fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
|
||||
let at_root = ctxt.tcx.opt_local_parent(id.def_id) == Some(CRATE_DEF_ID);
|
||||
|
||||
match entry_point_type(ctxt, id, at_root) {
|
||||
EntryPointType::None => (),
|
||||
_ if !matches!(item.kind, ItemKind::Fn(..)) => {
|
||||
let attrs = ctxt.tcx.hir().attrs(item.hir_id());
|
||||
_ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => {
|
||||
let attrs = ctxt.tcx.hir().attrs(id.hir_id());
|
||||
if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::start) {
|
||||
throw_attr_err(&ctxt.tcx.sess, attr.span, "start");
|
||||
}
|
||||
|
@ -103,31 +93,39 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_>, at_root: bool) {
|
|||
}
|
||||
EntryPointType::MainNamed => (),
|
||||
EntryPointType::OtherMain => {
|
||||
ctxt.non_main_fns.push(item.span);
|
||||
ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
|
||||
}
|
||||
EntryPointType::MainAttr => {
|
||||
if ctxt.attr_main_fn.is_none() {
|
||||
ctxt.attr_main_fn = Some((item.def_id, item.span));
|
||||
ctxt.attr_main_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
|
||||
} else {
|
||||
struct_span_err!(
|
||||
ctxt.tcx.sess,
|
||||
item.span,
|
||||
ctxt.tcx.def_span(id.def_id.to_def_id()),
|
||||
E0137,
|
||||
"multiple functions with a `#[main]` attribute"
|
||||
)
|
||||
.span_label(item.span, "additional `#[main]` function")
|
||||
.span_label(
|
||||
ctxt.tcx.def_span(id.def_id.to_def_id()),
|
||||
"additional `#[main]` function",
|
||||
)
|
||||
.span_label(ctxt.attr_main_fn.unwrap().1, "first `#[main]` function")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
EntryPointType::Start => {
|
||||
if ctxt.start_fn.is_none() {
|
||||
ctxt.start_fn = Some((item.def_id, item.span));
|
||||
ctxt.start_fn = Some((id.def_id, ctxt.tcx.def_span(id.def_id.to_def_id())));
|
||||
} else {
|
||||
struct_span_err!(ctxt.tcx.sess, item.span, E0138, "multiple `start` functions")
|
||||
.span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
|
||||
.span_label(item.span, "multiple `start` functions")
|
||||
.emit();
|
||||
struct_span_err!(
|
||||
ctxt.tcx.sess,
|
||||
ctxt.tcx.def_span(id.def_id.to_def_id()),
|
||||
E0138,
|
||||
"multiple `start` functions"
|
||||
)
|
||||
.span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
|
||||
.span_label(ctxt.tcx.def_span(id.def_id.to_def_id()), "multiple `start` functions")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ use rustc_data_structures::sync::Lock;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_hir::intravisit;
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::{HirId, ItemLocalId};
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::hir::nested_filter;
|
||||
|
@ -20,8 +19,14 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
|||
let hir_map = tcx.hir();
|
||||
|
||||
hir_map.par_for_each_module(|module_id| {
|
||||
hir_map
|
||||
.visit_item_likes_in_module(module_id, &mut OuterVisitor { hir_map, errors: &errors })
|
||||
let mut v = HirIdValidator {
|
||||
hir_map,
|
||||
owner: None,
|
||||
hir_ids_seen: Default::default(),
|
||||
errors: &errors,
|
||||
};
|
||||
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_id, &mut v);
|
||||
});
|
||||
|
||||
let errors = errors.into_inner();
|
||||
|
@ -39,13 +44,8 @@ struct HirIdValidator<'a, 'hir> {
|
|||
errors: &'a Lock<Vec<String>>,
|
||||
}
|
||||
|
||||
struct OuterVisitor<'a, 'hir> {
|
||||
hir_map: Map<'hir>,
|
||||
errors: &'a Lock<Vec<String>>,
|
||||
}
|
||||
|
||||
impl<'a, 'hir> OuterVisitor<'a, 'hir> {
|
||||
fn new_inner_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> {
|
||||
impl<'a, 'hir> HirIdValidator<'a, 'hir> {
|
||||
fn new_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> {
|
||||
HirIdValidator {
|
||||
hir_map,
|
||||
owner: None,
|
||||
|
@ -53,31 +53,7 @@ impl<'a, 'hir> OuterVisitor<'a, 'hir> {
|
|||
errors: self.errors,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'hir> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> {
|
||||
fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
|
||||
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i));
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
|
||||
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
|
||||
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i));
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
|
||||
let mut inner_visitor = self.new_inner_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'hir> HirIdValidator<'a, 'hir> {
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn error(&self, f: impl FnOnce() -> String) {
|
||||
|
@ -146,6 +122,11 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
|
|||
self.hir_map
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
|
||||
let mut inner_visitor = self.new_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i));
|
||||
}
|
||||
|
||||
fn visit_id(&mut self, hir_id: HirId) {
|
||||
let owner = self.owner.expect("no owner");
|
||||
|
||||
|
@ -163,17 +144,18 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
|
|||
self.hir_ids_seen.insert(hir_id.local_id);
|
||||
}
|
||||
|
||||
fn visit_impl_item_ref(&mut self, _: &'hir hir::ImplItemRef) {
|
||||
// Explicitly do nothing here. ImplItemRefs contain hir::Visibility
|
||||
// values that actually belong to an ImplItem instead of the ItemKind::Impl
|
||||
// we are currently in. So for those it's correct that they have a
|
||||
// different owner.
|
||||
fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
|
||||
let mut inner_visitor = self.new_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
|
||||
}
|
||||
|
||||
fn visit_foreign_item_ref(&mut self, _: &'hir hir::ForeignItemRef) {
|
||||
// Explicitly do nothing here. ForeignItemRefs contain hir::Visibility
|
||||
// values that actually belong to an ForeignItem instead of the ItemKind::ForeignMod
|
||||
// we are currently in. So for those it's correct that they have a
|
||||
// different owner.
|
||||
fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
|
||||
let mut inner_visitor = self.new_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
|
||||
let mut inner_visitor = self.new_visitor(self.hir_map);
|
||||
inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ use rustc_target::asm::{InlineAsmRegOrRegClass, InlineAsmType};
|
|||
use rustc_target::spec::abi::Abi::RustIntrinsic;
|
||||
|
||||
fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx }.as_deep_visitor());
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx });
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
use rustc_ast::Attribute;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::ItemKind;
|
||||
use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
|
||||
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
||||
use rustc_span::symbol::sym;
|
||||
|
@ -12,97 +10,87 @@ use rustc_target::abi::{HasDataLayout, TargetDataLayout};
|
|||
pub fn test_layout(tcx: TyCtxt<'_>) {
|
||||
if tcx.features().rustc_attrs {
|
||||
// if the `rustc_attrs` feature is not enabled, don't bother testing layout
|
||||
tcx.hir().visit_all_item_likes(&mut LayoutTest { tcx });
|
||||
}
|
||||
}
|
||||
|
||||
struct LayoutTest<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ItemLikeVisitor<'tcx> for LayoutTest<'tcx> {
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
|
||||
match item.kind {
|
||||
ItemKind::TyAlias(..)
|
||||
| ItemKind::Enum(..)
|
||||
| ItemKind::Struct(..)
|
||||
| ItemKind::Union(..) => {
|
||||
for attr in self.tcx.get_attrs(item.def_id.to_def_id(), sym::rustc_layout) {
|
||||
self.dump_layout_of(item.def_id, item, attr);
|
||||
for id in tcx.hir().items() {
|
||||
if matches!(
|
||||
tcx.def_kind(id.def_id),
|
||||
DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
|
||||
) {
|
||||
for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) {
|
||||
dump_layout_of(tcx, id.def_id, attr);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {}
|
||||
fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {}
|
||||
fn visit_foreign_item(&mut self, _: &'tcx hir::ForeignItem<'tcx>) {}
|
||||
}
|
||||
|
||||
impl<'tcx> LayoutTest<'tcx> {
|
||||
fn dump_layout_of(&self, item_def_id: LocalDefId, item: &hir::Item<'tcx>, attr: &Attribute) {
|
||||
let tcx = self.tcx;
|
||||
let param_env = self.tcx.param_env(item_def_id);
|
||||
let ty = self.tcx.type_of(item_def_id);
|
||||
match self.tcx.layout_of(param_env.and(ty)) {
|
||||
Ok(ty_layout) => {
|
||||
// Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
|
||||
// The `..` are the names of fields to dump.
|
||||
let meta_items = attr.meta_item_list().unwrap_or_default();
|
||||
for meta_item in meta_items {
|
||||
match meta_item.name_or_empty() {
|
||||
sym::abi => {
|
||||
self.tcx.sess.span_err(item.span, &format!("abi: {:?}", ty_layout.abi));
|
||||
}
|
||||
fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attribute) {
|
||||
let tcx = tcx;
|
||||
let param_env = tcx.param_env(item_def_id);
|
||||
let ty = tcx.type_of(item_def_id);
|
||||
match tcx.layout_of(param_env.and(ty)) {
|
||||
Ok(ty_layout) => {
|
||||
// Check out the `#[rustc_layout(..)]` attribute to tell what to dump.
|
||||
// The `..` are the names of fields to dump.
|
||||
let meta_items = attr.meta_item_list().unwrap_or_default();
|
||||
for meta_item in meta_items {
|
||||
match meta_item.name_or_empty() {
|
||||
sym::abi => {
|
||||
tcx.sess.span_err(
|
||||
tcx.def_span(item_def_id.to_def_id()),
|
||||
&format!("abi: {:?}", ty_layout.abi),
|
||||
);
|
||||
}
|
||||
|
||||
sym::align => {
|
||||
self.tcx
|
||||
.sess
|
||||
.span_err(item.span, &format!("align: {:?}", ty_layout.align));
|
||||
}
|
||||
sym::align => {
|
||||
tcx.sess.span_err(
|
||||
tcx.def_span(item_def_id.to_def_id()),
|
||||
&format!("align: {:?}", ty_layout.align),
|
||||
);
|
||||
}
|
||||
|
||||
sym::size => {
|
||||
self.tcx
|
||||
.sess
|
||||
.span_err(item.span, &format!("size: {:?}", ty_layout.size));
|
||||
}
|
||||
sym::size => {
|
||||
tcx.sess.span_err(
|
||||
tcx.def_span(item_def_id.to_def_id()),
|
||||
&format!("size: {:?}", ty_layout.size),
|
||||
);
|
||||
}
|
||||
|
||||
sym::homogeneous_aggregate => {
|
||||
self.tcx.sess.span_err(
|
||||
item.span,
|
||||
&format!(
|
||||
"homogeneous_aggregate: {:?}",
|
||||
ty_layout
|
||||
.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
|
||||
),
|
||||
);
|
||||
}
|
||||
sym::homogeneous_aggregate => {
|
||||
tcx.sess.span_err(
|
||||
tcx.def_span(item_def_id.to_def_id()),
|
||||
&format!(
|
||||
"homogeneous_aggregate: {:?}",
|
||||
ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
sym::debug => {
|
||||
let normalized_ty = self.tcx.normalize_erasing_regions(
|
||||
param_env.with_reveal_all_normalized(self.tcx),
|
||||
ty,
|
||||
);
|
||||
self.tcx.sess.span_err(
|
||||
item.span,
|
||||
&format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
|
||||
);
|
||||
}
|
||||
sym::debug => {
|
||||
let normalized_ty = tcx.normalize_erasing_regions(
|
||||
param_env.with_reveal_all_normalized(tcx),
|
||||
ty,
|
||||
);
|
||||
tcx.sess.span_err(
|
||||
tcx.def_span(item_def_id.to_def_id()),
|
||||
&format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout),
|
||||
);
|
||||
}
|
||||
|
||||
name => {
|
||||
self.tcx.sess.span_err(
|
||||
meta_item.span(),
|
||||
&format!("unrecognized field name `{}`", name),
|
||||
);
|
||||
}
|
||||
name => {
|
||||
tcx.sess.span_err(
|
||||
meta_item.span(),
|
||||
&format!("unrecognized field name `{}`", name),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(layout_error) => {
|
||||
self.tcx.sess.span_err(item.span, &format!("layout error: {:?}", layout_error));
|
||||
}
|
||||
Err(layout_error) => {
|
||||
tcx.sess.span_err(
|
||||
tcx.def_span(item_def_id.to_def_id()),
|
||||
&format!("layout error: {:?}", layout_error),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
|
|||
}
|
||||
|
||||
fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx).as_deep_visitor());
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx));
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
|
|
|
@ -31,9 +31,9 @@ struct CheckLoopVisitor<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
tcx.hir().visit_item_likes_in_module(
|
||||
tcx.hir().deep_visit_item_likes_in_module(
|
||||
module_def_id,
|
||||
&mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal }.as_deep_visitor(),
|
||||
&mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal },
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,10 +14,7 @@ use rustc_span::Span;
|
|||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
tcx.hir().visit_item_likes_in_module(
|
||||
module_def_id,
|
||||
&mut CheckNakedFunctions { tcx }.as_deep_visitor(),
|
||||
);
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx });
|
||||
}
|
||||
|
||||
crate fn provide(providers: &mut Providers) {
|
||||
|
|
|
@ -10,7 +10,6 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::Node;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
use rustc_middle::middle::privacy;
|
||||
|
@ -314,79 +313,60 @@ impl<'tcx> ReachableContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Some methods from non-exported (completely private) trait impls still have to be
|
||||
// reachable if they are called from inlinable code. Generally, it's not known until
|
||||
// monomorphization if a specific trait impl item can be reachable or not. So, we
|
||||
// conservatively mark all of them as reachable.
|
||||
// FIXME: One possible strategy for pruning the reachable set is to avoid marking impl
|
||||
// items of non-exported traits (or maybe all local traits?) unless their respective
|
||||
// trait items are used from inlinable code through method call syntax or UFCS, or their
|
||||
// trait is a lang item.
|
||||
struct CollectPrivateImplItemsVisitor<'a, 'tcx> {
|
||||
fn check_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
access_levels: &'a privacy::AccessLevels,
|
||||
worklist: &'a mut Vec<LocalDefId>,
|
||||
}
|
||||
id: hir::ItemId,
|
||||
worklist: &mut Vec<LocalDefId>,
|
||||
access_levels: &privacy::AccessLevels,
|
||||
) {
|
||||
if has_custom_linkage(tcx, id.def_id) {
|
||||
worklist.push(id.def_id);
|
||||
}
|
||||
|
||||
impl CollectPrivateImplItemsVisitor<'_, '_> {
|
||||
fn push_to_worklist_if_has_custom_linkage(&mut self, def_id: LocalDefId) {
|
||||
// Anything which has custom linkage gets thrown on the worklist no
|
||||
// matter where it is in the crate, along with "special std symbols"
|
||||
// which are currently akin to allocator symbols.
|
||||
if self.tcx.def_kind(def_id).has_codegen_attrs() {
|
||||
let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
|
||||
if codegen_attrs.contains_extern_indicator()
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
||||
// FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
|
||||
// `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
|
||||
// `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|
||||
{
|
||||
self.worklist.push(def_id);
|
||||
if !matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need only trait impls here, not inherent impls, and only non-exported ones
|
||||
let item = tcx.hir().item(id);
|
||||
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
|
||||
item.kind
|
||||
{
|
||||
if !access_levels.is_reachable(item.def_id) {
|
||||
// FIXME(#53488) remove `let`
|
||||
let tcx = tcx;
|
||||
worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
|
||||
|
||||
let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
if !trait_def_id.is_local() {
|
||||
return;
|
||||
}
|
||||
|
||||
worklist.extend(
|
||||
tcx.provided_trait_methods(trait_def_id).map(|assoc| assoc.def_id.expect_local()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item<'_>) {
|
||||
self.push_to_worklist_if_has_custom_linkage(item.def_id);
|
||||
|
||||
// We need only trait impls here, not inherent impls, and only non-exported ones
|
||||
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
|
||||
item.kind
|
||||
{
|
||||
if !self.access_levels.is_reachable(item.def_id) {
|
||||
// FIXME(#53488) remove `let`
|
||||
let tcx = self.tcx;
|
||||
self.worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
|
||||
|
||||
let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
if !trait_def_id.is_local() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.worklist.extend(
|
||||
tcx.provided_trait_methods(trait_def_id)
|
||||
.map(|assoc| assoc.def_id.expect_local()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
|
||||
|
||||
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
|
||||
self.push_to_worklist_if_has_custom_linkage(impl_item.def_id);
|
||||
}
|
||||
|
||||
fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {
|
||||
// We never export foreign functions as they have no body to export.
|
||||
fn has_custom_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
|
||||
// Anything which has custom linkage gets thrown on the worklist no
|
||||
// matter where it is in the crate, along with "special std symbols"
|
||||
// which are currently akin to allocator symbols.
|
||||
if !tcx.def_kind(def_id).has_codegen_attrs() {
|
||||
return false;
|
||||
}
|
||||
let codegen_attrs = tcx.codegen_fn_attrs(def_id);
|
||||
codegen_attrs.contains_extern_indicator()
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
||||
// FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
|
||||
// `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
|
||||
// `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
|
||||
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
|
||||
}
|
||||
|
||||
fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
|
||||
|
@ -418,12 +398,25 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
|
|||
}
|
||||
}
|
||||
{
|
||||
let mut collect_private_impl_items = CollectPrivateImplItemsVisitor {
|
||||
tcx,
|
||||
access_levels,
|
||||
worklist: &mut reachable_context.worklist,
|
||||
};
|
||||
tcx.hir().visit_all_item_likes(&mut collect_private_impl_items);
|
||||
// Some methods from non-exported (completely private) trait impls still have to be
|
||||
// reachable if they are called from inlinable code. Generally, it's not known until
|
||||
// monomorphization if a specific trait impl item can be reachable or not. So, we
|
||||
// conservatively mark all of them as reachable.
|
||||
// FIXME: One possible strategy for pruning the reachable set is to avoid marking impl
|
||||
// items of non-exported traits (or maybe all local traits?) unless their respective
|
||||
// trait items are used from inlinable code through method call syntax or UFCS, or their
|
||||
// trait is a lang item.
|
||||
let crate_items = tcx.hir_crate_items(());
|
||||
|
||||
for id in crate_items.items() {
|
||||
check_item(tcx, id, &mut reachable_context.worklist, access_levels);
|
||||
}
|
||||
|
||||
for id in crate_items.impl_items() {
|
||||
if has_custom_linkage(tcx, id.def_id) {
|
||||
reachable_context.worklist.push(id.def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Mark all symbols that the symbols on the worklist touch.
|
||||
|
|
|
@ -661,7 +661,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
|
|||
/// Cross-references the feature names of unstable APIs with enabled
|
||||
/// features and possibly prints errors.
|
||||
fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
|
||||
tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }.as_deep_visitor());
|
||||
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
|
@ -837,7 +837,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
|
|||
let mut missing = MissingStabilityAnnotations { tcx, access_levels };
|
||||
missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
|
||||
tcx.hir().walk_toplevel_module(&mut missing);
|
||||
tcx.hir().visit_all_item_likes(&mut missing.as_deep_visitor());
|
||||
tcx.hir().deep_visit_all_item_likes(&mut missing);
|
||||
}
|
||||
|
||||
let declared_lang_features = &tcx.features().declared_lang_features;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue