First of all, note that `Map` has three different relevant meanings. - The `intravisit::Map` trait. - The `map::Map` struct. - The `NestedFilter::Map` associated type. The `intravisit::Map` trait is impl'd twice. - For `!`, where the methods are all unreachable. - For `map::Map`, which gets HIR stuff from the `TyCtxt`. As part of getting rid of `map::Map`, this commit changes `impl intravisit::Map for map::Map` to `impl intravisit::Map for TyCtxt`. It's fairly straightforward except various things are renamed, because the existing names would no longer have made sense. - `trait intravisit::Map` becomes `trait intravisit::HirTyCtxt`, so named because it gets some HIR stuff from a `TyCtxt`. - `NestedFilter::Map` assoc type becomes `NestedFilter::MaybeTyCtxt`, because it's always `!` or `TyCtxt`. - `Visitor::nested_visit_map` becomes `Visitor::maybe_tcx`. I deliberately made the new trait and associated type names different to avoid the old `type Map: Map` situation, which I found confusing. We now have `type MaybeTyCtxt: HirTyCtxt`.
179 lines
6.8 KiB
Rust
179 lines
6.8 KiB
Rust
use rustc_hir as hir;
|
|
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
|
|
use rustc_hir::intravisit;
|
|
use rustc_middle::hir::nested_filter;
|
|
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
|
use rustc_span::sym;
|
|
|
|
pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
|
|
if !tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) {
|
|
return;
|
|
}
|
|
|
|
for id in tcx.hir_crate_items(()).opaques() {
|
|
if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
|
|
| hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } =
|
|
tcx.hir().expect_opaque_ty(id).origin
|
|
&& let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)
|
|
&& let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
|
|
{
|
|
continue;
|
|
}
|
|
|
|
let ty = tcx.type_of(id).instantiate_identity();
|
|
let span = tcx.def_span(id);
|
|
tcx.dcx().emit_err(crate::errors::TypeOf { span, ty });
|
|
}
|
|
}
|
|
|
|
pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) {
|
|
for id in tcx.hir_crate_items(()).owners() {
|
|
if tcx.has_attr(id, sym::rustc_dump_predicates) {
|
|
let preds = tcx.predicates_of(id).instantiate_identity(tcx).predicates;
|
|
let span = tcx.def_span(id);
|
|
|
|
let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_predicates.as_str());
|
|
for pred in preds {
|
|
diag.note(format!("{pred:?}"));
|
|
}
|
|
diag.emit();
|
|
}
|
|
if tcx.has_attr(id, sym::rustc_dump_item_bounds) {
|
|
let bounds = tcx.item_bounds(id).instantiate_identity();
|
|
let span = tcx.def_span(id);
|
|
|
|
let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_item_bounds.as_str());
|
|
for bound in bounds {
|
|
diag.note(format!("{bound:?}"));
|
|
}
|
|
diag.emit();
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
|
|
for iid in tcx.hir_free_items() {
|
|
let did = iid.owner_id.def_id;
|
|
if tcx.has_attr(did, sym::rustc_dump_def_parents) {
|
|
struct AnonConstFinder<'tcx> {
|
|
tcx: TyCtxt<'tcx>,
|
|
anon_consts: Vec<LocalDefId>,
|
|
}
|
|
|
|
impl<'tcx> intravisit::Visitor<'tcx> for AnonConstFinder<'tcx> {
|
|
type NestedFilter = nested_filter::All;
|
|
|
|
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
|
|
self.tcx
|
|
}
|
|
|
|
fn visit_anon_const(&mut self, c: &'tcx rustc_hir::AnonConst) {
|
|
self.anon_consts.push(c.def_id);
|
|
intravisit::walk_anon_const(self, c)
|
|
}
|
|
}
|
|
|
|
// Look for any anon consts inside of this item as there is no way to apply
|
|
// the `rustc_dump_def_parents` attribute to the anon const so it would not be possible
|
|
// to see what its def parent is.
|
|
let mut anon_ct_finder = AnonConstFinder { tcx, anon_consts: vec![] };
|
|
intravisit::walk_item(&mut anon_ct_finder, tcx.hir_item(iid));
|
|
|
|
for did in [did].into_iter().chain(anon_ct_finder.anon_consts) {
|
|
let span = tcx.def_span(did);
|
|
|
|
let mut diag = tcx.dcx().struct_span_err(
|
|
span,
|
|
format!("{}: {did:?}", sym::rustc_dump_def_parents.as_str()),
|
|
);
|
|
|
|
let mut current_did = did.to_def_id();
|
|
while let Some(parent_did) = tcx.opt_parent(current_did) {
|
|
current_did = parent_did;
|
|
diag.span_note(tcx.def_span(parent_did), format!("{parent_did:?}"));
|
|
}
|
|
diag.emit();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
|
|
for id in tcx.hir_free_items() {
|
|
let def_id = id.owner_id.def_id;
|
|
|
|
let Some(attr) = tcx.get_attr(def_id, sym::rustc_dump_vtable) else {
|
|
continue;
|
|
};
|
|
|
|
let vtable_entries = match tcx.hir_item(id).kind {
|
|
hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
|
|
let trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate_identity();
|
|
if trait_ref.has_non_region_param() {
|
|
tcx.dcx().span_err(
|
|
attr.span,
|
|
"`rustc_dump_vtable` must be applied to non-generic impl",
|
|
);
|
|
continue;
|
|
}
|
|
if !tcx.is_dyn_compatible(trait_ref.def_id) {
|
|
tcx.dcx().span_err(
|
|
attr.span,
|
|
"`rustc_dump_vtable` must be applied to dyn-compatible trait",
|
|
);
|
|
continue;
|
|
}
|
|
let Ok(trait_ref) = tcx
|
|
.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref)
|
|
else {
|
|
tcx.dcx().span_err(
|
|
attr.span,
|
|
"`rustc_dump_vtable` applied to impl header that cannot be normalized",
|
|
);
|
|
continue;
|
|
};
|
|
tcx.vtable_entries(trait_ref)
|
|
}
|
|
hir::ItemKind::TyAlias(_, _) => {
|
|
let ty = tcx.type_of(def_id).instantiate_identity();
|
|
if ty.has_non_region_param() {
|
|
tcx.dcx().span_err(
|
|
attr.span,
|
|
"`rustc_dump_vtable` must be applied to non-generic type",
|
|
);
|
|
continue;
|
|
}
|
|
let Ok(ty) =
|
|
tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty)
|
|
else {
|
|
tcx.dcx().span_err(
|
|
attr.span,
|
|
"`rustc_dump_vtable` applied to type alias that cannot be normalized",
|
|
);
|
|
continue;
|
|
};
|
|
let ty::Dynamic(data, _, _) = *ty.kind() else {
|
|
tcx.dcx().span_err(attr.span, "`rustc_dump_vtable` to type alias of dyn type");
|
|
continue;
|
|
};
|
|
if let Some(principal) = data.principal() {
|
|
tcx.vtable_entries(
|
|
tcx.instantiate_bound_regions_with_erased(principal).with_self_ty(tcx, ty),
|
|
)
|
|
} else {
|
|
TyCtxt::COMMON_VTABLE_ENTRIES
|
|
}
|
|
}
|
|
_ => {
|
|
tcx.dcx().span_err(
|
|
attr.span,
|
|
"`rustc_dump_vtable` only applies to impl, or type alias of dyn type",
|
|
);
|
|
continue;
|
|
}
|
|
};
|
|
|
|
tcx.dcx().span_err(tcx.def_span(def_id), format!("vtable entries: {vtable_entries:#?}"));
|
|
}
|
|
}
|