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 }
378 AssertMessage::MisalignedPointerDereference { required, found } => {
379 self.visit_operand(required, location);
380 self.visit_operand(found, location);
381 }
382 }
383 }
384 }
385 };
386}
387
388macro_rules! super_body {
389 ($self:ident, $body:ident, mut) => {
390 for bb in $body.blocks.iter_mut() {
391 $self.visit_basic_block(bb);
392 }
393
394 $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local_mut());
395
396 for (idx, arg) in $body.arg_locals_mut().iter_mut().enumerate() {
397 $self.visit_arg_decl(idx + 1, arg)
398 }
399
400 let local_start = $body.arg_count + 1;
401 for (idx, arg) in $body.inner_locals_mut().iter_mut().enumerate() {
402 $self.visit_local_decl(idx + local_start, arg)
403 }
404
405 for info in $body.var_debug_info.iter_mut() {
406 $self.visit_var_debug_info(info);
407 }
408
409 $self.visit_span(&mut $body.span)
410 };
411
412 ($self:ident, $body:ident, ) => {
413 let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _, span } = $body;
414
415 for bb in blocks {
416 $self.visit_basic_block(bb);
417 }
418
419 $self.visit_ret_decl(RETURN_LOCAL, $body.ret_local());
420
421 for (idx, arg) in $body.arg_locals().iter().enumerate() {
422 $self.visit_arg_decl(idx + 1, arg)
423 }
424
425 let local_start = arg_count + 1;
426 for (idx, arg) in $body.inner_locals().iter().enumerate() {
427 $self.visit_local_decl(idx + local_start, arg)
428 }
429
430 for info in var_debug_info.iter() {
431 $self.visit_var_debug_info(info);
432 }
433
434 $self.visit_span(span)
435 };
436}
437
438macro_rules! visit_place_fns {
439 (mut) => {
440 fn super_place(&mut self, place: &mut Place, ptx: PlaceContext, location: Location) {
441 self.visit_local(&mut place.local, ptx, location);
442
443 for elem in place.projection.iter_mut() {
444 self.visit_projection_elem(elem, ptx, location);
445 }
446 }
447
448 fn visit_projection_elem(
452 &mut self,
453 elem: &mut ProjectionElem,
454 ptx: PlaceContext,
455 location: Location,
456 ) {
457 self.super_projection_elem(elem, ptx, location)
458 }
459
460 fn super_projection_elem(
461 &mut self,
462 elem: &mut ProjectionElem,
463 ptx: PlaceContext,
464 location: Location,
465 ) {
466 match elem {
467 ProjectionElem::Deref => {}
468 ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
469 ProjectionElem::Index(local) => self.visit_local(local, ptx, location),
470 ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {}
471 ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
472 ProjectionElem::Downcast(_idx) => {}
473 ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
474 ProjectionElem::Subtype(ty) => self.visit_ty(ty, location),
475 }
476 }
477 };
478
479 () => {
480 fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) {
481 self.visit_local(&place.local, ptx, location);
482
483 for (idx, elem) in place.projection.iter().enumerate() {
484 let place_ref =
485 PlaceRef { local: place.local, projection: &place.projection[..idx] };
486 self.visit_projection_elem(place_ref, elem, ptx, location);
487 }
488 }
489
490 fn visit_projection_elem<'a>(
491 &mut self,
492 place_ref: PlaceRef<'a>,
493 elem: &ProjectionElem,
494 ptx: PlaceContext,
495 location: Location,
496 ) {
497 let _ = place_ref;
498 self.super_projection_elem(elem, ptx, location);
499 }
500
501 fn super_projection_elem(
502 &mut self,
503 elem: &ProjectionElem,
504 ptx: PlaceContext,
505 location: Location,
506 ) {
507 match elem {
508 ProjectionElem::Deref => {}
509 ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
510 ProjectionElem::Index(local) => self.visit_local(local, ptx, location),
511 ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {}
512 ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
513 ProjectionElem::Downcast(_idx) => {}
514 ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
515 ProjectionElem::Subtype(ty) => self.visit_ty(ty, location),
516 }
517 }
518 };
519}
520
521make_mir_visitor!(MirVisitor,);
522make_mir_visitor!(MutMirVisitor, mut);
523
524fn visit_opaque(_: &Opaque) {}
532
533#[derive(Clone, Copy, PartialEq, Eq, Debug)]
535pub struct Location(Span);
536
537impl Location {
538 pub fn span(&self) -> Span {
539 self.0
540 }
541}
542
543pub fn statement_location(body: &Body, bb_idx: &BasicBlockIdx, stmt_idx: usize) -> Location {
546 let bb = &body.blocks[*bb_idx];
547 let stmt = &bb.statements[stmt_idx];
548 Location(stmt.span)
549}
550
551pub fn terminator_location(body: &Body, bb_idx: &BasicBlockIdx) -> Location {
554 let bb = &body.blocks[*bb_idx];
555 let terminator = &bb.terminator;
556 Location(terminator.span)
557}
558
559pub struct PlaceRef<'a> {
561 pub local: Local,
562 pub projection: &'a [ProjectionElem],
563}
564
565impl PlaceRef<'_> {
566 pub fn ty(&self, locals: &[LocalDecl]) -> Result<Ty, Error> {
568 self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty))
569 }
570}
571
572#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
574pub struct PlaceContext {
575 is_mut: bool,
578}
579
580impl PlaceContext {
581 const MUTATING: Self = PlaceContext { is_mut: true };
582 const NON_MUTATING: Self = PlaceContext { is_mut: false };
583 const NON_USE: Self = PlaceContext { is_mut: false };
584
585 pub fn is_mutating(&self) -> bool {
586 self.is_mut
587 }
588}