rustc_mir_transform/
mentioned_items.rs
1use 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 { ref 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 | mir::CastKind::PointerCoercion(PointerCoercion::DynStar, _),
79 ref operand,
80 target_ty,
81 ) => {
82 let source_ty = operand.ty(self.body, self.tcx);
85 let may_involve_vtable = match (
86 source_ty.builtin_deref(true).map(|t| t.kind()),
87 target_ty.builtin_deref(true).map(|t| t.kind()),
88 ) {
89 (Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false,
91
92 _ => true,
93 };
94 if may_involve_vtable {
95 self.mentioned_items.push(Spanned {
96 node: MentionedItem::UnsizeCast { source_ty, target_ty },
97 span: span(),
98 });
99 }
100 }
101 mir::Rvalue::Cast(
103 mir::CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(_), _),
104 ref operand,
105 _,
106 ) => {
107 let source_ty = operand.ty(self.body, self.tcx);
108 self.mentioned_items
109 .push(Spanned { node: MentionedItem::Closure(source_ty), span: span() });
110 }
111 mir::Rvalue::Cast(
113 mir::CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, _),
114 ref operand,
115 _,
116 ) => {
117 let fn_ty = operand.ty(self.body, self.tcx);
118 self.mentioned_items.push(Spanned { node: MentionedItem::Fn(fn_ty), span: span() });
119 }
120 _ => {}
121 }
122 }
123}