rust/compiler/rustc_mir_transform/src/mentioned_items.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

111 lines
4.7 KiB
Rust
Raw Normal View History

use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{self, Location, MentionedItem, MirPass};
use rustc_middle::ty::{adjustment::PointerCoercion, TyCtxt};
use rustc_session::Session;
use rustc_span::source_map::Spanned;
pub struct MentionedItems;
struct MentionedItemsVisitor<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
body: &'a mir::Body<'tcx>,
mentioned_items: &'a mut Vec<Spanned<MentionedItem<'tcx>>>,
}
impl<'tcx> MirPass<'tcx> for MentionedItems {
fn is_enabled(&self, _sess: &Session) -> bool {
// If this pass is skipped the collector assume that nothing got mentioned! We could
// potentially skip it in opt-level 0 if we are sure that opt-level will never *remove* uses
// of anything, but that still seems fragile. Furthermore, even debug builds use level 1, so
// special-casing level 0 is just not worth it.
true
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
debug_assert!(body.mentioned_items.is_empty());
let mut mentioned_items = Vec::new();
MentionedItemsVisitor { tcx, body, mentioned_items: &mut mentioned_items }.visit_body(body);
body.mentioned_items = mentioned_items;
}
}
// This visitor is carefully in sync with the one in `rustc_monomorphize::collector`. We are
// visiting the exact same places but then instead of monomorphizing and creating `MonoItems`, we
// have to remain generic and just recording the relevant information in `mentioned_items`, where it
// will then be monomorphized later during "mentioned items" collection.
impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
self.super_terminator(terminator, location);
let span = || self.body.source_info(location).span;
match &terminator.kind {
mir::TerminatorKind::Call { func, .. } => {
let callee_ty = func.ty(self.body, self.tcx);
self.mentioned_items
.push(Spanned { node: MentionedItem::Fn(callee_ty), span: span() });
}
mir::TerminatorKind::Drop { place, .. } => {
let ty = place.ty(self.body, self.tcx).ty;
self.mentioned_items.push(Spanned { node: MentionedItem::Drop(ty), span: span() });
}
mir::TerminatorKind::InlineAsm { ref operands, .. } => {
for op in operands {
match *op {
mir::InlineAsmOperand::SymFn { ref value } => {
self.mentioned_items.push(Spanned {
node: MentionedItem::Fn(value.const_.ty()),
span: span(),
});
}
_ => {}
}
}
}
_ => {}
}
}
2024-03-17 13:28:31 +01:00
fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
self.super_rvalue(rvalue, location);
let span = || self.body.source_info(location).span;
2024-03-17 13:28:31 +01:00
match *rvalue {
// We need to detect unsizing casts that required vtables.
mir::Rvalue::Cast(
mir::CastKind::PointerCoercion(PointerCoercion::Unsize),
ref operand,
target_ty,
)
| mir::Rvalue::Cast(mir::CastKind::DynStar, ref operand, target_ty) => {
// This isn't monomorphized yet so we can't tell what the actual types are -- just
// add everything.
2024-03-17 13:28:31 +01:00
self.mentioned_items.push(Spanned {
node: MentionedItem::UnsizeCast {
source_ty: operand.ty(self.body, self.tcx),
target_ty,
},
span: span(),
2024-03-17 13:28:31 +01:00
});
}
// Similarly, record closures that are turned into function pointers.
mir::Rvalue::Cast(
mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_)),
ref operand,
_,
) => {
let source_ty = operand.ty(self.body, self.tcx);
self.mentioned_items
.push(Spanned { node: MentionedItem::Closure(source_ty), span: span() });
}
// And finally, function pointer reification casts.
mir::Rvalue::Cast(
mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer),
ref operand,
_,
) => {
let fn_ty = operand.ty(self.body, self.tcx);
self.mentioned_items.push(Spanned { node: MentionedItem::Fn(fn_ty), span: span() });
}
2024-03-17 13:28:31 +01:00
_ => {}
}
}
}