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