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