rustc_mir_transform/
mentioned_items.rs1use rustc_middle::mir::visit::Visitor;
2use rustc_middle::mir::{self, Location, MentionedItem};
3use rustc_middle::ty::adjustment::PointerCoercion;
4use rustc_middle::ty::{self, TyCtxt};
5use rustc_session::Session;
6use rustc_span::Spanned;
7
8use crate::PassPolicy;
9
10pub(super) struct MentionedItems;
11
12struct MentionedItemsVisitor<'a, 'tcx> {
13 tcx: TyCtxt<'tcx>,
14 body: &'a mir::Body<'tcx>,
15 mentioned_items: Vec<Spanned<MentionedItem<'tcx>>>,
16}
17
18impl<'tcx> crate::MirPass<'tcx> for MentionedItems {
19 fn policy(&self, _sess: &Session) -> PassPolicy {
20 PassPolicy::Required
25 }
26
27 fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
28 let mut visitor = MentionedItemsVisitor { tcx, body, mentioned_items: Vec::new() };
29 visitor.visit_body(body);
30 body.set_mentioned_items(visitor.mentioned_items);
31 }
32}
33
34impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> {
39 fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
40 self.super_terminator(terminator, location);
41 let span = || self.body.source_info(location).span;
42 match &terminator.kind {
43 mir::TerminatorKind::Call { func, .. } | mir::TerminatorKind::TailCall { func, .. } => {
44 let callee_ty = func.ty(self.body, self.tcx);
45 self.mentioned_items
46 .push(Spanned { node: MentionedItem::Fn(callee_ty), span: span() });
47 }
48 mir::TerminatorKind::Drop { place, .. } => {
49 let ty = place.ty(self.body, self.tcx).ty;
50 self.mentioned_items.push(Spanned { node: MentionedItem::Drop(ty), span: span() });
51 }
52 mir::TerminatorKind::InlineAsm { operands, .. } => {
53 for op in operands {
54 match *op {
55 mir::InlineAsmOperand::SymFn { ref value } => {
56 self.mentioned_items.push(Spanned {
57 node: MentionedItem::Fn(value.const_.ty()),
58 span: span(),
59 });
60 }
61 _ => {}
62 }
63 }
64 }
65 _ => {}
66 }
67 }
68
69 fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
70 self.super_rvalue(rvalue, location);
71 let span = || self.body.source_info(location).span;
72 match *rvalue {
73 mir::Rvalue::Cast(
75 mir::CastKind::PointerCoercion(PointerCoercion::Unsize, _),
76 ref operand,
77 target_ty,
78 ) => {
79 let source_ty = operand.ty(self.body, self.tcx);
82 let may_involve_vtable = match (
83 source_ty.builtin_deref(true).map(|t| t.kind()),
84 target_ty.builtin_deref(true).map(|t| t.kind()),
85 ) {
86 (Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false,
88
89 _ => true,
90 };
91 if may_involve_vtable {
92 self.mentioned_items.push(Spanned {
93 node: MentionedItem::UnsizeCast { source_ty, target_ty },
94 span: span(),
95 });
96 }
97 }
98 mir::Rvalue::Cast(
100 mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _),
101 ref operand,
102 _,
103 ) => {
104 let source_ty = operand.ty(self.body, self.tcx);
105 self.mentioned_items
106 .push(Spanned { node: MentionedItem::Closure(source_ty), span: span() });
107 }
108 mir::Rvalue::Cast(
110 mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer(_), _),
111 ref operand,
112 _,
113 ) => {
114 let fn_ty = operand.ty(self.body, self.tcx);
115 self.mentioned_items.push(Spanned { node: MentionedItem::Fn(fn_ty), span: span() });
116 }
117 _ => {}
118 }
119 }
120}