1use crate::mir::*;
39use crate::ty::{GenericArgs, MirConst, Region, Ty, TyConst};
40use crate::{Error, Opaque, Span};
41
42pub trait MirVisitor {
43 fn visit_body(&mut self, body: &Body) {
44 self.super_body(body)
45 }
46
47 fn visit_basic_block(&mut self, bb: &BasicBlock) {
48 self.super_basic_block(bb)
49 }
50
51 fn visit_ret_decl(&mut self, local: Local, decl: &LocalDecl) {
52 self.super_ret_decl(local, decl)
53 }
54
55 fn visit_arg_decl(&mut self, local: Local, decl: &LocalDecl) {
56 self.super_arg_decl(local, decl)
57 }
58
59 fn visit_local_decl(&mut self, local: Local, decl: &LocalDecl) {
60 self.super_local_decl(local, decl)
61 }
62
63 fn visit_statement(&mut self, stmt: &Statement, location: Location) {
64 self.super_statement(stmt, location)
65 }
66
67 fn visit_terminator(&mut self, term: &Terminator, location: Location) {
68 self.super_terminator(term, location)
69 }
70
71 fn visit_span(&mut self, span: &Span) {
72 self.super_span(span)
73 }
74
75 fn visit_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) {
76 self.super_place(place, ptx, location)
77 }
78
79 fn visit_projection_elem(
80 &mut self,
81 place_ref: PlaceRef<'_>,
82 elem: &ProjectionElem,
83 ptx: PlaceContext,
84 location: Location,
85 ) {
86 let _ = place_ref;
87 self.super_projection_elem(elem, ptx, location);
88 }
89
90 fn visit_local(&mut self, local: &Local, ptx: PlaceContext, location: Location) {
91 let _ = (local, ptx, location);
92 }
93
94 fn visit_rvalue(&mut self, rvalue: &Rvalue, location: Location) {
95 self.super_rvalue(rvalue, location)
96 }
97
98 fn visit_operand(&mut self, operand: &Operand, location: Location) {
99 self.super_operand(operand, location)
100 }
101
102 fn visit_user_type_projection(&mut self, projection: &UserTypeProjection) {
103 self.super_user_type_projection(projection)
104 }
105
106 fn visit_ty(&mut self, ty: &Ty, location: Location) {
107 let _ = location;
108 self.super_ty(ty)
109 }
110
111 fn visit_const_operand(&mut self, constant: &ConstOperand, location: Location) {
112 self.super_const_operand(constant, location)
113 }
114
115 fn visit_mir_const(&mut self, constant: &MirConst, location: Location) {
116 self.super_mir_const(constant, location)
117 }
118
119 fn visit_ty_const(&mut self, constant: &TyConst, location: Location) {
120 let _ = location;
121 self.super_ty_const(constant)
122 }
123
124 fn visit_region(&mut self, region: &Region, location: Location) {
125 let _ = location;
126 self.super_region(region)
127 }
128
129 fn visit_args(&mut self, args: &GenericArgs, location: Location) {
130 let _ = location;
131 self.super_args(args)
132 }
133
134 fn visit_assert_msg(&mut self, msg: &AssertMessage, location: Location) {
135 self.super_assert_msg(msg, location)
136 }
137
138 fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo) {
139 self.super_var_debug_info(var_debug_info);
140 }
141
142 fn super_body(&mut self, body: &Body) {
143 let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _, span } = body;
144
145 for bb in blocks {
146 self.visit_basic_block(bb);
147 }
148
149 self.visit_ret_decl(RETURN_LOCAL, body.ret_local());
150
151 for (idx, arg) in body.arg_locals().iter().enumerate() {
152 self.visit_arg_decl(idx + 1, arg)
153 }
154
155 let local_start = arg_count + 1;
156 for (idx, arg) in body.inner_locals().iter().enumerate() {
157 self.visit_local_decl(idx + local_start, arg)
158 }
159
160 for info in var_debug_info.iter() {
161 self.visit_var_debug_info(info);
162 }
163
164 self.visit_span(span)
165 }
166
167 fn super_basic_block(&mut self, bb: &BasicBlock) {
168 let BasicBlock { statements, terminator } = bb;
169 for stmt in statements {
170 self.visit_statement(stmt, Location(stmt.span));
171 }
172 self.visit_terminator(terminator, Location(terminator.span));
173 }
174
175 fn super_local_decl(&mut self, local: Local, decl: &LocalDecl) {
176 let _ = local;
177 let LocalDecl { ty, span, .. } = decl;
178 self.visit_ty(ty, Location(*span));
179 }
180
181 fn super_ret_decl(&mut self, local: Local, decl: &LocalDecl) {
182 self.super_local_decl(local, decl)
183 }
184
185 fn super_arg_decl(&mut self, local: Local, decl: &LocalDecl) {
186 self.super_local_decl(local, decl)
187 }
188
189 fn super_statement(&mut self, stmt: &Statement, location: Location) {
190 let Statement { kind, span } = stmt;
191 self.visit_span(span);
192 match kind {
193 StatementKind::Assign(place, rvalue) => {
194 self.visit_place(place, PlaceContext::MUTATING, location);
195 self.visit_rvalue(rvalue, location);
196 }
197 StatementKind::FakeRead(_, place) | StatementKind::PlaceMention(place) => {
198 self.visit_place(place, PlaceContext::NON_MUTATING, location);
199 }
200 StatementKind::SetDiscriminant { place, .. }
201 | StatementKind::Deinit(place)
202 | StatementKind::Retag(_, place) => {
203 self.visit_place(place, PlaceContext::MUTATING, location);
204 }
205 StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
206 self.visit_local(local, PlaceContext::NON_USE, location);
207 }
208 StatementKind::AscribeUserType { place, projections, variance: _ } => {
209 self.visit_place(place, PlaceContext::NON_USE, location);
210 self.visit_user_type_projection(projections);
211 }
212 StatementKind::Coverage(coverage) => visit_opaque(coverage),
213 StatementKind::Intrinsic(intrisic) => match intrisic {
214 NonDivergingIntrinsic::Assume(operand) => {
215 self.visit_operand(operand, location);
216 }
217 NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
218 src,
219 dst,
220 count,
221 }) => {
222 self.visit_operand(src, location);
223 self.visit_operand(dst, location);
224 self.visit_operand(count, location);
225 }
226 },
227 StatementKind::ConstEvalCounter | StatementKind::Nop => {}
228 }
229 }
230
231 fn super_terminator(&mut self, term: &Terminator, location: Location) {
232 let Terminator { kind, span } = term;
233 self.visit_span(span);
234 match kind {
235 TerminatorKind::Goto { .. }
236 | TerminatorKind::Resume
237 | TerminatorKind::Abort
238 | TerminatorKind::Unreachable => {}
239 TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
240 self.visit_operand(cond, location);
241 self.visit_assert_msg(msg, location);
242 }
243 TerminatorKind::Drop { place, target: _, unwind: _ } => {
244 self.visit_place(place, PlaceContext::MUTATING, location);
245 }
246 TerminatorKind::Call { func, args, destination, target: _, unwind: _ } => {
247 self.visit_operand(func, location);
248 for arg in args {
249 self.visit_operand(arg, location);
250 }
251 self.visit_place(destination, PlaceContext::MUTATING, location);
252 }
253 TerminatorKind::InlineAsm { operands, .. } => {
254 for op in operands {
255 let InlineAsmOperand { in_value, out_place, raw_rpr: _ } = op;
256 if let Some(input) = in_value {
257 self.visit_operand(input, location);
258 }
259 if let Some(output) = out_place {
260 self.visit_place(output, PlaceContext::MUTATING, location);
261 }
262 }
263 }
264 TerminatorKind::Return => {
265 let local = RETURN_LOCAL;
266 self.visit_local(&local, PlaceContext::NON_MUTATING, location);
267 }
268 TerminatorKind::SwitchInt { discr, targets: _ } => {
269 self.visit_operand(discr, location);
270 }
271 }
272 }
273
274 fn super_span(&mut self, span: &Span) {
275 let _ = span;
276 }
277
278 fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) {
279 let _ = location;
280 let _ = ptx;
281 self.visit_local(&place.local, ptx, location);
282
283 for (idx, elem) in place.projection.iter().enumerate() {
284 let place_ref = PlaceRef { local: place.local, projection: &place.projection[..idx] };
285 self.visit_projection_elem(place_ref, elem, ptx, location);
286 }
287 }
288
289 fn super_projection_elem(
290 &mut self,
291 elem: &ProjectionElem,
292 ptx: PlaceContext,
293 location: Location,
294 ) {
295 match elem {
296 ProjectionElem::Downcast(_idx) => {}
297 ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ }
298 | ProjectionElem::Deref
299 | ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
300 ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
301 ProjectionElem::Index(local) => self.visit_local(local, ptx, location),
302 ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => {
303 self.visit_ty(ty, location)
304 }
305 }
306 }
307
308 fn super_rvalue(&mut self, rvalue: &Rvalue, location: Location) {
309 match rvalue {
310 Rvalue::AddressOf(mutability, place) => {
311 let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut };
312 self.visit_place(place, pcx, location);
313 }
314 Rvalue::Aggregate(_, operands) => {
315 for op in operands {
316 self.visit_operand(op, location);
317 }
318 }
319 Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
320 self.visit_operand(lhs, location);
321 self.visit_operand(rhs, location);
322 }
323 Rvalue::Cast(_, op, ty) => {
324 self.visit_operand(op, location);
325 self.visit_ty(ty, location);
326 }
327 Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) | Rvalue::Len(place) => {
328 self.visit_place(place, PlaceContext::NON_MUTATING, location);
329 }
330 Rvalue::Ref(region, kind, place) => {
331 self.visit_region(region, location);
332 let pcx = PlaceContext { is_mut: matches!(kind, BorrowKind::Mut { .. }) };
333 self.visit_place(place, pcx, location);
334 }
335 Rvalue::Repeat(op, constant) => {
336 self.visit_operand(op, location);
337 self.visit_ty_const(constant, location);
338 }
339 Rvalue::ShallowInitBox(op, ty) => {
340 self.visit_ty(ty, location);
341 self.visit_operand(op, location)
342 }
343 Rvalue::ThreadLocalRef(_) => {}
344 Rvalue::NullaryOp(_, ty) => {
345 self.visit_ty(ty, location);
346 }
347 Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => {
348 self.visit_operand(op, location);
349 }
350 }
351 }
352
353 fn super_operand(&mut self, operand: &Operand, location: Location) {
354 match operand {
355 Operand::Copy(place) | Operand::Move(place) => {
356 self.visit_place(place, PlaceContext::NON_MUTATING, location)
357 }
358 Operand::Constant(constant) => {
359 self.visit_const_operand(constant, location);
360 }
361 }
362 }
363
364 fn super_user_type_projection(&mut self, projection: &UserTypeProjection) {
365 let _ = projection;
367 }
368
369 fn super_ty(&mut self, ty: &Ty) {
370 let _ = ty;
371 }
372
373 fn super_const_operand(&mut self, constant: &ConstOperand, location: Location) {
374 let ConstOperand { span, user_ty: _, const_ } = constant;
375 self.visit_span(span);
376 self.visit_mir_const(const_, location);
377 }
378
379 fn super_mir_const(&mut self, constant: &MirConst, location: Location) {
380 let MirConst { kind: _, ty, id: _ } = constant;
381 self.visit_ty(ty, location);
382 }
383
384 fn super_ty_const(&mut self, constant: &TyConst) {
385 let _ = constant;
386 }
387
388 fn super_region(&mut self, region: &Region) {
389 let _ = region;
390 }
391
392 fn super_args(&mut self, args: &GenericArgs) {
393 let _ = args;
394 }
395
396 fn super_var_debug_info(&mut self, var_debug_info: &VarDebugInfo) {
397 let VarDebugInfo { source_info, composite, value, name: _, argument_index: _ } =
398 var_debug_info;
399 self.visit_span(&source_info.span);
400 let location = Location(source_info.span);
401 if let Some(composite) = composite {
402 self.visit_ty(&composite.ty, location);
403 }
404 match value {
405 VarDebugInfoContents::Place(place) => {
406 self.visit_place(place, PlaceContext::NON_USE, location);
407 }
408 VarDebugInfoContents::Const(constant) => {
409 self.visit_mir_const(&constant.const_, location);
410 }
411 }
412 }
413
414 fn super_assert_msg(&mut self, msg: &AssertMessage, location: Location) {
415 match msg {
416 AssertMessage::BoundsCheck { len, index } => {
417 self.visit_operand(len, location);
418 self.visit_operand(index, location);
419 }
420 AssertMessage::Overflow(_, left, right) => {
421 self.visit_operand(left, location);
422 self.visit_operand(right, location);
423 }
424 AssertMessage::OverflowNeg(op)
425 | AssertMessage::DivisionByZero(op)
426 | AssertMessage::RemainderByZero(op) => {
427 self.visit_operand(op, location);
428 }
429 AssertMessage::ResumedAfterReturn(_)
430 | AssertMessage::ResumedAfterPanic(_)
431 | AssertMessage::NullPointerDereference => {
432 }
434 AssertMessage::MisalignedPointerDereference { required, found } => {
435 self.visit_operand(required, location);
436 self.visit_operand(found, location);
437 }
438 }
439 }
440}
441
442fn visit_opaque(_: &Opaque) {}
450
451#[derive(Clone, Copy, PartialEq, Eq, Debug)]
453pub struct Location(Span);
454
455impl Location {
456 pub fn span(&self) -> Span {
457 self.0
458 }
459}
460
461pub fn statement_location(body: &Body, bb_idx: &BasicBlockIdx, stmt_idx: usize) -> Location {
464 let bb = &body.blocks[*bb_idx];
465 let stmt = &bb.statements[stmt_idx];
466 Location(stmt.span)
467}
468
469pub fn terminator_location(body: &Body, bb_idx: &BasicBlockIdx) -> Location {
472 let bb = &body.blocks[*bb_idx];
473 let terminator = &bb.terminator;
474 Location(terminator.span)
475}
476
477pub struct PlaceRef<'a> {
479 pub local: Local,
480 pub projection: &'a [ProjectionElem],
481}
482
483impl PlaceRef<'_> {
484 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
486 self.projection.iter().fold(Ok(locals[self.local].ty), |place_ty, elem| elem.ty(place_ty?))
487 }
488}
489
490#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
492pub struct PlaceContext {
493 is_mut: bool,
496}
497
498impl PlaceContext {
499 const MUTATING: Self = PlaceContext { is_mut: true };
500 const NON_MUTATING: Self = PlaceContext { is_mut: false };
501 const NON_USE: Self = PlaceContext { is_mut: false };
502
503 pub fn is_mutating(&self) -> bool {
504 self.is_mut
505 }
506}