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